zilmate 1.8.1 → 1.9.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/.agents/skills/copywriting/SKILL.md +252 -0
- package/.agents/skills/copywriting/evals/evals.json +111 -0
- package/.agents/skills/copywriting/references/copy-frameworks.md +344 -0
- package/.agents/skills/copywriting/references/natural-transitions.md +272 -0
- package/.agents/skills/firecrawl-deep-research/SKILL.md +108 -0
- package/.agents/skills/shadcn/SKILL.md +267 -0
- package/.agents/skills/shadcn/agents/openai.yml +5 -0
- package/.agents/skills/shadcn/assets/shadcn-small.png +0 -0
- package/.agents/skills/shadcn/assets/shadcn.png +0 -0
- package/.agents/skills/shadcn/cli.md +290 -0
- package/.agents/skills/shadcn/customization.md +209 -0
- package/.agents/skills/shadcn/evals/evals.json +47 -0
- package/.agents/skills/shadcn/mcp.md +105 -0
- package/.agents/skills/shadcn/registry.md +277 -0
- package/.agents/skills/shadcn/rules/base-vs-radix.md +306 -0
- package/.agents/skills/shadcn/rules/composition.md +195 -0
- package/.agents/skills/shadcn/rules/forms.md +192 -0
- package/.agents/skills/shadcn/rules/icons.md +101 -0
- package/.agents/skills/shadcn/rules/styling.md +162 -0
- package/.agents/skills/tavily-research/SKILL.md +100 -0
- package/.agents/skills/upstash/SKILL.md +48 -0
- package/.agents/skills/upstash/upstash-box-js/overview.md +243 -0
- package/.agents/skills/upstash/upstash-box-py/overview.md +275 -0
- package/.agents/skills/upstash/upstash-cli/overview.md +138 -0
- package/.agents/skills/upstash/upstash-qstash-js/advanced/callbacks.md +147 -0
- package/.agents/skills/upstash/upstash-qstash-js/advanced/deduplication.md +86 -0
- package/.agents/skills/upstash/upstash-qstash-js/advanced/dlq.md +164 -0
- package/.agents/skills/upstash/upstash-qstash-js/advanced/multi-region/summary.md +388 -0
- package/.agents/skills/upstash/upstash-qstash-js/advanced/multi-region/verify-multi-region-setup.ts +388 -0
- package/.agents/skills/upstash/upstash-qstash-js/fundamentals/local-development.md +106 -0
- package/.agents/skills/upstash/upstash-qstash-js/fundamentals/publishing-messages.md +144 -0
- package/.agents/skills/upstash/upstash-qstash-js/fundamentals/queues-and-flow-control.md +148 -0
- package/.agents/skills/upstash/upstash-qstash-js/fundamentals/schedules.md +177 -0
- package/.agents/skills/upstash/upstash-qstash-js/fundamentals/url-groups.md +127 -0
- package/.agents/skills/upstash/upstash-qstash-js/overview.md +81 -0
- package/.agents/skills/upstash/upstash-qstash-js/verification/platform-specific/nextjs.md +171 -0
- package/.agents/skills/upstash/upstash-qstash-js/verification/receiver.md +213 -0
- package/.agents/skills/upstash/upstash-ratelimit-js/algorithms.md +84 -0
- package/.agents/skills/upstash/upstash-ratelimit-js/features.md +117 -0
- package/.agents/skills/upstash/upstash-ratelimit-js/methods-getting-started.md +77 -0
- package/.agents/skills/upstash/upstash-ratelimit-js/overview.md +26 -0
- package/.agents/skills/upstash/upstash-ratelimit-js/pricing-cost.md +146 -0
- package/.agents/skills/upstash/upstash-ratelimit-js/traffic-protection.md +77 -0
- package/.agents/skills/upstash/upstash-redis-js/advanced-features/auto-pipeline.md +49 -0
- package/.agents/skills/upstash/upstash-redis-js/advanced-features/pipeline-and-transactions.md +42 -0
- package/.agents/skills/upstash/upstash-redis-js/advanced-features/scripting.md +124 -0
- package/.agents/skills/upstash/upstash-redis-js/data-structures/hashes.md +71 -0
- package/.agents/skills/upstash/upstash-redis-js/data-structures/json.md +133 -0
- package/.agents/skills/upstash/upstash-redis-js/data-structures/lists.md +72 -0
- package/.agents/skills/upstash/upstash-redis-js/data-structures/sets.md +90 -0
- package/.agents/skills/upstash/upstash-redis-js/data-structures/sorted-sets.md +126 -0
- package/.agents/skills/upstash/upstash-redis-js/data-structures/streams.md +196 -0
- package/.agents/skills/upstash/upstash-redis-js/data-structures/strings.md +73 -0
- package/.agents/skills/upstash/upstash-redis-js/migrations/from-ioredis.md +163 -0
- package/.agents/skills/upstash/upstash-redis-js/migrations/from-redis-node.md +205 -0
- package/.agents/skills/upstash/upstash-redis-js/overview.md +183 -0
- package/.agents/skills/upstash/upstash-redis-js/patterns/caching.md +58 -0
- package/.agents/skills/upstash/upstash-redis-js/patterns/distributed-locks.md +130 -0
- package/.agents/skills/upstash/upstash-redis-js/patterns/leaderboard.md +134 -0
- package/.agents/skills/upstash/upstash-redis-js/patterns/rate-limiting.md +187 -0
- package/.agents/skills/upstash/upstash-redis-js/patterns/session-management.md +217 -0
- package/.agents/skills/upstash/upstash-redis-js/performance/batching-operations.md +76 -0
- package/.agents/skills/upstash/upstash-redis-js/performance/data-serialization.md +134 -0
- package/.agents/skills/upstash/upstash-redis-js/performance/error-handling.md +118 -0
- package/.agents/skills/upstash/upstash-redis-js/performance/pipeline-optimization.md +105 -0
- package/.agents/skills/upstash/upstash-redis-js/performance/redis-replicas.md +14 -0
- package/.agents/skills/upstash/upstash-redis-js/performance/ttl-expiration.md +32 -0
- package/.agents/skills/upstash/upstash-redis-js/search/adapters.md +99 -0
- package/.agents/skills/upstash/upstash-redis-js/search/commands/aggregating.md +234 -0
- package/.agents/skills/upstash/upstash-redis-js/search/commands/aliases.md +76 -0
- package/.agents/skills/upstash/upstash-redis-js/search/commands/index-management.md +124 -0
- package/.agents/skills/upstash/upstash-redis-js/search/commands/querying.md +315 -0
- package/.agents/skills/upstash/upstash-redis-js/search/overview.md +155 -0
- package/.agents/skills/upstash/upstash-redis-start/overview.md +71 -0
- package/.agents/skills/upstash/upstash-search-js/overview.md +48 -0
- package/.agents/skills/upstash/upstash-search-js/quick-start.md +158 -0
- package/.agents/skills/upstash/upstash-search-js/sdk-overview.md +158 -0
- package/.agents/skills/upstash/upstash-vector-js/features/filtering-and-metadata.md +82 -0
- package/.agents/skills/upstash/upstash-vector-js/features/index-structure.md +193 -0
- package/.agents/skills/upstash/upstash-vector-js/features/namespaces.md +32 -0
- package/.agents/skills/upstash/upstash-vector-js/overview.md +44 -0
- package/.agents/skills/upstash/upstash-vector-js/sdk-methods.md +210 -0
- package/.agents/skills/upstash/upstash-workflow-js/agents.md +248 -0
- package/.agents/skills/upstash/upstash-workflow-js/basics/client.md +180 -0
- package/.agents/skills/upstash/upstash-workflow-js/basics/context.md +230 -0
- package/.agents/skills/upstash/upstash-workflow-js/basics/serve.md +70 -0
- package/.agents/skills/upstash/upstash-workflow-js/features/flow-control.md +145 -0
- package/.agents/skills/upstash/upstash-workflow-js/features/invoke.md +97 -0
- package/.agents/skills/upstash/upstash-workflow-js/features/retries-failures-reliability.md +239 -0
- package/.agents/skills/upstash/upstash-workflow-js/features/wait-for-event.md +97 -0
- package/.agents/skills/upstash/upstash-workflow-js/features/webhooks.md +79 -0
- package/.agents/skills/upstash/upstash-workflow-js/how-to/local-dev.md +177 -0
- package/.agents/skills/upstash/upstash-workflow-js/how-to/middleware.md +166 -0
- package/.agents/skills/upstash/upstash-workflow-js/how-to/migrations.md +201 -0
- package/.agents/skills/upstash/upstash-workflow-js/how-to/realtime.md +186 -0
- package/.agents/skills/upstash/upstash-workflow-js/overview.md +55 -0
- package/.agents/skills/upstash/upstash-workflow-js/rest-api.md +156 -0
- package/.agents/skills/upstash/upstash-workflow-js/troubleshooting.md +201 -0
- package/.agents/skills/upstash-box-js/SKILL.md +248 -0
- package/.agents/skills/upstash-box-py/SKILL.md +280 -0
- package/.agents/skills/upstash-cli/SKILL.md +143 -0
- package/.agents/skills/upstash-qstash-js/SKILL.md +86 -0
- package/.agents/skills/upstash-qstash-js/advanced/callbacks.md +147 -0
- package/.agents/skills/upstash-qstash-js/advanced/deduplication.md +86 -0
- package/.agents/skills/upstash-qstash-js/advanced/dlq.md +164 -0
- package/.agents/skills/upstash-qstash-js/advanced/multi-region/summary.md +388 -0
- package/.agents/skills/upstash-qstash-js/advanced/multi-region/verify-multi-region-setup.ts +388 -0
- package/.agents/skills/upstash-qstash-js/fundamentals/local-development.md +106 -0
- package/.agents/skills/upstash-qstash-js/fundamentals/publishing-messages.md +144 -0
- package/.agents/skills/upstash-qstash-js/fundamentals/queues-and-flow-control.md +148 -0
- package/.agents/skills/upstash-qstash-js/fundamentals/schedules.md +177 -0
- package/.agents/skills/upstash-qstash-js/fundamentals/url-groups.md +127 -0
- package/.agents/skills/upstash-qstash-js/verification/platform-specific/nextjs.md +171 -0
- package/.agents/skills/upstash-qstash-js/verification/receiver.md +213 -0
- package/.agents/skills/upstash-ratelimit-js/SKILL.md +31 -0
- package/.agents/skills/upstash-ratelimit-js/algorithms.md +84 -0
- package/.agents/skills/upstash-ratelimit-js/features.md +117 -0
- package/.agents/skills/upstash-ratelimit-js/methods-getting-started.md +77 -0
- package/.agents/skills/upstash-ratelimit-js/pricing-cost.md +146 -0
- package/.agents/skills/upstash-ratelimit-js/traffic-protection.md +77 -0
- package/.agents/skills/upstash-redis-js/SKILL.md +188 -0
- package/.agents/skills/upstash-redis-js/advanced-features/auto-pipeline.md +49 -0
- package/.agents/skills/upstash-redis-js/advanced-features/pipeline-and-transactions.md +42 -0
- package/.agents/skills/upstash-redis-js/advanced-features/scripting.md +124 -0
- package/.agents/skills/upstash-redis-js/data-structures/hashes.md +71 -0
- package/.agents/skills/upstash-redis-js/data-structures/json.md +133 -0
- package/.agents/skills/upstash-redis-js/data-structures/lists.md +72 -0
- package/.agents/skills/upstash-redis-js/data-structures/sets.md +90 -0
- package/.agents/skills/upstash-redis-js/data-structures/sorted-sets.md +126 -0
- package/.agents/skills/upstash-redis-js/data-structures/streams.md +196 -0
- package/.agents/skills/upstash-redis-js/data-structures/strings.md +73 -0
- package/.agents/skills/upstash-redis-js/migrations/from-ioredis.md +163 -0
- package/.agents/skills/upstash-redis-js/migrations/from-redis-node.md +205 -0
- package/.agents/skills/upstash-redis-js/patterns/caching.md +58 -0
- package/.agents/skills/upstash-redis-js/patterns/distributed-locks.md +130 -0
- package/.agents/skills/upstash-redis-js/patterns/leaderboard.md +134 -0
- package/.agents/skills/upstash-redis-js/patterns/rate-limiting.md +187 -0
- package/.agents/skills/upstash-redis-js/patterns/session-management.md +217 -0
- package/.agents/skills/upstash-redis-js/performance/batching-operations.md +76 -0
- package/.agents/skills/upstash-redis-js/performance/data-serialization.md +134 -0
- package/.agents/skills/upstash-redis-js/performance/error-handling.md +118 -0
- package/.agents/skills/upstash-redis-js/performance/pipeline-optimization.md +105 -0
- package/.agents/skills/upstash-redis-js/performance/redis-replicas.md +14 -0
- package/.agents/skills/upstash-redis-js/performance/ttl-expiration.md +32 -0
- package/.agents/skills/upstash-redis-js/search/adapters.md +99 -0
- package/.agents/skills/upstash-redis-js/search/commands/aggregating.md +234 -0
- package/.agents/skills/upstash-redis-js/search/commands/aliases.md +76 -0
- package/.agents/skills/upstash-redis-js/search/commands/index-management.md +124 -0
- package/.agents/skills/upstash-redis-js/search/commands/querying.md +315 -0
- package/.agents/skills/upstash-redis-js/search/overview.md +155 -0
- package/.agents/skills/upstash-redis-start/SKILL.md +76 -0
- package/.agents/skills/upstash-search-js/SKILL.md +53 -0
- package/.agents/skills/upstash-search-js/quick-start.md +158 -0
- package/.agents/skills/upstash-search-js/sdk-overview.md +158 -0
- package/.agents/skills/upstash-vector-js/SKILL.md +49 -0
- package/.agents/skills/upstash-vector-js/features/filtering-and-metadata.md +82 -0
- package/.agents/skills/upstash-vector-js/features/index-structure.md +193 -0
- package/.agents/skills/upstash-vector-js/features/namespaces.md +32 -0
- package/.agents/skills/upstash-vector-js/sdk-methods.md +210 -0
- package/.agents/skills/upstash-workflow-js/SKILL.md +60 -0
- package/.agents/skills/upstash-workflow-js/agents.md +248 -0
- package/.agents/skills/upstash-workflow-js/basics/client.md +180 -0
- package/.agents/skills/upstash-workflow-js/basics/context.md +230 -0
- package/.agents/skills/upstash-workflow-js/basics/serve.md +70 -0
- package/.agents/skills/upstash-workflow-js/features/flow-control.md +145 -0
- package/.agents/skills/upstash-workflow-js/features/invoke.md +97 -0
- package/.agents/skills/upstash-workflow-js/features/retries-failures-reliability.md +239 -0
- package/.agents/skills/upstash-workflow-js/features/wait-for-event.md +97 -0
- package/.agents/skills/upstash-workflow-js/features/webhooks.md +79 -0
- package/.agents/skills/upstash-workflow-js/how-to/local-dev.md +177 -0
- package/.agents/skills/upstash-workflow-js/how-to/middleware.md +166 -0
- package/.agents/skills/upstash-workflow-js/how-to/migrations.md +201 -0
- package/.agents/skills/upstash-workflow-js/how-to/realtime.md +186 -0
- package/.agents/skills/upstash-workflow-js/rest-api.md +156 -0
- package/.agents/skills/upstash-workflow-js/troubleshooting.md +201 -0
- package/dist/agents/coding.agent.d.ts +185 -42
- package/dist/agents/coding.agent.d.ts.map +1 -1
- package/dist/agents/coding.agent.js +42 -5
- package/dist/agents/coding.agent.js.map +1 -1
- package/dist/agents/manager.d.ts +216 -41
- package/dist/agents/manager.d.ts.map +1 -1
- package/dist/agents/manager.js +103 -140
- package/dist/agents/manager.js.map +1 -1
- package/dist/agents/security.agent.d.ts +3 -3
- package/dist/agents/swarm/development/lead.d.ts +3 -0
- package/dist/agents/swarm/development/lead.d.ts.map +1 -0
- package/dist/agents/swarm/development/lead.js +24 -0
- package/dist/agents/swarm/development/lead.js.map +1 -0
- package/dist/agents/swarm/main.d.ts +69 -0
- package/dist/agents/swarm/main.d.ts.map +1 -1
- package/dist/agents/swarm/main.js +65 -11
- package/dist/agents/swarm/main.js.map +1 -1
- package/dist/agents/swarm/registry.d.ts +2 -1
- package/dist/agents/swarm/registry.d.ts.map +1 -1
- package/dist/agents/swarm/registry.js +225 -95
- package/dist/agents/swarm/registry.js.map +1 -1
- package/dist/cli/composer.d.ts.map +1 -1
- package/dist/cli/composer.js +85 -30
- package/dist/cli/composer.js.map +1 -1
- package/dist/cli/confirm.d.ts +2 -2
- package/dist/cli/confirm.d.ts.map +1 -1
- package/dist/cli/confirm.js +373 -4
- package/dist/cli/confirm.js.map +1 -1
- package/dist/cli/doctor.d.ts +1 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +47 -2
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/format.d.ts +4 -0
- package/dist/cli/format.d.ts.map +1 -1
- package/dist/cli/format.js +352 -65
- package/dist/cli/format.js.map +1 -1
- package/dist/cli/interactive.d.ts.map +1 -1
- package/dist/cli/interactive.js +80 -2
- package/dist/cli/interactive.js.map +1 -1
- package/dist/cli/menu.d.ts.map +1 -1
- package/dist/cli/menu.js +93 -83
- package/dist/cli/menu.js.map +1 -1
- package/dist/cli/render.d.ts.map +1 -1
- package/dist/cli/render.js +2 -1
- package/dist/cli/render.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +292 -28
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/swarm.d.ts.map +1 -1
- package/dist/cli/swarm.js +13 -10
- package/dist/cli/swarm.js.map +1 -1
- package/dist/cli/theme.d.ts +7 -1
- package/dist/cli/theme.d.ts.map +1 -1
- package/dist/cli/theme.js +4 -16
- package/dist/cli/theme.js.map +1 -1
- package/dist/cli/tunnel.d.ts +2 -0
- package/dist/cli/tunnel.d.ts.map +1 -1
- package/dist/cli/tunnel.js +63 -7
- package/dist/cli/tunnel.js.map +1 -1
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +12 -4
- package/dist/cli/update.js.map +1 -1
- package/dist/config/env.d.ts +3 -1
- package/dist/config/env.d.ts.map +1 -1
- package/dist/config/env.js +22 -2
- package/dist/config/env.js.map +1 -1
- package/dist/config/models.d.ts +1 -0
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +17 -1
- package/dist/config/models.js.map +1 -1
- package/dist/documents/pdf.d.ts.map +1 -1
- package/dist/documents/pdf.js +282 -22
- package/dist/documents/pdf.js.map +1 -1
- package/dist/documents/slides.d.ts.map +1 -1
- package/dist/documents/slides.js +160 -30
- package/dist/documents/slides.js.map +1 -1
- package/dist/index.js +73 -18
- package/dist/index.js.map +1 -1
- package/dist/memory/history.js +1 -1
- package/dist/observability/doctor.d.ts.map +1 -1
- package/dist/observability/doctor.js +3 -0
- package/dist/observability/doctor.js.map +1 -1
- package/dist/runtime/progress.d.ts +5 -1
- package/dist/runtime/progress.d.ts.map +1 -1
- package/dist/runtime/progress.js.map +1 -1
- package/dist/runtime/swarm.d.ts +1 -1
- package/dist/runtime/swarm.d.ts.map +1 -1
- package/dist/runtime/swarm.js +19 -3
- package/dist/runtime/swarm.js.map +1 -1
- package/dist/runtime/tool-utils.d.ts +2 -0
- package/dist/runtime/tool-utils.d.ts.map +1 -1
- package/dist/runtime/tool-utils.js +91 -0
- package/dist/runtime/tool-utils.js.map +1 -1
- package/dist/server.js +1 -1
- package/dist/server.js.map +1 -1
- package/dist/skills/loader.d.ts.map +1 -1
- package/dist/skills/loader.js +16 -0
- package/dist/skills/loader.js.map +1 -1
- package/dist/test-call.d.ts +2 -0
- package/dist/test-call.d.ts.map +1 -0
- package/dist/test-call.js +29 -0
- package/dist/test-call.js.map +1 -0
- package/dist/test-manager-call.d.ts +2 -0
- package/dist/test-manager-call.d.ts.map +1 -0
- package/dist/test-manager-call.js +138 -0
- package/dist/test-manager-call.js.map +1 -0
- package/dist/test-manager-filtered.d.ts +2 -0
- package/dist/test-manager-filtered.d.ts.map +1 -0
- package/dist/test-manager-filtered.js +130 -0
- package/dist/test-manager-filtered.js.map +1 -0
- package/dist/test-mcp-call.d.ts +2 -0
- package/dist/test-mcp-call.d.ts.map +1 -0
- package/dist/test-mcp-call.js +103 -0
- package/dist/test-mcp-call.js.map +1 -0
- package/dist/tools/composio.tool.d.ts +1 -1
- package/dist/tools/composio.tool.d.ts.map +1 -1
- package/dist/tools/composio.tool.js +7 -16
- package/dist/tools/composio.tool.js.map +1 -1
- package/dist/tools/executive.tool.d.ts +40 -0
- package/dist/tools/executive.tool.d.ts.map +1 -0
- package/dist/tools/executive.tool.js +74 -0
- package/dist/tools/executive.tool.js.map +1 -0
- package/dist/tools/filesystem.tool.d.ts +183 -40
- package/dist/tools/filesystem.tool.d.ts.map +1 -1
- package/dist/tools/filesystem.tool.js +564 -111
- package/dist/tools/filesystem.tool.js.map +1 -1
- package/dist/tools/mcp.tool.d.ts +56 -0
- package/dist/tools/mcp.tool.d.ts.map +1 -0
- package/dist/tools/mcp.tool.js +285 -0
- package/dist/tools/mcp.tool.js.map +1 -0
- package/dist/tools/osint.tool.d.ts +4 -4
- package/dist/tools/pentest.tool.d.ts +2 -2
- package/dist/tools/setup-assistant.tool.d.ts +1 -1
- package/dist/tools/setup-assistant.tool.js +1 -1
- package/dist/tools/setup-assistant.tool.js.map +1 -1
- package/dist/workspace/paths.d.ts +1 -0
- package/dist/workspace/paths.d.ts.map +1 -1
- package/dist/workspace/paths.js +3 -4
- package/dist/workspace/paths.js.map +1 -1
- package/package.json +6 -3
- package/scripts/postinstall.mjs +19 -4
- package/scripts/release-github.mjs +13 -11
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Traffic Protection
|
|
2
|
+
|
|
3
|
+
This skill documents how to use deny lists and automatic IP protection in the Upstash Ratelimit TypeScript SDK. It explains configuration, behavior, caching, update patterns, and common pitfalls.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Deny Lists
|
|
8
|
+
|
|
9
|
+
Deny lists block requests based on IP, user agent, country, or identifier. Enable protection by setting `enableProtection: true` when creating your Ratelimit client.
|
|
10
|
+
|
|
11
|
+
Example usage:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
const ratelimit = new Ratelimit({
|
|
15
|
+
redis: Redis.fromEnv(),
|
|
16
|
+
limiter: Ratelimit.slidingWindow(10, "10 s"),
|
|
17
|
+
enableProtection: true,
|
|
18
|
+
analytics: true,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const result = await ratelimit.limit("userId", {
|
|
22
|
+
ip: "203.0.113.5",
|
|
23
|
+
userAgent: "malicious-bot",
|
|
24
|
+
country: "CN",
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
await result.pending; // analytics sync
|
|
28
|
+
|
|
29
|
+
if (!result.success && result.reason === "denyList") {
|
|
30
|
+
console.log("Blocked value:", result.deniedValue);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Behavior & Pitfalls
|
|
35
|
+
|
|
36
|
+
- Exact match only; pattern matching is **not supported**.
|
|
37
|
+
- Denied values are cached for 1 minute to reduce Redis load. Removal from the deny list may take up to a minute to propagate.
|
|
38
|
+
- Adding a value propagates instantly.
|
|
39
|
+
- Dashboard manages all deny list entries; analytics can show aggregated blocks.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Auto IP Deny List
|
|
44
|
+
|
|
45
|
+
Automatically blocks IPs aggregated from >30 open‑source abuse lists (via GitHub's *ipsum* repository). Updates occur daily at **2 AM UTC**.
|
|
46
|
+
|
|
47
|
+
Enable protection:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
const ratelimit = new Ratelimit({
|
|
51
|
+
redis: Redis.fromEnv(),
|
|
52
|
+
limiter: Ratelimit.slidingWindow(10, "10 s"),
|
|
53
|
+
enableProtection: true,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const { success, pending } = await ratelimit.limit("userId", { ip: "203.0.113.77" });
|
|
57
|
+
await pending; // ensures async sync completion
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Update Flow
|
|
61
|
+
|
|
62
|
+
- First call to `limit` after 2 AM UTC triggers asynchronous list refresh.
|
|
63
|
+
- Request results are returned immediately; updates complete in the background.
|
|
64
|
+
- Use the `pending` promise when accuracy depends on the sync.
|
|
65
|
+
|
|
66
|
+
### Dashboard Integration
|
|
67
|
+
|
|
68
|
+
- All auto‑blocked IPs appear in the "Denied" section.
|
|
69
|
+
- Feature can be disabled from the Upstash Console without disabling standard deny lists.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Common Mistakes
|
|
74
|
+
|
|
75
|
+
- Forgetting to pass `ip`, `userAgent`, or `country` to `limit` → protection does not apply.
|
|
76
|
+
- Expecting pattern or CIDR matches; only exact strings are checked.
|
|
77
|
+
- Confusing auto IP deny list with manual deny list entries; both operate independently.
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: upstash-redis-js
|
|
3
|
+
description: Work with the Upstash Redis TypeScript/JavaScript SDK for serverless Redis operations. Use for caching, session storage, rate limiting, leaderboards, full-text search (querying, filtering, aggregating) with Upstash Redis Search (different from regular FT.SEARCH), and all Redis data structures. Supports automatic serialization/deserialization of JavaScript types. Upstash Redis Search also available via @upstash/search-redis and @upstash/search-ioredis adapters for TCP clients.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Upstash Redis SDK - Complete Skills Guide
|
|
7
|
+
|
|
8
|
+
This directory contains comprehensive guides for using the `@upstash/redis` SDK. These skill files are designed to help developers and AI assistants understand and use the SDK effectively.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @upstash/redis
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
### Basic Initialization
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { Redis } from "@upstash/redis";
|
|
22
|
+
|
|
23
|
+
// Initialize with explicit credentials
|
|
24
|
+
const redis = new Redis({
|
|
25
|
+
url: "UPSTASH_REDIS_REST_URL",
|
|
26
|
+
token: "UPSTASH_REDIS_REST_TOKEN",
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Or initialize from environment variables
|
|
30
|
+
const redis = Redis.fromEnv();
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Environment Variables
|
|
34
|
+
|
|
35
|
+
Set these in your `.env` file:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
UPSTASH_REDIS_REST_URL=https://your-redis.upstash.io
|
|
39
|
+
UPSTASH_REDIS_REST_TOKEN=your-token-here
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
> **No credentials yet?** If you're an agent that needs scratch Redis and the user hasn't provided a database, you can mint a temporary one with a single POST to `https://upstash.com/start-redis` (3-day TTL, no signup).
|
|
43
|
+
|
|
44
|
+
## Skill Files Overview
|
|
45
|
+
|
|
46
|
+
### Data Structures (data-structures/)
|
|
47
|
+
|
|
48
|
+
Redis data types with auto-serialization examples:
|
|
49
|
+
|
|
50
|
+
- **strings.md** - GET, SET, INCR, DECR, APPEND with automatic type handling
|
|
51
|
+
- **hashes.md** - HSET, HGET, HMGET with object serialization
|
|
52
|
+
- **lists.md** - LPUSH, RPUSH, LRANGE with array handling
|
|
53
|
+
- **sets.md** - SADD, SMEMBERS, set operations
|
|
54
|
+
- **sorted-sets.md** - ZADD, ZRANGE, ZRANK, leaderboard patterns
|
|
55
|
+
- **json.md** - JSON.SET, JSON.GET, JSONPath queries for nested objects
|
|
56
|
+
- **streams.md** - XADD, XREAD, XGROUP, consumer groups
|
|
57
|
+
|
|
58
|
+
### Advanced Features (advanced-features/)
|
|
59
|
+
|
|
60
|
+
Complex operations and optimizations:
|
|
61
|
+
|
|
62
|
+
- **auto-pipeline.md** - Automatic request batching, performance optimization
|
|
63
|
+
- **pipeline-and-transactions.md** - Manual pipelines, MULTI/EXEC for atomic operations
|
|
64
|
+
- **scripting.md** - Lua scripts, EVAL, EVALSHA for server-side logic
|
|
65
|
+
|
|
66
|
+
### Patterns (patterns/)
|
|
67
|
+
|
|
68
|
+
Common use cases and architectural patterns:
|
|
69
|
+
|
|
70
|
+
- **caching.md** - Cache-aside, write-through, TTL strategies
|
|
71
|
+
- **rate-limiting.md** - Integration with @upstash/ratelimit package
|
|
72
|
+
- **session-management.md** - Session storage and user state management
|
|
73
|
+
- **distributed-locks.md** - Lock implementations, deadlock prevention
|
|
74
|
+
- **leaderboard.md** - Sorted set leaderboards, real-time rankings
|
|
75
|
+
|
|
76
|
+
### Performance (performance/)
|
|
77
|
+
|
|
78
|
+
Optimization techniques and best practices:
|
|
79
|
+
|
|
80
|
+
- **batching-operations.md** - MGET, MSET, batch operations
|
|
81
|
+
- **pipeline-optimization.md** - When to use pipelines, performance tips
|
|
82
|
+
- **ttl-expiration.md** - Key expiration strategies, memory management
|
|
83
|
+
- **data-serialization.md** - Deep dive into auto serialization, custom serializers, edge cases
|
|
84
|
+
- **error-handling.md** - Error types, retry strategies, timeout handling, debugging tips
|
|
85
|
+
- **redis-replicas.md** - Global database setup, read replicas, read-your-writes consistency
|
|
86
|
+
|
|
87
|
+
### Search (search/)
|
|
88
|
+
|
|
89
|
+
Full-text search, filtering, and aggregation extension for Redis:
|
|
90
|
+
|
|
91
|
+
- **overview.md** - Schema definition, field types, pitfalls, package overview
|
|
92
|
+
- **commands/querying.md** - Query and count with filters, pagination, sorting, highlighting
|
|
93
|
+
- **commands/aggregating.md** - Metric aggregations ($avg, $sum, $stats), bucket aggregations ($terms, $range, $histogram, $facet)
|
|
94
|
+
- **commands/index-management.md** - Create, describe, drop indexes, waitIndexing
|
|
95
|
+
- **commands/aliases.md** - Index aliases for zero-downtime reindexing
|
|
96
|
+
- **adapters.md** - Using search with node-redis and ioredis via @upstash/search-redis and @upstash/search-ioredis
|
|
97
|
+
|
|
98
|
+
### Migrations (migrations/)
|
|
99
|
+
|
|
100
|
+
Migration guides from other libraries:
|
|
101
|
+
|
|
102
|
+
- **from-ioredis.md** - Migration from ioredis, key differences, serialization changes
|
|
103
|
+
- **from-redis-node.md** - Migration from node-redis, API differences
|
|
104
|
+
|
|
105
|
+
## Common Mistakes (Especially for LLMs)
|
|
106
|
+
|
|
107
|
+
### ❌ Mistake 1: Treating Everything as Strings
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
// ❌ WRONG - Don't do this with @upstash/redis
|
|
111
|
+
await redis.set("count", "42"); // Stored as string "42"
|
|
112
|
+
const count = await redis.get("count");
|
|
113
|
+
const incremented = parseInt(count) + 1; // Manual parsing needed
|
|
114
|
+
|
|
115
|
+
// ✅ CORRECT - Let the SDK handle it
|
|
116
|
+
await redis.set("count", 42); // Stored as number
|
|
117
|
+
const count = await redis.get("count");
|
|
118
|
+
const incremented = count + 1; // Just use it
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### ❌ Mistake 2: Manual JSON Serialization
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
// ❌ WRONG - Unnecessary with @upstash/redis
|
|
125
|
+
await redis.set("user", JSON.stringify({ name: "Alice" }));
|
|
126
|
+
const user = JSON.parse(await redis.get("user"));
|
|
127
|
+
|
|
128
|
+
// ✅ CORRECT - Automatic handling
|
|
129
|
+
await redis.set("user", { name: "Alice" });
|
|
130
|
+
const user = await redis.get("user");
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Quick Command Reference
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
// Strings
|
|
137
|
+
await redis.set("key", "value");
|
|
138
|
+
await redis.get("key");
|
|
139
|
+
await redis.incr("counter");
|
|
140
|
+
await redis.decr("counter");
|
|
141
|
+
|
|
142
|
+
// Hashes
|
|
143
|
+
await redis.hset("user:1", { name: "Alice", age: 30 });
|
|
144
|
+
await redis.hget("user:1", "name");
|
|
145
|
+
await redis.hgetall("user:1");
|
|
146
|
+
|
|
147
|
+
// Lists
|
|
148
|
+
await redis.lpush("tasks", "task1", "task2");
|
|
149
|
+
await redis.rpush("tasks", "task3");
|
|
150
|
+
await redis.lrange("tasks", 0, -1);
|
|
151
|
+
|
|
152
|
+
// Sets
|
|
153
|
+
await redis.sadd("tags", "javascript", "redis");
|
|
154
|
+
await redis.smembers("tags");
|
|
155
|
+
|
|
156
|
+
// Sorted Sets
|
|
157
|
+
await redis.zadd("leaderboard", { score: 100, member: "player1" });
|
|
158
|
+
await redis.zrange("leaderboard", 0, -1);
|
|
159
|
+
|
|
160
|
+
// JSON
|
|
161
|
+
await redis.json.set("user:1", "$", { name: "Alice", address: { city: "NYC" } });
|
|
162
|
+
await redis.json.get("user:1");
|
|
163
|
+
|
|
164
|
+
// Expiration
|
|
165
|
+
await redis.setex("session", 3600, { userId: "123" });
|
|
166
|
+
await redis.expire("key", 60);
|
|
167
|
+
await redis.ttl("key");
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Best Practices
|
|
171
|
+
|
|
172
|
+
1. **Use environment variables** for credentials, never hardcode
|
|
173
|
+
2. **Leverage auto-serialization** - pass native JavaScript types
|
|
174
|
+
3. **Use TypeScript types** for better type safety
|
|
175
|
+
4. **Set appropriate TTLs** to manage memory
|
|
176
|
+
5. **Use pipelines** for multiple operations
|
|
177
|
+
6. **Namespace your keys** (e.g., `user:123`, `session:abc`)
|
|
178
|
+
|
|
179
|
+
## Resources
|
|
180
|
+
|
|
181
|
+
- [Official Documentation](https://upstash.com/docs/redis)
|
|
182
|
+
- [GitHub Repository](https://github.com/upstash/redis-js)
|
|
183
|
+
- [API Reference](https://upstash.com/docs/redis/sdks/ts/overview)
|
|
184
|
+
- [Examples](https://github.com/upstash/redis-js/tree/main/examples)
|
|
185
|
+
|
|
186
|
+
## Getting Help
|
|
187
|
+
|
|
188
|
+
For detailed information on specific topics, refer to the individual skill files in the `skills/` directory. Each file contains comprehensive examples, use cases, and best practices for its topic.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Automatic Pipelining
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Automatic pipelining batches multiple Redis commands into a single HTTP request, reducing round-trip latency for independent operations.
|
|
6
|
+
|
|
7
|
+
It's enabled by default. Use `enableAutoPipelining: false` to disable automatic pipelining.
|
|
8
|
+
|
|
9
|
+
## Good For
|
|
10
|
+
|
|
11
|
+
- Multiple independent GET/SET operations
|
|
12
|
+
- Batch reads across different keys
|
|
13
|
+
- Reducing latency in high-latency networks
|
|
14
|
+
- Serverless environments with cold starts
|
|
15
|
+
|
|
16
|
+
## Limitations
|
|
17
|
+
|
|
18
|
+
- Only works with independent commands (no command depends on another's result)
|
|
19
|
+
- Not beneficial for single commands
|
|
20
|
+
|
|
21
|
+
## Examples
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { Redis } from "@upstash/redis";
|
|
25
|
+
|
|
26
|
+
const redis = new Redis({
|
|
27
|
+
url: process.env.UPSTASH_REDIS_REST_URL!,
|
|
28
|
+
token: process.env.UPSTASH_REDIS_REST_TOKEN!,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Without auto-pipeline: 3 separate HTTP requests
|
|
32
|
+
// With auto-pipeline: 1 HTTP request containing all 3 commands
|
|
33
|
+
const [user, posts, comments] = await Promise.all([
|
|
34
|
+
redis.get("user:1"),
|
|
35
|
+
redis.get("posts:1"),
|
|
36
|
+
redis.get("comments:1"),
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
// Auto-pipeline batches these independent operations
|
|
40
|
+
async function fetchUserData(userId: string) {
|
|
41
|
+
const [profile, settings, activity] = await Promise.all([
|
|
42
|
+
redis.hgetall(`user:${userId}:profile`),
|
|
43
|
+
redis.hgetall(`user:${userId}:settings`),
|
|
44
|
+
redis.zrange(`user:${userId}:activity`, 0, 9),
|
|
45
|
+
]);
|
|
46
|
+
|
|
47
|
+
return { profile, settings, activity };
|
|
48
|
+
}
|
|
49
|
+
```
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Pipelines and Transactions
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
**Pipelines** batch multiple commands for efficiency. **Transactions** (MULTI/EXEC) execute commands atomically.
|
|
6
|
+
|
|
7
|
+
## Good For
|
|
8
|
+
|
|
9
|
+
- **Pipelines**: Reducing round trips for independent operations
|
|
10
|
+
- **Transactions**: Atomic operations that must succeed or fail together
|
|
11
|
+
|
|
12
|
+
## Limitations
|
|
13
|
+
|
|
14
|
+
- Pipeline commands execute independently (no atomicity)
|
|
15
|
+
- No WATCH / optimistic locking over the REST client — use a Lua script (`redis.eval`) for atomic check-and-set
|
|
16
|
+
|
|
17
|
+
## Examples
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { Redis } from "@upstash/redis";
|
|
21
|
+
|
|
22
|
+
const redis = Redis.fromEnv();
|
|
23
|
+
|
|
24
|
+
// Manual Pipeline - batch operations for efficiency
|
|
25
|
+
const pipeline = redis.pipeline();
|
|
26
|
+
pipeline.set("user:1:name", "Alice");
|
|
27
|
+
pipeline.set("user:1:email", "alice@example.com");
|
|
28
|
+
pipeline.incr("user:count");
|
|
29
|
+
pipeline.lpush("recent:users", "user:1");
|
|
30
|
+
|
|
31
|
+
const results = await pipeline.exec();
|
|
32
|
+
// Returns array of results: [OK, OK, 1, 1]
|
|
33
|
+
|
|
34
|
+
// Transaction (MULTI/EXEC) - atomic operations
|
|
35
|
+
const tx = redis.multi();
|
|
36
|
+
tx.decrby("inventory:item:1", 5); // Deduct inventory
|
|
37
|
+
tx.incrby("user:123:purchases", 5); // Add to user purchases
|
|
38
|
+
tx.lpush("orders", JSON.stringify({ userId: 123, itemId: 1, qty: 5 }));
|
|
39
|
+
|
|
40
|
+
const txResults = await tx.exec();
|
|
41
|
+
// All commands succeed together or all fail
|
|
42
|
+
```
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Lua Scripting
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Execute Lua scripts atomically on Redis server. Scripts run as a single atomic operation with access to all Redis commands.
|
|
6
|
+
|
|
7
|
+
## Good For
|
|
8
|
+
|
|
9
|
+
- Complex atomic operations
|
|
10
|
+
- Conditional logic on the server
|
|
11
|
+
- Reducing round trips for multi-step operations
|
|
12
|
+
|
|
13
|
+
## Limitations
|
|
14
|
+
|
|
15
|
+
- Blocks other operations while executing
|
|
16
|
+
- Scripts should be fast (avoid heavy computation)
|
|
17
|
+
- Debugging can be challenging
|
|
18
|
+
|
|
19
|
+
## Examples
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { Redis } from "@upstash/redis";
|
|
23
|
+
|
|
24
|
+
const redis = Redis.fromEnv();
|
|
25
|
+
|
|
26
|
+
// Simple script: conditional increment
|
|
27
|
+
const script = `
|
|
28
|
+
local current = redis.call('GET', KEYS[1])
|
|
29
|
+
if current and tonumber(current) < tonumber(ARGV[1]) then
|
|
30
|
+
return redis.call('INCR', KEYS[1])
|
|
31
|
+
end
|
|
32
|
+
return current
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
const result = await redis.eval(script, ["counter"], [100]);
|
|
36
|
+
// Increments only if current value < 100
|
|
37
|
+
|
|
38
|
+
// Atomic rate limiter
|
|
39
|
+
const rateLimitScript = `
|
|
40
|
+
local key = KEYS[1]
|
|
41
|
+
local limit = tonumber(ARGV[1])
|
|
42
|
+
local window = tonumber(ARGV[2])
|
|
43
|
+
|
|
44
|
+
local current = redis.call('INCR', key)
|
|
45
|
+
|
|
46
|
+
if current == 1 then
|
|
47
|
+
redis.call('EXPIRE', key, window)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
if current > limit then
|
|
51
|
+
return 0
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
return 1
|
|
55
|
+
`;
|
|
56
|
+
|
|
57
|
+
const allowed = await redis.eval<number>(
|
|
58
|
+
rateLimitScript,
|
|
59
|
+
["ratelimit:user:123"],
|
|
60
|
+
[10, 60] // 10 requests per 60 seconds
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
if (allowed === 1) {
|
|
64
|
+
console.log("Request allowed");
|
|
65
|
+
} else {
|
|
66
|
+
console.log("Rate limit exceeded");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Script with multiple operations
|
|
70
|
+
const purchaseScript = `
|
|
71
|
+
local inventory = KEYS[1]
|
|
72
|
+
local userBalance = KEYS[2]
|
|
73
|
+
local qty = tonumber(ARGV[1])
|
|
74
|
+
local price = tonumber(ARGV[2])
|
|
75
|
+
|
|
76
|
+
local stock = tonumber(redis.call('GET', inventory) or 0)
|
|
77
|
+
local balance = tonumber(redis.call('GET', userBalance) or 0)
|
|
78
|
+
|
|
79
|
+
local cost = qty * price
|
|
80
|
+
|
|
81
|
+
if stock < qty then
|
|
82
|
+
return {err = "insufficient_stock"}
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
if balance < cost then
|
|
86
|
+
return {err = "insufficient_balance"}
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
redis.call('DECRBY', inventory, qty)
|
|
90
|
+
redis.call('DECRBY', userBalance, cost)
|
|
91
|
+
|
|
92
|
+
return {ok = "success"}
|
|
93
|
+
`;
|
|
94
|
+
|
|
95
|
+
const purchase = await redis.eval<{ err?: string; ok?: string }>(
|
|
96
|
+
purchaseScript,
|
|
97
|
+
["inventory:item:1", "balance:user:123"],
|
|
98
|
+
[5, 20] // Buy 5 items at 20 each
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
// Cache script with EVALSHA for better performance
|
|
102
|
+
const scriptSha = await redis.scriptLoad(rateLimitScript);
|
|
103
|
+
|
|
104
|
+
// Use cached script (faster)
|
|
105
|
+
const allowed2 = await redis.evalsha<number>(scriptSha, ["ratelimit:user:456"], [10, 60]);
|
|
106
|
+
|
|
107
|
+
// Conditional update script
|
|
108
|
+
const setIfHigherScript = `
|
|
109
|
+
local key = KEYS[1]
|
|
110
|
+
local newValue = tonumber(ARGV[1])
|
|
111
|
+
local current = tonumber(redis.call('GET', key) or 0)
|
|
112
|
+
|
|
113
|
+
if newValue > current then
|
|
114
|
+
redis.call('SET', key, newValue)
|
|
115
|
+
return 1
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
return 0
|
|
119
|
+
`;
|
|
120
|
+
|
|
121
|
+
const updated = await redis.eval<number>(setIfHigherScript, ["high_score:user:123"], [1500]);
|
|
122
|
+
|
|
123
|
+
console.log(updated === 1 ? "New high score!" : "Score not higher");
|
|
124
|
+
```
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Hashes
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Hashes store field-value pairs under a single key. They're optimized for storing objects with multiple attributes.
|
|
6
|
+
|
|
7
|
+
## Good For
|
|
8
|
+
|
|
9
|
+
- User profiles
|
|
10
|
+
- Product details
|
|
11
|
+
- Configuration settings
|
|
12
|
+
- Any structured data with named fields
|
|
13
|
+
|
|
14
|
+
## Limitations
|
|
15
|
+
|
|
16
|
+
- For nested objects, use JSON data type instead
|
|
17
|
+
|
|
18
|
+
## Examples
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { Redis } from "@upstash/redis";
|
|
22
|
+
|
|
23
|
+
const redis = Redis.fromEnv();
|
|
24
|
+
|
|
25
|
+
await redis.hset("user:1", {
|
|
26
|
+
name: "Alice",
|
|
27
|
+
email: "alice@example.com",
|
|
28
|
+
age: 30,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Get single field
|
|
32
|
+
const name = await redis.hget("user:1", "name"); // "Alice"
|
|
33
|
+
|
|
34
|
+
// Get multiple fields
|
|
35
|
+
const fields = await redis.hmget("user:1", "name", "email"); // ["Alice", "alice@example.com"]
|
|
36
|
+
|
|
37
|
+
// Get all fields and values
|
|
38
|
+
const user = await redis.hgetall("user:1");
|
|
39
|
+
// { name: "Alice", email: "alice@example.com", age: 30 }
|
|
40
|
+
|
|
41
|
+
// Get all field names
|
|
42
|
+
const fieldNames = await redis.hkeys("user:1"); // ["name", "email", "age"]
|
|
43
|
+
|
|
44
|
+
// Get all values
|
|
45
|
+
const values = await redis.hvals("user:1"); // ["Alice", "alice@example.com", 30]
|
|
46
|
+
|
|
47
|
+
// Check if field exists
|
|
48
|
+
const hasEmail = await redis.hexists("user:1", "email"); // 1 if exists, 0 if not
|
|
49
|
+
|
|
50
|
+
// Get number of fields
|
|
51
|
+
const fieldCount = await redis.hlen("user:1"); // 3
|
|
52
|
+
|
|
53
|
+
// Increment numeric field
|
|
54
|
+
await redis.hset("user:1", { loginCount: 0 });
|
|
55
|
+
await redis.hincrby("user:1", "loginCount", 1); // 1
|
|
56
|
+
await redis.hincrby("user:1", "loginCount", 5); // 6
|
|
57
|
+
|
|
58
|
+
// Increment float field
|
|
59
|
+
await redis.hset("user:1", { balance: 100.5 });
|
|
60
|
+
await redis.hincrbyfloat("user:1", "balance", 25.75); // 126.25
|
|
61
|
+
|
|
62
|
+
// Set only if field doesn't exist
|
|
63
|
+
await redis.hsetnx("user:1", "verified", "true"); // Returns 1 if set, 0 if exists
|
|
64
|
+
|
|
65
|
+
// Delete fields
|
|
66
|
+
await redis.hdel("user:1", "age");
|
|
67
|
+
await redis.hdel("user:1", "loginCount", "balance"); // Delete multiple fields
|
|
68
|
+
|
|
69
|
+
// Delete entire hash
|
|
70
|
+
await redis.del("user:1");
|
|
71
|
+
```
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# JSON
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
JSON data type stores JSON documents with support for nested objects and arrays. It enables operations on specific paths within the document using JSONPath syntax.
|
|
6
|
+
|
|
7
|
+
## Good For
|
|
8
|
+
|
|
9
|
+
- Complex nested objects
|
|
10
|
+
- Document storage (user profiles, product catalogs)
|
|
11
|
+
- Partial updates of large objects
|
|
12
|
+
- Querying nested data
|
|
13
|
+
|
|
14
|
+
## Limitations
|
|
15
|
+
|
|
16
|
+
- Maximum document size: 512 MB
|
|
17
|
+
- JSONPath queries have performance cost on deeply nested structures
|
|
18
|
+
- Some JSONPath features may not be supported
|
|
19
|
+
|
|
20
|
+
## Examples
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { Redis } from "@upstash/redis";
|
|
24
|
+
|
|
25
|
+
const redis = Redis.fromEnv();
|
|
26
|
+
|
|
27
|
+
// Set entire JSON document
|
|
28
|
+
await redis.json.set("user:1", "$", {
|
|
29
|
+
name: "Alice",
|
|
30
|
+
age: 30,
|
|
31
|
+
email: "alice@example.com",
|
|
32
|
+
address: {
|
|
33
|
+
city: "New York",
|
|
34
|
+
country: "USA",
|
|
35
|
+
zip: "10001",
|
|
36
|
+
},
|
|
37
|
+
hobbies: ["reading", "coding"],
|
|
38
|
+
metadata: {
|
|
39
|
+
registered: "2024-01-15",
|
|
40
|
+
verified: true,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Get entire document
|
|
45
|
+
const user = await redis.json.get("user:1");
|
|
46
|
+
// Returns the full object
|
|
47
|
+
|
|
48
|
+
// Get specific path
|
|
49
|
+
const name = await redis.json.get("user:1", "$.name"); // ["Alice"]
|
|
50
|
+
const city = await redis.json.get("user:1", "$.address.city"); // ["New York"]
|
|
51
|
+
|
|
52
|
+
// Get multiple paths
|
|
53
|
+
const details = await redis.json.get("user:1", "$.name", "$.email");
|
|
54
|
+
// { "$.name": ["Alice"], "$.email": ["alice@example.com"] }
|
|
55
|
+
|
|
56
|
+
// Set nested field
|
|
57
|
+
await redis.json.set("user:1", "$.address.city", "San Francisco");
|
|
58
|
+
|
|
59
|
+
// Set multiple fields (overwrites at path)
|
|
60
|
+
await redis.json.set("user:1", "$.metadata", {
|
|
61
|
+
registered: "2024-01-15",
|
|
62
|
+
verified: true,
|
|
63
|
+
lastLogin: "2024-01-23",
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Type-specific operations on JSON
|
|
67
|
+
await redis.json.set("product:1", "$", {
|
|
68
|
+
name: "Laptop",
|
|
69
|
+
price: 999.99,
|
|
70
|
+
stock: 50,
|
|
71
|
+
tags: ["electronics", "computers"],
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Increment numeric field
|
|
75
|
+
await redis.json.numincrby("product:1", "$.price", 100); // 1099.99
|
|
76
|
+
await redis.json.numincrby("product:1", "$.stock", -5); // 45
|
|
77
|
+
|
|
78
|
+
// String append
|
|
79
|
+
await redis.json.strappend("product:1", "$.name", " Pro"); // "Laptop Pro"
|
|
80
|
+
|
|
81
|
+
// Get string length
|
|
82
|
+
const nameLength = await redis.json.strlen("product:1", "$.name"); // [10]
|
|
83
|
+
|
|
84
|
+
// Array operations
|
|
85
|
+
await redis.json.set("cart:1", "$", {
|
|
86
|
+
items: ["item1", "item2"],
|
|
87
|
+
quantities: [1, 2],
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Append to array
|
|
91
|
+
await redis.json.arrappend("cart:1", "$.items", "item3", "item4");
|
|
92
|
+
// items: ["item1", "item2", "item3", "item4"]
|
|
93
|
+
|
|
94
|
+
// Insert into array at index
|
|
95
|
+
await redis.json.arrinsert("cart:1", "$.items", 1, "item-new");
|
|
96
|
+
// items: ["item1", "item-new", "item2", "item3", "item4"]
|
|
97
|
+
|
|
98
|
+
// Get array length
|
|
99
|
+
const itemCount = await redis.json.arrlen("cart:1", "$.items"); // [5]
|
|
100
|
+
|
|
101
|
+
// Get element by index
|
|
102
|
+
const firstItem = await redis.json.arrindex("cart:1", "$.items", "item1"); // [0]
|
|
103
|
+
|
|
104
|
+
// Pop from array
|
|
105
|
+
const lastItem = await redis.json.arrpop("cart:1", "$.items"); // ["item4"]
|
|
106
|
+
const firstFromItems = await redis.json.arrpop("cart:1", "$.items", 0); // ["item1"]
|
|
107
|
+
|
|
108
|
+
// Trim array to range
|
|
109
|
+
await redis.json.arrtrim("cart:1", "$.items", 0, 1); // Keep first 2 elements
|
|
110
|
+
|
|
111
|
+
// Object operations
|
|
112
|
+
await redis.json.set("config:1", "$", {
|
|
113
|
+
database: { host: "localhost", port: 5432 },
|
|
114
|
+
cache: { enabled: true },
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Get object keys
|
|
118
|
+
const dbKeys = await redis.json.objkeys("config:1", "$.database");
|
|
119
|
+
// [["host", "port"]]
|
|
120
|
+
|
|
121
|
+
// Get object length (number of keys)
|
|
122
|
+
const dbKeyCount = await redis.json.objlen("config:1", "$.database"); // [2]
|
|
123
|
+
|
|
124
|
+
// Delete path
|
|
125
|
+
await redis.json.del("user:1", "$.metadata.lastLogin");
|
|
126
|
+
|
|
127
|
+
// Delete entire document
|
|
128
|
+
await redis.json.del("user:1");
|
|
129
|
+
|
|
130
|
+
// Type checking
|
|
131
|
+
await redis.json.set("data:1", "$", { str: "hello", num: 42, bool: true, arr: [1, 2] });
|
|
132
|
+
const type = await redis.json.type("data:1", "$.num"); // ["number"]
|
|
133
|
+
```
|