zilmate 1.8.0 → 1.8.5
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 +262 -27
- 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/update.d.ts.map +1 -1
- package/dist/cli/update.js +27 -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/daytona-browser.tool.js +1 -1
- package/dist/tools/daytona-browser.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 +8 -4
- package/scripts/postinstall.mjs +19 -4
- package/scripts/release-github.mjs +11 -11
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Error Handling
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Handle Redis errors gracefully with try-catch, implement retry logic for transient failures, and provide fallbacks for degraded operation.
|
|
6
|
+
|
|
7
|
+
## Good For
|
|
8
|
+
|
|
9
|
+
- Network failure recovery
|
|
10
|
+
- Timeout handling
|
|
11
|
+
- Graceful degradation
|
|
12
|
+
- Debugging and monitoring
|
|
13
|
+
- Production reliability
|
|
14
|
+
|
|
15
|
+
## Limitations
|
|
16
|
+
|
|
17
|
+
- Some errors are not recoverable
|
|
18
|
+
- Retries can increase latency
|
|
19
|
+
- Too many retries may cause cascading failures
|
|
20
|
+
|
|
21
|
+
## Examples
|
|
22
|
+
|
|
23
|
+
### Built-in Retry Configuration
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { Redis } from "@upstash/redis";
|
|
27
|
+
|
|
28
|
+
// Default: 5 retries with exponential backoff
|
|
29
|
+
const redis = Redis.fromEnv();
|
|
30
|
+
|
|
31
|
+
// Customize retry behavior
|
|
32
|
+
const redisWithRetry = new Redis({
|
|
33
|
+
url: process.env.UPSTASH_REDIS_REST_URL!,
|
|
34
|
+
token: process.env.UPSTASH_REDIS_REST_TOKEN!,
|
|
35
|
+
retry: {
|
|
36
|
+
retries: 3,
|
|
37
|
+
backoff: (retryCount) => Math.exp(retryCount) * 50, // Exponential backoff
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Disable retries
|
|
42
|
+
const redisNoRetry = new Redis({
|
|
43
|
+
url: process.env.UPSTASH_REDIS_REST_URL!,
|
|
44
|
+
token: process.env.UPSTASH_REDIS_REST_TOKEN!,
|
|
45
|
+
retry: false, // No retries
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Custom backoff strategy
|
|
49
|
+
const redisCustomBackoff = new Redis({
|
|
50
|
+
url: process.env.UPSTASH_REDIS_REST_URL!,
|
|
51
|
+
token: process.env.UPSTASH_REDIS_REST_TOKEN!,
|
|
52
|
+
retry: {
|
|
53
|
+
retries: 10,
|
|
54
|
+
backoff: (retryCount) => {
|
|
55
|
+
// Linear backoff: 100ms, 200ms, 300ms...
|
|
56
|
+
return retryCount * 100;
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Request Cancellation with AbortSignal
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { Redis } from "@upstash/redis";
|
|
66
|
+
|
|
67
|
+
const redis = Redis.fromEnv();
|
|
68
|
+
|
|
69
|
+
const redisWithTimeout = new Redis({
|
|
70
|
+
url: process.env.UPSTASH_REDIS_REST_URL!,
|
|
71
|
+
token: process.env.UPSTASH_REDIS_REST_TOKEN!,
|
|
72
|
+
signal: () => AbortSignal.timeout(5000), // 5 second timeout per request
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
await redisWithTimeout.get("key");
|
|
77
|
+
} catch (error) {
|
|
78
|
+
if (error.name === "TimeoutError") {
|
|
79
|
+
console.error("Request timed out");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Error Types
|
|
85
|
+
|
|
86
|
+
All SDK error classes are importable from `@upstash/redis`:
|
|
87
|
+
|
|
88
|
+
| Error | `error.name` | When it's thrown |
|
|
89
|
+
| --- | --- | --- |
|
|
90
|
+
| `UpstashError` | `"UpstashError"` | A command failed server-side, or the REST response contained an `error` field. The base error type. |
|
|
91
|
+
| `UpstashJSONParseError` | `"UpstashJSONParseError"` | The response body could not be parsed as JSON. Extends `UpstashError`. |
|
|
92
|
+
| `UrlError` | `"UrlError"` | The client was constructed with an invalid URL (must start with `https`). Thrown synchronously at construction, before any request. |
|
|
93
|
+
| `TimeoutError` | `"TimeoutError"` | A request was aborted by an `AbortSignal.timeout(...)`. This is the native DOM error, not an SDK class. |
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import { Redis, UpstashError } from "@upstash/redis";
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
await redis.get("key");
|
|
100
|
+
} catch (error) {
|
|
101
|
+
if (error instanceof UpstashError) {
|
|
102
|
+
// command failed or bad request to Upstash
|
|
103
|
+
console.error("Upstash command failed:", error.message);
|
|
104
|
+
} else if (error.name === "TimeoutError") {
|
|
105
|
+
console.error("Request timed out");
|
|
106
|
+
} else {
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Because `UpstashJSONParseError extends UpstashError`, a single `instanceof UpstashError` check catches both. `UrlError` is thrown when you construct the client, so it surfaces at startup rather than inside request `try/catch` blocks.
|
|
113
|
+
|
|
114
|
+
### Debugging
|
|
115
|
+
|
|
116
|
+
- **Read the message — it includes the failed command.** `UpstashError` messages are formatted like `<server error>, command was: ["GET","key"]`, so logging `error.message` shows exactly what was sent.
|
|
117
|
+
- **`UrlError` at startup** almost always means a missing or typo'd `UPSTASH_REDIS_REST_URL` (it must start with `https://`). Verify env vars before suspecting the network.
|
|
118
|
+
- **Retryable vs. fatal.** Network and `TimeoutError` failures are transient and already covered by the built-in `retry`. An `UpstashError` from a bad command (wrong argument types, `WRONGTYPE`, unknown command) is deterministic — retrying won't help, so fix the call instead of raising the retry count.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Pipeline Optimization
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Pipelines batch multiple Redis commands into one HTTP request. Use automatic pipelines for Promise.all patterns, manual pipelines for sequential operations.
|
|
6
|
+
|
|
7
|
+
## Good For
|
|
8
|
+
|
|
9
|
+
- Multiple independent operations
|
|
10
|
+
- High-latency networks
|
|
11
|
+
- Serverless functions with cold starts
|
|
12
|
+
- Operations that don't depend on each other's results
|
|
13
|
+
|
|
14
|
+
## Limitations
|
|
15
|
+
|
|
16
|
+
- Commands in pipeline cannot depend on previous results
|
|
17
|
+
- Large pipelines increase memory usage
|
|
18
|
+
- Errors in one command don't stop others
|
|
19
|
+
|
|
20
|
+
## Examples
|
|
21
|
+
|
|
22
|
+
### Auto-Pipeline Basics
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { Redis } from "@upstash/redis";
|
|
26
|
+
|
|
27
|
+
// Auto-pipeline: enable globally
|
|
28
|
+
const redis = new Redis({
|
|
29
|
+
url: process.env.UPSTASH_REDIS_REST_URL!,
|
|
30
|
+
token: process.env.UPSTASH_REDIS_REST_TOKEN!,
|
|
31
|
+
enableAutoPipelining: true,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// With auto-pipeline: Promise.all batches automatically
|
|
35
|
+
const [user, posts, comments] = await Promise.all([
|
|
36
|
+
redis.get("user:1"),
|
|
37
|
+
redis.lrange("posts:1", 0, 9),
|
|
38
|
+
redis.lrange("comments:1", 0, 9),
|
|
39
|
+
]);
|
|
40
|
+
// Single HTTP request!
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Manual Pipeline
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { Redis } from "@upstash/redis";
|
|
47
|
+
|
|
48
|
+
const redis = Redis.fromEnv();
|
|
49
|
+
|
|
50
|
+
// Manual pipeline: explicit control
|
|
51
|
+
const pipeline = redis.pipeline();
|
|
52
|
+
pipeline.get("user:1");
|
|
53
|
+
pipeline.lrange("posts:1", 0, 9);
|
|
54
|
+
pipeline.lrange("comments:1", 0, 9);
|
|
55
|
+
|
|
56
|
+
const results = await pipeline.exec();
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### When to Use Pipelines
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { Redis } from "@upstash/redis";
|
|
63
|
+
|
|
64
|
+
const redis = Redis.fromEnv();
|
|
65
|
+
|
|
66
|
+
// ❌ Bad: second operation depends on first
|
|
67
|
+
const bad = redis.pipeline();
|
|
68
|
+
bad.get("counter");
|
|
69
|
+
bad.incr("counter"); // Might not see previous get result
|
|
70
|
+
await bad.exec();
|
|
71
|
+
|
|
72
|
+
// ✅ Good: independent operations
|
|
73
|
+
const good = redis.pipeline();
|
|
74
|
+
good.get("user:1");
|
|
75
|
+
good.get("user:2");
|
|
76
|
+
good.get("user:3");
|
|
77
|
+
await good.exec();
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Pipeline Size Optimization
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import { Redis } from "@upstash/redis";
|
|
84
|
+
|
|
85
|
+
const redis = Redis.fromEnv();
|
|
86
|
+
const OPTIMAL_SIZE = 50;
|
|
87
|
+
|
|
88
|
+
async function pipelinedBatch(keys: string[]) {
|
|
89
|
+
const results = [];
|
|
90
|
+
for (let i = 0; i < keys.length; i += OPTIMAL_SIZE) {
|
|
91
|
+
const batch = keys.slice(i, i + OPTIMAL_SIZE);
|
|
92
|
+
const pipeline = redis.pipeline();
|
|
93
|
+
batch.forEach((key) => pipeline.get(key));
|
|
94
|
+
|
|
95
|
+
const batchResults = await pipeline.exec();
|
|
96
|
+
results.push(...batchResults);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return results;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Usage
|
|
103
|
+
const keys = Array.from({ length: 200 }, (_, i) => `key:${i}`);
|
|
104
|
+
const allResults = await pipelinedBatch(keys);
|
|
105
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Global Redis Replicas
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Upstash Redis uses global replication with one primary and multiple replicas worldwide. Writes go to primary, reads can use nearest replica. Read-your-writes ensures consistency.
|
|
6
|
+
|
|
7
|
+
If you want to optimize read latency, you can add more read regions to your Upstash Redis database via the Upstash Console.
|
|
8
|
+
|
|
9
|
+
## Good For
|
|
10
|
+
|
|
11
|
+
- Low-latency reads from nearby regions
|
|
12
|
+
- Global applications with distributed users
|
|
13
|
+
- Read-heavy workloads
|
|
14
|
+
- High availability
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# TTL and Key Expiration
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Set Time-To-Live (TTL) on keys for automatic expiration. Useful for caches, sessions, and temporary data to manage memory usage.
|
|
6
|
+
|
|
7
|
+
## Good For
|
|
8
|
+
|
|
9
|
+
- Cache expiration (prevent stale data)
|
|
10
|
+
- Session timeouts
|
|
11
|
+
- Temporary data storage
|
|
12
|
+
- Memory management
|
|
13
|
+
|
|
14
|
+
## Examples
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { Redis } from "@upstash/redis";
|
|
18
|
+
|
|
19
|
+
const redis = Redis.fromEnv();
|
|
20
|
+
|
|
21
|
+
// Set with expiration (EX = seconds)
|
|
22
|
+
await redis.set("session:123", { userId: "user1" }, { ex: 3600 });
|
|
23
|
+
|
|
24
|
+
// Add TTL to existing key
|
|
25
|
+
await redis.set("key", "value");
|
|
26
|
+
await redis.expire("key", 300); // Expire in 5 minutes
|
|
27
|
+
|
|
28
|
+
// Get TTL of a key
|
|
29
|
+
const ttl = await redis.ttl("key");
|
|
30
|
+
console.log(`TTL: ${ttl} seconds`);
|
|
31
|
+
// Returns: remaining seconds, -1 (no expiry), -2 (key doesn't exist)
|
|
32
|
+
```
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Adapters
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`@upstash/redis` works over HTTP, which is ideal for serverless environments. If you need TCP-based connections (e.g., long-running servers with `redis` or `ioredis`), use the adapter packages `@upstash/search-redis` and `@upstash/search-ioredis`. They provide the exact same search API.
|
|
6
|
+
|
|
7
|
+
## Packages
|
|
8
|
+
|
|
9
|
+
| Package | Client | Protocol | Install |
|
|
10
|
+
| ------------------------- | ---------- | --------- | --------------------------------------------- |
|
|
11
|
+
| `@upstash/redis` | Built-in | HTTP/REST | `npm install @upstash/redis` |
|
|
12
|
+
| `@upstash/search-redis` | node-redis | TCP | `npm install @upstash/search-redis redis` |
|
|
13
|
+
| `@upstash/search-ioredis` | ioredis | TCP | `npm install @upstash/search-ioredis ioredis` |
|
|
14
|
+
|
|
15
|
+
## Examples
|
|
16
|
+
|
|
17
|
+
### With @upstash/redis (HTTP)
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { Redis, s } from "@upstash/redis";
|
|
21
|
+
|
|
22
|
+
const redis = Redis.fromEnv();
|
|
23
|
+
|
|
24
|
+
const index = await redis.search.createIndex({
|
|
25
|
+
name: "products",
|
|
26
|
+
prefix: "product:",
|
|
27
|
+
dataType: "json",
|
|
28
|
+
schema: s.object({ name: s.string(), price: s.number("F64") }),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const results = await index.query({
|
|
32
|
+
filter: { name: { $eq: "laptop" } },
|
|
33
|
+
select: { name: true, price: true },
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### With node-redis (TCP)
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { createClient } from "redis";
|
|
41
|
+
import { createSearch, s } from "@upstash/search-redis";
|
|
42
|
+
|
|
43
|
+
const client = createClient({ url: process.env.REDIS_URL });
|
|
44
|
+
await client.connect();
|
|
45
|
+
|
|
46
|
+
const search = createSearch(client);
|
|
47
|
+
|
|
48
|
+
const index = await search.createIndex({
|
|
49
|
+
name: "products",
|
|
50
|
+
prefix: "product:",
|
|
51
|
+
dataType: "json",
|
|
52
|
+
schema: s.object({ name: s.string(), price: s.number("F64") }),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const results = await index.query({
|
|
56
|
+
filter: { name: { $eq: "laptop" } },
|
|
57
|
+
select: { name: true, price: true },
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
await client.disconnect();
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### With ioredis (TCP)
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import IORedis from "ioredis";
|
|
67
|
+
import { createSearch, s } from "@upstash/search-ioredis";
|
|
68
|
+
|
|
69
|
+
const ioredis = new IORedis(process.env.REDIS_URL);
|
|
70
|
+
|
|
71
|
+
const search = createSearch(ioredis);
|
|
72
|
+
|
|
73
|
+
const index = await search.createIndex({
|
|
74
|
+
name: "products",
|
|
75
|
+
prefix: "product:",
|
|
76
|
+
dataType: "json",
|
|
77
|
+
schema: s.object({ name: s.string(), price: s.number("F64") }),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const results = await index.query({
|
|
81
|
+
filter: { name: { $eq: "laptop" } },
|
|
82
|
+
select: { name: true, price: true },
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
await ioredis.disconnect();
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## API Parity
|
|
89
|
+
|
|
90
|
+
All three packages expose identical search APIs:
|
|
91
|
+
|
|
92
|
+
- `search.createIndex()` / `createSearch(client).createIndex()`
|
|
93
|
+
- `search.index()` / `createSearch(client).index()`
|
|
94
|
+
- `search.alias.list()`, `search.alias.add()`, `search.alias.delete()`
|
|
95
|
+
- `index.query()`, `index.aggregate()`, `index.count()`
|
|
96
|
+
- `index.describe()`, `index.drop()`, `index.waitIndexing()`
|
|
97
|
+
- `index.addAlias()`
|
|
98
|
+
|
|
99
|
+
The only difference is initialization. The `s` schema builder is re-exported from all packages.
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# Aggregations
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Run analytics over indexed data using metric and bucket aggregations. Compute statistics, group documents, build histograms, and perform faceted navigation. Aggregations can be nested for multi-level analysis.
|
|
6
|
+
|
|
7
|
+
## Good For
|
|
8
|
+
|
|
9
|
+
- Computing averages, sums, min/max across documents
|
|
10
|
+
- Grouping documents by field values (category breakdown)
|
|
11
|
+
- Building price range facets for e-commerce
|
|
12
|
+
- Histogram distributions (price ranges, date ranges)
|
|
13
|
+
- Multi-level analytics (average price per category)
|
|
14
|
+
|
|
15
|
+
## Examples
|
|
16
|
+
|
|
17
|
+
### Metric Aggregations
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { Redis, s } from "@upstash/redis";
|
|
21
|
+
|
|
22
|
+
const redis = Redis.fromEnv();
|
|
23
|
+
|
|
24
|
+
const index = await redis.search.createIndex({
|
|
25
|
+
name: "orders",
|
|
26
|
+
prefix: "order:",
|
|
27
|
+
dataType: "json",
|
|
28
|
+
schema: s.object({
|
|
29
|
+
product: s.string(),
|
|
30
|
+
category: s.facet(),
|
|
31
|
+
price: s.number("F64"),
|
|
32
|
+
quantity: s.number("U64"),
|
|
33
|
+
date: s.date(),
|
|
34
|
+
}),
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Insert sample data
|
|
38
|
+
await redis.json.set("order:1", "$", {
|
|
39
|
+
product: "Laptop",
|
|
40
|
+
category: "electronics",
|
|
41
|
+
price: 999.99,
|
|
42
|
+
quantity: 1,
|
|
43
|
+
date: "2024-06-15",
|
|
44
|
+
});
|
|
45
|
+
await redis.json.set("order:2", "$", {
|
|
46
|
+
product: "Mouse",
|
|
47
|
+
category: "electronics",
|
|
48
|
+
price: 29.99,
|
|
49
|
+
quantity: 3,
|
|
50
|
+
date: "2024-06-16",
|
|
51
|
+
});
|
|
52
|
+
await redis.json.set("order:3", "$", {
|
|
53
|
+
product: "Desk",
|
|
54
|
+
category: "furniture",
|
|
55
|
+
price: 249.99,
|
|
56
|
+
quantity: 1,
|
|
57
|
+
date: "2024-07-01",
|
|
58
|
+
});
|
|
59
|
+
await index.waitIndexing();
|
|
60
|
+
|
|
61
|
+
// Average price
|
|
62
|
+
const result = await index.aggregate({
|
|
63
|
+
aggregations: {
|
|
64
|
+
avg_price: { $avg: { field: "price" } },
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
// result.avg_price -> number
|
|
68
|
+
|
|
69
|
+
// Multiple metrics at once
|
|
70
|
+
const stats = await index.aggregate({
|
|
71
|
+
aggregations: {
|
|
72
|
+
avg_price: { $avg: { field: "price" } },
|
|
73
|
+
total_revenue: { $sum: { field: "price" } },
|
|
74
|
+
cheapest: { $min: { field: "price" } },
|
|
75
|
+
most_expensive: { $max: { field: "price" } },
|
|
76
|
+
order_count: { $count: { field: "price" } },
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Combined statistics
|
|
81
|
+
const priceStats = await index.aggregate({
|
|
82
|
+
aggregations: {
|
|
83
|
+
price_stats: { $stats: { field: "price" } },
|
|
84
|
+
// Returns: { count, min, max, sum, avg }
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Extended statistics (includes variance and standard deviation)
|
|
89
|
+
const extended = await index.aggregate({
|
|
90
|
+
aggregations: {
|
|
91
|
+
price_extended: { $extendedStats: { field: "price" } },
|
|
92
|
+
// Returns: { count, min, max, sum, avg, sumOfSquares, variance, stdDeviation }
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Percentiles
|
|
97
|
+
const percentiles = await index.aggregate({
|
|
98
|
+
aggregations: {
|
|
99
|
+
price_percentiles: { $percentiles: { field: "price", percents: [25, 50, 75, 95] } },
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Count distinct values
|
|
104
|
+
const uniqueCategories = await index.aggregate({
|
|
105
|
+
aggregations: {
|
|
106
|
+
unique_cats: { $cardinality: { field: "category" } },
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Bucket Aggregations
|
|
112
|
+
|
|
113
|
+
#### $terms - Group by field values
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
const byCategory = await index.aggregate({
|
|
117
|
+
aggregations: {
|
|
118
|
+
categories: {
|
|
119
|
+
$terms: { field: "category", size: 10 },
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
// categories.buckets -> [{ key: "electronics", doc_count: 2 }, { key: "furniture", doc_count: 1 }]
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
#### $range - Group by numeric ranges
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
const priceRanges = await index.aggregate({
|
|
130
|
+
aggregations: {
|
|
131
|
+
price_ranges: {
|
|
132
|
+
$range: {
|
|
133
|
+
field: "price",
|
|
134
|
+
ranges: [
|
|
135
|
+
{ to: 50 }, // Under $50
|
|
136
|
+
{ from: 50, to: 200 }, // $50-$200
|
|
137
|
+
{ from: 200 }, // Over $200
|
|
138
|
+
],
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
#### $histogram - Fixed-interval numeric buckets
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
const priceHistogram = await index.aggregate({
|
|
149
|
+
aggregations: {
|
|
150
|
+
price_distribution: {
|
|
151
|
+
$histogram: { field: "price", interval: 100 },
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### $facet - Faceted navigation
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
const facets = await index.aggregate({
|
|
161
|
+
aggregations: {
|
|
162
|
+
brand_facets: { $facet: { field: "brand" } },
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Nested Aggregations
|
|
168
|
+
|
|
169
|
+
Combine buckets with metrics for multi-level analysis:
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
// Average price per category
|
|
173
|
+
const result = await index.aggregate({
|
|
174
|
+
aggregations: {
|
|
175
|
+
by_category: {
|
|
176
|
+
$terms: { field: "category" },
|
|
177
|
+
$aggs: {
|
|
178
|
+
avg_price: { $avg: { field: "price" } },
|
|
179
|
+
min_price: { $min: { field: "price" } },
|
|
180
|
+
max_price: { $max: { field: "price" } },
|
|
181
|
+
total_orders: { $count: { field: "price" } },
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
// by_category.buckets -> [
|
|
187
|
+
// { key: "electronics", doc_count: 2, avg_price: 514.99, min_price: 29.99, max_price: 999.99, total_orders: 2 },
|
|
188
|
+
// { key: "furniture", doc_count: 1, avg_price: 249.99, ... },
|
|
189
|
+
// ]
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Filtered Aggregations
|
|
193
|
+
|
|
194
|
+
Apply a filter before aggregating:
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
const electronicsStats = await index.aggregate({
|
|
198
|
+
filter: { category: { $eq: "electronics" } },
|
|
199
|
+
aggregations: {
|
|
200
|
+
avg_price: { $avg: { field: "price" } },
|
|
201
|
+
price_ranges: {
|
|
202
|
+
$range: {
|
|
203
|
+
field: "price",
|
|
204
|
+
ranges: [{ to: 100 }, { from: 100, to: 500 }, { from: 500 }],
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Available Aggregations
|
|
212
|
+
|
|
213
|
+
### Metric Aggregations
|
|
214
|
+
|
|
215
|
+
| Aggregation | Description |
|
|
216
|
+
| ---------------- | ------------------------------------------ |
|
|
217
|
+
| `$avg` | Average value of a numeric field |
|
|
218
|
+
| `$sum` | Sum of values |
|
|
219
|
+
| `$min` | Minimum value |
|
|
220
|
+
| `$max` | Maximum value |
|
|
221
|
+
| `$count` | Count of documents |
|
|
222
|
+
| `$cardinality` | Count of distinct values |
|
|
223
|
+
| `$stats` | Combined count/min/max/sum/avg |
|
|
224
|
+
| `$extendedStats` | Stats + variance/stdDeviation/sumOfSquares |
|
|
225
|
+
| `$percentiles` | Percentile values at specified thresholds |
|
|
226
|
+
|
|
227
|
+
### Bucket Aggregations
|
|
228
|
+
|
|
229
|
+
| Aggregation | Description |
|
|
230
|
+
| ------------ | --------------------------------- |
|
|
231
|
+
| `$terms` | Group by field values |
|
|
232
|
+
| `$range` | Group by custom numeric ranges |
|
|
233
|
+
| `$histogram` | Fixed-interval numeric buckets |
|
|
234
|
+
| `$facet` | Faceted navigation (hierarchical) |
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Aliases
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Index aliases provide an indirection layer between your application and the actual index. You can point an alias to any index and swap it atomically, enabling zero-downtime reindexing.
|
|
6
|
+
|
|
7
|
+
## Good For
|
|
8
|
+
|
|
9
|
+
- Zero-downtime index rebuilds (blue/green reindexing)
|
|
10
|
+
- A/B testing different index configurations
|
|
11
|
+
- Versioned index management
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### Add an Alias
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { Redis, s } from "@upstash/redis";
|
|
19
|
+
|
|
20
|
+
const redis = Redis.fromEnv();
|
|
21
|
+
|
|
22
|
+
// Create an index
|
|
23
|
+
const index = await redis.search.createIndex({
|
|
24
|
+
name: "products-v1",
|
|
25
|
+
prefix: "product:",
|
|
26
|
+
dataType: "json",
|
|
27
|
+
schema: s.object({ name: s.string(), price: s.number("F64") }),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Add alias via the index instance
|
|
31
|
+
await index.addAlias({ alias: "products" });
|
|
32
|
+
|
|
33
|
+
// Or via the redis.search.alias API
|
|
34
|
+
await redis.search.alias.add({ indexName: "products-v1", alias: "products" });
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### List All Aliases
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
const aliases = await redis.search.alias.list();
|
|
41
|
+
// { "products": "products-v1", "users": "users-v2" }
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Delete an Alias
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
await redis.search.alias.delete({ alias: "products" });
|
|
48
|
+
// Returns 1 if deleted, 0 if alias didn't exist
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Zero-Downtime Reindexing
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
// 1. Create new index with updated schema
|
|
55
|
+
const newIndex = await redis.search.createIndex({
|
|
56
|
+
name: "products-v2",
|
|
57
|
+
prefix: "product:",
|
|
58
|
+
dataType: "json",
|
|
59
|
+
schema: s.object({
|
|
60
|
+
name: s.string(),
|
|
61
|
+
price: s.number("F64"),
|
|
62
|
+
description: s.string(), // new field
|
|
63
|
+
}),
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// 2. Wait for new index to finish scanning existing keys
|
|
67
|
+
await newIndex.waitIndexing();
|
|
68
|
+
|
|
69
|
+
// 3. Atomically swap the alias to the new index
|
|
70
|
+
// (addAlias updates the alias if it already exists)
|
|
71
|
+
await redis.search.alias.add({ indexName: "products-v2", alias: "products" });
|
|
72
|
+
|
|
73
|
+
// 4. Drop the old index
|
|
74
|
+
const oldIndex = redis.search.index({ name: "products" });
|
|
75
|
+
await oldIndex.drop();
|
|
76
|
+
```
|