@simplysm/sd-claude 14.0.65 → 14.0.68
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/claude/references/sd-requirement-source-handling.md +64 -0
- package/claude/references/sd-simplysm14/README.md +44 -40
- package/claude/references/sd-simplysm14/apis/angular/README.md +95 -0
- package/claude/references/sd-simplysm14/apis/angular/app-structure.md +49 -0
- package/claude/references/sd-simplysm14/apis/angular/buttons.md +42 -0
- package/claude/references/sd-simplysm14/apis/angular/crud.md +35 -0
- package/claude/references/sd-simplysm14/apis/angular/forms.md +63 -0
- package/claude/references/sd-simplysm14/apis/angular/infrastructure.md +80 -0
- package/claude/references/sd-simplysm14/apis/angular/kanban.md +33 -0
- package/claude/references/sd-simplysm14/apis/angular/layout.md +41 -0
- package/claude/references/sd-simplysm14/apis/angular/modal.md +63 -0
- package/claude/references/sd-simplysm14/apis/angular/routing.md +45 -0
- package/claude/references/sd-simplysm14/apis/angular/select-dropdown.md +35 -0
- package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +50 -0
- package/claude/references/sd-simplysm14/apis/angular/shared-data.md +42 -0
- package/claude/references/sd-simplysm14/apis/angular/sheet.md +52 -0
- package/claude/references/sd-simplysm14/apis/angular/toast.md +46 -0
- package/claude/references/sd-simplysm14/apis/angular/visual.md +41 -0
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +76 -0
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +83 -0
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +80 -0
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +39 -0
- package/claude/references/sd-simplysm14/apis/core-browser/README.md +112 -0
- package/claude/references/sd-simplysm14/apis/core-common/README.md +53 -0
- package/claude/references/sd-simplysm14/apis/core-common/extensions.md +123 -0
- package/claude/references/sd-simplysm14/apis/core-common/features.md +46 -0
- package/claude/references/sd-simplysm14/apis/core-common/types.md +114 -0
- package/claude/references/sd-simplysm14/apis/core-common/utils.md +158 -0
- package/claude/references/sd-simplysm14/apis/core-node/README.md +12 -0
- package/claude/references/sd-simplysm14/apis/core-node/consola.md +64 -0
- package/claude/references/sd-simplysm14/apis/core-node/cpx.md +52 -0
- package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +53 -0
- package/claude/references/sd-simplysm14/apis/core-node/fsx.md +81 -0
- package/claude/references/sd-simplysm14/apis/core-node/pathx.md +55 -0
- package/claude/references/sd-simplysm14/apis/core-node/worker.md +111 -0
- package/claude/references/sd-simplysm14/apis/excel/README.md +81 -0
- package/claude/references/sd-simplysm14/apis/lint/README.md +80 -0
- package/claude/references/sd-simplysm14/apis/orm-common/README.md +33 -0
- package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +77 -0
- package/claude/references/sd-simplysm14/apis/orm-common/executable.md +20 -0
- package/claude/references/sd-simplysm14/apis/orm-common/expr.md +92 -0
- package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +98 -0
- package/claude/references/sd-simplysm14/apis/orm-common/schema-builders.md +128 -0
- package/claude/references/sd-simplysm14/apis/orm-node/README.md +59 -0
- package/claude/references/sd-simplysm14/apis/sd-claude/README.md +9 -0
- package/claude/references/sd-simplysm14/apis/sd-cli/README.md +50 -0
- package/claude/references/sd-simplysm14/apis/sd-cli/sd-config.md +155 -0
- package/claude/references/sd-simplysm14/apis/service-client/README.md +92 -0
- package/claude/references/sd-simplysm14/apis/service-common/README.md +29 -0
- package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +63 -0
- package/claude/references/sd-simplysm14/apis/service-common/messages.md +56 -0
- package/claude/references/sd-simplysm14/apis/service-common/protocol.md +64 -0
- package/claude/references/sd-simplysm14/apis/service-common/service-types.md +43 -0
- package/claude/references/sd-simplysm14/apis/service-server/README.md +20 -0
- package/claude/references/sd-simplysm14/apis/service-server/auth.md +31 -0
- package/claude/references/sd-simplysm14/apis/service-server/builtin-services.md +47 -0
- package/claude/references/sd-simplysm14/apis/service-server/define-service.md +71 -0
- package/claude/references/sd-simplysm14/apis/service-server/internals.md +41 -0
- package/claude/references/sd-simplysm14/apis/service-server/server.md +66 -0
- package/claude/references/sd-simplysm14/apis/storage/README.md +69 -0
- package/claude/references/sd-simplysm14/{client-component.md → manuals/client-component.md} +134 -128
- package/claude/references/sd-simplysm14/manuals/client-crud.md +102 -0
- package/claude/references/sd-simplysm14/manuals/client-demo.md +128 -0
- package/claude/references/sd-simplysm14/manuals/client-rules.md +7 -0
- package/claude/references/sd-simplysm14/{client-setup.md → manuals/client-setup.md} +2 -2
- package/claude/references/sd-simplysm14/{client-tab.md → manuals/client-tab.md} +13 -11
- package/claude/references/sd-simplysm14/{orm-union.md → manuals/orm-union.md} +1 -1
- package/claude/references/sd-simplysm14/manuals/orm.md +75 -0
- package/claude/rules/sd-base-rules.md +191 -79
- package/claude/scripts/sd_paths.py +22 -0
- package/claude/sd-check-bash.py +19 -0
- package/claude/sd-statusline.py +7 -12
- package/claude/skills/sd-commit/SKILL.md +8 -3
- package/claude/skills/sd-demo/SKILL.md +103 -62
- package/claude/skills/sd-demo/evals/fixtures/empty/.specs/260513120000_warehouse/spec.md +45 -0
- package/claude/skills/sd-demo/evals/fixtures/with-existing-screen/.specs/260513120000_warehouse/spec.md +42 -0
- package/claude/skills/sd-demo/evals/fixtures/with-existing-screen/packages/app/src/screens/dashboard/dashboard.view.ts +33 -0
- package/claude/skills/sd-demo/evals/fixtures/with-master-screen/.specs/260513120000_warehouse/spec.md +45 -0
- package/claude/skills/sd-demo/evals/fixtures/with-master-screen/packages/app/src/screens/dashboard/dashboard.view.ts +33 -0
- package/claude/skills/sd-demo/evals/fixtures/with-modal/.specs/260513120000_warehouse/spec.md +75 -0
- package/claude/skills/sd-demo/evals/fixtures/with-modal/packages/app/src/screens/dashboard/dashboard.view.ts +33 -0
- package/claude/skills/sd-demo/evals/fixtures/with-screens/.specs/260513120000_warehouse/spec.md +45 -0
- package/claude/skills/sd-demo/evals/fixtures/with-screens/packages/app/src/screens/dashboard/dashboard.view.ts +33 -0
- package/claude/skills/sd-demo/evals/golden.jsonl +5 -3
- package/claude/skills/sd-dev/SKILL.md +33 -63
- package/claude/skills/sd-dev/evals/fixtures/case-add/package.json +13 -0
- package/claude/skills/sd-dev/evals/fixtures/case-add/src/index.ts +10 -0
- package/claude/skills/sd-dev/evals/fixtures/case-add/tests/index.test.ts +11 -0
- package/claude/skills/sd-dev/evals/fixtures/case-add/tsconfig.json +12 -0
- package/claude/skills/sd-dev/evals/fixtures/case-bug/package.json +13 -0
- package/claude/skills/sd-dev/evals/fixtures/case-bug/src/index.ts +10 -0
- package/claude/skills/sd-dev/evals/fixtures/case-bug/tests/index.test.ts +11 -0
- package/claude/skills/sd-dev/evals/fixtures/case-bug/tsconfig.json +12 -0
- package/claude/skills/sd-dev/evals/fixtures/case-modify/package.json +13 -0
- package/claude/skills/sd-dev/evals/fixtures/case-modify/src/index.ts +10 -0
- package/claude/skills/sd-dev/evals/fixtures/case-modify/tests/index.test.ts +11 -0
- package/claude/skills/sd-dev/evals/fixtures/case-modify/tsconfig.json +12 -0
- package/claude/skills/sd-dev/evals/golden.jsonl +3 -3
- package/claude/skills/sd-docs/SKILL.md +53 -0
- package/claude/skills/sd-docs/evals/fixtures/new-write/.claude/references/sd-simplysm14/README.md +7 -0
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/bar/package.json +5 -0
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/bar/src/index.ts +3 -0
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/baz/package.json +6 -0
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/baz/src/index.ts +1 -0
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/foo/package.json +5 -0
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/foo/src/index.ts +8 -0
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/.claude/references/sd-simplysm14/README.md +7 -0
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/.claude/references/sd-simplysm14/apis/foo/README.md +3 -0
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/bar/package.json +5 -0
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/bar/src/index.ts +3 -0
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/baz/package.json +6 -0
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/baz/src/index.ts +1 -0
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/foo/package.json +5 -0
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/foo/src/index.ts +8 -0
- package/claude/skills/sd-docs/evals/golden.jsonl +2 -0
- package/claude/skills/sd-docs/references/subagent-prompt.md +100 -0
- package/claude/skills/sd-impl/SKILL.md +149 -46
- package/claude/skills/sd-impl/evals/fixtures/case-001-new-screen/spec.md +55 -0
- package/claude/skills/sd-impl/evals/fixtures/case-002-auto-process/spec.md +55 -0
- package/claude/skills/sd-impl/evals/fixtures/case-003-update-screen/packages/client/src/pages/book-list.ts +22 -0
- package/claude/skills/sd-impl/evals/fixtures/case-003-update-screen/spec.md +57 -0
- package/claude/skills/sd-impl/evals/fixtures/case-004-ambiguous-spec/spec.md +58 -0
- package/claude/skills/sd-impl/evals/fixtures/case-005-id-mismatch/spec.md +52 -0
- package/claude/skills/sd-impl/evals/fixtures/case-006-with-reference-units/packages/client/src/pages//352/261/260/353/236/230/354/262/230//352/261/260/353/236/230/354/262/230-/353/252/251/353/241/235.test.ts +10 -0
- package/claude/skills/sd-impl/evals/fixtures/case-006-with-reference-units/packages/client/src/pages//352/261/260/353/236/230/354/262/230//352/261/260/353/236/230/354/262/230-/353/252/251/353/241/235.ts +11 -0
- package/claude/skills/sd-impl/evals/fixtures/case-006-with-reference-units/packages/server/src/data-access//352/261/260/353/236/230/354/262/230-/354/240/221/352/267/274.ts +12 -0
- package/claude/skills/sd-impl/evals/fixtures/case-006-with-reference-units/packages/server/src/models//352/261/260/353/236/230/354/262/230.ts +8 -0
- package/claude/skills/sd-impl/evals/fixtures/case-006-with-reference-units/spec.md +77 -0
- package/claude/skills/sd-impl/evals/fixtures/case-new/.specs/260514120000_/352/261/260/353/236/230/354/262/230/spec.md +101 -0
- package/claude/skills/sd-impl/evals/fixtures/case-update/.specs/260514120000_/352/261/260/353/236/230/354/262/230/spec.md +101 -0
- package/claude/skills/sd-impl/evals/fixtures/case-update/src//352/261/260/353/236/230/354/262/230//352/261/260/353/236/230/354/262/230-/353/252/250/353/215/270.txt +1 -0
- package/claude/skills/sd-impl/evals/fixtures/case-update/src//352/261/260/353/236/230/354/262/230//352/261/260/353/236/230/354/262/230-/353/252/251/353/241/235.txt +1 -0
- package/claude/skills/sd-impl/evals/golden.jsonl +6 -3
- package/claude/skills/sd-impl/references/spec-cross-check.md +82 -0
- package/claude/skills/sd-skill/SKILL.md +4 -4
- package/claude/skills/sd-skill/evals/golden.jsonl +1 -2
- package/claude/skills/sd-skill/references/eval-authoring.md +31 -0
- package/claude/skills/sd-skill/references/eval-run.md +1 -1
- package/claude/skills/sd-skill/references/skill-authoring.md +8 -5
- package/claude/skills/sd-skill/scripts/run_eval.py +39 -60
- package/claude/skills/sd-spec/SKILL.md +163 -105
- package/claude/skills/sd-spec/references/example-spec.md +585 -0
- package/claude/skills/sd-spec/references/spec-authoring.md +287 -0
- package/claude/skills/sd-spec/references/spec-md-template.md +15 -93
- package/claude/skills/sd-unpack/SKILL.md +7 -1
- package/claude/skills/sd-unpack/scripts/handlers/_common.py +10 -0
- package/claude/skills/sd-unpack/scripts/handlers/eml_handler.py +5 -13
- package/claude/skills/sd-unpack/scripts/handlers/msg_handler.py +3 -12
- package/claude/skills/sd-unpack/scripts/handlers/office_com.py +23 -37
- package/claude/skills/sd-unpack/scripts/handlers/office_worker.py +1 -4
- package/claude/skills/sd-unpack/scripts/handlers/pdf_handler.py +4 -13
- package/claude/skills/sd-unpack/scripts/unpack.py +4 -4
- package/claude/skills/sd-use/SKILL.md +1 -0
- package/claude/skills/sd-wip/SKILL.md +38 -0
- package/claude/skills/sd-wip/evals/fixtures/with-artifact/projects/acct/_wip.md +3 -0
- package/claude/skills/sd-wip/evals/fixtures/with-artifact/projects/acct/spec.md +15 -0
- package/claude/skills/sd-wip/evals/fixtures/with-existing-wip/.wips/260101120000_acct.md +6 -0
- package/claude/skills/sd-wip/evals/fixtures/with-existing-wip-for-compact/.wips/260101120000_acct.md +14 -0
- package/claude/skills/sd-wip/evals/golden.jsonl +4 -0
- package/claude/skills/sd-wip/references/compact.md +79 -0
- package/package.json +1 -1
- package/scripts/sd-entries.mjs +2 -2
- package/claude/references/sd-simplysm14/orm.md +0 -11
- package/claude/skills/sd-demo/evals/fixtures/basic-single-req/.specs/260503143025/REQ-001-/354/236/205/352/263/240/354/247/200/354/213/234/354/204/234/352/270/264/352/270/211/355/221/234/354/213/234/spec.md +0 -27
- package/claude/skills/sd-demo/evals/fixtures/basic-single-req/.specs/260503143025/overview.md +0 -12
- package/claude/skills/sd-demo/evals/fixtures/basic-single-req/src/components/Button.tsx +0 -12
- package/claude/skills/sd-demo/evals/fixtures/basic-single-req/src/components/Input.tsx +0 -27
- package/claude/skills/sd-demo/evals/fixtures/mock-data-policy/.specs/260503143025/REQ-001-/352/261/260/353/236/230/354/262/230/353/252/251/353/241/235/355/231/224/353/251/264/spec.md +0 -25
- package/claude/skills/sd-demo/evals/fixtures/mock-data-policy/.specs/260503143025/overview.md +0 -12
- package/claude/skills/sd-demo/evals/fixtures/mock-data-policy/src/components/Input.tsx +0 -25
- package/claude/skills/sd-demo/evals/fixtures/mock-data-policy/src/pages/.gitkeep +0 -0
- package/claude/skills/sd-demo/evals/fixtures/multi-req-domain/.specs/260503143025/REQ-001-RTP/354/236/205/353/240/245/355/231/224/353/251/264/spec.md +0 -19
- package/claude/skills/sd-demo/evals/fixtures/multi-req-domain/.specs/260503143025/REQ-002-RTP/354/266/234/353/240/245/355/231/224/353/251/264/spec.md +0 -20
- package/claude/skills/sd-demo/evals/fixtures/multi-req-domain/.specs/260503143025/overview.md +0 -16
- package/claude/skills/sd-demo/evals/fixtures/multi-req-domain/src/components/Button.tsx +0 -6
- package/claude/skills/sd-demo/evals/fixtures/multi-req-domain/src/components/Input.tsx +0 -15
- package/claude/skills/sd-demo/evals/fixtures/multi-req-domain/src/pages/.gitkeep +0 -0
- package/claude/skills/sd-demo/references/demo-md-template.md +0 -92
- package/claude/skills/sd-dev/evals/fixtures/multi-req-stop-after-spec/.docs/20260301_/352/263/240/352/260/235/354/202/254_/354/236/205/352/263/240/354/232/224/354/262/255.eml +0 -5
- package/claude/skills/sd-dev/evals/fixtures/multi-req-stop-after-spec/.docs/20260305_/352/263/240/352/260/235/354/202/254_/354/266/234/352/263/240/354/232/224/354/262/255.eml +0 -6
- package/claude/skills/sd-dev/evals/fixtures/multi-req-stop-after-spec/.docs/20260310_/352/263/240/352/260/235/354/202/254_/352/266/214/355/225/234.eml +0 -6
- package/claude/skills/sd-dev/evals/fixtures/single-req-auto-chain/src/lib/.gitkeep +0 -0
- package/claude/skills/sd-dev/evals/fixtures/start-from-plan/.specs/260503143025/REQ-001-/355/225/240/354/235/270/352/263/204/354/202/260/spec.md +0 -12
- package/claude/skills/sd-dev/evals/fixtures/start-from-plan/src/lib/.gitkeep +0 -0
- package/claude/skills/sd-impl/evals/fixtures/basic-single-r/.specs/260503143025/REQ-001-/354/236/205/352/263/240/354/247/200/354/213/234/354/204/234/352/270/264/352/270/211/355/221/234/354/213/234/plan.md +0 -28
- package/claude/skills/sd-impl/evals/fixtures/basic-single-r/.specs/260503143025/REQ-001-/354/236/205/352/263/240/354/247/200/354/213/234/354/204/234/352/270/264/352/270/211/355/221/234/354/213/234/spec.md +0 -14
- package/claude/skills/sd-impl/evals/fixtures/basic-single-r/src/components/Input.tsx +0 -6
- package/claude/skills/sd-impl/evals/fixtures/basic-single-r/src/pages/.gitkeep +0 -0
- package/claude/skills/sd-impl/evals/fixtures/multi-r/.specs/260503143025/REQ-001-/352/261/260/353/236/230/354/262/230/353/252/251/353/241/235/plan.md +0 -40
- package/claude/skills/sd-impl/evals/fixtures/multi-r/.specs/260503143025/REQ-001-/352/261/260/353/236/230/354/262/230/353/252/251/353/241/235/spec.md +0 -13
- package/claude/skills/sd-impl/evals/fixtures/multi-r/src/components/Input.tsx +0 -25
- package/claude/skills/sd-impl/evals/fixtures/multi-r/src/pages/.gitkeep +0 -0
- package/claude/skills/sd-impl/evals/fixtures/with-test-file/.specs/260503143025/REQ-001-/355/225/240/354/235/270/352/263/204/354/202/260/plan.md +0 -26
- package/claude/skills/sd-impl/evals/fixtures/with-test-file/.specs/260503143025/REQ-001-/355/225/240/354/235/270/352/263/204/354/202/260/spec.md +0 -12
- package/claude/skills/sd-impl/evals/fixtures/with-test-file/src/lib/.gitkeep +0 -0
- package/claude/skills/sd-impl/references/impl-md-template.md +0 -87
- package/claude/skills/sd-impl/references/modes-and-failure.md +0 -65
- package/claude/skills/sd-plan/SKILL.md +0 -130
- package/claude/skills/sd-plan/evals/fixtures/already-implemented/.specs/260503143025/REQ-001-/354/202/254/354/232/251/354/236/220/353/252/251/353/241/235/spec.md +0 -14
- package/claude/skills/sd-plan/evals/fixtures/already-implemented/src/api/user.ts +0 -13
- package/claude/skills/sd-plan/evals/fixtures/already-implemented/src/components/Input.tsx +0 -15
- package/claude/skills/sd-plan/evals/fixtures/already-implemented/src/pages/UserList.tsx +0 -29
- package/claude/skills/sd-plan/evals/fixtures/basic-greenfield/.specs/260503143025/REQ-001-/354/236/205/352/263/240/354/247/200/354/213/234/354/204/234/352/270/264/352/270/211/355/221/234/354/213/234/spec.md +0 -17
- package/claude/skills/sd-plan/evals/fixtures/basic-greenfield/src/components/Input.tsx +0 -6
- package/claude/skills/sd-plan/evals/fixtures/basic-greenfield/src/pages/.gitkeep +0 -0
- package/claude/skills/sd-plan/evals/fixtures/demo-built/.specs/260503143025/DEMO-001-/352/261/260/353/236/230/354/262/230/demo.md +0 -26
- package/claude/skills/sd-plan/evals/fixtures/demo-built/.specs/260503143025/REQ-001-/352/261/260/353/236/230/354/262/230/353/252/251/353/241/235/355/231/224/353/251/264/spec.md +0 -15
- package/claude/skills/sd-plan/evals/fixtures/demo-built/src/components/Input.tsx +0 -25
- package/claude/skills/sd-plan/evals/fixtures/demo-built/src/data/mock-customer.ts +0 -16
- package/claude/skills/sd-plan/evals/fixtures/demo-built/src/pages/CustomerList.tsx +0 -25
- package/claude/skills/sd-plan/evals/golden.jsonl +0 -3
- package/claude/skills/sd-plan/references/plan-md-template.md +0 -138
- package/claude/skills/sd-spec/evals/fixtures/bulk-multi-source/.docs/20260122_/352/263/240/352/260/235/354/202/254_/354/236/205/352/263/240/354/247/200/354/213/234/354/204/234/352/260/234/354/204/240/354/232/224/354/262/255.eml +0 -20
- package/claude/skills/sd-spec/evals/fixtures/bulk-multi-source/.docs/20260205_/352/263/240/352/260/235/354/202/254_/354/266/234/352/263/240/355/231/224/353/251/264/352/264/200/353/240/250.eml +0 -17
- package/claude/skills/sd-spec/evals/fixtures/bulk-multi-source/.docs/20260301_/352/263/240/352/260/235/354/202/254_/352/266/214/355/225/234/354/262/264/352/263/204.eml +0 -18
- package/claude/skills/sd-spec/evals/fixtures/conflict-detection/.docs/20260317_/352/263/240/352/260/235/354/202/254_/352/270/264/352/270/211/354/262/230/353/246/254/353/260/251/354/271/250.eml +0 -17
- package/claude/skills/sd-spec/evals/fixtures/conflict-detection/.docs//355/232/214/354/235/230/353/214/200/353/263/270_20260320.txt +0 -13
- package/claude/skills/sd-spec/evals/fixtures/direct-simple/.gitkeep +0 -0
- package/claude/skills/sd-spec/evals/fixtures/spec-md-input/.specs/260101120000/REQ-001-test/spec.md +0 -19
- package/claude/skills/sd-spec/evals/fixtures/spec-md-input/.specs/260101120000/overview.md +0 -18
- package/claude/skills/sd-spec/evals/golden.jsonl +0 -4
- package/claude/skills/sd-spec/references/overview-md-template.md +0 -89
- package/claude/skills/sd-spec/references/raw-input-handling.md +0 -96
- package/claude/skills/sd-verify/SKILL.md +0 -96
- package/claude/skills/sd-verify/evals/fixtures/all-satisfied/.specs/260503143025/REQ-001-/355/225/240/354/235/270/352/263/204/354/202/260/impl.md +0 -20
- package/claude/skills/sd-verify/evals/fixtures/all-satisfied/.specs/260503143025/REQ-001-/355/225/240/354/235/270/352/263/204/354/202/260/plan.md +0 -14
- package/claude/skills/sd-verify/evals/fixtures/all-satisfied/.specs/260503143025/REQ-001-/355/225/240/354/235/270/352/263/204/354/202/260/spec.md +0 -12
- package/claude/skills/sd-verify/evals/fixtures/all-satisfied/src/lib/discount.test.ts +0 -11
- package/claude/skills/sd-verify/evals/fixtures/all-satisfied/src/lib/discount.ts +0 -7
- package/claude/skills/sd-verify/evals/fixtures/partial-mismatch/.specs/260503143025/REQ-001-/354/202/254/354/232/251/354/236/220/353/252/251/353/241/235/impl.md +0 -21
- package/claude/skills/sd-verify/evals/fixtures/partial-mismatch/.specs/260503143025/REQ-001-/354/202/254/354/232/251/354/236/220/353/252/251/353/241/235/plan.md +0 -21
- package/claude/skills/sd-verify/evals/fixtures/partial-mismatch/.specs/260503143025/REQ-001-/354/202/254/354/232/251/354/236/220/353/252/251/353/241/235/spec.md +0 -12
- package/claude/skills/sd-verify/evals/fixtures/partial-mismatch/src/pages/UserList.tsx +0 -19
- package/claude/skills/sd-verify/evals/fixtures/tdd-only/.specs/260503143025/REQ-001-/352/270/210/354/225/241/352/262/200/354/246/235/impl.md +0 -19
- package/claude/skills/sd-verify/evals/fixtures/tdd-only/.specs/260503143025/REQ-001-/352/270/210/354/225/241/352/262/200/354/246/235/plan.md +0 -14
- package/claude/skills/sd-verify/evals/fixtures/tdd-only/.specs/260503143025/REQ-001-/352/270/210/354/225/241/352/262/200/354/246/235/spec.md +0 -12
- package/claude/skills/sd-verify/evals/fixtures/tdd-only/src/lib/validate-amount.test.ts +0 -10
- package/claude/skills/sd-verify/evals/fixtures/tdd-only/src/lib/validate-amount.ts +0 -7
- package/claude/skills/sd-verify/evals/golden.jsonl +0 -3
- package/claude/skills/sd-verify/references/verify-md-template.md +0 -99
- /package/claude/skills/{sd-demo/evals/fixtures/basic-single-req/src/pages → sd-wip/evals/fixtures/empty}/.gitkeep +0 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# @simplysm/angular — modal
|
|
2
|
+
|
|
3
|
+
선언형 `<sd-modal>` 과 프로그래밍 방식 `SdModalProvider` 둘 다 지원.
|
|
4
|
+
|
|
5
|
+
## 프로그래밍 방식
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
const result = await inject(SdModalProvider).showAsync(
|
|
9
|
+
{
|
|
10
|
+
title: "주문 선택",
|
|
11
|
+
type: OrderSelectModal, // SdModalContentDef<TOutput> 구현
|
|
12
|
+
inputs: { mode: "single" }, // DirectiveInputSignals<T> (close/initialized 등 제외)
|
|
13
|
+
},
|
|
14
|
+
{ fill: true, resizable: true, key: "order-select" },
|
|
15
|
+
);
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
- `showAsync<T>(info, options?)` → `Promise<TOutput | undefined>`. `close.emit(value)` 시 resolve.
|
|
19
|
+
- `SdModalProvider.modalCount = signal(0)` (열린 모달 수).
|
|
20
|
+
- `key`를 주면 `SdSystemConfigProvider` 통해 width/height/위치 영속화.
|
|
21
|
+
- `noFirstControlFocusing: true`면 첫 tabbable 요소가 아닌 dialog 자체 포커스.
|
|
22
|
+
|
|
23
|
+
### 모달 컨텐츠 컴포넌트 인터페이스
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
interface SdModalContentDef<O> {
|
|
27
|
+
initialized: Signal<boolean>;
|
|
28
|
+
close: OutputEmitterRef<O | undefined>;
|
|
29
|
+
actionTplRef?: TemplateRef<any>;
|
|
30
|
+
readonly _optionalModalInputs?: string; // 키 union → 해당 input들이 optional 처리
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`SdModalInfo<T, X>`: `X`는 inputs에서 제외할 추가 키 union (예: `SdSelectModalInfo`가 `selectMode|selectedKeys` 제외).
|
|
35
|
+
|
|
36
|
+
### `SdModalOptions`
|
|
37
|
+
|
|
38
|
+
`key`, `hideHeader`, `hideCloseButton`, `headerStyle`, `useCloseByBackdrop`, `useCloseByEscapeKey`, `float`, `fill`, `resizable`, `movable`, `position: "bottom-right"|"top-right"`, `minHeightPx`, `minWidthPx`, `heightPx`, `widthPx`, `noFirstControlFocusing`.
|
|
39
|
+
|
|
40
|
+
## 선언형 `<sd-modal>`
|
|
41
|
+
|
|
42
|
+
`open` model, `title`/`key`/`hideHeader`/`hideCloseButton`/`headerStyle`/`useCloseByBackdrop`/`useCloseByEscapeKey`/`float`/`fill`/`resizable`/`movable`/`position`/`minHeightPx`/`minWidthPx`/`heightPx`/`widthPx`/`actionTplRef` input. `closeRequest` output (배경 클릭/ESC/닫기 버튼).
|
|
43
|
+
|
|
44
|
+
## 내부에서 모달 정보 사용
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
const am = inject(SdActivatedModalProvider, { optional: true });
|
|
48
|
+
am?.modalComponent(); // SdModal 인스턴스 (title() 등)
|
|
49
|
+
am?.contentComponent(); // 컨텐츠 인스턴스
|
|
50
|
+
am.canDeactivateFn = () => isClean(); // 닫기 차단 (false 반환 시)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 내장 컨텐츠 컴포넌트
|
|
54
|
+
|
|
55
|
+
- `SdPromptModal` (`SdModalContentDef<string>`): `message` input. Enter/확인 → `close.emit(value)` (빈 값이면 emit X), 취소 → `undefined`.
|
|
56
|
+
- `SdConfirmModal` (`SdModalContentDef<boolean>`): `message` input. 확인 → `true`, 취소 → `undefined`.
|
|
57
|
+
- `SdAddressSearchModal` (`SdModalContentDef<Address>`): Daum Postcode 스크립트 자동 로드. `Address = { postNumber, address, buildingName }`.
|
|
58
|
+
|
|
59
|
+
## 주의
|
|
60
|
+
|
|
61
|
+
- `SdModalContentDef` 의 `initialized` signal 은 컨텐츠 준비 후 `true` 로 (인쇄/모달 등이 대기).
|
|
62
|
+
- 모달은 body에 직접 attach (z-index 자동 할당, 최상위로 끌어올림). focus trap 적용.
|
|
63
|
+
- 닫힘 애니메이션 transition duration 대기 후 destroy.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# @simplysm/angular — routing
|
|
2
|
+
|
|
3
|
+
Angular Router 위에 페이지 코드(`a.b.c` 형식)·뷰 타입·새창 네비게이션을 얹는 헬퍼.
|
|
4
|
+
|
|
5
|
+
## `SdRouterLink` 디렉티브
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<a [sdRouterLink]="{ link: '/home/order/list', params: { id }, queryParams, outletName, window: { width, height } }">go</a>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
- 일반 클릭 → `router.navigate`. Ctrl/Shift 클릭 또는 새창 모드(`isWindow`)일 때 → `SdNavigateWindowProvider.open` 으로 새 창. Alt+click 무시.
|
|
12
|
+
- `outletName` 지정 시 named outlet 으로 navigate.
|
|
13
|
+
|
|
14
|
+
## `SdNavigateWindowProvider`
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
const nav = inject(SdNavigateWindowProvider);
|
|
18
|
+
nav.open("/home/order/list", { id }, "width=800,height=600");
|
|
19
|
+
nav.isWindow; // 현재 컨텍스트가 팝업 윈도우인지
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
URL hash 끝에 `;window=true` 가 있으면 `isWindow=true`. 부모 unload 시 자기가 연 창 자동 close.
|
|
23
|
+
|
|
24
|
+
## Page Code Signal
|
|
25
|
+
|
|
26
|
+
페이지 코드 = activated route URL segment 를 `.` 으로 join.
|
|
27
|
+
|
|
28
|
+
- `injectCurrentPageCodeSignal()`: 현재 라우트의 segment 신호 (`undefined` if no ActivatedRoute).
|
|
29
|
+
- `injectFullPageCodeSignal()`: router.url 기반 풀 코드.
|
|
30
|
+
- `injectViewTitleSignal()`: 모달이면 `modalComponent.title()`, 아니면 `SdAppStructureProvider.getTitleByFullCode`.
|
|
31
|
+
- `injectViewTypeSignal(): Signal<SdViewType>`. `SdViewType = "page" | "modal" | "control"`. 모달 컨텍스트면 `"modal"`, page-level route component면 `"page"`, 그 외 `"control"`.
|
|
32
|
+
|
|
33
|
+
## `setupCanDeactivate(fn: () => boolean)`
|
|
34
|
+
|
|
35
|
+
constructor 내 호출. 모달 컨텍스트면 `SdActivatedModalProvider.canDeactivateFn` 설정, 라우트 컨텍스트면 `route.routeConfig.canDeactivate` 에 push (destroy 시 제거).
|
|
36
|
+
|
|
37
|
+
## 메뉴 유틸
|
|
38
|
+
|
|
39
|
+
- `getMenuRouterLinkOption(menu: SdMenu)`: leaf 메뉴를 `SdRouterLink` 옵션(`{ link, queryParams }`)으로 변환. children/url 있으면 `undefined`.
|
|
40
|
+
- `getIsMenuSelected(menu, fullPageCode, customFn?)`: 현재 페이지가 메뉴와 일치하는지.
|
|
41
|
+
|
|
42
|
+
## 주의
|
|
43
|
+
|
|
44
|
+
- 페이지 코드는 hash router 기준 `/home/<code>` 구조 가정.
|
|
45
|
+
- `injectCurrentPageCodeSignal` 은 `pathFromRoot.slice(2)` 사용 — root + `home` 두 레벨 위 라우트 컴포넌트에서 의미 있음.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# @simplysm/angular — select-dropdown
|
|
2
|
+
|
|
3
|
+
## `<sd-dropdown>` / `<sd-dropdown-popup>`
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<sd-dropdown [(open)]="open" [disabled]="false">
|
|
7
|
+
trigger 컨텐츠
|
|
8
|
+
<sd-dropdown-popup>팝업 컨텐츠</sd-dropdown-popup>
|
|
9
|
+
</sd-dropdown>
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
- `open` 시 popup을 body로 이동(트리거 위치 기준 배치). 모바일(`max-width:520px`)이면 backdrop+bottom sheet.
|
|
13
|
+
- 트리거 클릭/Enter/ArrowDown 으로 open.
|
|
14
|
+
|
|
15
|
+
## `<sd-select<M extends "single"|"multi", T>>`
|
|
16
|
+
|
|
17
|
+
```html
|
|
18
|
+
<sd-select [items]="items" [(value)]="value" [selectMode]="'single'" [trackByFn]="byId">
|
|
19
|
+
<sd-select-item *ngFor="let it of items" [value]="it.id">{{ it.name }}</sd-select-item>
|
|
20
|
+
</sd-select>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`SelectModeValue<T> = { single: T; multi: T[] }`. value type = `SelectModeValue<T>[M]`.
|
|
24
|
+
|
|
25
|
+
주요 input: `selectMode`, `value` (model), `placeholder`, `disabled`, `inline`, `inset`, `size`, `required`, `hideSelectAll`, `multiSelectionDisplayDirection: "vertical"`, `items`, `trackByFn`, `getChildrenFn` (트리), `contentClass/Style`, `dropdownOpen` (model).
|
|
26
|
+
|
|
27
|
+
`<ng-template #headerTpl>`, `<ng-template #beforeTpl>`, `<ng-template itemOf>` (`SdItemOfTemplate`) 으로 커스터마이즈.
|
|
28
|
+
|
|
29
|
+
## `<sd-select-item<T> [value]>`
|
|
30
|
+
|
|
31
|
+
projected content 가 옵션 라벨.
|
|
32
|
+
|
|
33
|
+
## `<sd-select-button>`
|
|
34
|
+
|
|
35
|
+
검색 트리거 버튼만 노출하는 경량 select (내부 사용용).
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# @simplysm/angular — selection-managers
|
|
2
|
+
|
|
3
|
+
`<sd-sheet>`/`<sd-select>` 등이 내부에서 쓰는 선택·확장·정렬 로직을 외부 컴포넌트에서도 재사용할 수 있도록 추출된 함수 훅들. signal 바인딩.
|
|
4
|
+
|
|
5
|
+
## `useSelectionManager<TItem, TKey>(options)`
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
const sm = useSelectionManager({
|
|
9
|
+
displayItems, // Signal<TItem[]>
|
|
10
|
+
selectedKeys, // WritableSignal<TKey[]>
|
|
11
|
+
selectMode, // Signal<"single"|"multi"|undefined>
|
|
12
|
+
getItemSelectableFn, // Signal<((item) => boolean|string) | undefined>
|
|
13
|
+
trackByFn, // Signal<(item, idx) => TKey>
|
|
14
|
+
});
|
|
15
|
+
sm.hasSelectable; sm.isAllSelected;
|
|
16
|
+
sm.getSelectable(item); // true | string(reason) | undefined
|
|
17
|
+
sm.select(item); sm.deselect(item); sm.toggle(item); sm.toggleAll();
|
|
18
|
+
sm.isSelected(item); sm.getCanChangeFn(item);
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
- `single`이면 select 시 기존 키 대체. `multi` 면 추가.
|
|
22
|
+
- 키 비교는 `obj.equal` (`@simplysm/core-common`).
|
|
23
|
+
- `trackByFn` 반환이 `null`이면 선택 불가.
|
|
24
|
+
|
|
25
|
+
## `useExpandingManager<T>(binding)`
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
interface ExpandItemDef<T> { item; parentDef?; hasChildren; depth }
|
|
29
|
+
const em = useExpandingManager({
|
|
30
|
+
items, expandedItems,
|
|
31
|
+
getChildrenFn, // Signal<((item, idx) => T[] | undefined) | undefined>
|
|
32
|
+
sort, // (items: T[]) => T[]
|
|
33
|
+
});
|
|
34
|
+
em.displayItems; em.hasExpandable; em.isAllExpanded;
|
|
35
|
+
em.toggle(item); em.toggleAll(); em.isVisible(item); em.def(item);
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
부모가 collapsed면 자식은 `isVisible=false`.
|
|
39
|
+
|
|
40
|
+
## `useSortingManager(options)`
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
interface SortingDef { key: string; desc: boolean }
|
|
44
|
+
const sm = useSortingManager({ sorts });
|
|
45
|
+
sm.defMap; // Signal<Map<key, { indexText?, desc }>>
|
|
46
|
+
sm.toggle(key, multiple); // multiple=true면 multi-key sort, 아니면 단일
|
|
47
|
+
sm.sort(items); // null < non-null, string localeCompare
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`toggle` 토글 순서: 없음 → asc → desc → 제거.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# @simplysm/angular — shared-data
|
|
2
|
+
|
|
3
|
+
서버에서 가져오는 코드성 데이터(부서, 거래처 등)를 키 기반으로 등록/구독, 변경 이벤트로 자동 부분 갱신.
|
|
4
|
+
|
|
5
|
+
## `SdSharedDataProvider<T>` (abstract)
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
@Injectable({ providedIn: "root" })
|
|
9
|
+
class MySharedData extends SdSharedDataProvider<{ depts: DeptDto; vendors: VendorDto }> {
|
|
10
|
+
initialize(): void {
|
|
11
|
+
this.register("depts", {
|
|
12
|
+
serviceKey: "main",
|
|
13
|
+
getter: (changeKeys) => svc.depts.getList(changeKeys),
|
|
14
|
+
orderBy: (it) => it.name,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
- 각 아이템 타입은 `SharedDataBase<TKey>` 확장: `{ __valueKey: TKey, __searchText: string, __isHidden: boolean, __parentKey? }`.
|
|
21
|
+
- `register(name, info)` 후 `getHandle(name)` → `SharedDataHandle<T> { items: Signal<T[]>; get(key) }`. 첫 호출 시 lazy load + 이벤트 리스너 등록.
|
|
22
|
+
- `emitAsync(name, changeKeys?)` → 다른 클라이언트(또는 자기 자신)에 `SdSharedDataChangeEvent` 발행. `changeKeys` 없으면 전체 리로드, 있으면 해당 키들만 재조회 후 merge (orderBy 재적용).
|
|
23
|
+
- `loadingCount = signal(0)`, `wait()` (loadingCount 0까지).
|
|
24
|
+
- `SdSharedDataChangeEvent` = `defineEvent<{ name; filter }, (string|number)[] | undefined>("SdSharedDataChange")` — 동일 name+filter 매칭 리스너에 키 발행.
|
|
25
|
+
|
|
26
|
+
## `<sd-shared-data-select<TItem, TMode, TModal>>`
|
|
27
|
+
|
|
28
|
+
`SharedDataBase` 항목에서 키를 선택하는 셀렉트. `__isHidden`/`__searchText` 활용.
|
|
29
|
+
|
|
30
|
+
inputs: `items` (required), `value` (model: 단일/배열 키), `selectMode`, `disabled`, `required`, `useUndefined`, `inset`, `inline`, `size`, `filterFn(item, index, ...params)`, `filterFnParams`, `modal: SdSelectModalInfo<TModal>` (검색 모달), `editModal: SdModalInfo<SdModalContentDef<boolean>>` (신규 등록), `selectClass`, `multiSelectionDisplayDirection: "vertical"`, `getIsHiddenFn` (default `__isHidden`), `getSearchTextFn` (default `__searchText`), `displayOrderKeyProp`.
|
|
31
|
+
|
|
32
|
+
## `<sd-shared-data-select-button>`
|
|
33
|
+
|
|
34
|
+
modal 강제(검색 모달 필수). value: 단일/배열 키.
|
|
35
|
+
|
|
36
|
+
## `<sd-shared-data-select-list>`
|
|
37
|
+
|
|
38
|
+
list 형태 단일 선택. inputs: `items` (req), `selectedItem` (model), `canChangeFn(item) => boolean | Promise<boolean>`, `selectedIcon`, `useUndefined`, `filterFn`, `modal`, `header`, `pageItemCount`.
|
|
39
|
+
|
|
40
|
+
## `matchesSearchText(itemText, searchQuery)`
|
|
41
|
+
|
|
42
|
+
공백 분리 AND 매칭(lowercase). 빈 쿼리는 true.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# @simplysm/angular — sheet
|
|
2
|
+
|
|
3
|
+
가상 스크롤 데이터 그리드. 컬럼·셀 템플릿·정렬·페이징·선택·확장 트리·설정 모달 내장.
|
|
4
|
+
|
|
5
|
+
## 기본 사용
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<sd-sheet
|
|
9
|
+
[key]="'order-list'"
|
|
10
|
+
[items]="items"
|
|
11
|
+
[trackByFn]="byId"
|
|
12
|
+
[selectMode]="'multi'"
|
|
13
|
+
[(selectedKeys)]="selectedKeys"
|
|
14
|
+
[(sorts)]="sorts"
|
|
15
|
+
[(currentPage)]="page"
|
|
16
|
+
[totalPageCount]="totalPages"
|
|
17
|
+
[itemsPerPage]="50"
|
|
18
|
+
[useAutoSort]="false">
|
|
19
|
+
|
|
20
|
+
<sd-sheet-column [key]="'no'" [header]="'번호'" [width]="'80px'" [fixed]="true">
|
|
21
|
+
<ng-template cell let-item="item" let-index="index">{{ index + 1 }}</ng-template>
|
|
22
|
+
</sd-sheet-column>
|
|
23
|
+
</sd-sheet>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## `<sd-sheet<TItem>>` 입력/출력
|
|
27
|
+
|
|
28
|
+
- inputs: `key`, `items`, `trackByFn`, `selectMode`, `autoSelect: "click"|"focus"`, `getItemSelectableFn`, `getChildrenFn` (트리), `useAutoSort`, `visiblePageCount=10`, `totalPageCount`, `itemsPerPage`, `focusMode: "row"|"cell" = "cell"`, `inset`, `contentStyle`, `getItemCellClassFn`, `getItemCellStyleFn`, `hideConfigBar`, `columnControlsInput` (외부 정의된 컬럼 추가).
|
|
29
|
+
- outputs: `itemKeydown: SdSheetItemKeydownEventParam<T> { item, event }`, `cellKeydown: SdSheetCellKeydownEventParam<T> { item, key, event }`.
|
|
30
|
+
- models: `selectedKeys: unknown[]`, `expandedItems: TItem[]`, `sorts: SortingDef[]`, `currentPage: number`.
|
|
31
|
+
- `key` 지정 시 설정 모달(`SdSheetConfigModal`)로 너비/숨김/고정/순서를 `SdSystemConfigProvider`에 영속화.
|
|
32
|
+
|
|
33
|
+
## `<sd-sheet-column<T> [key] [header]>`
|
|
34
|
+
|
|
35
|
+
inputs: `key`(required), `header: string|string[]` (배열은 다중 행 헤더), `headerStyle`, `tooltip`, `width`, `fixed`, `hidden`, `collapse`, `disableSorting`, `disableResizing`, `ordering`.
|
|
36
|
+
|
|
37
|
+
자식 template:
|
|
38
|
+
- `<ng-template cell let-item="item">` (필수, `SdSheetColumnCellTemplate`, ctx: `SdSheetCellContext<T> = { $implicit, item, index, depth, edit }`).
|
|
39
|
+
- `<ng-template #headerTpl>` (선택, 커스텀 헤더).
|
|
40
|
+
- `<ng-template #summaryTpl>` (선택, 합계 행).
|
|
41
|
+
|
|
42
|
+
## 타입
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
interface SdSheetColumnDef { key; header; headerStyle?; tooltip?; width?; fixed; hidden; collapse; disableSorting; disableResizing; ordering }
|
|
46
|
+
interface SdSheetHeaderDef { text; colspan; rowspan; isLastRow; fixed; colDef?; colIndex }
|
|
47
|
+
interface SdSheetConfig { columnRecord: Record<string, { width?; hidden?; fixed?; ordering? }> }
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## 설정 모달
|
|
51
|
+
|
|
52
|
+
`SdSheetConfigModal` (`SdModalContentDef<SdSheetConfig | undefined>`): `sheetKey`, `controls: SdSheetColumn[]`, `config: SdSheetConfig | undefined` inputs. 사용자가 컬럼 너비/숨김/고정/순서 편집 후 저장 → `close.emit(config)`.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# @simplysm/angular — toast
|
|
2
|
+
|
|
3
|
+
전역 토스트. `SdToastContainer`는 첫 호출 시 body에 자동 생성.
|
|
4
|
+
|
|
5
|
+
## 기본 사용
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
const toast = inject(SdToastProvider);
|
|
9
|
+
toast.info("저장되었습니다.");
|
|
10
|
+
toast.success("...");
|
|
11
|
+
toast.warning("...");
|
|
12
|
+
toast.danger("...");
|
|
13
|
+
|
|
14
|
+
const progress = toast.info("업로드 중", true); // WritableSignal<number>
|
|
15
|
+
progress.set(50); // 100 도달 시 1초 후 자동 dismiss
|
|
16
|
+
|
|
17
|
+
await toast.try(async () => svc.save(), (e) => `저장 실패: ${e.message}`);
|
|
18
|
+
// 에러 시 danger 토스트 + systemLog, 성공 시 결과 반환
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
- 일반 토스트: 3초 후 자동 해제(호버 중이면 leave 후 1초 지연).
|
|
22
|
+
- progress 토스트: 100% 도달 후 1초.
|
|
23
|
+
- `alertThemes = signal<SdToastSeverity[]>([])`: 포함된 severity는 토스트 대신 `window.alert`.
|
|
24
|
+
- `overlap = signal(false)`: 새 토스트 표시 시 기존 토스트 모두 제거.
|
|
25
|
+
- `beforeShowFn?: (theme) => void`: 표시 직전 후크 (예: 사운드).
|
|
26
|
+
|
|
27
|
+
## 커스텀 컨텐츠 토스트
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
interface SdToastContentDef<O> { close: OutputEmitterRef<O | undefined>; }
|
|
31
|
+
interface SdToastInput<T> { type: Type<T>; inputs: DirectiveInputSignals<T> 제외 close }
|
|
32
|
+
|
|
33
|
+
const result = await toast.notify({ type: MyToastComp, inputs: { kind: "x" } });
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`close.emit` 시 resolve. 5초 자동 dismiss (resolve undefined).
|
|
37
|
+
|
|
38
|
+
## 타입
|
|
39
|
+
|
|
40
|
+
- `SdToastSeverity = "info" | "success" | "warning" | "danger"`
|
|
41
|
+
- `SdToastTheme = "primary" | "secondary" | SdToastSeverity | "gray" | "blue-gray"` (SdToast 컴포넌트의 theme input)
|
|
42
|
+
|
|
43
|
+
## `SdToast` / `SdToastContainer` (직접 사용은 비권장)
|
|
44
|
+
|
|
45
|
+
- `<sd-toast [open] [theme] [useProgress] [(progress)] [(message)]>` — aria-live 자동 (`polite` info/success, `assertive` warning/danger).
|
|
46
|
+
- `<sd-toast-container [overlap]>` — 위치 컨테이너. `SdToastProvider`가 lazily 생성.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# @simplysm/angular — visual
|
|
2
|
+
|
|
3
|
+
데이터 시각화/표시 전용 컴포넌트.
|
|
4
|
+
|
|
5
|
+
## `<sd-label>`
|
|
6
|
+
|
|
7
|
+
배지 형 라벨. `theme`(테마 컬러), `color` (커스텀), `clickable`. content projection.
|
|
8
|
+
|
|
9
|
+
## `<sd-note>`
|
|
10
|
+
|
|
11
|
+
알림 박스 형. `theme`, `size`, `inset`. content projection.
|
|
12
|
+
|
|
13
|
+
## `<sd-progress>`
|
|
14
|
+
|
|
15
|
+
```html
|
|
16
|
+
<sd-progress [theme]="'primary'" [value]="60" [size]="'sm'" [inset]="false" />
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`theme` (required), `value: number` (0-100, required), `size`, `inset`.
|
|
20
|
+
|
|
21
|
+
## `<sd-calendar<T>>`
|
|
22
|
+
|
|
23
|
+
월별 달력 렌더.
|
|
24
|
+
|
|
25
|
+
- 필수: `items: T[]`, `getItemDateFn: (item, idx) => DateOnly`.
|
|
26
|
+
- `yearMonth = input(new DateOnly().setDay(1))` (해당 월).
|
|
27
|
+
- `weekStartDay = 0`, `minDaysInFirstWeek = 1`.
|
|
28
|
+
|
|
29
|
+
## `<sd-barcode>`
|
|
30
|
+
|
|
31
|
+
`bwip-js` 래퍼. `type: BarcodeType` (required), `value: string`. `BarcodeType` 은 bwip-js 지원 심볼로지 union (`code128`, `qrcode`, `ean13`, ... — `sd-barcode.ts` 참조).
|
|
32
|
+
|
|
33
|
+
## `<sd-echarts>`
|
|
34
|
+
|
|
35
|
+
ECharts 5/6 래퍼.
|
|
36
|
+
|
|
37
|
+
```html
|
|
38
|
+
<sd-echarts [option]="option" [notMerge]="false" [loading]="false" />
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`option: echarts.EChartsOption` (required).
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# @simplysm/capacitor-plugin-auto-update
|
|
2
|
+
|
|
3
|
+
Android Capacitor 앱의 APK 자동 업데이트 플러그인 (서버 또는 외부 저장소 기반).
|
|
4
|
+
|
|
5
|
+
## 사용 트리거 인덱스
|
|
6
|
+
|
|
7
|
+
- **AutoUpdate** — 앱 부팅 시 최신 APK 확인·다운로드·설치 전 과정을 한 번에 실행할 때.
|
|
8
|
+
- **ApkInstaller** — APK 설치 권한 체크/요청, 임의 APK 파일 설치, 현재 앱 버전 조회 등 저수준 단위 동작이 필요할 때.
|
|
9
|
+
- **VersionInfo / ApkInstallerPlugin** — 위 두 API 호출 결과 타입을 참조할 때.
|
|
10
|
+
|
|
11
|
+
## AutoUpdate
|
|
12
|
+
|
|
13
|
+
`abstract class AutoUpdate` (static 메서드만). Android 전용. 호출 시 권한 확인 → 버전 비교 → 다운로드 → 설치 → 무한 대기(freeze)까지 자동 처리. 오류는 catch 후 `log` 로 메시지 노출 후 freeze.
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
AutoUpdate.run(opt: {
|
|
17
|
+
log: (messageHtml: string) => void;
|
|
18
|
+
serviceClient: ServiceClient; // @simplysm/service-client
|
|
19
|
+
}): Promise<void>
|
|
20
|
+
```
|
|
21
|
+
서버의 `AutoUpdateService` 에 `getLastVersion("android")` 호출 → `{ version, downloadPath }` 수신 → `serviceClient.hostUrl + downloadPath` 에서 APK 다운로드 → `appCache/latest.apk` 로 저장 후 설치. 다운로드 진행률은 `log` 로 갱신.
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
AutoUpdate.runByExternalStorage(opt: {
|
|
25
|
+
log: (messageHtml: string) => void;
|
|
26
|
+
dirPath: string; // external 스토리지 기준 상대 경로
|
|
27
|
+
}): Promise<void>
|
|
28
|
+
```
|
|
29
|
+
외부 저장소 `external/<dirPath>` 폴더의 `<semver>.apk` 파일 중 가장 높은 버전을 골라 설치. 파일명이 semver 가 아니거나 없으면 조용히 반환.
|
|
30
|
+
|
|
31
|
+
공통:
|
|
32
|
+
- 현재 앱 버전(`ApkInstaller.getVersionInfo().versionName`) 보다 높은 버전만 설치.
|
|
33
|
+
- semver 유효성 실패 시 업데이트 스킵.
|
|
34
|
+
- 설치 권한이 없으면 설정 화면 이동 + "재시도" 버튼 HTML 을 `log` 로 표시하고 최대 5분 대기.
|
|
35
|
+
- 설치 후 `_freezeApp()` 으로 무한 대기 — 호출측에서 별도 후속 처리 불필요.
|
|
36
|
+
- `log` 인자에는 HTML 문자열이 전달됨 (innerHTML 로 렌더링하도록 구성할 것).
|
|
37
|
+
|
|
38
|
+
## ApkInstaller
|
|
39
|
+
|
|
40
|
+
`abstract class ApkInstaller` (static 메서드만). Capacitor 플러그인 `"ApkInstaller"` 래퍼. Web 환경에서는 알림만 표시 후 정상 반환.
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
ApkInstaller.checkPermissions(): Promise<{ granted: boolean; manifest: boolean }>
|
|
44
|
+
```
|
|
45
|
+
`granted` = REQUEST_INSTALL_PACKAGES 승인 여부, `manifest` = AndroidManifest 에 권한 선언 여부. `manifest=false` 면 APK 재설치 필요.
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
ApkInstaller.requestPermissions(): Promise<void>
|
|
49
|
+
```
|
|
50
|
+
설정 화면으로 이동시켜 사용자에게 권한 요청. 사용자 응답을 await 하지 않으므로 호출측에서 polling 필요 (`checkPermissions` 반복).
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
ApkInstaller.install(apkUri: string): Promise<void>
|
|
54
|
+
```
|
|
55
|
+
`apkUri` 는 FileProvider 의 `content://` URI. `@simplysm/capacitor-plugin-file-system` 의 `FileSystem.getUri(path)` 로 변환해 전달.
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
ApkInstaller.getVersionInfo(): Promise<VersionInfo>
|
|
59
|
+
```
|
|
60
|
+
현재 설치된 앱 자체의 버전을 반환.
|
|
61
|
+
|
|
62
|
+
## 타입
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
interface VersionInfo {
|
|
66
|
+
versionName: string; // 예: "1.2.3"
|
|
67
|
+
versionCode: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface ApkInstallerPlugin {
|
|
71
|
+
install(options: { uri: string }): Promise<void>;
|
|
72
|
+
checkPermissions(): Promise<{ granted: boolean; manifest: boolean }>;
|
|
73
|
+
requestPermissions(): Promise<void>;
|
|
74
|
+
getVersionInfo(): Promise<VersionInfo>;
|
|
75
|
+
}
|
|
76
|
+
```
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# @simplysm/capacitor-plugin-file-system
|
|
2
|
+
|
|
3
|
+
Capacitor 기반 파일 시스템 접근 플러그인. Android(11+ MANAGE_EXTERNAL_STORAGE, 10- READ/WRITE_EXTERNAL_STORAGE) 네이티브, Web 은 IndexedDB 에뮬레이션.
|
|
4
|
+
|
|
5
|
+
## 사용 트리거 인덱스
|
|
6
|
+
|
|
7
|
+
- **`FileSystem`** — 모바일/웹에서 파일·디렉토리 읽기/쓰기/삭제, 저장소 경로·URI 조회, 권한 처리 필요 시.
|
|
8
|
+
- **`FileInfo`, `StorageType`** — `readdir` 결과 처리, `getStoragePath` 호출 시 타입.
|
|
9
|
+
- **`FileSystemPlugin`** — 저수준 Capacitor 플러그인 인터페이스 직접 호출 필요 시(정상적으론 `FileSystem` 정적 메서드 사용).
|
|
10
|
+
|
|
11
|
+
## FileSystem
|
|
12
|
+
|
|
13
|
+
`abstract class` — 정적 메서드만 호출.
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
// 권한
|
|
17
|
+
await FileSystem.checkPermissions(): Promise<boolean>
|
|
18
|
+
await FileSystem.requestPermissions(): Promise<void> // Android 11+: 설정 화면 이동, 10-: 권한 대화상자
|
|
19
|
+
|
|
20
|
+
// 경로/URI
|
|
21
|
+
await FileSystem.getStoragePath(type: StorageType): Promise<string>
|
|
22
|
+
await FileSystem.getUri(filePath: string): Promise<string> // FileProvider URI
|
|
23
|
+
|
|
24
|
+
// 디렉토리
|
|
25
|
+
await FileSystem.readdir(dirPath: string): Promise<FileInfo[]>
|
|
26
|
+
await FileSystem.mkdir(targetPath: string): Promise<void> // 재귀
|
|
27
|
+
|
|
28
|
+
// 파일
|
|
29
|
+
await FileSystem.writeFile(filePath: string, data: string | Bytes): Promise<void>
|
|
30
|
+
await FileSystem.readFile(filePath: string): Promise<Bytes>
|
|
31
|
+
await FileSystem.readFile(filePath: string, encoding: "utf8"): Promise<string>
|
|
32
|
+
|
|
33
|
+
// 공통
|
|
34
|
+
await FileSystem.remove(targetPath: string): Promise<void> // 파일/디렉토리 재귀 삭제
|
|
35
|
+
await FileSystem.exists(targetPath: string): Promise<boolean>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`writeFile`: `string` 은 utf8, `Bytes`(=`Uint8Array`, `@simplysm/core-common`) 는 base64 로 전달. cross-realm 안전.
|
|
39
|
+
`readFile`: encoding 미지정 시 `Bytes`, `"utf8"` 지정 시 `string`.
|
|
40
|
+
|
|
41
|
+
사용 예:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
if (!(await FileSystem.checkPermissions())) await FileSystem.requestPermissions();
|
|
45
|
+
const root = await FileSystem.getStoragePath("externalFiles");
|
|
46
|
+
await FileSystem.mkdir(`${root}/logs`);
|
|
47
|
+
await FileSystem.writeFile(`${root}/logs/a.txt`, "hello");
|
|
48
|
+
const files = await FileSystem.readdir(`${root}/logs`);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## FileInfo / StorageType
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
interface FileInfo { name: string; isDirectory: boolean; }
|
|
55
|
+
|
|
56
|
+
type StorageType =
|
|
57
|
+
| "external" // 외부 저장소 루트 (Environment.getExternalStorageDirectory)
|
|
58
|
+
| "externalFiles" // 앱 전용 외부 파일
|
|
59
|
+
| "externalCache" // 앱 전용 외부 캐시
|
|
60
|
+
| "externalMedia" // 앱 전용 외부 미디어
|
|
61
|
+
| "appData" // 앱 데이터
|
|
62
|
+
| "appFiles" // 앱 파일
|
|
63
|
+
| "appCache"; // 앱 캐시
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## FileSystemPlugin
|
|
67
|
+
|
|
68
|
+
저수준 Capacitor 인터페이스. `FileSystem` 의 모든 정적 메서드가 위임 대상. 직접 사용 시 `writeFile`/`readFile` 의 `encoding` 은 `"utf8" | "base64"`, `data` 는 항상 `string`.
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
interface FileSystemPlugin {
|
|
72
|
+
checkPermissions(): Promise<{ granted: boolean }>;
|
|
73
|
+
requestPermissions(): Promise<void>;
|
|
74
|
+
readdir(options: { path: string }): Promise<{ files: FileInfo[] }>;
|
|
75
|
+
getStoragePath(options: { type: StorageType }): Promise<{ path: string }>;
|
|
76
|
+
getUri(options: { path: string }): Promise<{ uri: string }>;
|
|
77
|
+
writeFile(options: { path: string; data: string; encoding?: "utf8" | "base64" }): Promise<void>;
|
|
78
|
+
readFile(options: { path: string; encoding?: "utf8" | "base64" }): Promise<{ data: string }>;
|
|
79
|
+
remove(options: { path: string }): Promise<void>;
|
|
80
|
+
mkdir(options: { path: string }): Promise<void>;
|
|
81
|
+
exists(options: { path: string }): Promise<{ exists: boolean }>;
|
|
82
|
+
}
|
|
83
|
+
```
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# @simplysm/capacitor-plugin-intent
|
|
2
|
+
|
|
3
|
+
Android 인텐트(브로드캐스트 송수신, 실행 인텐트 조회, startActivityForResult) Capacitor 플러그인. 산업용 디바이스 연동(바코드 스캐너, PDA 등) 용도. 웹 환경에서는 no-op + 경고 로그.
|
|
4
|
+
|
|
5
|
+
## 사용 트리거 인덱스
|
|
6
|
+
- **`Intent.subscribe` / `Intent.unsubscribeAll`** — 특정 액션 브로드캐스트 수신.
|
|
7
|
+
- **`Intent.send`** — 외부 앱에 브로드캐스트 송신(예: DataWedge 트리거).
|
|
8
|
+
- **`Intent.getLaunchIntent`** — 앱이 인텐트로 기동될 때 초기 데이터 조회.
|
|
9
|
+
- **`Intent.addListener("newIntent", ...)` / `Intent.removeAllListeners`** — 앱 실행 중 새 인텐트 수신.
|
|
10
|
+
- **`Intent.startActivityForResult`** — 외부 Activity 실행 후 결과 수신(결제·인증 모듈 등).
|
|
11
|
+
- **`IntentResult` / `StartActivityForResultOptions` / `StartActivityForResultResult`** — 타입 정의.
|
|
12
|
+
|
|
13
|
+
## Intent (abstract class, static only)
|
|
14
|
+
|
|
15
|
+
### `subscribe(filters, callback) → Promise<() => Promise<void>>`
|
|
16
|
+
`filters`: 수신할 action 문자열 배열. `callback`: 매 수신마다 호출. 반환값은 구독 해제 함수.
|
|
17
|
+
```ts
|
|
18
|
+
const unsub = await Intent.subscribe(
|
|
19
|
+
["com.symbol.datawedge.api.RESULT_ACTION"],
|
|
20
|
+
(result) => console.log(result.extras),
|
|
21
|
+
);
|
|
22
|
+
await unsub();
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### `unsubscribeAll() → Promise<void>`
|
|
26
|
+
프로세스 내 모든 `subscribe` 구독 해제.
|
|
27
|
+
|
|
28
|
+
### `send({ action, extras? }) → Promise<void>`
|
|
29
|
+
브로드캐스트 송신.
|
|
30
|
+
```ts
|
|
31
|
+
await Intent.send({
|
|
32
|
+
action: "com.symbol.datawedge.api.ACTION",
|
|
33
|
+
extras: { "com.symbol.datawedge.api.SOFT_SCAN_TRIGGER": "TOGGLE_SCANNING" },
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### `getLaunchIntent() → Promise<IntentResult>`
|
|
38
|
+
현재 앱을 실행시킨 인텐트의 action/extras 조회. 웹은 `{}` 반환.
|
|
39
|
+
|
|
40
|
+
### `addListener("newIntent", callback) → Promise<PluginListenerHandle>`
|
|
41
|
+
앱 실행 중 수신되는 새 인텐트(`onNewIntent`)에 대한 리스너 등록. `handle.remove()` 로 개별 해제.
|
|
42
|
+
|
|
43
|
+
### `removeAllListeners() → Promise<void>`
|
|
44
|
+
`addListener` 로 등록된 모든 리스너 제거.
|
|
45
|
+
|
|
46
|
+
### `startActivityForResult(options) → Promise<StartActivityForResultResult>`
|
|
47
|
+
외부 Activity 실행 후 결과 수신. `resultCode === -1` 이 `RESULT_OK`.
|
|
48
|
+
```ts
|
|
49
|
+
const result = await Intent.startActivityForResult({
|
|
50
|
+
action: "com.example.PAY",
|
|
51
|
+
extras: { amount: 1000 },
|
|
52
|
+
});
|
|
53
|
+
if (result.resultCode === -1) { /* OK */ }
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## 타입
|
|
57
|
+
|
|
58
|
+
### `IntentResult`
|
|
59
|
+
- `action?: string` — 브로드캐스트 액션.
|
|
60
|
+
- `extras?: Record<string, unknown>` — 추가 데이터.
|
|
61
|
+
|
|
62
|
+
### `StartActivityForResultOptions`
|
|
63
|
+
- `action?: string`
|
|
64
|
+
- `uri?: string`
|
|
65
|
+
- `extras?: Record<string, unknown>`
|
|
66
|
+
- `type?: string` — MIME type.
|
|
67
|
+
- `packageName?: string` — 특정 앱 지정.
|
|
68
|
+
- `className?: string` — 특정 Activity 지정.
|
|
69
|
+
- `flags?: number` — Intent flags.
|
|
70
|
+
|
|
71
|
+
### `StartActivityForResultResult`
|
|
72
|
+
- `resultCode: number` — Android `RESULT_*` 코드 (`-1` = OK, `0` = CANCELED).
|
|
73
|
+
- `data?: { action?: string; uri?: string; extras?: Record<string, unknown> }`
|
|
74
|
+
|
|
75
|
+
### `IntentPlugin`
|
|
76
|
+
저수준 Capacitor 플러그인 인터페이스. 일반적으로 직접 사용하지 않고 `Intent` static API 사용. 커스텀 래핑이 필요할 때만 참조.
|
|
77
|
+
|
|
78
|
+
## 플랫폼 동작
|
|
79
|
+
- Android: 네이티브 구현.
|
|
80
|
+
- Web: 모든 변경 메서드(`subscribe`/`send`/`startActivityForResult`)는 `console.warn` 후 stub 값 반환. `getLaunchIntent`/`unsubscribe*` 는 조용히 no-op.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# @simplysm/capacitor-plugin-usb-storage
|
|
2
|
+
|
|
3
|
+
USB Mass Storage 접근용 Capacitor 플러그인 (Android: libaums, Browser: IndexedDB 가상 USB 에뮬레이션).
|
|
4
|
+
|
|
5
|
+
## 사용 트리거 인덱스
|
|
6
|
+
|
|
7
|
+
- **`UsbStorage`** — 정적 메서드로 장치 목록·권한·디렉토리·파일 읽기. USB 저장 장치에서 데이터를 가져올 때.
|
|
8
|
+
- **`UsbDeviceInfo` / `UsbDeviceFilter` / `UsbFileInfo`** — 인자·반환 타입. 호출부 타입 선언에.
|
|
9
|
+
- **`UsbStoragePlugin`** — 원시 Capacitor 플러그인 인터페이스. `UsbStorage` 래퍼로 충분하면 직접 사용 X.
|
|
10
|
+
|
|
11
|
+
## UsbStorage
|
|
12
|
+
|
|
13
|
+
모든 메서드 `static async`. 장치 식별은 `{ vendorId, productId }` (`UsbDeviceFilter`)로 한다.
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { UsbStorage } from "@simplysm/capacitor-plugin-usb-storage";
|
|
17
|
+
|
|
18
|
+
const devices = await UsbStorage.getDevices(); // UsbDeviceInfo[]
|
|
19
|
+
const filter = { vendorId: devices[0].vendorId, productId: devices[0].productId };
|
|
20
|
+
|
|
21
|
+
if (!(await UsbStorage.checkPermissions(filter))) {
|
|
22
|
+
if (!(await UsbStorage.requestPermissions(filter))) return; // boolean
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const files = await UsbStorage.readdir(filter, "/"); // UsbFileInfo[]
|
|
26
|
+
const data = await UsbStorage.readFile(filter, "/a.txt"); // Bytes | undefined
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- `getDevices()` — 연결된 USB 장치 전체 반환.
|
|
30
|
+
- `requestPermissions(filter)` / `checkPermissions(filter)` — 권한 승인/보유 여부 `boolean`.
|
|
31
|
+
- `readdir(filter, dirPath)` — 디렉토리 항목 목록 (`name`, `isDirectory`).
|
|
32
|
+
- `readFile(filter, filePath)` — 파일 바이트. 없으면 `undefined`. 내부에서 base64 → `Bytes`(@simplysm/core-common) 변환.
|
|
33
|
+
|
|
34
|
+
## 타입
|
|
35
|
+
|
|
36
|
+
- `UsbDeviceInfo` — `deviceName`, `manufacturerName`, `productName`, `vendorId`, `productId`.
|
|
37
|
+
- `UsbDeviceFilter` — `vendorId`, `productId`.
|
|
38
|
+
- `UsbFileInfo` — `name`, `isDirectory`.
|
|
39
|
+
- `UsbStoragePlugin` — Capacitor `registerPlugin` 원시 인터페이스. 메서드 반환이 `{ devices }`/`{ granted }`/`{ files }`/`{ data: string | null }` 형태의 base64 raw 응답.
|