ads-fe 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -0
- package/dist/cli.js +545 -0
- package/dist/meta.js +93 -0
- package/package.json +43 -0
- package/skill.md +66 -0
- package/skills/core/SKILL.md +66 -0
- package/skills/core/references/app-development.md +45 -0
- package/skills/core/references/git.md +66 -0
- package/skills/core/references/monorepo.md +124 -0
- package/skills/element-plus-vue3/LICENSE.md +405 -0
- package/skills/element-plus-vue3/LICENSE.txt +202 -0
- package/skills/element-plus-vue3/SKILL.md +218 -0
- package/skills/element-plus-vue3/SYNC.md +5 -0
- package/skills/element-plus-vue3/api/component-api.md +94 -0
- package/skills/element-plus-vue3/api/global-config.md +89 -0
- package/skills/element-plus-vue3/api/props-and-events.md +101 -0
- package/skills/element-plus-vue3/examples/components/button.md +99 -0
- package/skills/element-plus-vue3/examples/components/date-picker.md +115 -0
- package/skills/element-plus-vue3/examples/components/dialog.md +106 -0
- package/skills/element-plus-vue3/examples/components/form.md +127 -0
- package/skills/element-plus-vue3/examples/components/input.md +123 -0
- package/skills/element-plus-vue3/examples/components/message.md +93 -0
- package/skills/element-plus-vue3/examples/components/overview.md +59 -0
- package/skills/element-plus-vue3/examples/components/select.md +133 -0
- package/skills/element-plus-vue3/examples/components/table.md +166 -0
- package/skills/element-plus-vue3/examples/guide/design.md +68 -0
- package/skills/element-plus-vue3/examples/guide/global-config.md +95 -0
- package/skills/element-plus-vue3/examples/guide/i18n.md +95 -0
- package/skills/element-plus-vue3/examples/guide/installation.md +110 -0
- package/skills/element-plus-vue3/examples/guide/quick-start.md +103 -0
- package/skills/element-plus-vue3/examples/guide/theme.md +78 -0
- package/skills/element-plus-vue3/templates/component-usage.md +92 -0
- package/skills/element-plus-vue3/templates/installation.md +82 -0
- package/skills/element-plus-vue3/templates/project-setup.md +83 -0
- package/skills/node/LICENSE.md +21 -0
- package/skills/node/SKILL.md +94 -0
- package/skills/node/SYNC.md +5 -0
- package/skills/node/rules/assets/graceful-server.test.ts +88 -0
- package/skills/node/rules/assets/graceful-server.ts +80 -0
- package/skills/node/rules/async-patterns.md +136 -0
- package/skills/node/rules/caching.md +198 -0
- package/skills/node/rules/environment.md +253 -0
- package/skills/node/rules/error-handling.md +164 -0
- package/skills/node/rules/flaky-tests.md +439 -0
- package/skills/node/rules/graceful-shutdown.md +204 -0
- package/skills/node/rules/logging.md +205 -0
- package/skills/node/rules/modules.md +105 -0
- package/skills/node/rules/node-modules-exploration.md +172 -0
- package/skills/node/rules/performance.md +130 -0
- package/skills/node/rules/profiling.md +183 -0
- package/skills/node/rules/streams.md +213 -0
- package/skills/node/rules/stuck-processes-and-tests.md +124 -0
- package/skills/node/rules/testing.md +218 -0
- package/skills/node/rules/typescript.md +262 -0
- package/skills/node/tile.json +11 -0
- package/skills/nuxt/GENERATION.md +5 -0
- package/skills/nuxt/LICENSE.md +21 -0
- package/skills/nuxt/SKILL.md +55 -0
- package/skills/nuxt/SYNC.md +5 -0
- package/skills/nuxt/references/advanced-hooks.md +289 -0
- package/skills/nuxt/references/advanced-layers.md +299 -0
- package/skills/nuxt/references/advanced-module-authoring.md +554 -0
- package/skills/nuxt/references/best-practices-data-fetching.md +357 -0
- package/skills/nuxt/references/best-practices-ssr.md +355 -0
- package/skills/nuxt/references/core-cli.md +263 -0
- package/skills/nuxt/references/core-config.md +162 -0
- package/skills/nuxt/references/core-data-fetching.md +236 -0
- package/skills/nuxt/references/core-deployment.md +224 -0
- package/skills/nuxt/references/core-directory-structure.md +269 -0
- package/skills/nuxt/references/core-modules.md +292 -0
- package/skills/nuxt/references/core-routing.md +226 -0
- package/skills/nuxt/references/features-components-autoimport.md +328 -0
- package/skills/nuxt/references/features-components.md +264 -0
- package/skills/nuxt/references/features-composables.md +276 -0
- package/skills/nuxt/references/features-server.md +265 -0
- package/skills/nuxt/references/features-state.md +194 -0
- package/skills/nuxt/references/rendering-modes.md +237 -0
- package/skills/pinia/GENERATION.md +5 -0
- package/skills/pinia/LICENSE.md +21 -0
- package/skills/pinia/SKILL.md +59 -0
- package/skills/pinia/SYNC.md +5 -0
- package/skills/pinia/references/advanced-hmr.md +61 -0
- package/skills/pinia/references/advanced-nuxt.md +119 -0
- package/skills/pinia/references/advanced-ssr.md +121 -0
- package/skills/pinia/references/best-practices-outside-component.md +115 -0
- package/skills/pinia/references/best-practices-testing.md +212 -0
- package/skills/pinia/references/core-stores.md +389 -0
- package/skills/pinia/references/features-composables.md +114 -0
- package/skills/pinia/references/features-composing-stores.md +134 -0
- package/skills/pinia/references/features-plugins.md +203 -0
- package/skills/pnpm/GENERATION.md +5 -0
- package/skills/pnpm/LICENSE.md +21 -0
- package/skills/pnpm/SKILL.md +42 -0
- package/skills/pnpm/SYNC.md +5 -0
- package/skills/pnpm/references/best-practices-ci.md +285 -0
- package/skills/pnpm/references/best-practices-migration.md +291 -0
- package/skills/pnpm/references/best-practices-performance.md +284 -0
- package/skills/pnpm/references/core-cli.md +229 -0
- package/skills/pnpm/references/core-config.md +188 -0
- package/skills/pnpm/references/core-store.md +179 -0
- package/skills/pnpm/references/core-workspaces.md +205 -0
- package/skills/pnpm/references/features-aliases.md +168 -0
- package/skills/pnpm/references/features-catalogs.md +159 -0
- package/skills/pnpm/references/features-hooks.md +233 -0
- package/skills/pnpm/references/features-overrides.md +184 -0
- package/skills/pnpm/references/features-patches.md +201 -0
- package/skills/pnpm/references/features-peer-deps.md +250 -0
- package/skills/slidev/LICENSE.md +21 -0
- package/skills/slidev/README.md +61 -0
- package/skills/slidev/SKILL.md +189 -0
- package/skills/slidev/SYNC.md +5 -0
- package/skills/slidev/references/animation-click-marker.md +37 -0
- package/skills/slidev/references/animation-drawing.md +68 -0
- package/skills/slidev/references/animation-rough-marker.md +53 -0
- package/skills/slidev/references/api-slide-hooks.md +37 -0
- package/skills/slidev/references/build-og-image.md +36 -0
- package/skills/slidev/references/build-pdf.md +40 -0
- package/skills/slidev/references/build-remote-assets.md +34 -0
- package/skills/slidev/references/build-seo-meta.md +43 -0
- package/skills/slidev/references/code-groups.md +64 -0
- package/skills/slidev/references/code-import-snippet.md +55 -0
- package/skills/slidev/references/code-line-highlighting.md +50 -0
- package/skills/slidev/references/code-line-numbers.md +46 -0
- package/skills/slidev/references/code-magic-move.md +57 -0
- package/skills/slidev/references/code-max-height.md +37 -0
- package/skills/slidev/references/code-twoslash.md +42 -0
- package/skills/slidev/references/core-animations.md +196 -0
- package/skills/slidev/references/core-cli.md +140 -0
- package/skills/slidev/references/core-components.md +197 -0
- package/skills/slidev/references/core-exporting.md +148 -0
- package/skills/slidev/references/core-frontmatter.md +195 -0
- package/skills/slidev/references/core-global-context.md +155 -0
- package/skills/slidev/references/core-headmatter.md +188 -0
- package/skills/slidev/references/core-hosting.md +152 -0
- package/skills/slidev/references/core-layouts.md +286 -0
- package/skills/slidev/references/core-syntax.md +155 -0
- package/skills/slidev/references/diagram-latex.md +55 -0
- package/skills/slidev/references/diagram-mermaid.md +44 -0
- package/skills/slidev/references/diagram-plantuml.md +45 -0
- package/skills/slidev/references/editor-monaco-run.md +44 -0
- package/skills/slidev/references/editor-monaco-write.md +24 -0
- package/skills/slidev/references/editor-monaco.md +50 -0
- package/skills/slidev/references/editor-prettier.md +40 -0
- package/skills/slidev/references/editor-side.md +23 -0
- package/skills/slidev/references/editor-vscode.md +55 -0
- package/skills/slidev/references/layout-canvas-size.md +25 -0
- package/skills/slidev/references/layout-draggable.md +57 -0
- package/skills/slidev/references/layout-global-layers.md +50 -0
- package/skills/slidev/references/layout-slots.md +75 -0
- package/skills/slidev/references/layout-transform.md +33 -0
- package/skills/slidev/references/layout-zoom.md +39 -0
- package/skills/slidev/references/presenter-notes-ruby.md +35 -0
- package/skills/slidev/references/presenter-recording.md +30 -0
- package/skills/slidev/references/presenter-remote.md +40 -0
- package/skills/slidev/references/presenter-timer.md +34 -0
- package/skills/slidev/references/style-direction.md +34 -0
- package/skills/slidev/references/style-icons.md +46 -0
- package/skills/slidev/references/style-scoped.md +50 -0
- package/skills/slidev/references/syntax-block-frontmatter.md +39 -0
- package/skills/slidev/references/syntax-comark.md +51 -0
- package/skills/slidev/references/syntax-frontmatter-merging.md +49 -0
- package/skills/slidev/references/syntax-importing-slides.md +60 -0
- package/skills/slidev/references/tool-eject-theme.md +27 -0
- package/skills/tsdown/LICENSE.md +22 -0
- package/skills/tsdown/README.md +77 -0
- package/skills/tsdown/SKILL.md +416 -0
- package/skills/tsdown/SYNC.md +5 -0
- package/skills/tsdown/references/README.md +139 -0
- package/skills/tsdown/references/advanced-benchmark.md +8 -0
- package/skills/tsdown/references/advanced-ci.md +89 -0
- package/skills/tsdown/references/advanced-hooks.md +363 -0
- package/skills/tsdown/references/advanced-plugins.md +381 -0
- package/skills/tsdown/references/advanced-programmatic.md +378 -0
- package/skills/tsdown/references/advanced-rolldown-options.md +117 -0
- package/skills/tsdown/references/guide-getting-started.md +183 -0
- package/skills/tsdown/references/guide-introduction.md +42 -0
- package/skills/tsdown/references/guide-migrate-from-tsup.md +199 -0
- package/skills/tsdown/references/option-cjs-default.md +98 -0
- package/skills/tsdown/references/option-cleaning.md +275 -0
- package/skills/tsdown/references/option-config-file.md +291 -0
- package/skills/tsdown/references/option-css.md +301 -0
- package/skills/tsdown/references/option-dependencies.md +385 -0
- package/skills/tsdown/references/option-dts.md +251 -0
- package/skills/tsdown/references/option-entry.md +211 -0
- package/skills/tsdown/references/option-exe.md +120 -0
- package/skills/tsdown/references/option-lint.md +127 -0
- package/skills/tsdown/references/option-log-level.md +91 -0
- package/skills/tsdown/references/option-minification.md +177 -0
- package/skills/tsdown/references/option-output-directory.md +272 -0
- package/skills/tsdown/references/option-output-format.md +183 -0
- package/skills/tsdown/references/option-package-exports.md +320 -0
- package/skills/tsdown/references/option-platform.md +256 -0
- package/skills/tsdown/references/option-root.md +88 -0
- package/skills/tsdown/references/option-shims.md +299 -0
- package/skills/tsdown/references/option-sourcemap.md +301 -0
- package/skills/tsdown/references/option-target.md +222 -0
- package/skills/tsdown/references/option-tree-shaking.md +335 -0
- package/skills/tsdown/references/option-unbundle.md +310 -0
- package/skills/tsdown/references/option-watch-mode.md +261 -0
- package/skills/tsdown/references/recipe-react.md +338 -0
- package/skills/tsdown/references/recipe-solid.md +42 -0
- package/skills/tsdown/references/recipe-svelte.md +54 -0
- package/skills/tsdown/references/recipe-vue.md +387 -0
- package/skills/tsdown/references/recipe-wasm.md +125 -0
- package/skills/tsdown/references/reference-cli.md +472 -0
- package/skills/turborepo/LICENSE.md +7 -0
- package/skills/turborepo/SKILL.md +951 -0
- package/skills/turborepo/SYNC.md +5 -0
- package/skills/turborepo/command/turborepo.md +70 -0
- package/skills/turborepo/references/best-practices/RULE.md +241 -0
- package/skills/turborepo/references/best-practices/dependencies.md +246 -0
- package/skills/turborepo/references/best-practices/packages.md +335 -0
- package/skills/turborepo/references/best-practices/structure.md +297 -0
- package/skills/turborepo/references/boundaries/RULE.md +126 -0
- package/skills/turborepo/references/caching/RULE.md +153 -0
- package/skills/turborepo/references/caching/gotchas.md +190 -0
- package/skills/turborepo/references/caching/remote-cache.md +127 -0
- package/skills/turborepo/references/ci/RULE.md +79 -0
- package/skills/turborepo/references/ci/github-actions.md +162 -0
- package/skills/turborepo/references/ci/patterns.md +145 -0
- package/skills/turborepo/references/ci/vercel.md +103 -0
- package/skills/turborepo/references/cli/RULE.md +100 -0
- package/skills/turborepo/references/cli/commands.md +297 -0
- package/skills/turborepo/references/configuration/RULE.md +235 -0
- package/skills/turborepo/references/configuration/global-options.md +239 -0
- package/skills/turborepo/references/configuration/gotchas.md +368 -0
- package/skills/turborepo/references/configuration/tasks.md +325 -0
- package/skills/turborepo/references/environment/RULE.md +123 -0
- package/skills/turborepo/references/environment/gotchas.md +175 -0
- package/skills/turborepo/references/environment/modes.md +101 -0
- package/skills/turborepo/references/filtering/RULE.md +148 -0
- package/skills/turborepo/references/filtering/patterns.md +152 -0
- package/skills/turborepo/references/watch/RULE.md +99 -0
- package/skills/vite/GENERATION.md +5 -0
- package/skills/vite/LICENSE.md +21 -0
- package/skills/vite/SKILL.md +72 -0
- package/skills/vite/SYNC.md +5 -0
- package/skills/vite/references/build-and-ssr.md +164 -0
- package/skills/vite/references/core-config.md +162 -0
- package/skills/vite/references/core-features.md +205 -0
- package/skills/vite/references/core-plugin-api.md +235 -0
- package/skills/vite/references/environment-api.md +108 -0
- package/skills/vite/references/rolldown-migration.md +157 -0
- package/skills/vitepress/GENERATION.md +5 -0
- package/skills/vitepress/LICENSE.md +21 -0
- package/skills/vitepress/SKILL.md +65 -0
- package/skills/vitepress/SYNC.md +5 -0
- package/skills/vitepress/references/advanced-i18n.md +299 -0
- package/skills/vitepress/references/advanced-ssr.md +228 -0
- package/skills/vitepress/references/core-cli.md +119 -0
- package/skills/vitepress/references/core-config.md +189 -0
- package/skills/vitepress/references/core-markdown.md +277 -0
- package/skills/vitepress/references/core-routing.md +169 -0
- package/skills/vitepress/references/features-code-blocks.md +243 -0
- package/skills/vitepress/references/features-data-loading.md +220 -0
- package/skills/vitepress/references/features-dynamic-routes.md +235 -0
- package/skills/vitepress/references/features-vue.md +224 -0
- package/skills/vitepress/references/recipes-deploy.md +240 -0
- package/skills/vitepress/references/theme-config.md +315 -0
- package/skills/vitepress/references/theme-custom.md +269 -0
- package/skills/vitepress/references/theme-customization.md +290 -0
- package/skills/vitest/GENERATION.md +5 -0
- package/skills/vitest/LICENSE.md +21 -0
- package/skills/vitest/SKILL.md +52 -0
- package/skills/vitest/SYNC.md +5 -0
- package/skills/vitest/references/advanced-environments.md +264 -0
- package/skills/vitest/references/advanced-projects.md +300 -0
- package/skills/vitest/references/advanced-type-testing.md +237 -0
- package/skills/vitest/references/advanced-vi.md +249 -0
- package/skills/vitest/references/core-cli.md +166 -0
- package/skills/vitest/references/core-config.md +174 -0
- package/skills/vitest/references/core-describe.md +193 -0
- package/skills/vitest/references/core-expect.md +219 -0
- package/skills/vitest/references/core-hooks.md +244 -0
- package/skills/vitest/references/core-test-api.md +233 -0
- package/skills/vitest/references/features-concurrency.md +250 -0
- package/skills/vitest/references/features-context.md +238 -0
- package/skills/vitest/references/features-coverage.md +207 -0
- package/skills/vitest/references/features-filtering.md +211 -0
- package/skills/vitest/references/features-mocking.md +265 -0
- package/skills/vitest/references/features-snapshots.md +207 -0
- package/skills/vue/GENERATION.md +5 -0
- package/skills/vue/LICENSE.md +21 -0
- package/skills/vue/SKILL.md +84 -0
- package/skills/vue/SYNC.md +5 -0
- package/skills/vue/references/advanced-patterns.md +314 -0
- package/skills/vue/references/core-new-apis.md +264 -0
- package/skills/vue/references/script-setup-macros.md +204 -0
- package/skills/vue-best-practices/LICENSE.md +21 -0
- package/skills/vue-best-practices/SKILL.md +154 -0
- package/skills/vue-best-practices/SYNC.md +5 -0
- package/skills/vue-best-practices/references/animation-class-based-technique.md +254 -0
- package/skills/vue-best-practices/references/animation-state-driven-technique.md +291 -0
- package/skills/vue-best-practices/references/component-async.md +97 -0
- package/skills/vue-best-practices/references/component-data-flow.md +307 -0
- package/skills/vue-best-practices/references/component-fallthrough-attrs.md +174 -0
- package/skills/vue-best-practices/references/component-keep-alive.md +137 -0
- package/skills/vue-best-practices/references/component-slots.md +216 -0
- package/skills/vue-best-practices/references/component-suspense.md +228 -0
- package/skills/vue-best-practices/references/component-teleport.md +108 -0
- package/skills/vue-best-practices/references/component-transition-group.md +128 -0
- package/skills/vue-best-practices/references/component-transition.md +125 -0
- package/skills/vue-best-practices/references/composables.md +290 -0
- package/skills/vue-best-practices/references/directives.md +162 -0
- package/skills/vue-best-practices/references/perf-avoid-component-abstraction-in-lists.md +159 -0
- package/skills/vue-best-practices/references/perf-v-once-v-memo-directives.md +182 -0
- package/skills/vue-best-practices/references/perf-virtualize-large-lists.md +187 -0
- package/skills/vue-best-practices/references/plugins.md +166 -0
- package/skills/vue-best-practices/references/reactivity.md +344 -0
- package/skills/vue-best-practices/references/render-functions.md +201 -0
- package/skills/vue-best-practices/references/sfc.md +310 -0
- package/skills/vue-best-practices/references/state-management.md +135 -0
- package/skills/vue-best-practices/references/updated-hook-performance.md +187 -0
- package/skills/vue-router-best-practices/LICENSE.md +21 -0
- package/skills/vue-router-best-practices/SKILL.md +23 -0
- package/skills/vue-router-best-practices/SYNC.md +5 -0
- package/skills/vue-router-best-practices/reference/router-beforeenter-no-param-trigger.md +167 -0
- package/skills/vue-router-best-practices/reference/router-beforerouteenter-no-this.md +176 -0
- package/skills/vue-router-best-practices/reference/router-guard-async-await-pattern.md +227 -0
- package/skills/vue-router-best-practices/reference/router-navigation-guard-infinite-loop.md +187 -0
- package/skills/vue-router-best-practices/reference/router-navigation-guard-next-deprecated.md +150 -0
- package/skills/vue-router-best-practices/reference/router-param-change-no-lifecycle.md +181 -0
- package/skills/vue-router-best-practices/reference/router-simple-routing-cleanup.md +209 -0
- package/skills/vue-router-best-practices/reference/router-use-vue-router-for-production.md +183 -0
- package/skills/vue-testing-best-practices/LICENSE.md +21 -0
- package/skills/vue-testing-best-practices/SKILL.md +29 -0
- package/skills/vue-testing-best-practices/SYNC.md +5 -0
- package/skills/vue-testing-best-practices/reference/async-component-testing.md +163 -0
- package/skills/vue-testing-best-practices/reference/teleport-testing-complexity.md +158 -0
- package/skills/vue-testing-best-practices/reference/testing-async-await-flushpromises.md +175 -0
- package/skills/vue-testing-best-practices/reference/testing-browser-vs-node-runners.md +208 -0
- package/skills/vue-testing-best-practices/reference/testing-component-blackbox-approach.md +144 -0
- package/skills/vue-testing-best-practices/reference/testing-composables-helper-wrapper.md +238 -0
- package/skills/vue-testing-best-practices/reference/testing-e2e-playwright-recommended.md +242 -0
- package/skills/vue-testing-best-practices/reference/testing-no-snapshot-only.md +197 -0
- package/skills/vue-testing-best-practices/reference/testing-pinia-store-setup.md +228 -0
- package/skills/vue-testing-best-practices/reference/testing-suspense-async-components.md +229 -0
- package/skills/vue-testing-best-practices/reference/testing-vitest-recommended-for-vue.md +204 -0
- package/skills/vueuse-functions/LICENSE.md +21 -0
- package/skills/vueuse-functions/SKILL.md +419 -0
- package/skills/vueuse-functions/SYNC.md +5 -0
- package/skills/vueuse-functions/references/computedAsync.md +195 -0
- package/skills/vueuse-functions/references/computedEager.md +62 -0
- package/skills/vueuse-functions/references/computedInject.md +137 -0
- package/skills/vueuse-functions/references/computedWithControl.md +98 -0
- package/skills/vueuse-functions/references/createEventHook.md +86 -0
- package/skills/vueuse-functions/references/createGenericProjection.md +25 -0
- package/skills/vueuse-functions/references/createGlobalState.md +95 -0
- package/skills/vueuse-functions/references/createInjectionState.md +226 -0
- package/skills/vueuse-functions/references/createProjection.md +31 -0
- package/skills/vueuse-functions/references/createRef.md +54 -0
- package/skills/vueuse-functions/references/createReusableTemplate.md +361 -0
- package/skills/vueuse-functions/references/createSharedComposable.md +42 -0
- package/skills/vueuse-functions/references/createTemplatePromise.md +306 -0
- package/skills/vueuse-functions/references/createUnrefFn.md +51 -0
- package/skills/vueuse-functions/references/extendRef.md +76 -0
- package/skills/vueuse-functions/references/from.md +80 -0
- package/skills/vueuse-functions/references/get.md +30 -0
- package/skills/vueuse-functions/references/injectLocal.md +35 -0
- package/skills/vueuse-functions/references/isDefined.md +31 -0
- package/skills/vueuse-functions/references/logicAnd.md +40 -0
- package/skills/vueuse-functions/references/logicNot.md +36 -0
- package/skills/vueuse-functions/references/logicOr.md +40 -0
- package/skills/vueuse-functions/references/makeDestructurable.md +41 -0
- package/skills/vueuse-functions/references/onClickOutside.md +228 -0
- package/skills/vueuse-functions/references/onElementRemoval.md +88 -0
- package/skills/vueuse-functions/references/onKeyStroke.md +212 -0
- package/skills/vueuse-functions/references/onLongPress.md +235 -0
- package/skills/vueuse-functions/references/onStartTyping.md +53 -0
- package/skills/vueuse-functions/references/provideLocal.md +37 -0
- package/skills/vueuse-functions/references/reactify.md +144 -0
- package/skills/vueuse-functions/references/reactifyObject.md +62 -0
- package/skills/vueuse-functions/references/reactiveComputed.md +34 -0
- package/skills/vueuse-functions/references/reactiveOmit.md +86 -0
- package/skills/vueuse-functions/references/reactivePick.md +106 -0
- package/skills/vueuse-functions/references/refAutoReset.md +46 -0
- package/skills/vueuse-functions/references/refDebounced.md +81 -0
- package/skills/vueuse-functions/references/refDefault.md +36 -0
- package/skills/vueuse-functions/references/refManualReset.md +48 -0
- package/skills/vueuse-functions/references/refThrottled.md +99 -0
- package/skills/vueuse-functions/references/refWithControl.md +146 -0
- package/skills/vueuse-functions/references/set.md +30 -0
- package/skills/vueuse-functions/references/syncRef.md +195 -0
- package/skills/vueuse-functions/references/syncRefs.md +128 -0
- package/skills/vueuse-functions/references/templateRef.md +86 -0
- package/skills/vueuse-functions/references/toObserver.md +38 -0
- package/skills/vueuse-functions/references/toReactive.md +41 -0
- package/skills/vueuse-functions/references/toRef.md +74 -0
- package/skills/vueuse-functions/references/toRefs.md +78 -0
- package/skills/vueuse-functions/references/tryOnBeforeMount.md +34 -0
- package/skills/vueuse-functions/references/tryOnBeforeUnmount.md +32 -0
- package/skills/vueuse-functions/references/tryOnMounted.md +34 -0
- package/skills/vueuse-functions/references/tryOnScopeDispose.md +31 -0
- package/skills/vueuse-functions/references/tryOnUnmounted.md +32 -0
- package/skills/vueuse-functions/references/unrefElement.md +54 -0
- package/skills/vueuse-functions/references/until.md +161 -0
- package/skills/vueuse-functions/references/useAbs.md +31 -0
- package/skills/vueuse-functions/references/useActiveElement.md +86 -0
- package/skills/vueuse-functions/references/useAnimate.md +180 -0
- package/skills/vueuse-functions/references/useArrayDifference.md +84 -0
- package/skills/vueuse-functions/references/useArrayEvery.md +59 -0
- package/skills/vueuse-functions/references/useArrayFilter.md +63 -0
- package/skills/vueuse-functions/references/useArrayFind.md +50 -0
- package/skills/vueuse-functions/references/useArrayFindIndex.md +59 -0
- package/skills/vueuse-functions/references/useArrayFindLast.md +52 -0
- package/skills/vueuse-functions/references/useArrayIncludes.md +63 -0
- package/skills/vueuse-functions/references/useArrayJoin.md +74 -0
- package/skills/vueuse-functions/references/useArrayMap.md +59 -0
- package/skills/vueuse-functions/references/useArrayReduce.md +81 -0
- package/skills/vueuse-functions/references/useArraySome.md +59 -0
- package/skills/vueuse-functions/references/useArrayUnique.md +76 -0
- package/skills/vueuse-functions/references/useAsyncQueue.md +136 -0
- package/skills/vueuse-functions/references/useAsyncState.md +185 -0
- package/skills/vueuse-functions/references/useAsyncValidator.md +70 -0
- package/skills/vueuse-functions/references/useAuth.md +123 -0
- package/skills/vueuse-functions/references/useAverage.md +36 -0
- package/skills/vueuse-functions/references/useAxios.md +325 -0
- package/skills/vueuse-functions/references/useBase64.md +136 -0
- package/skills/vueuse-functions/references/useBattery.md +80 -0
- package/skills/vueuse-functions/references/useBluetooth.md +174 -0
- package/skills/vueuse-functions/references/useBreakpoints.md +176 -0
- package/skills/vueuse-functions/references/useBroadcastChannel.md +73 -0
- package/skills/vueuse-functions/references/useBrowserLocation.md +56 -0
- package/skills/vueuse-functions/references/useCached.md +52 -0
- package/skills/vueuse-functions/references/useCeil.md +31 -0
- package/skills/vueuse-functions/references/useChangeCase.md +79 -0
- package/skills/vueuse-functions/references/useClamp.md +85 -0
- package/skills/vueuse-functions/references/useClipboard.md +122 -0
- package/skills/vueuse-functions/references/useClipboardItems.md +93 -0
- package/skills/vueuse-functions/references/useCloned.md +91 -0
- package/skills/vueuse-functions/references/useColorMode.md +172 -0
- package/skills/vueuse-functions/references/useConfirmDialog.md +159 -0
- package/skills/vueuse-functions/references/useCookies.md +162 -0
- package/skills/vueuse-functions/references/useCountdown.md +105 -0
- package/skills/vueuse-functions/references/useCounter.md +86 -0
- package/skills/vueuse-functions/references/useCssSupports.md +33 -0
- package/skills/vueuse-functions/references/useCssVar.md +50 -0
- package/skills/vueuse-functions/references/useCurrentElement.md +61 -0
- package/skills/vueuse-functions/references/useCycleList.md +75 -0
- package/skills/vueuse-functions/references/useDark.md +142 -0
- package/skills/vueuse-functions/references/useDateFormat.md +145 -0
- package/skills/vueuse-functions/references/useDebounceFn.md +100 -0
- package/skills/vueuse-functions/references/useDebouncedRefHistory.md +40 -0
- package/skills/vueuse-functions/references/useDeviceMotion.md +80 -0
- package/skills/vueuse-functions/references/useDeviceOrientation.md +64 -0
- package/skills/vueuse-functions/references/useDevicePixelRatio.md +47 -0
- package/skills/vueuse-functions/references/useDevicesList.md +89 -0
- package/skills/vueuse-functions/references/useDisplayMedia.md +67 -0
- package/skills/vueuse-functions/references/useDocumentVisibility.md +44 -0
- package/skills/vueuse-functions/references/useDraggable.md +289 -0
- package/skills/vueuse-functions/references/useDrauu.md +65 -0
- package/skills/vueuse-functions/references/useDropZone.md +83 -0
- package/skills/vueuse-functions/references/useElementBounding.md +131 -0
- package/skills/vueuse-functions/references/useElementByPoint.md +46 -0
- package/skills/vueuse-functions/references/useElementHover.md +79 -0
- package/skills/vueuse-functions/references/useElementSize.md +79 -0
- package/skills/vueuse-functions/references/useElementVisibility.md +163 -0
- package/skills/vueuse-functions/references/useEventBus.md +101 -0
- package/skills/vueuse-functions/references/useEventListener.md +226 -0
- package/skills/vueuse-functions/references/useEventSource.md +204 -0
- package/skills/vueuse-functions/references/useExtractedObservable.md +198 -0
- package/skills/vueuse-functions/references/useEyeDropper.md +72 -0
- package/skills/vueuse-functions/references/useFavicon.md +69 -0
- package/skills/vueuse-functions/references/useFetch.md +546 -0
- package/skills/vueuse-functions/references/useFileDialog.md +91 -0
- package/skills/vueuse-functions/references/useFileSystemAccess.md +161 -0
- package/skills/vueuse-functions/references/useFirestore.md +129 -0
- package/skills/vueuse-functions/references/useFloor.md +31 -0
- package/skills/vueuse-functions/references/useFocus.md +99 -0
- package/skills/vueuse-functions/references/useFocusTrap.md +245 -0
- package/skills/vueuse-functions/references/useFocusWithin.md +57 -0
- package/skills/vueuse-functions/references/useFps.md +28 -0
- package/skills/vueuse-functions/references/useFullscreen.md +74 -0
- package/skills/vueuse-functions/references/useFuse.md +75 -0
- package/skills/vueuse-functions/references/useGamepad.md +176 -0
- package/skills/vueuse-functions/references/useGeolocation.md +63 -0
- package/skills/vueuse-functions/references/useIDBKeyval.md +93 -0
- package/skills/vueuse-functions/references/useIdle.md +88 -0
- package/skills/vueuse-functions/references/useImage.md +90 -0
- package/skills/vueuse-functions/references/useInfiniteScroll.md +156 -0
- package/skills/vueuse-functions/references/useIntersectionObserver.md +117 -0
- package/skills/vueuse-functions/references/useInterval.md +112 -0
- package/skills/vueuse-functions/references/useIntervalFn.md +50 -0
- package/skills/vueuse-functions/references/useIpcRenderer.md +144 -0
- package/skills/vueuse-functions/references/useIpcRendererInvoke.md +58 -0
- package/skills/vueuse-functions/references/useIpcRendererOn.md +52 -0
- package/skills/vueuse-functions/references/useJwt.md +57 -0
- package/skills/vueuse-functions/references/useKeyModifier.md +87 -0
- package/skills/vueuse-functions/references/useLastChanged.md +63 -0
- package/skills/vueuse-functions/references/useLocalStorage.md +41 -0
- package/skills/vueuse-functions/references/useMagicKeys.md +245 -0
- package/skills/vueuse-functions/references/useManualRefHistory.md +204 -0
- package/skills/vueuse-functions/references/useMath.md +47 -0
- package/skills/vueuse-functions/references/useMax.md +36 -0
- package/skills/vueuse-functions/references/useMediaControls.md +201 -0
- package/skills/vueuse-functions/references/useMediaQuery.md +53 -0
- package/skills/vueuse-functions/references/useMemoize.md +175 -0
- package/skills/vueuse-functions/references/useMemory.md +70 -0
- package/skills/vueuse-functions/references/useMin.md +36 -0
- package/skills/vueuse-functions/references/useMounted.md +38 -0
- package/skills/vueuse-functions/references/useMouse.md +113 -0
- package/skills/vueuse-functions/references/useMouseInElement.md +132 -0
- package/skills/vueuse-functions/references/useMousePressed.md +116 -0
- package/skills/vueuse-functions/references/useMutationObserver.md +60 -0
- package/skills/vueuse-functions/references/useNProgress.md +78 -0
- package/skills/vueuse-functions/references/useNavigatorLanguage.md +57 -0
- package/skills/vueuse-functions/references/useNetwork.md +106 -0
- package/skills/vueuse-functions/references/useNow.md +83 -0
- package/skills/vueuse-functions/references/useObjectUrl.md +55 -0
- package/skills/vueuse-functions/references/useObservable.md +91 -0
- package/skills/vueuse-functions/references/useOffsetPagination.md +199 -0
- package/skills/vueuse-functions/references/useOnline.md +41 -0
- package/skills/vueuse-functions/references/usePageLeave.md +43 -0
- package/skills/vueuse-functions/references/useParallax.md +58 -0
- package/skills/vueuse-functions/references/useParentElement.md +54 -0
- package/skills/vueuse-functions/references/usePerformanceObserver.md +48 -0
- package/skills/vueuse-functions/references/usePermission.md +78 -0
- package/skills/vueuse-functions/references/usePointer.md +91 -0
- package/skills/vueuse-functions/references/usePointerLock.md +59 -0
- package/skills/vueuse-functions/references/usePointerSwipe.md +80 -0
- package/skills/vueuse-functions/references/usePrecision.md +49 -0
- package/skills/vueuse-functions/references/usePreferredColorScheme.md +42 -0
- package/skills/vueuse-functions/references/usePreferredContrast.md +42 -0
- package/skills/vueuse-functions/references/usePreferredDark.md +41 -0
- package/skills/vueuse-functions/references/usePreferredLanguages.md +41 -0
- package/skills/vueuse-functions/references/usePreferredReducedMotion.md +42 -0
- package/skills/vueuse-functions/references/usePreferredReducedTransparency.md +42 -0
- package/skills/vueuse-functions/references/usePrevious.md +40 -0
- package/skills/vueuse-functions/references/useProjection.md +38 -0
- package/skills/vueuse-functions/references/useQRCode.md +53 -0
- package/skills/vueuse-functions/references/useRTDB.md +83 -0
- package/skills/vueuse-functions/references/useRafFn.md +68 -0
- package/skills/vueuse-functions/references/useRefHistory.md +285 -0
- package/skills/vueuse-functions/references/useResizeObserver.md +108 -0
- package/skills/vueuse-functions/references/useRound.md +31 -0
- package/skills/vueuse-functions/references/useRouteHash.md +27 -0
- package/skills/vueuse-functions/references/useRouteParams.md +38 -0
- package/skills/vueuse-functions/references/useRouteQuery.md +79 -0
- package/skills/vueuse-functions/references/useSSRWidth.md +47 -0
- package/skills/vueuse-functions/references/useScreenOrientation.md +98 -0
- package/skills/vueuse-functions/references/useScreenSafeArea.md +60 -0
- package/skills/vueuse-functions/references/useScriptTag.md +116 -0
- package/skills/vueuse-functions/references/useScroll.md +238 -0
- package/skills/vueuse-functions/references/useScrollLock.md +66 -0
- package/skills/vueuse-functions/references/useSessionStorage.md +41 -0
- package/skills/vueuse-functions/references/useShare.md +67 -0
- package/skills/vueuse-functions/references/useSortable.md +276 -0
- package/skills/vueuse-functions/references/useSorted.md +90 -0
- package/skills/vueuse-functions/references/useSpeechRecognition.md +90 -0
- package/skills/vueuse-functions/references/useSpeechSynthesis.md +101 -0
- package/skills/vueuse-functions/references/useStepper.md +137 -0
- package/skills/vueuse-functions/references/useStorage.md +278 -0
- package/skills/vueuse-functions/references/useStorageAsync.md +136 -0
- package/skills/vueuse-functions/references/useStyleTag.md +131 -0
- package/skills/vueuse-functions/references/useSubject.md +77 -0
- package/skills/vueuse-functions/references/useSubscription.md +33 -0
- package/skills/vueuse-functions/references/useSum.md +36 -0
- package/skills/vueuse-functions/references/useSupported.md +29 -0
- package/skills/vueuse-functions/references/useSwipe.md +75 -0
- package/skills/vueuse-functions/references/useTemplateRefsList.md +37 -0
- package/skills/vueuse-functions/references/useTextDirection.md +75 -0
- package/skills/vueuse-functions/references/useTextSelection.md +43 -0
- package/skills/vueuse-functions/references/useTextareaAutosize.md +94 -0
- package/skills/vueuse-functions/references/useThrottleFn.md +57 -0
- package/skills/vueuse-functions/references/useThrottledRefHistory.md +47 -0
- package/skills/vueuse-functions/references/useTimeAgo.md +154 -0
- package/skills/vueuse-functions/references/useTimeAgoIntl.md +117 -0
- package/skills/vueuse-functions/references/useTimeout.md +113 -0
- package/skills/vueuse-functions/references/useTimeoutFn.md +51 -0
- package/skills/vueuse-functions/references/useTimeoutPoll.md +47 -0
- package/skills/vueuse-functions/references/useTimestamp.md +93 -0
- package/skills/vueuse-functions/references/useTitle.md +115 -0
- package/skills/vueuse-functions/references/useToNumber.md +54 -0
- package/skills/vueuse-functions/references/useToString.md +34 -0
- package/skills/vueuse-functions/references/useToggle.md +103 -0
- package/skills/vueuse-functions/references/useTransition.md +265 -0
- package/skills/vueuse-functions/references/useTrunc.md +33 -0
- package/skills/vueuse-functions/references/useUrlSearchParams.md +121 -0
- package/skills/vueuse-functions/references/useUserMedia.md +96 -0
- package/skills/vueuse-functions/references/useVModel.md +182 -0
- package/skills/vueuse-functions/references/useVModels.md +67 -0
- package/skills/vueuse-functions/references/useVibrate.md +86 -0
- package/skills/vueuse-functions/references/useVirtualList.md +182 -0
- package/skills/vueuse-functions/references/useWakeLock.md +51 -0
- package/skills/vueuse-functions/references/useWebNotification.md +175 -0
- package/skills/vueuse-functions/references/useWebSocket.md +299 -0
- package/skills/vueuse-functions/references/useWebWorker.md +60 -0
- package/skills/vueuse-functions/references/useWebWorkerFn.md +102 -0
- package/skills/vueuse-functions/references/useWindowFocus.md +46 -0
- package/skills/vueuse-functions/references/useWindowScroll.md +46 -0
- package/skills/vueuse-functions/references/useWindowSize.md +78 -0
- package/skills/vueuse-functions/references/useZoomFactor.md +53 -0
- package/skills/vueuse-functions/references/useZoomLevel.md +53 -0
- package/skills/vueuse-functions/references/watchArray.md +53 -0
- package/skills/vueuse-functions/references/watchAtMost.md +63 -0
- package/skills/vueuse-functions/references/watchDebounced.md +101 -0
- package/skills/vueuse-functions/references/watchDeep.md +54 -0
- package/skills/vueuse-functions/references/watchExtractedObservable.md +192 -0
- package/skills/vueuse-functions/references/watchIgnorable.md +120 -0
- package/skills/vueuse-functions/references/watchImmediate.md +44 -0
- package/skills/vueuse-functions/references/watchOnce.md +41 -0
- package/skills/vueuse-functions/references/watchPausable.md +86 -0
- package/skills/vueuse-functions/references/watchThrottled.md +108 -0
- package/skills/vueuse-functions/references/watchTriggerable.md +98 -0
- package/skills/vueuse-functions/references/watchWithFilter.md +54 -0
- package/skills/vueuse-functions/references/whenever.md +108 -0
- package/skills/web-design-guidelines/SKILL.md +39 -0
- package/skills/web-design-guidelines/SYNC.md +5 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { createServer, IncomingMessage, ServerResponse, Server } from 'node:http';
|
|
2
|
+
import closeWithGrace from 'close-with-grace';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Example of a graceful HTTP server using close-with-grace.
|
|
6
|
+
* Demonstrates proper shutdown handling without connection tracking.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
let isShuttingDown = false;
|
|
10
|
+
|
|
11
|
+
function createHandler() {
|
|
12
|
+
return (req: IncomingMessage, res: ServerResponse) => {
|
|
13
|
+
// During shutdown, disable keep-alive to drain connections
|
|
14
|
+
if (isShuttingDown) {
|
|
15
|
+
res.setHeader('Connection', 'close');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Health check endpoint
|
|
19
|
+
if (req.url === '/health') {
|
|
20
|
+
if (isShuttingDown) {
|
|
21
|
+
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
22
|
+
res.end(JSON.stringify({ status: 'shutting_down' }));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
26
|
+
res.end(JSON.stringify({ status: 'healthy' }));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Default response
|
|
31
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
32
|
+
res.end(JSON.stringify({ message: 'Hello, World!' }));
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function closeServer(server: Server): Promise<void> {
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
// Close idle connections immediately
|
|
39
|
+
server.closeIdleConnections();
|
|
40
|
+
|
|
41
|
+
server.close((err) => {
|
|
42
|
+
if (err && err.message !== 'Server is not running') {
|
|
43
|
+
reject(err);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
resolve();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Force close all connections after timeout
|
|
50
|
+
setTimeout(() => {
|
|
51
|
+
server.closeAllConnections();
|
|
52
|
+
}, 5000);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function main(): Promise<void> {
|
|
57
|
+
const server = createServer(createHandler());
|
|
58
|
+
|
|
59
|
+
server.listen(3000, '0.0.0.0', () => {
|
|
60
|
+
console.log('Server listening on http://0.0.0.0:3000');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
closeWithGrace({ delay: 10000 }, async ({ signal, err }) => {
|
|
64
|
+
if (err) {
|
|
65
|
+
console.error('Error triggered shutdown:', err);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
console.log(`${signal} received, starting graceful shutdown...`);
|
|
69
|
+
isShuttingDown = true;
|
|
70
|
+
|
|
71
|
+
await closeServer(server);
|
|
72
|
+
console.log('Server closed successfully');
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Run if executed directly
|
|
77
|
+
const isMain = process.argv[1]?.endsWith('graceful-server.ts') ?? false;
|
|
78
|
+
if (isMain) {
|
|
79
|
+
main().catch(console.error);
|
|
80
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: async-patterns
|
|
3
|
+
description: Async/await and Promise patterns
|
|
4
|
+
metadata:
|
|
5
|
+
tags: async, await, promises, concurrency
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Async Patterns in Node.js
|
|
9
|
+
|
|
10
|
+
## Always Prefer async/await
|
|
11
|
+
|
|
12
|
+
Use async/await over raw Promises for readability:
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
// GOOD
|
|
16
|
+
async function processItems(items: Item[]): Promise<Result[]> {
|
|
17
|
+
const results: Result[] = [];
|
|
18
|
+
for (const item of items) {
|
|
19
|
+
const result = await processItem(item);
|
|
20
|
+
results.push(result);
|
|
21
|
+
}
|
|
22
|
+
return results;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// AVOID - callback-style Promise chains
|
|
26
|
+
function processItems(items: Item[]): Promise<Result[]> {
|
|
27
|
+
return Promise.resolve([])
|
|
28
|
+
.then((results) => {
|
|
29
|
+
return items.reduce((chain, item) => {
|
|
30
|
+
return chain.then((r) => processItem(item).then((res) => [...r, res]));
|
|
31
|
+
}, Promise.resolve(results));
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Parallel Execution with Promise.all
|
|
37
|
+
|
|
38
|
+
Use Promise.all for independent operations:
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
async function fetchAllData(ids: string[]): Promise<Data[]> {
|
|
42
|
+
const promises = ids.map((id) => fetchData(id));
|
|
43
|
+
return Promise.all(promises);
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Controlled Concurrency
|
|
48
|
+
|
|
49
|
+
Limit concurrent operations to prevent resource exhaustion and extreme memory usage. Use [p-limit](https://github.com/sindresorhus/p-limit) or [p-map](https://github.com/sindresorhus/p-map):
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import pLimit from 'p-limit';
|
|
53
|
+
|
|
54
|
+
const limit = pLimit(5); // Max 5 concurrent operations
|
|
55
|
+
|
|
56
|
+
const results = await Promise.all(
|
|
57
|
+
items.map((item) => limit(() => processItem(item)))
|
|
58
|
+
);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Or use p-map for cleaner syntax:
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import pMap from 'p-map';
|
|
65
|
+
|
|
66
|
+
const results = await pMap(items, processItem, { concurrency: 5 });
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Promise.allSettled for Fault Tolerance
|
|
70
|
+
|
|
71
|
+
Use Promise.allSettled when some failures are acceptable:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
async function fetchMultiple(urls: string[]): Promise<Map<string, string | Error>> {
|
|
75
|
+
const results = await Promise.allSettled(
|
|
76
|
+
urls.map((url) => fetch(url).then((r) => r.text()))
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const map = new Map<string, string | Error>();
|
|
80
|
+
urls.forEach((url, i) => {
|
|
81
|
+
const result = results[i];
|
|
82
|
+
map.set(
|
|
83
|
+
url,
|
|
84
|
+
result.status === 'fulfilled' ? result.value : result.reason
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
return map;
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Avoid Async in Constructors
|
|
93
|
+
|
|
94
|
+
Constructors cannot be async. Use factory functions instead:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
// BAD - constructor cannot await
|
|
98
|
+
class Database {
|
|
99
|
+
constructor() {
|
|
100
|
+
// Cannot use await here
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// GOOD - factory function
|
|
105
|
+
class Database {
|
|
106
|
+
private constructor(private connection: Connection) {}
|
|
107
|
+
|
|
108
|
+
static async create(config: Config): Promise<Database> {
|
|
109
|
+
const connection = await connect(config);
|
|
110
|
+
return new Database(connection);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Usage
|
|
115
|
+
const db = await Database.create(config);
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## AbortController for Cancellation
|
|
119
|
+
|
|
120
|
+
Use AbortController to cancel long-running operations:
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
async function fetchWithTimeout(
|
|
124
|
+
url: string,
|
|
125
|
+
timeoutMs: number
|
|
126
|
+
): Promise<Response> {
|
|
127
|
+
const controller = new AbortController();
|
|
128
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
return await fetch(url, { signal: controller.signal });
|
|
132
|
+
} finally {
|
|
133
|
+
clearTimeout(timeoutId);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: caching
|
|
3
|
+
description: Caching patterns and libraries
|
|
4
|
+
metadata:
|
|
5
|
+
tags: caching, memoization, performance, async-cache-dedupe
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Caching in Node.js
|
|
9
|
+
|
|
10
|
+
## High-signal triggers
|
|
11
|
+
|
|
12
|
+
If prompts mention **repeated async lookups**, **duplicate concurrent requests**, **CSV enrichment**, **ETL transforms**, **N+1 remote calls**, or **cache hot keys**, select a cache strategy explicitly and justify it.
|
|
13
|
+
|
|
14
|
+
## Cache selection quick guide
|
|
15
|
+
|
|
16
|
+
- Use **`lru-cache`** for process-local, bounded in-memory reuse where deduplicating concurrent requests is not the main concern.
|
|
17
|
+
- Use **`async-cache-dedupe`** when multiple concurrent calls can request the same key and you want one in-flight request per key.
|
|
18
|
+
- In stream/ETL scenarios, prefer `async-cache-dedupe` for enrichment calls inside an `async function*` transform.
|
|
19
|
+
|
|
20
|
+
## Memoization with mnemoist
|
|
21
|
+
|
|
22
|
+
Use [mnemoist](https://github.com/Yomguithereal/mnemonist) for synchronous memoization:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { LRUCache } from 'mnemonist';
|
|
26
|
+
|
|
27
|
+
const cache = new LRUCache<string, User>(1000);
|
|
28
|
+
|
|
29
|
+
function getUser(id: string): User | undefined {
|
|
30
|
+
if (cache.has(id)) {
|
|
31
|
+
return cache.get(id);
|
|
32
|
+
}
|
|
33
|
+
const user = fetchUserSync(id);
|
|
34
|
+
cache.set(id, user);
|
|
35
|
+
return user;
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Async Caching with async-cache-dedupe
|
|
40
|
+
|
|
41
|
+
Use [async-cache-dedupe](https://github.com/mcollina/async-cache-dedupe) for async operations with request deduplication:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { createCache } from 'async-cache-dedupe';
|
|
45
|
+
|
|
46
|
+
const cache = createCache({
|
|
47
|
+
ttl: 60, // seconds
|
|
48
|
+
stale: 5, // serve stale while revalidating
|
|
49
|
+
storage: { type: 'memory' },
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
cache.define('getUser', async (id: string) => {
|
|
53
|
+
return await db.users.findById(id);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
cache.define('getPost', {
|
|
57
|
+
ttl: 300,
|
|
58
|
+
stale: 30,
|
|
59
|
+
}, async (id: string) => {
|
|
60
|
+
return await db.posts.findById(id);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Usage - concurrent calls are deduplicated
|
|
64
|
+
const user = await cache.getUser('123');
|
|
65
|
+
const post = await cache.getPost('456');
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Request Deduplication
|
|
69
|
+
|
|
70
|
+
async-cache-dedupe automatically deduplicates concurrent requests:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
// These three concurrent calls result in only ONE database query
|
|
74
|
+
const [user1, user2, user3] = await Promise.all([
|
|
75
|
+
cache.getUser('123'),
|
|
76
|
+
cache.getUser('123'),
|
|
77
|
+
cache.getUser('123'),
|
|
78
|
+
]);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Stream/ETL enrichment example
|
|
82
|
+
|
|
83
|
+
Use deduplicated async cache inside an `async function*` transform when rows repeatedly reference the same key:
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import { createCache } from 'async-cache-dedupe';
|
|
87
|
+
|
|
88
|
+
const cache = createCache({ ttl: 120, stale: 10, storage: { type: 'memory' } });
|
|
89
|
+
|
|
90
|
+
cache.define('getPlan', async (planId: string) => {
|
|
91
|
+
return await db.plans.findById(planId);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
async function* enrichRows(source: AsyncIterable<{ userId: string, planId: string }>) {
|
|
95
|
+
for await (const row of source) {
|
|
96
|
+
const plan = await cache.getPlan(row.planId); // one in-flight call per planId
|
|
97
|
+
yield { ...row, planName: plan.name };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Redis Storage
|
|
103
|
+
|
|
104
|
+
For distributed caching across multiple instances:
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
import { createCache } from 'async-cache-dedupe';
|
|
108
|
+
import Redis from 'ioredis';
|
|
109
|
+
|
|
110
|
+
const redis = new Redis();
|
|
111
|
+
|
|
112
|
+
const cache = createCache({
|
|
113
|
+
ttl: 60,
|
|
114
|
+
storage: {
|
|
115
|
+
type: 'redis',
|
|
116
|
+
options: { client: redis },
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## LRU Cache
|
|
122
|
+
|
|
123
|
+
Use [lru-cache](https://github.com/isaacs/node-lru-cache) for bounded in-memory caching:
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
import { LRUCache } from 'lru-cache';
|
|
127
|
+
|
|
128
|
+
const cache = new LRUCache<string, User>({
|
|
129
|
+
max: 500, // Maximum items
|
|
130
|
+
ttl: 1000 * 60 * 5, // 5 minutes
|
|
131
|
+
updateAgeOnGet: true,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
cache.set('user:123', user);
|
|
135
|
+
const cached = cache.get('user:123');
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Cache Invalidation Patterns
|
|
139
|
+
|
|
140
|
+
### Time-Based Expiration
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
const cache = createCache({
|
|
144
|
+
ttl: 60, // Fresh for 60 seconds
|
|
145
|
+
stale: 30, // Serve stale for 30 more seconds while revalidating
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Manual Invalidation
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
// Invalidate single entry
|
|
153
|
+
await cache.invalidate('getUser', '123');
|
|
154
|
+
|
|
155
|
+
// Invalidate all entries for a function
|
|
156
|
+
await cache.clear('getUser');
|
|
157
|
+
|
|
158
|
+
// Clear entire cache
|
|
159
|
+
await cache.clear();
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Reference-Based Invalidation
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
const cache = createCache({
|
|
166
|
+
ttl: 60,
|
|
167
|
+
storage: { type: 'memory' },
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
cache.define('getUser', {
|
|
171
|
+
references: (args, key, result) => [`user:${result.id}`],
|
|
172
|
+
}, async (id: string) => {
|
|
173
|
+
return await db.users.findById(id);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
cache.define('getUserPosts', {
|
|
177
|
+
references: (args, key, result) => [`user:${args[0]}`],
|
|
178
|
+
}, async (userId: string) => {
|
|
179
|
+
return await db.posts.findByUserId(userId);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Invalidate all cache entries referencing this user
|
|
183
|
+
await cache.invalidateAll(`user:123`);
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## When to Cache
|
|
187
|
+
|
|
188
|
+
- Database query results
|
|
189
|
+
- External API responses
|
|
190
|
+
- Computed values that are expensive to calculate
|
|
191
|
+
- Configuration that rarely changes
|
|
192
|
+
|
|
193
|
+
## When NOT to Cache
|
|
194
|
+
|
|
195
|
+
- User-specific sensitive data (without proper isolation)
|
|
196
|
+
- Rapidly changing data
|
|
197
|
+
- Data that must always be consistent
|
|
198
|
+
- Large objects that would exhaust memory
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: environment
|
|
3
|
+
description: Environment configuration and secrets management
|
|
4
|
+
metadata:
|
|
5
|
+
tags: environment, configuration, env, secrets
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Environment Configuration in Node.js
|
|
9
|
+
|
|
10
|
+
## Loading Environment Files
|
|
11
|
+
|
|
12
|
+
Use Node.js built-in `--env-file` flag to load environment variables:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# Load from .env file
|
|
16
|
+
node --env-file=.env app.ts
|
|
17
|
+
|
|
18
|
+
# Load multiple env files (later files override earlier ones)
|
|
19
|
+
node --env-file=.env --env-file=.env.local app.ts
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Programmatic API
|
|
23
|
+
|
|
24
|
+
Load environment files programmatically with `process.loadEnvFile()`:
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { loadEnvFile } from 'node:process';
|
|
28
|
+
|
|
29
|
+
// Load .env from current directory
|
|
30
|
+
loadEnvFile();
|
|
31
|
+
|
|
32
|
+
// Load specific file
|
|
33
|
+
loadEnvFile('.env.local');
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Environment Variables Validation
|
|
37
|
+
|
|
38
|
+
### Using env-schema with TypeBox
|
|
39
|
+
|
|
40
|
+
Use [env-schema](https://github.com/fastify/env-schema) with [TypeBox](https://github.com/sinclairzx81/typebox) for type-safe environment validation:
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import { envSchema } from 'env-schema';
|
|
44
|
+
import { Type, Static } from '@sinclair/typebox';
|
|
45
|
+
|
|
46
|
+
const schema = Type.Object({
|
|
47
|
+
PORT: Type.Number({ default: 3000 }),
|
|
48
|
+
DATABASE_URL: Type.String(),
|
|
49
|
+
API_KEY: Type.String({ minLength: 1 }),
|
|
50
|
+
LOG_LEVEL: Type.Union([
|
|
51
|
+
Type.Literal('debug'),
|
|
52
|
+
Type.Literal('info'),
|
|
53
|
+
Type.Literal('warn'),
|
|
54
|
+
Type.Literal('error'),
|
|
55
|
+
], { default: 'info' }),
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
type Env = Static<typeof schema>;
|
|
59
|
+
|
|
60
|
+
export const env = envSchema<Env>({ schema });
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Using Zod
|
|
64
|
+
|
|
65
|
+
Alternatively, use [Zod](https://github.com/colinhacks/zod) for validation:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { z } from 'zod';
|
|
69
|
+
|
|
70
|
+
const EnvSchema = z.object({
|
|
71
|
+
PORT: z.coerce.number().default(3000),
|
|
72
|
+
DATABASE_URL: z.string().url(),
|
|
73
|
+
API_KEY: z.string().min(1),
|
|
74
|
+
LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
type Env = z.infer<typeof EnvSchema>;
|
|
78
|
+
|
|
79
|
+
function loadEnv(): Env {
|
|
80
|
+
const result = EnvSchema.safeParse(process.env);
|
|
81
|
+
|
|
82
|
+
if (!result.success) {
|
|
83
|
+
console.error('Invalid environment variables:');
|
|
84
|
+
console.error(result.error.format());
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return result.data;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const env = loadEnv();
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Avoid NODE_ENV
|
|
95
|
+
|
|
96
|
+
`NODE_ENV` is an antipattern. It conflates multiple concerns into a single variable:
|
|
97
|
+
|
|
98
|
+
- **Environment detection** (development vs production vs staging)
|
|
99
|
+
- **Behavior toggling** (verbose logging, debug features)
|
|
100
|
+
- **Optimization flags** (minification, caching)
|
|
101
|
+
- **Security settings** (strict validation, HTTPS)
|
|
102
|
+
|
|
103
|
+
This leads to problems:
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
// BAD - NODE_ENV conflates concerns
|
|
107
|
+
if (process.env.NODE_ENV === 'development') {
|
|
108
|
+
enableDebugLogging(); // logging concern
|
|
109
|
+
disableRateLimiting(); // security concern
|
|
110
|
+
useMockDatabase(); // infrastructure concern
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Instead, use explicit environment variables for each concern:
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
// GOOD - explicit variables for each concern
|
|
118
|
+
const config = {
|
|
119
|
+
logging: {
|
|
120
|
+
level: process.env.LOG_LEVEL || 'info',
|
|
121
|
+
pretty: process.env.LOG_PRETTY === 'true',
|
|
122
|
+
},
|
|
123
|
+
security: {
|
|
124
|
+
rateLimitEnabled: process.env.RATE_LIMIT_ENABLED !== 'false',
|
|
125
|
+
httpsOnly: process.env.HTTPS_ONLY === 'true',
|
|
126
|
+
},
|
|
127
|
+
database: {
|
|
128
|
+
url: process.env.DATABASE_URL,
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
This approach:
|
|
134
|
+
- Makes configuration explicit and discoverable
|
|
135
|
+
- Allows fine-grained control per environment
|
|
136
|
+
- Avoids hidden behavior changes
|
|
137
|
+
- Makes testing easier (toggle individual features)
|
|
138
|
+
|
|
139
|
+
## Configuration Object Pattern
|
|
140
|
+
|
|
141
|
+
Create a typed configuration object:
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
interface Config {
|
|
145
|
+
server: {
|
|
146
|
+
port: number;
|
|
147
|
+
host: string;
|
|
148
|
+
};
|
|
149
|
+
database: {
|
|
150
|
+
url: string;
|
|
151
|
+
poolSize: number;
|
|
152
|
+
};
|
|
153
|
+
auth: {
|
|
154
|
+
jwtSecret: string;
|
|
155
|
+
jwtExpiresIn: string;
|
|
156
|
+
};
|
|
157
|
+
features: {
|
|
158
|
+
enableMetrics: boolean;
|
|
159
|
+
enableTracing: boolean;
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function createConfig(): Config {
|
|
164
|
+
return {
|
|
165
|
+
server: {
|
|
166
|
+
port: parseInt(process.env.PORT || '3000', 10),
|
|
167
|
+
host: process.env.HOST || '0.0.0.0',
|
|
168
|
+
},
|
|
169
|
+
database: {
|
|
170
|
+
url: requireEnv('DATABASE_URL'),
|
|
171
|
+
poolSize: parseInt(process.env.DB_POOL_SIZE || '10', 10),
|
|
172
|
+
},
|
|
173
|
+
auth: {
|
|
174
|
+
jwtSecret: requireEnv('JWT_SECRET'),
|
|
175
|
+
jwtExpiresIn: process.env.JWT_EXPIRES_IN || '1h',
|
|
176
|
+
},
|
|
177
|
+
features: {
|
|
178
|
+
enableMetrics: process.env.ENABLE_METRICS === 'true',
|
|
179
|
+
enableTracing: process.env.ENABLE_TRACING === 'true',
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function requireEnv(name: string): string {
|
|
185
|
+
const value = process.env[name];
|
|
186
|
+
if (!value) {
|
|
187
|
+
throw new Error(`Missing required environment variable: ${name}`);
|
|
188
|
+
}
|
|
189
|
+
return value;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export const config = createConfig();
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## .env File Structure
|
|
196
|
+
|
|
197
|
+
Organize .env files properly:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
# .env.example - committed to git, documents all variables
|
|
201
|
+
PORT=3000
|
|
202
|
+
DATABASE_URL=postgresql://user:pass@localhost:5432/db
|
|
203
|
+
API_KEY=your-api-key-here
|
|
204
|
+
|
|
205
|
+
# .env - local development, NOT committed
|
|
206
|
+
PORT=3000
|
|
207
|
+
DATABASE_URL=postgresql://dev:dev@localhost:5432/myapp
|
|
208
|
+
API_KEY=sk-dev-key-123
|
|
209
|
+
|
|
210
|
+
# .env.test - test environment
|
|
211
|
+
DATABASE_URL=postgresql://test:test@localhost:5432/myapp_test
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Secrets in Production
|
|
215
|
+
|
|
216
|
+
Never commit secrets to version control. Use a secrets management service appropriate for your infrastructure:
|
|
217
|
+
|
|
218
|
+
**Cloud Provider Services:**
|
|
219
|
+
- [AWS Secrets Manager](https://aws.amazon.com/secrets-manager/)
|
|
220
|
+
- [Google Cloud Secret Manager](https://cloud.google.com/secret-manager)
|
|
221
|
+
- [Azure Key Vault](https://azure.microsoft.com/en-us/products/key-vault)
|
|
222
|
+
|
|
223
|
+
**Infrastructure Tools:**
|
|
224
|
+
- [HashiCorp Vault](https://www.vaultproject.io/)
|
|
225
|
+
- [Doppler](https://www.doppler.com/)
|
|
226
|
+
- [Infisical](https://infisical.com/)
|
|
227
|
+
|
|
228
|
+
**Container Orchestration:**
|
|
229
|
+
- Kubernetes Secrets
|
|
230
|
+
- Docker Swarm Secrets
|
|
231
|
+
|
|
232
|
+
**CI/CD Platforms:**
|
|
233
|
+
- GitHub Actions Secrets
|
|
234
|
+
- GitLab CI/CD Variables
|
|
235
|
+
- CircleCI Contexts
|
|
236
|
+
|
|
237
|
+
These services inject secrets as environment variables at runtime, keeping them out of your codebase and version history.
|
|
238
|
+
|
|
239
|
+
## Feature Flags
|
|
240
|
+
|
|
241
|
+
Implement feature flags via environment:
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
const features = {
|
|
245
|
+
newDashboard: process.env.FEATURE_NEW_DASHBOARD === 'true',
|
|
246
|
+
betaApi: process.env.FEATURE_BETA_API === 'true',
|
|
247
|
+
darkMode: process.env.FEATURE_DARK_MODE === 'true',
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
export function isFeatureEnabled(feature: keyof typeof features): boolean {
|
|
251
|
+
return features[feature] ?? false;
|
|
252
|
+
}
|
|
253
|
+
```
|