@ngockhoale/ukit 1.1.6
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/CHANGELOG.md +179 -0
- package/LICENSE +21 -0
- package/README.md +189 -0
- package/bin/ukit +30 -0
- package/manifests/platform.full.yaml +1194 -0
- package/package.json +71 -0
- package/scripts/bug/triage.mjs +37 -0
- package/scripts/index/build-index.mjs +35 -0
- package/scripts/index/query-index.mjs +92 -0
- package/scripts/index/refresh-index.mjs +85 -0
- package/scripts/release/verify-release.mjs +56 -0
- package/src/bug/triageBug.js +123 -0
- package/src/cli/adapters.js +148 -0
- package/src/cli/commands/diff.js +51 -0
- package/src/cli/commands/doctor.js +125 -0
- package/src/cli/commands/indexArgs.js +73 -0
- package/src/cli/commands/indexTools.js +509 -0
- package/src/cli/commands/install.js +293 -0
- package/src/cli/commands/memory.js +126 -0
- package/src/cli/commands/status.js +8 -0
- package/src/cli/commands/uninstall.js +51 -0
- package/src/cli/index.js +109 -0
- package/src/context/detectProjectContext.js +49 -0
- package/src/context/detectProviders.js +12 -0
- package/src/core/applyPlan.js +89 -0
- package/src/core/buildPlan.js +228 -0
- package/src/core/compact/index.js +294 -0
- package/src/core/compact/threshold.js +936 -0
- package/src/core/diffPlan.js +73 -0
- package/src/core/ensureGitignore.js +117 -0
- package/src/core/fileOps.js +188 -0
- package/src/core/memory/hygiene.js +160 -0
- package/src/core/memory/index.js +2 -0
- package/src/core/memory/retrieval.js +476 -0
- package/src/core/memory/store.js +202 -0
- package/src/core/metadata.js +132 -0
- package/src/core/migrateLegacy.js +139 -0
- package/src/core/output/index.js +1309 -0
- package/src/core/paths.js +13 -0
- package/src/core/report.js +17 -0
- package/src/core/router/advisor.js +42 -0
- package/src/core/router/index.js +2 -0
- package/src/core/router/router.js +164 -0
- package/src/core/runInstallPipeline.js +365 -0
- package/src/core/runtimeConfig.js +190 -0
- package/src/core/runtimePaths.js +24 -0
- package/src/core/status.js +186 -0
- package/src/core/token/index.js +328 -0
- package/src/core/uninstall.js +246 -0
- package/src/core/validation/confidence.js +89 -0
- package/src/core/validation/index.js +2 -0
- package/src/core/validation/validator.js +165 -0
- package/src/index/buildIndex.js +1392 -0
- package/src/index/gitHooks.js +109 -0
- package/src/index/importResolution.js +377 -0
- package/src/index/languageTools.js +127 -0
- package/src/index/paths.js +27 -0
- package/src/index/queryIndex.js +637 -0
- package/src/index/relatedTests.js +237 -0
- package/src/index/resolveContext.js +345 -0
- package/src/index/routeCatalog.js +258 -0
- package/src/index/taskRouting.js +677 -0
- package/src/index/verificationPlan.js +437 -0
- package/src/manifest/loadManifest.js +22 -0
- package/src/manifest/selectItems.js +78 -0
- package/src/manifest/validateManifest.js +115 -0
- package/src/render/buildVariables.js +39 -0
- package/src/render/renderTemplate.js +44 -0
- package/src/stack/detectStack.js +213 -0
- package/templates/.claude/agents/bug-debugger.md +57 -0
- package/templates/.claude/agents/feature-implementer.md +55 -0
- package/templates/.claude/config/providers.md +25 -0
- package/templates/.claude/hooks/auto-allow-bash.sh +155 -0
- package/templates/.claude/hooks/auto-prune-bash.sh +75 -0
- package/templates/.claude/hooks/block-dangerous.sh +54 -0
- package/templates/.claude/hooks/compress-output.sh +17 -0
- package/templates/.claude/hooks/protect-files.sh +37 -0
- package/templates/.claude/hooks/reinject-context.sh +28 -0
- package/templates/.claude/hooks/session-start.md +13 -0
- package/templates/.claude/hooks/skill-router.sh +1681 -0
- package/templates/.claude/hooks/verification-guard.sh +271 -0
- package/templates/.claude/settings.json +144 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/mce/mc.xsd +75 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/pack.py +159 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/unpack.py +29 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/validate.py +69 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/validation/__init__.py +15 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/validation/base.py +951 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/validation/docx.py +274 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/validation/pptx.py +315 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/validation/redlining.py +279 -0
- package/templates/.claude/skills/backend-api/SKILL.md +26 -0
- package/templates/.claude/skills/canvas-design/LICENSE.txt +202 -0
- package/templates/.claude/skills/canvas-design/SKILL.md +130 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Lora-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
- package/templates/.claude/skills/code-review/SKILL.md +97 -0
- package/templates/.claude/skills/debugging-toolkit/SKILL.md +156 -0
- package/templates/.claude/skills/delivery/SKILL.md +92 -0
- package/templates/.claude/skills/discover-security/SKILL.md +86 -0
- package/templates/.claude/skills/docker-packaging/SKILL.md +60 -0
- package/templates/.claude/skills/docs-manager/SKILL.md +465 -0
- package/templates/.claude/skills/docs-manager/init-project-docs.sh +70 -0
- package/templates/.claude/skills/docs-manager/templates/README.md.template +50 -0
- package/templates/.claude/skills/docs-manager/templates/agent-roles.md.template +24 -0
- package/templates/.claude/skills/docs-manager/templates/coding-conventions.md.template +28 -0
- package/templates/.claude/skills/docs-manager/templates/memory.md.template +30 -0
- package/templates/.claude/skills/docs-manager/templates/onboarding.md.template +20 -0
- package/templates/.claude/skills/docs-manager/templates/project.md.template +26 -0
- package/templates/.claude/skills/docs-quality/SKILL.md +148 -0
- package/templates/.claude/skills/docx/LICENSE.txt +30 -0
- package/templates/.claude/skills/docx/SKILL.md +197 -0
- package/templates/.claude/skills/docx/docx-js.md +350 -0
- package/templates/.claude/skills/docx/ooxml.md +610 -0
- package/templates/.claude/skills/docx/scripts/__init__.py +1 -0
- package/templates/.claude/skills/docx/scripts/document.py +1276 -0
- package/templates/.claude/skills/docx/scripts/templates/comments.xml +3 -0
- package/templates/.claude/skills/docx/scripts/templates/commentsExtended.xml +3 -0
- package/templates/.claude/skills/docx/scripts/templates/commentsExtensible.xml +3 -0
- package/templates/.claude/skills/docx/scripts/templates/commentsIds.xml +3 -0
- package/templates/.claude/skills/docx/scripts/templates/people.xml +3 -0
- package/templates/.claude/skills/docx/scripts/utilities.py +374 -0
- package/templates/.claude/skills/duraone/SKILL.md +204 -0
- package/templates/.claude/skills/duraone/references/backend.md +636 -0
- package/templates/.claude/skills/duraone/references/frontend.md +1506 -0
- package/templates/.claude/skills/duraone/references/sql.md +631 -0
- package/templates/.claude/skills/duraone/references/workflow.md +520 -0
- package/templates/.claude/skills/executing-plans/SKILL.md +76 -0
- package/templates/.claude/skills/file-organizer/SKILL.md +433 -0
- package/templates/.claude/skills/frontend/SKILL.md +26 -0
- package/templates/.claude/skills/frontend-design/LICENSE.txt +177 -0
- package/templates/.claude/skills/frontend-design/SKILL.md +42 -0
- package/templates/.claude/skills/frontend-vue/SKILL.md +127 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Box.vue +137 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Button.vue +93 -0
- package/templates/.claude/skills/frontend-vue/components/Control/ButtonBar.vue +29 -0
- package/templates/.claude/skills/frontend-vue/components/Control/ButtonFloat.vue +62 -0
- package/templates/.claude/skills/frontend-vue/components/Control/CheckButton.vue +75 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Checkbox.vue +58 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Datetime.vue +148 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Dropdownlist.vue +156 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Input.vue +106 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Label.vue +38 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Master/BoxColumn.vue +24 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Popup/Confirm.vue +33 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Popup/Info.vue +32 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Popup/ModalInfo.vue +39 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Popup/Reject.vue +64 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Tag.vue +82 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Upload.vue +61 -0
- package/templates/.claude/skills/frontend-vue/components/ControlMobile/Dropdownlist.vue +103 -0
- package/templates/.claude/skills/frontend-vue/components/ControlMobile/PagingBar.vue +108 -0
- package/templates/.claude/skills/frontend-vue/components/ControlMobile/UploadImage.vue +137 -0
- package/templates/.claude/skills/frontend-vue/components/Grid/AG.vue +806 -0
- package/templates/.claude/skills/frontend-vue/components/Grid/AntTable.vue +253 -0
- package/templates/.claude/skills/frontend-vue/components/Grid/CustomDropdownEditor.vue +43 -0
- package/templates/.claude/skills/frontend-vue/components/Grid/CustomDropdownEditorEnable.vue +55 -0
- package/templates/.claude/skills/frontend-vue/components/Grid/HtmlTable.vue +40 -0
- package/templates/.claude/skills/frontend-vue/components/PDFViewer.vue +25 -0
- package/templates/.claude/skills/frontend-vue/components/Panel/FormView.vue +309 -0
- package/templates/.claude/skills/frontend-vue/components/Partial/Footer.vue +23 -0
- package/templates/.claude/skills/frontend-vue/components/Partial/Header.vue +265 -0
- package/templates/.claude/skills/frontend-vue/components/Partial/Sidebar.vue +122 -0
- package/templates/.claude/skills/frontend-vue/components/Template.vue +16 -0
- package/templates/.claude/skills/frontend-vue/components/View/Form.vue +89 -0
- package/templates/.claude/skills/frontend-vue/composables/indexDBStore.js +140 -0
- package/templates/.claude/skills/frontend-vue/composables/masterApi.js +362 -0
- package/templates/.claude/skills/frontend-vue/composables/state.js +578 -0
- package/templates/.claude/skills/frontend-vue/composables/useRequest.js +221 -0
- package/templates/.claude/skills/frontend-vue/composables/useSession.js +179 -0
- package/templates/.claude/skills/frontend-vue/composables/useTranslation.js +54 -0
- package/templates/.claude/skills/frontend-vue/composables/useWebSocket.js +257 -0
- package/templates/.claude/skills/frontend-vue/composables/userObj.js +111 -0
- package/templates/.claude/skills/frontend-vue/composables/utils.js +322 -0
- package/templates/.claude/skills/frontend-vue/reference/composables-example.vue +320 -0
- package/templates/.claude/skills/frontend-vue/reference/form-example.vue +183 -0
- package/templates/.claude/skills/frontend-vue/reference/grid-example.vue +147 -0
- package/templates/.claude/skills/frontend-vue/reference/masterdata-example/[id].vue +106 -0
- package/templates/.claude/skills/frontend-vue/reference/masterdata-example/index.vue +58 -0
- package/templates/.claude/skills/frontend-vue/reference/popup-example.vue +159 -0
- package/templates/.claude/skills/pdf/LICENSE.txt +30 -0
- package/templates/.claude/skills/pdf/SKILL.md +294 -0
- package/templates/.claude/skills/pdf/forms.md +205 -0
- package/templates/.claude/skills/pdf/reference.md +612 -0
- package/templates/.claude/skills/pdf/scripts/check_bounding_boxes.py +70 -0
- package/templates/.claude/skills/pdf/scripts/check_bounding_boxes_test.py +226 -0
- package/templates/.claude/skills/pdf/scripts/check_fillable_fields.py +12 -0
- package/templates/.claude/skills/pdf/scripts/convert_pdf_to_images.py +35 -0
- package/templates/.claude/skills/pdf/scripts/create_validation_image.py +41 -0
- package/templates/.claude/skills/pdf/scripts/extract_form_field_info.py +152 -0
- package/templates/.claude/skills/pdf/scripts/fill_fillable_fields.py +114 -0
- package/templates/.claude/skills/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
- package/templates/.claude/skills/pdf-processing/SKILL.md +107 -0
- package/templates/.claude/skills/pdf-processing-pro/FORMS.md +610 -0
- package/templates/.claude/skills/pdf-processing-pro/OCR.md +137 -0
- package/templates/.claude/skills/pdf-processing-pro/SKILL.md +296 -0
- package/templates/.claude/skills/pdf-processing-pro/TABLES.md +626 -0
- package/templates/.claude/skills/pdf-processing-pro/scripts/analyze_form.py +307 -0
- package/templates/.claude/skills/postgres/SKILL.md +69 -0
- package/templates/.claude/skills/postgres/reference/fn_get_examples.sql +208 -0
- package/templates/.claude/skills/postgres/reference/fn_rpt_examples.sql +239 -0
- package/templates/.claude/skills/postgres/reference/utility_functions.sql +94 -0
- package/templates/.claude/skills/pptx/LICENSE.txt +30 -0
- package/templates/.claude/skills/pptx/SKILL.md +484 -0
- package/templates/.claude/skills/pptx/html2pptx.md +625 -0
- package/templates/.claude/skills/pptx/ooxml.md +427 -0
- package/templates/.claude/skills/pptx/scripts/html2pptx.js +979 -0
- package/templates/.claude/skills/pptx/scripts/inventory.py +1020 -0
- package/templates/.claude/skills/pptx/scripts/rearrange.py +231 -0
- package/templates/.claude/skills/pptx/scripts/replace.py +385 -0
- package/templates/.claude/skills/pptx/scripts/thumbnail.py +450 -0
- package/templates/.claude/skills/repo-maintenance/SKILL.md +97 -0
- package/templates/.claude/skills/research/EXAMPLES.md +434 -0
- package/templates/.claude/skills/research/REFERENCE.md +399 -0
- package/templates/.claude/skills/research/SKILL.md +136 -0
- package/templates/.claude/skills/root-cause-tracing/SKILL.md +174 -0
- package/templates/.claude/skills/root-cause-tracing/find-polluter.sh +63 -0
- package/templates/.claude/skills/sharing-skills/SKILL.md +194 -0
- package/templates/.claude/skills/sql-optimization-patterns/SKILL.md +493 -0
- package/templates/.claude/skills/subagent-driven-development/SKILL.md +189 -0
- package/templates/.claude/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/templates/.claude/skills/systematic-debugging/SKILL.md +295 -0
- package/templates/.claude/skills/systematic-debugging/test-academic.md +14 -0
- package/templates/.claude/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/templates/.claude/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/templates/.claude/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/templates/.claude/skills/test-driven-development/SKILL.md +364 -0
- package/templates/.claude/skills/testing-anti-patterns/SKILL.md +302 -0
- package/templates/.claude/skills/testing-quality/SKILL.md +97 -0
- package/templates/.claude/skills/verification-before-completion/SKILL.md +139 -0
- package/templates/.claude/skills/webapp-testing/LICENSE.txt +202 -0
- package/templates/.claude/skills/webapp-testing/SKILL.md +96 -0
- package/templates/.claude/skills/webapp-testing/examples/console_logging.py +35 -0
- package/templates/.claude/skills/webapp-testing/examples/element_discovery.py +40 -0
- package/templates/.claude/skills/webapp-testing/examples/static_html_automation.py +33 -0
- package/templates/.claude/skills/webapp-testing/scripts/with_server.py +106 -0
- package/templates/.claude/ukit/index/build-index.mjs +28 -0
- package/templates/.claude/ukit/index/cache-utils.mjs +140 -0
- package/templates/.claude/ukit/index/lib/index-core.mjs +2800 -0
- package/templates/.claude/ukit/index/query-index.mjs +150 -0
- package/templates/.claude/ukit/index/refresh-index.mjs +57 -0
- package/templates/.claude/ukit/index/reset-auto-permissions.mjs +76 -0
- package/templates/.claude/ukit/index/resolve-context.mjs +279 -0
- package/templates/.claude/ukit/index/route-catalog.mjs +258 -0
- package/templates/.claude/ukit/index/route-task.mjs +1994 -0
- package/templates/.claude/ukit/index/triage.mjs +133 -0
- package/templates/.claude/ukit/index/verify-context.mjs +689 -0
- package/templates/.claude/ukit/runtime/compact-threshold.mjs +1013 -0
- package/templates/.claude/ukit/runtime/output-compression.mjs +1340 -0
- package/templates/.claude/ukit/runtime/reinject-context.mjs +874 -0
- package/templates/.claude/ukit/runtime/token-utils.mjs +500 -0
- package/templates/.codex/README.md +83 -0
- package/templates/.codex/settings.json +187 -0
- package/templates/.gitignore +75 -0
- package/templates/AGENTS.md +116 -0
- package/templates/CLAUDE.md +93 -0
- package/templates/adapter-presets/antigravity/README.md +22 -0
- package/templates/adapter-presets/antigravity/rules.md +49 -0
- package/templates/adapter-presets/claude/settings.local.json +42 -0
- package/templates/adapter-presets/codex/settings.local.json +6 -0
- package/templates/adapter-presets/opencode/opencode.template.json +1 -0
- package/templates/docs/BUGFIX.md +20 -0
- package/templates/docs/BUG_INDEX.md +12 -0
- package/templates/docs/BUG_METRICS.md +7 -0
- package/templates/docs/BUG_TEMPLATE.md +13 -0
- package/templates/docs/CODE_MAP.md +35 -0
- package/templates/docs/INSTALL.md +113 -0
- package/templates/docs/MEMORY.md +49 -0
- package/templates/docs/PROJECT.md +50 -0
- package/templates/docs/UKIT_USAGE_GUIDE.md +147 -0
- package/templates/docs/WORKLOG.md +10 -0
- package/templates/ukit/README.md +14 -0
- package/templates/ukit/storage/cache/compact-history.json +3 -0
- package/templates/ukit/storage/cache/compact-pressure.json +1 -0
- package/templates/ukit/storage/cache/output-history.json +3 -0
- package/templates/ukit/storage/cache/prompt-cache.json +3 -0
- package/templates/ukit/storage/config.json +37 -0
- package/templates/ukit/storage/memory/projects/.gitkeep +2 -0
- package/templates/ukit/storage/memory/sessions/.gitkeep +0 -0
- package/templates/ukit/storage/memory/user.json +5 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file useRequest.js
|
|
3
|
+
* @description HTTP request composable — wrapper duy nhất cho mọi API call trong hệ thống.
|
|
4
|
+
* Tự động GZIP compress/decompress, quản lý loading state global (state.loading).
|
|
5
|
+
*
|
|
6
|
+
* ⚠️ QUAN TRỌNG: Không được dùng fetch() hay axios() trực tiếp. Luôn dùng 3 hàm chính:
|
|
7
|
+
* - request() → gọi API thông thường (JSON)
|
|
8
|
+
* - requestForm() → upload file (multipart/form-data)
|
|
9
|
+
* - request_origin() → gọi endpoint custom (không qua /api/ prefix)
|
|
10
|
+
*
|
|
11
|
+
* @requires pako - Thư viện GZIP compression
|
|
12
|
+
* @requires axios - HTTP client
|
|
13
|
+
*/
|
|
14
|
+
import axios from "axios";
|
|
15
|
+
import pako from "pako";
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Giải nén dữ liệu GZIP từ base64 string → JSON string
|
|
20
|
+
* @param {string} compressedData - Dữ liệu đã nén dạng base64
|
|
21
|
+
* @returns {string} Chuỗi JSON đã giải nén
|
|
22
|
+
*/
|
|
23
|
+
export const decompressData = (compressedData) => {
|
|
24
|
+
// Convert the compressed data (base64 string) to a Uint8Array
|
|
25
|
+
const compressedUint8Array = Uint8Array.from(atob(compressedData), c => c.charCodeAt(0));
|
|
26
|
+
// Decompress the data using pako
|
|
27
|
+
const decompressedUint8Array = pako.ungzip(compressedUint8Array);
|
|
28
|
+
// Convert the decompressed data to a string
|
|
29
|
+
const decompressedString = new TextDecoder().decode(decompressedUint8Array);
|
|
30
|
+
// Now you can use decompressedString as needed
|
|
31
|
+
return decompressedString;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Nén dữ liệu thành GZIP base64 string
|
|
36
|
+
* @param {string} data - Chuỗi cần nén
|
|
37
|
+
* @returns {string} Dữ liệu đã nén dạng base64
|
|
38
|
+
*/
|
|
39
|
+
export const compressData = (data) => {
|
|
40
|
+
// Convert the string data to a Uint8Array
|
|
41
|
+
const inputUint8Array = new TextEncoder().encode(data);
|
|
42
|
+
// Compress the data using pako
|
|
43
|
+
const compressedUint8Array = pako.gzip(inputUint8Array);
|
|
44
|
+
// Convert the compressed data to a base64 string
|
|
45
|
+
const compressedData = btoa(String.fromCharCode(...new Uint8Array(compressedUint8Array.buffer)));
|
|
46
|
+
// Now you can use compressedData as needed
|
|
47
|
+
return compressedData;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Gọi API tới endpoint custom (baseURL gốc, KHÔNG qua /api/ prefix).
|
|
51
|
+
* Dùng khi cần gọi endpoint đặc biệt nằm ngoài cấu trúc /api/ chuẩn.
|
|
52
|
+
* Tự động decompress GZIP nếu response là string.
|
|
53
|
+
* @param {string} url - Đường dẫn endpoint (vd: "custom/report")
|
|
54
|
+
* @param {Object} data - Request body hoặc query params
|
|
55
|
+
* @param {"post"|"get"} [method="post"] - HTTP method
|
|
56
|
+
* @returns {Promise<Object|Array>} Response data đã parse, trả [] nếu lỗi
|
|
57
|
+
* @example
|
|
58
|
+
* const res = await request_origin("export/excel", { id: 123 })
|
|
59
|
+
*/
|
|
60
|
+
export const request_origin = async (url, data = {}, method = "post") => {
|
|
61
|
+
const ax = axios.create({
|
|
62
|
+
baseURL: baseurl() + "/",
|
|
63
|
+
});
|
|
64
|
+
if (method === "get") {
|
|
65
|
+
data = { params: data };
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
state.loading_count += 1;
|
|
69
|
+
if (state.loading_count === 1) {
|
|
70
|
+
state.loading = true;
|
|
71
|
+
}
|
|
72
|
+
let response = await ax[method.toLowerCase()](url, data);
|
|
73
|
+
state.loading_count -= 1;
|
|
74
|
+
if (state.loading_count === 0) {
|
|
75
|
+
state.loading = false;
|
|
76
|
+
}
|
|
77
|
+
if(typeof response?.data === 'object'){
|
|
78
|
+
return response?.data;
|
|
79
|
+
} else {
|
|
80
|
+
const gzipBuffer = decompressData(response?.data);
|
|
81
|
+
return JSON.parse(gzipBuffer);
|
|
82
|
+
}
|
|
83
|
+
} catch {
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Hàm gọi API chính — dùng cho mọi request JSON thông thường.
|
|
89
|
+
* BaseURL: baseurl() + "api/" → tự động nối prefix /api/.
|
|
90
|
+
* Tự động GZIP compress request, decompress response.
|
|
91
|
+
* Quản lý state.loading toàn cục (trừ khi with_loading=false).
|
|
92
|
+
* @param {string} url - API endpoint (vd: "/select", "/save", "/delete")
|
|
93
|
+
* @param {Object} [data={}] - Request body (POST) hoặc query params (GET)
|
|
94
|
+
* @param {"post"|"get"} [method="post"] - HTTP method
|
|
95
|
+
* @param {boolean} [with_loading=true] - Có hiển thị loading spinner không
|
|
96
|
+
* @returns {Promise<Object|Array>} Response data đã parse, trả [] nếu lỗi
|
|
97
|
+
* @example
|
|
98
|
+
* // GET danh sách
|
|
99
|
+
* const list = await request("/select", { schema: get_schema(), table: "branch" }, "get")
|
|
100
|
+
* // POST lưu dữ liệu
|
|
101
|
+
* const res = await request("/save", { schema: get_schema(), table: "branch", ...workingObj })
|
|
102
|
+
*/
|
|
103
|
+
export const request = async (url, data = {}, method = "post", with_loading=true) => {
|
|
104
|
+
const ax = axios.create({
|
|
105
|
+
baseURL: baseurl() + "api/",
|
|
106
|
+
});
|
|
107
|
+
const headers = { 'Content-Type': 'application/json', 'is_compress': 'true'};
|
|
108
|
+
if (method === "get") {
|
|
109
|
+
data = { params: data, headers: headers };
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
if(with_loading){
|
|
113
|
+
state.loading_count += 1;
|
|
114
|
+
if (state.loading_count === 1) {
|
|
115
|
+
state.loading = true;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
let response = null;
|
|
119
|
+
if(method === 'post'){
|
|
120
|
+
response = await ax[method.toLowerCase()](url, data, {headers: headers});
|
|
121
|
+
} else {
|
|
122
|
+
response = await ax[method.toLowerCase()](url,data );
|
|
123
|
+
}
|
|
124
|
+
let to_return = [];
|
|
125
|
+
if(typeof response?.data === 'object'){
|
|
126
|
+
to_return = response?.data;
|
|
127
|
+
} else {
|
|
128
|
+
const gzipBuffer = decompressData(response?.data);
|
|
129
|
+
to_return = JSON.parse(gzipBuffer);
|
|
130
|
+
}
|
|
131
|
+
if(with_loading){
|
|
132
|
+
state.loading_count -= 1;
|
|
133
|
+
if (state.loading_count === 0) {
|
|
134
|
+
state.loading = false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return to_return;
|
|
138
|
+
} catch {
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Gọi API upload file — dùng multipart/form-data.
|
|
145
|
+
* Dùng khi cần upload file (ảnh, excel, pdf...).
|
|
146
|
+
* @param {string} url - API endpoint (vd: "/upload")
|
|
147
|
+
* @param {FormData|Object} [data={}] - FormData chứa file và metadata
|
|
148
|
+
* @param {"post"} [method="post"] - Luôn là POST
|
|
149
|
+
* @param {boolean} [with_loading=true] - Có hiển thị loading spinner không
|
|
150
|
+
* @returns {Promise<Object|Array>} Response data đã parse, trả [] nếu lỗi
|
|
151
|
+
* @example
|
|
152
|
+
* const formData = new FormData()
|
|
153
|
+
* formData.append("file", file)
|
|
154
|
+
* formData.append("schema", get_schema())
|
|
155
|
+
* const res = await requestForm("/upload", formData)
|
|
156
|
+
*/
|
|
157
|
+
export const requestForm = async (url, data = {}, method = "post", with_loading=true) => {
|
|
158
|
+
const ax = axios.create({
|
|
159
|
+
baseURL: baseurl() + "api/",
|
|
160
|
+
});
|
|
161
|
+
const headers = { 'Content-Type': 'multipart/form-data' };
|
|
162
|
+
try {
|
|
163
|
+
if(with_loading){
|
|
164
|
+
state.loading_count += 1;
|
|
165
|
+
if (state.loading_count === 1) {
|
|
166
|
+
state.loading = true;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
let response = await ax['post'](url, data, { headers: headers });
|
|
170
|
+
let to_return = [];
|
|
171
|
+
if(typeof response?.data === 'object'){
|
|
172
|
+
to_return = response?.data;
|
|
173
|
+
} else {
|
|
174
|
+
const gzipBuffer = decompressData(response?.data);
|
|
175
|
+
to_return = JSON.parse(gzipBuffer);
|
|
176
|
+
}
|
|
177
|
+
if(with_loading){
|
|
178
|
+
state.loading_count -= 1;
|
|
179
|
+
if (state.loading_count === 0) {
|
|
180
|
+
state.loading = false;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return to_return;
|
|
184
|
+
} catch {
|
|
185
|
+
return [];
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Gọi API đăng nhập — endpoint riêng: baseurl() + "user/login"
|
|
191
|
+
* @param {Object} [data={}] - { username, password }
|
|
192
|
+
* @param {"post"} [method="post"] - HTTP method
|
|
193
|
+
* @returns {Promise<Object|Array>} User data hoặc [] nếu lỗi
|
|
194
|
+
*/
|
|
195
|
+
export const requestLogin = async (data = {}, method = "post") => {
|
|
196
|
+
const ax = axios.create({
|
|
197
|
+
baseURL: baseurl() + "user/login",
|
|
198
|
+
});
|
|
199
|
+
try {
|
|
200
|
+
let response = await ax[method.toLowerCase()]("", data);
|
|
201
|
+
return response?.data;
|
|
202
|
+
} catch {
|
|
203
|
+
return [];
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
/**
|
|
207
|
+
* Gửi email qua API — endpoint: baseurl() + "send_email/send_email"
|
|
208
|
+
* @param {Object} [data={}] - Nội dung email { to, subject, body, ... }
|
|
209
|
+
* @returns {Promise<Object|Array>} Kết quả gửi mail hoặc [] nếu lỗi
|
|
210
|
+
*/
|
|
211
|
+
export const requestSendmail = async (data = {}) => {
|
|
212
|
+
const ax = axios.create({
|
|
213
|
+
baseURL: baseurl() + "send_email/send_email",
|
|
214
|
+
});
|
|
215
|
+
try {
|
|
216
|
+
let response = await ax['post']("", data);
|
|
217
|
+
return response?.data;
|
|
218
|
+
} catch {
|
|
219
|
+
return [];
|
|
220
|
+
}
|
|
221
|
+
};
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file useSession.js
|
|
3
|
+
* @description Quản lý session user qua localStorage với cơ chế hết hạn + hash bảo vệ.
|
|
4
|
+
* Session lưu dưới key "unic_service", mặc định hết hạn sau 2 giờ.
|
|
5
|
+
*
|
|
6
|
+
* Exported functions:
|
|
7
|
+
* - setSession(key, value) → Lưu giá trị vào session
|
|
8
|
+
* - getSession(key) → Đọc giá trị từ session (kiểm tra hash + expiry)
|
|
9
|
+
* - clearSession() → Xóa toàn bộ session
|
|
10
|
+
* - refreshSession() → Gia hạn thời gian session
|
|
11
|
+
* - encrypt_string(str) → Hash chuỗi (dùng nội bộ cho integrity check)
|
|
12
|
+
*/
|
|
13
|
+
const SESSION_KEY = 'unic_service'
|
|
14
|
+
const DEFAULT_EXPIRATION = 2 * 60 * 60 * 1000 // 2 hours in milliseconds
|
|
15
|
+
const RANDOM_STRING = "3e23e8160039594a33894f6564e1b1348bbd7a0088d42c4acb73eeaed59c009d";
|
|
16
|
+
|
|
17
|
+
/** @private Đọc session từ localStorage, kiểm tra expiry */
|
|
18
|
+
const getStoredSession = () => {
|
|
19
|
+
if (process.client) {
|
|
20
|
+
try {
|
|
21
|
+
const storedSession = localStorage.getItem(SESSION_KEY)
|
|
22
|
+
if (storedSession) {
|
|
23
|
+
const { data, expiry } = JSON.parse(storedSession)
|
|
24
|
+
if (expiry > Date.now()) {
|
|
25
|
+
return data
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error('Failed to get session from localStorage:', error)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return {}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Hash chuỗi — dùng nội bộ để tạo integrity hash cho session expiry.
|
|
37
|
+
* KHÔNG phải mã hóa bảo mật, chỉ dùng để detect tampering.
|
|
38
|
+
* @param {string} string - Chuỗi cần hash
|
|
39
|
+
* @returns {string} Chuỗi hash 64 ký tự lowercase
|
|
40
|
+
*/
|
|
41
|
+
export const encrypt_string = (string) => {
|
|
42
|
+
const hash = '';
|
|
43
|
+
const char = string.split('');
|
|
44
|
+
const len = char.length;
|
|
45
|
+
let a = 0x67452301;
|
|
46
|
+
let b = 0xefcdab89;
|
|
47
|
+
let c = 0x98badcfe;
|
|
48
|
+
let d = 0x10325476;
|
|
49
|
+
|
|
50
|
+
for (let i = 0; i < len; i += 16) {
|
|
51
|
+
const w = new Array(16);
|
|
52
|
+
for (let t = 0; t < 16; t++) {
|
|
53
|
+
w[t] = char[i + t] || 0;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let a1 = a;
|
|
57
|
+
let b1 = b;
|
|
58
|
+
let c1 = c;
|
|
59
|
+
let d1 = d;
|
|
60
|
+
|
|
61
|
+
for (let t = 0; t < 64; t++) {
|
|
62
|
+
const f = (t < 16) ? (b1 & c1 | ~b1 & d1) : ((t < 32) ? (b1 ^ c1 ^ d1) : (b1 & c1 | b1 & d1 | c1 & d1));
|
|
63
|
+
const g = (t < 16) ? t : ((t < 32) ? (5 * t + 1) : ((t < 48) ? (3 * t + 5) : (7 * t)));
|
|
64
|
+
const f4 = (a1 + f + w[g] + 0x5a827999).toString(16);
|
|
65
|
+
const a2 = d1;
|
|
66
|
+
const b2 = a1;
|
|
67
|
+
const c2 = b1 ^ f4;
|
|
68
|
+
const d2 = c1;
|
|
69
|
+
|
|
70
|
+
a1 = a2;
|
|
71
|
+
b1 = b2;
|
|
72
|
+
c1 = c2;
|
|
73
|
+
d1 = d2;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
a = (a + a1).toString(16);
|
|
77
|
+
b = (b + b1).toString(16);
|
|
78
|
+
c = (c + c1).toString(16);
|
|
79
|
+
d = (d + d1).toString(16);
|
|
80
|
+
}
|
|
81
|
+
return (a + b + RANDOM_STRING + c + d).toLowerCase().substring(0, 64);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const session = ref(getStoredSession())
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Lưu giá trị vào session (localStorage) với expiration + hash
|
|
88
|
+
* @param {string} key - Tên key (vd: "username", "usergroup", "language")
|
|
89
|
+
* @param {*} value - Giá trị cần lưu
|
|
90
|
+
* @param {number} [expirationMs=7200000] - Thời gian hết hạn (ms), mặc định 2 giờ
|
|
91
|
+
* @example setSession("username", "admin@duraone.com")
|
|
92
|
+
*/
|
|
93
|
+
export const setSession = (key, value, expirationMs = DEFAULT_EXPIRATION) => {
|
|
94
|
+
session.value[key] = value
|
|
95
|
+
if (process.client) {
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
const expire_str = Date.now() + expirationMs;
|
|
99
|
+
const hash = encrypt_string(expire_str.toString());
|
|
100
|
+
const sessionData = {
|
|
101
|
+
data: session.value,
|
|
102
|
+
expiry: expire_str,
|
|
103
|
+
hash: hash
|
|
104
|
+
}
|
|
105
|
+
localStorage.setItem(SESSION_KEY, JSON.stringify(sessionData))
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.error('Failed to save session to localStorage:', error)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Đọc giá trị từ session. Tự kiểm tra hash integrity + expiry.
|
|
114
|
+
* Nếu hash bị thay đổi hoặc hết hạn → tự xóa session.
|
|
115
|
+
* @param {string} key - Tên key cần đọc (vd: "username", "usergroup")
|
|
116
|
+
* @returns {*|undefined} Giá trị hoặc undefined nếu không tìm thấy / hết hạn
|
|
117
|
+
* @example const username = getSession("username")
|
|
118
|
+
*/
|
|
119
|
+
export const getSession = (key) => {
|
|
120
|
+
if (process.client) {
|
|
121
|
+
const storedSession = localStorage.getItem(SESSION_KEY)
|
|
122
|
+
if (storedSession) {
|
|
123
|
+
const { data, expiry, hash } = JSON.parse(storedSession)
|
|
124
|
+
// check hash
|
|
125
|
+
const check_hash = encrypt_string(expiry.toString());
|
|
126
|
+
if (hash !== check_hash) {
|
|
127
|
+
clearSession();
|
|
128
|
+
return undefined;
|
|
129
|
+
} else {
|
|
130
|
+
if (expiry > Date.now()) {
|
|
131
|
+
session.value = data
|
|
132
|
+
return session.value[key]
|
|
133
|
+
} else {
|
|
134
|
+
clearSession()
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return undefined
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Xóa toàn bộ session (logout)
|
|
144
|
+
*/
|
|
145
|
+
export const clearSession = () => {
|
|
146
|
+
session.value = {}
|
|
147
|
+
if (process.client) {
|
|
148
|
+
try {
|
|
149
|
+
localStorage.removeItem(SESSION_KEY)
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.error('Failed to clear session from localStorage:', error)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Gia hạn session — giữ nguyên data, cập nhật expiry mới
|
|
158
|
+
* @param {number} [expirationMs=7200000] - Thời gian gia hạn (ms), mặc định 2 giờ
|
|
159
|
+
*/
|
|
160
|
+
export const refreshSession = (expirationMs = DEFAULT_EXPIRATION) => {
|
|
161
|
+
if (process.client) {
|
|
162
|
+
try {
|
|
163
|
+
const storedSession = localStorage.getItem(SESSION_KEY)
|
|
164
|
+
if (storedSession) {
|
|
165
|
+
const { data } = JSON.parse(storedSession)
|
|
166
|
+
const expire_str = Date.now() + expirationMs;
|
|
167
|
+
const hash = encrypt_string(expire_str.toString());
|
|
168
|
+
const sessionData = {
|
|
169
|
+
data,
|
|
170
|
+
expiry: expire_str,
|
|
171
|
+
hash: hash
|
|
172
|
+
}
|
|
173
|
+
localStorage.setItem(SESSION_KEY, JSON.stringify(sessionData))
|
|
174
|
+
}
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.error('Failed to refresh session:', error)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file useTranslation.js
|
|
3
|
+
* @description Hệ thống đa ngôn ngữ (i18n). Load bản dịch từ DB, dịch text qua hàm t().
|
|
4
|
+
*
|
|
5
|
+
* Cách dùng:
|
|
6
|
+
* 1. Gọi translate() khi app init → load toàn bộ bản dịch vào state.objToTranslate
|
|
7
|
+
* 2. Dùng t("text gốc") ở bất kỳ đâu → trả về bản dịch hoặc text gốc nếu chưa có
|
|
8
|
+
*
|
|
9
|
+
* @requires request - từ useRequest.js
|
|
10
|
+
* @requires get_schema - từ state.js
|
|
11
|
+
* @requires getSession - từ useSession.js
|
|
12
|
+
*/
|
|
13
|
+
var objToTranslate = {};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Load toàn bộ bản dịch từ DB vào state.objToTranslate.
|
|
17
|
+
* Dữ liệu lấy từ table "translation", filter theo ngôn ngữ hiện tại trong session.
|
|
18
|
+
* @param {string} [page=""] - (Chưa sử dụng) Filter theo trang cụ thể
|
|
19
|
+
* @returns {Promise<void>}
|
|
20
|
+
* @example await translate() // gọi khi app init
|
|
21
|
+
*/
|
|
22
|
+
export const translate = async (page = "") => {
|
|
23
|
+
const body = {
|
|
24
|
+
schema: get_schema(),
|
|
25
|
+
table: "translation",
|
|
26
|
+
columns: ["origin", "local"],
|
|
27
|
+
conditions: { "lang": getSession("language")},
|
|
28
|
+
order_by: ["page"],
|
|
29
|
+
};
|
|
30
|
+
let resp = await request("select", body);
|
|
31
|
+
state.objToTranslate = {};
|
|
32
|
+
if (resp?.length > 0) {
|
|
33
|
+
for (let i = 0; i < resp.length; i++) {
|
|
34
|
+
if(!(resp[i]['origin'] in objToTranslate)){
|
|
35
|
+
state.objToTranslate[resp[i]['origin']] = resp[i]['local'];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Dịch chuỗi text. Trả về bản dịch nếu có, nguyên gốc nếu chưa có.
|
|
43
|
+
* Dùng ở template: {{ t("Agreement") }} hoặc trong JS: t("Save")
|
|
44
|
+
* @param {string} str - Chuỗi gốc cần dịch
|
|
45
|
+
* @returns {string} Bản dịch hoặc chuỗi gốc
|
|
46
|
+
* @example t("Agreement") → "Hợp đồng" (nếu lang=vi)
|
|
47
|
+
*/
|
|
48
|
+
export const t = (str) => {
|
|
49
|
+
if(str in state.objToTranslate){
|
|
50
|
+
return state.objToTranslate[str];
|
|
51
|
+
} else {
|
|
52
|
+
return str;
|
|
53
|
+
}
|
|
54
|
+
};
|