codexkit 1.0.0
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/.codex/.env.example +27 -0
- package/.codex/.template-manifest.json +631 -0
- package/.codex/.version +1 -0
- package/.codex/agents/builder.toml +104 -0
- package/.codex/agents/debugger.toml +67 -0
- package/.codex/agents/general.toml +41 -0
- package/.codex/agents/painter.toml +40 -0
- package/.codex/agents/planner.toml +60 -0
- package/.codex/agents/refactorer.toml +76 -0
- package/.codex/agents/reviewer.toml +60 -0
- package/.codex/agents/runner.toml +40 -0
- package/.codex/agents/scout.toml +133 -0
- package/.codex/agents/shipper.toml +69 -0
- package/.codex/agents/vision.toml +69 -0
- package/.codex/config.toml +146 -0
- package/.codex/context/architecture.md +66 -0
- package/.codex/context/conventions.md +98 -0
- package/.codex/context/current-priorities.md +33 -0
- package/.codex/context/decision-log.md +93 -0
- package/.codex/context/gotchas.md +42 -0
- package/.codex/context/index.md +21 -0
- package/.codex/context/session-context.md +11 -0
- package/.codex/context/worklog.md +9 -0
- package/.codex/hooks/README.md +17 -0
- package/.codex/hooks/after_agent.sh +11 -0
- package/.codex/hooks/after_tool_use.sh +10 -0
- package/.codex/hooks/post_commit.sh +10 -0
- package/.codex/hooks/pre_commit.sh +6 -0
- package/.codex/hooks/session_start.sh +18 -0
- package/.codex/hooks/stop.sh +10 -0
- package/.codex/mcp/README.md +143 -0
- package/.codex/mcp/basic-memory.toml.example +10 -0
- package/.codex/mcp/context7.toml.example +13 -0
- package/.codex/mcp/exa.toml.example +12 -0
- package/.codex/mcp/memory-bridge.toml.example +15 -0
- package/.codex/mcp/memory.toml.example +6 -0
- package/.codex/mcp/ref.toml.example +13 -0
- package/.codex/mcp/tilth.toml.example +10 -0
- package/.codex/memory/README.md +29 -0
- package/.codex/memory/_templates/README.md +26 -0
- package/.codex/memory/_templates/design.md +15 -0
- package/.codex/memory/_templates/gotcha.md +9 -0
- package/.codex/memory/_templates/handoff.md +9 -0
- package/.codex/memory/_templates/prd.md +13 -0
- package/.codex/memory/_templates/project.md +9 -0
- package/.codex/memory/_templates/proposal.md +13 -0
- package/.codex/memory/_templates/research.md +9 -0
- package/.codex/memory/_templates/roadmap.md +11 -0
- package/.codex/memory/_templates/session-context.md +7 -0
- package/.codex/memory/_templates/state.md +11 -0
- package/.codex/memory/_templates/tasks.md +9 -0
- package/.codex/memory/_templates/tech-stack.md +9 -0
- package/.codex/memory/_templates/user.md +7 -0
- package/.codex/memory/project/gotchas.md +5 -0
- package/.codex/memory/project/project.md +12 -0
- package/.codex/memory/project/roadmap.md +15 -0
- package/.codex/memory/project/state.md +22 -0
- package/.codex/memory/project/tech-stack.md +19 -0
- package/.codex/memory/project/user.md +10 -0
- package/.codex/memory/research/.gitkeep +1 -0
- package/.codex/memory/session-context.md +18 -0
- package/.codex/plans/README.md +7 -0
- package/.codex/prompts/compound.md +154 -0
- package/.codex/prompts/create.md +238 -0
- package/.codex/prompts/design.md +90 -0
- package/.codex/prompts/handoff.md +184 -0
- package/.codex/prompts/init-context.md +185 -0
- package/.codex/prompts/init-user.md +93 -0
- package/.codex/prompts/init.md +103 -0
- package/.codex/prompts/lfg.md +140 -0
- package/.codex/prompts/plan.md +140 -0
- package/.codex/prompts/pr.md +150 -0
- package/.codex/prompts/research.md +137 -0
- package/.codex/prompts/resume.md +105 -0
- package/.codex/prompts/review-codebase.md +147 -0
- package/.codex/prompts/ship.md +334 -0
- package/.codex/prompts/start.md +141 -0
- package/.codex/prompts/status.md +102 -0
- package/.codex/prompts/ui-inspire.md +151 -0
- package/.codex/prompts/ui-review.md +86 -0
- package/.codex/prompts/verify.md +181 -0
- package/.codex/scripts/append_worklog.sh +20 -0
- package/.codex/scripts/apply_worklog_archive.sh +48 -0
- package/.codex/scripts/audit_memory_hygiene.sh +102 -0
- package/.codex/scripts/build_memory_index.sh +167 -0
- package/.codex/scripts/build_prior_related_work.sh +127 -0
- package/.codex/scripts/build_startup_brief.sh +52 -0
- package/.codex/scripts/close_bead.sh +103 -0
- package/.codex/scripts/detect_changed_files.sh +38 -0
- package/.codex/scripts/ensure_beads.sh +14 -0
- package/.codex/scripts/memory_search.sh +292 -0
- package/.codex/scripts/prepare_worklog_archive.sh +115 -0
- package/.codex/scripts/search_bead_context.sh +214 -0
- package/.codex/scripts/start_bead.sh +129 -0
- package/.codex/scripts/sync_bead_context.sh +288 -0
- package/.codex/scripts/validate_memory_docs.sh +44 -0
- package/.codex/scripts/verify_bead.sh +154 -0
- package/.codex/skills/accessibility-audit/SKILL.md +191 -0
- package/.codex/skills/agent-browser/SKILL.md +413 -0
- package/.codex/skills/agent-teams/SKILL.md +268 -0
- package/.codex/skills/augment-context-engine/SKILL.md +115 -0
- package/.codex/skills/augment-context-engine/mcp.json +6 -0
- package/.codex/skills/beads/SKILL.md +181 -0
- package/.codex/skills/beads/references/BEST_PRACTICES.md +27 -0
- package/.codex/skills/beads/references/BOUNDARIES.md +219 -0
- package/.codex/skills/beads/references/DEPENDENCIES.md +124 -0
- package/.codex/skills/beads/references/EXAMPLES.md +45 -0
- package/.codex/skills/beads/references/FILE_CLAIMING.md +101 -0
- package/.codex/skills/beads/references/GIT_SYNC.md +25 -0
- package/.codex/skills/beads/references/HIERARCHY.md +71 -0
- package/.codex/skills/beads/references/MULTI_AGENT.md +40 -0
- package/.codex/skills/beads/references/RESUMABILITY.md +177 -0
- package/.codex/skills/beads/references/SESSION_PROTOCOL.md +61 -0
- package/.codex/skills/beads/references/TASK_CREATION.md +38 -0
- package/.codex/skills/beads/references/TROUBLESHOOTING.md +38 -0
- package/.codex/skills/beads/references/WORKFLOWS.md +226 -0
- package/.codex/skills/beads-bridge/SKILL.md +321 -0
- package/.codex/skills/brainstorming/SKILL.md +114 -0
- package/.codex/skills/bug-triage/SKILL.md +191 -0
- package/.codex/skills/chrome-devtools/SKILL.md +76 -0
- package/.codex/skills/chrome-devtools/mcp.json +19 -0
- package/.codex/skills/cloudflare/SKILL.md +253 -0
- package/.codex/skills/cloudflare/references/agents-sdk/README.md +35 -0
- package/.codex/skills/cloudflare/references/agents-sdk/api.md +100 -0
- package/.codex/skills/cloudflare/references/agents-sdk/configuration.md +99 -0
- package/.codex/skills/cloudflare/references/agents-sdk/gotchas.md +59 -0
- package/.codex/skills/cloudflare/references/agents-sdk/patterns.md +89 -0
- package/.codex/skills/cloudflare/references/ai-gateway/README.md +695 -0
- package/.codex/skills/cloudflare/references/ai-search/README.md +14 -0
- package/.codex/skills/cloudflare/references/ai-search/api.md +38 -0
- package/.codex/skills/cloudflare/references/ai-search/configuration.md +52 -0
- package/.codex/skills/cloudflare/references/ai-search/gotchas.md +41 -0
- package/.codex/skills/cloudflare/references/ai-search/patterns.md +45 -0
- package/.codex/skills/cloudflare/references/analytics-engine/README.md +14 -0
- package/.codex/skills/cloudflare/references/analytics-engine/api.md +27 -0
- package/.codex/skills/cloudflare/references/analytics-engine/configuration.md +45 -0
- package/.codex/skills/cloudflare/references/analytics-engine/gotchas.md +3 -0
- package/.codex/skills/cloudflare/references/analytics-engine/patterns.md +36 -0
- package/.codex/skills/cloudflare/references/api/README.md +21 -0
- package/.codex/skills/cloudflare/references/api/api.md +31 -0
- package/.codex/skills/cloudflare/references/api/configuration.md +20 -0
- package/.codex/skills/cloudflare/references/api/gotchas.md +28 -0
- package/.codex/skills/cloudflare/references/api/patterns.md +47 -0
- package/.codex/skills/cloudflare/references/api-shield/README.md +20 -0
- package/.codex/skills/cloudflare/references/api-shield/api.md +78 -0
- package/.codex/skills/cloudflare/references/api-shield/configuration.md +128 -0
- package/.codex/skills/cloudflare/references/api-shield/gotchas.md +51 -0
- package/.codex/skills/cloudflare/references/api-shield/patterns.md +145 -0
- package/.codex/skills/cloudflare/references/argo-smart-routing/README.md +16 -0
- package/.codex/skills/cloudflare/references/argo-smart-routing/api.md +50 -0
- package/.codex/skills/cloudflare/references/argo-smart-routing/configuration.md +53 -0
- package/.codex/skills/cloudflare/references/argo-smart-routing/gotchas.md +16 -0
- package/.codex/skills/cloudflare/references/argo-smart-routing/patterns.md +45 -0
- package/.codex/skills/cloudflare/references/bindings/README.md +14 -0
- package/.codex/skills/cloudflare/references/bindings/api.md +3 -0
- package/.codex/skills/cloudflare/references/bindings/configuration.md +58 -0
- package/.codex/skills/cloudflare/references/bindings/gotchas.md +35 -0
- package/.codex/skills/cloudflare/references/bindings/patterns.md +37 -0
- package/.codex/skills/cloudflare/references/bot-management/README.md +71 -0
- package/.codex/skills/cloudflare/references/bot-management/api.md +168 -0
- package/.codex/skills/cloudflare/references/bot-management/configuration.md +114 -0
- package/.codex/skills/cloudflare/references/bot-management/gotchas.md +99 -0
- package/.codex/skills/cloudflare/references/bot-management/patterns.md +125 -0
- package/.codex/skills/cloudflare/references/browser-rendering/README.md +16 -0
- package/.codex/skills/cloudflare/references/browser-rendering/api.md +54 -0
- package/.codex/skills/cloudflare/references/browser-rendering/configuration.md +47 -0
- package/.codex/skills/cloudflare/references/browser-rendering/gotchas.md +29 -0
- package/.codex/skills/cloudflare/references/browser-rendering/patterns.md +29 -0
- package/.codex/skills/cloudflare/references/c3/README.md +264 -0
- package/.codex/skills/cloudflare/references/cache-reserve/README.md +93 -0
- package/.codex/skills/cloudflare/references/cache-reserve/api.md +176 -0
- package/.codex/skills/cloudflare/references/cache-reserve/configuration.md +164 -0
- package/.codex/skills/cloudflare/references/cache-reserve/gotchas.md +203 -0
- package/.codex/skills/cloudflare/references/cache-reserve/patterns.md +180 -0
- package/.codex/skills/cloudflare/references/containers/README.md +16 -0
- package/.codex/skills/cloudflare/references/containers/api.md +43 -0
- package/.codex/skills/cloudflare/references/containers/configuration.md +56 -0
- package/.codex/skills/cloudflare/references/containers/gotchas.md +21 -0
- package/.codex/skills/cloudflare/references/containers/patterns.md +40 -0
- package/.codex/skills/cloudflare/references/cron-triggers/README.md +85 -0
- package/.codex/skills/cloudflare/references/cron-triggers/api.md +198 -0
- package/.codex/skills/cloudflare/references/cron-triggers/configuration.md +151 -0
- package/.codex/skills/cloudflare/references/cron-triggers/gotchas.md +129 -0
- package/.codex/skills/cloudflare/references/cron-triggers/patterns.md +122 -0
- package/.codex/skills/cloudflare/references/d1/README.md +92 -0
- package/.codex/skills/cloudflare/references/d1/api.md +141 -0
- package/.codex/skills/cloudflare/references/d1/configuration.md +127 -0
- package/.codex/skills/cloudflare/references/d1/gotchas.md +70 -0
- package/.codex/skills/cloudflare/references/d1/patterns.md +144 -0
- package/.codex/skills/cloudflare/references/ddos/README.md +34 -0
- package/.codex/skills/cloudflare/references/ddos/api.md +136 -0
- package/.codex/skills/cloudflare/references/ddos/configuration.md +67 -0
- package/.codex/skills/cloudflare/references/ddos/gotchas.md +114 -0
- package/.codex/skills/cloudflare/references/ddos/patterns.md +158 -0
- package/.codex/skills/cloudflare/references/do-storage/README.md +62 -0
- package/.codex/skills/cloudflare/references/do-storage/api.md +89 -0
- package/.codex/skills/cloudflare/references/do-storage/configuration.md +116 -0
- package/.codex/skills/cloudflare/references/do-storage/gotchas.md +93 -0
- package/.codex/skills/cloudflare/references/do-storage/patterns.md +112 -0
- package/.codex/skills/cloudflare/references/durable-objects/README.md +125 -0
- package/.codex/skills/cloudflare/references/durable-objects/api.md +152 -0
- package/.codex/skills/cloudflare/references/durable-objects/configuration.md +148 -0
- package/.codex/skills/cloudflare/references/durable-objects/gotchas.md +158 -0
- package/.codex/skills/cloudflare/references/durable-objects/patterns.md +255 -0
- package/.codex/skills/cloudflare/references/email-routing/README.md +18 -0
- package/.codex/skills/cloudflare/references/email-routing/api.md +46 -0
- package/.codex/skills/cloudflare/references/email-routing/configuration.md +63 -0
- package/.codex/skills/cloudflare/references/email-routing/gotchas.md +16 -0
- package/.codex/skills/cloudflare/references/email-routing/patterns.md +46 -0
- package/.codex/skills/cloudflare/references/email-workers/README.md +598 -0
- package/.codex/skills/cloudflare/references/hyperdrive/README.md +62 -0
- package/.codex/skills/cloudflare/references/hyperdrive/api.md +137 -0
- package/.codex/skills/cloudflare/references/hyperdrive/configuration.md +133 -0
- package/.codex/skills/cloudflare/references/hyperdrive/gotchas.md +184 -0
- package/.codex/skills/cloudflare/references/hyperdrive/patterns.md +176 -0
- package/.codex/skills/cloudflare/references/images/README.md +14 -0
- package/.codex/skills/cloudflare/references/images/api.md +3 -0
- package/.codex/skills/cloudflare/references/images/configuration.md +45 -0
- package/.codex/skills/cloudflare/references/images/gotchas.md +23 -0
- package/.codex/skills/cloudflare/references/images/patterns.md +31 -0
- package/.codex/skills/cloudflare/references/kv/README.md +60 -0
- package/.codex/skills/cloudflare/references/kv/api.md +114 -0
- package/.codex/skills/cloudflare/references/kv/configuration.md +92 -0
- package/.codex/skills/cloudflare/references/kv/gotchas.md +117 -0
- package/.codex/skills/cloudflare/references/kv/patterns.md +139 -0
- package/.codex/skills/cloudflare/references/miniflare/README.md +64 -0
- package/.codex/skills/cloudflare/references/miniflare/api.md +144 -0
- package/.codex/skills/cloudflare/references/miniflare/configuration.md +203 -0
- package/.codex/skills/cloudflare/references/miniflare/gotchas.md +187 -0
- package/.codex/skills/cloudflare/references/miniflare/patterns.md +211 -0
- package/.codex/skills/cloudflare/references/network-interconnect/README.md +60 -0
- package/.codex/skills/cloudflare/references/network-interconnect/api.md +240 -0
- package/.codex/skills/cloudflare/references/network-interconnect/configuration.md +127 -0
- package/.codex/skills/cloudflare/references/network-interconnect/gotchas.md +171 -0
- package/.codex/skills/cloudflare/references/network-interconnect/patterns.md +171 -0
- package/.codex/skills/cloudflare/references/observability/README.md +18 -0
- package/.codex/skills/cloudflare/references/observability/api.md +51 -0
- package/.codex/skills/cloudflare/references/observability/configuration.md +60 -0
- package/.codex/skills/cloudflare/references/observability/gotchas.md +36 -0
- package/.codex/skills/cloudflare/references/observability/patterns.md +42 -0
- package/.codex/skills/cloudflare/references/pages/README.md +76 -0
- package/.codex/skills/cloudflare/references/pages/api.md +200 -0
- package/.codex/skills/cloudflare/references/pages/configuration.md +228 -0
- package/.codex/skills/cloudflare/references/pages/gotchas.md +161 -0
- package/.codex/skills/cloudflare/references/pages/patterns.md +145 -0
- package/.codex/skills/cloudflare/references/pages-functions/README.md +57 -0
- package/.codex/skills/cloudflare/references/pages-functions/api.md +201 -0
- package/.codex/skills/cloudflare/references/pages-functions/configuration.md +159 -0
- package/.codex/skills/cloudflare/references/pages-functions/gotchas.md +151 -0
- package/.codex/skills/cloudflare/references/pages-functions/patterns.md +190 -0
- package/.codex/skills/cloudflare/references/pipelines/README.md +664 -0
- package/.codex/skills/cloudflare/references/pulumi/README.md +107 -0
- package/.codex/skills/cloudflare/references/pulumi/api.md +194 -0
- package/.codex/skills/cloudflare/references/pulumi/configuration.md +216 -0
- package/.codex/skills/cloudflare/references/pulumi/gotchas.md +223 -0
- package/.codex/skills/cloudflare/references/pulumi/patterns.md +139 -0
- package/.codex/skills/cloudflare/references/queues/README.md +69 -0
- package/.codex/skills/cloudflare/references/queues/api.md +138 -0
- package/.codex/skills/cloudflare/references/queues/configuration.md +125 -0
- package/.codex/skills/cloudflare/references/queues/gotchas.md +112 -0
- package/.codex/skills/cloudflare/references/queues/patterns.md +155 -0
- package/.codex/skills/cloudflare/references/r2/README.md +61 -0
- package/.codex/skills/cloudflare/references/r2/api.md +127 -0
- package/.codex/skills/cloudflare/references/r2/configuration.md +76 -0
- package/.codex/skills/cloudflare/references/r2/gotchas.md +94 -0
- package/.codex/skills/cloudflare/references/r2/patterns.md +127 -0
- package/.codex/skills/cloudflare/references/r2-data-catalog/README.md +18 -0
- package/.codex/skills/cloudflare/references/r2-data-catalog/api.md +29 -0
- package/.codex/skills/cloudflare/references/r2-data-catalog/configuration.md +39 -0
- package/.codex/skills/cloudflare/references/r2-data-catalog/gotchas.md +20 -0
- package/.codex/skills/cloudflare/references/r2-data-catalog/patterns.md +46 -0
- package/.codex/skills/cloudflare/references/r2-sql/README.md +512 -0
- package/.codex/skills/cloudflare/references/realtime-sfu/README.md +21 -0
- package/.codex/skills/cloudflare/references/realtime-sfu/api.md +135 -0
- package/.codex/skills/cloudflare/references/realtime-sfu/configuration.md +63 -0
- package/.codex/skills/cloudflare/references/realtime-sfu/gotchas.md +75 -0
- package/.codex/skills/cloudflare/references/realtime-sfu/patterns.md +102 -0
- package/.codex/skills/cloudflare/references/realtimekit/README.md +81 -0
- package/.codex/skills/cloudflare/references/realtimekit/api.md +164 -0
- package/.codex/skills/cloudflare/references/realtimekit/configuration.md +147 -0
- package/.codex/skills/cloudflare/references/realtimekit/gotchas.md +172 -0
- package/.codex/skills/cloudflare/references/realtimekit/patterns.md +155 -0
- package/.codex/skills/cloudflare/references/sandbox/README.md +90 -0
- package/.codex/skills/cloudflare/references/sandbox/api.md +178 -0
- package/.codex/skills/cloudflare/references/sandbox/configuration.md +131 -0
- package/.codex/skills/cloudflare/references/sandbox/gotchas.md +156 -0
- package/.codex/skills/cloudflare/references/sandbox/patterns.md +203 -0
- package/.codex/skills/cloudflare/references/secrets-store/README.md +58 -0
- package/.codex/skills/cloudflare/references/secrets-store/api.md +182 -0
- package/.codex/skills/cloudflare/references/secrets-store/configuration.md +140 -0
- package/.codex/skills/cloudflare/references/secrets-store/gotchas.md +129 -0
- package/.codex/skills/cloudflare/references/secrets-store/patterns.md +218 -0
- package/.codex/skills/cloudflare/references/smart-placement/README.md +91 -0
- package/.codex/skills/cloudflare/references/smart-placement/api.md +139 -0
- package/.codex/skills/cloudflare/references/smart-placement/configuration.md +129 -0
- package/.codex/skills/cloudflare/references/smart-placement/gotchas.md +87 -0
- package/.codex/skills/cloudflare/references/smart-placement/patterns.md +135 -0
- package/.codex/skills/cloudflare/references/snippets/README.md +15 -0
- package/.codex/skills/cloudflare/references/snippets/api.md +47 -0
- package/.codex/skills/cloudflare/references/snippets/configuration.md +33 -0
- package/.codex/skills/cloudflare/references/snippets/gotchas.md +21 -0
- package/.codex/skills/cloudflare/references/snippets/patterns.md +34 -0
- package/.codex/skills/cloudflare/references/spectrum/README.md +16 -0
- package/.codex/skills/cloudflare/references/spectrum/api.md +24 -0
- package/.codex/skills/cloudflare/references/spectrum/configuration.md +43 -0
- package/.codex/skills/cloudflare/references/spectrum/gotchas.md +42 -0
- package/.codex/skills/cloudflare/references/spectrum/patterns.md +40 -0
- package/.codex/skills/cloudflare/references/static-assets/README.md +14 -0
- package/.codex/skills/cloudflare/references/static-assets/api.md +3 -0
- package/.codex/skills/cloudflare/references/static-assets/configuration.md +47 -0
- package/.codex/skills/cloudflare/references/static-assets/gotchas.md +44 -0
- package/.codex/skills/cloudflare/references/static-assets/patterns.md +42 -0
- package/.codex/skills/cloudflare/references/stream/README.md +103 -0
- package/.codex/skills/cloudflare/references/stream/api.md +204 -0
- package/.codex/skills/cloudflare/references/stream/configuration.md +127 -0
- package/.codex/skills/cloudflare/references/stream/gotchas.md +131 -0
- package/.codex/skills/cloudflare/references/stream/patterns.md +152 -0
- package/.codex/skills/cloudflare/references/tail-workers/README.md +640 -0
- package/.codex/skills/cloudflare/references/terraform/README.md +76 -0
- package/.codex/skills/cloudflare/references/terraform/api.md +159 -0
- package/.codex/skills/cloudflare/references/terraform/configuration.md +156 -0
- package/.codex/skills/cloudflare/references/terraform/gotchas.md +207 -0
- package/.codex/skills/cloudflare/references/terraform/patterns.md +135 -0
- package/.codex/skills/cloudflare/references/tunnel/README.md +82 -0
- package/.codex/skills/cloudflare/references/tunnel/api.md +105 -0
- package/.codex/skills/cloudflare/references/tunnel/configuration.md +113 -0
- package/.codex/skills/cloudflare/references/tunnel/gotchas.md +115 -0
- package/.codex/skills/cloudflare/references/tunnel/patterns.md +157 -0
- package/.codex/skills/cloudflare/references/turn/README.md +699 -0
- package/.codex/skills/cloudflare/references/turnstile/README.md +14 -0
- package/.codex/skills/cloudflare/references/turnstile/api.md +3 -0
- package/.codex/skills/cloudflare/references/turnstile/configuration.md +19 -0
- package/.codex/skills/cloudflare/references/turnstile/gotchas.md +27 -0
- package/.codex/skills/cloudflare/references/turnstile/patterns.md +41 -0
- package/.codex/skills/cloudflare/references/vectorize/README.md +682 -0
- package/.codex/skills/cloudflare/references/waf/README.md +14 -0
- package/.codex/skills/cloudflare/references/waf/api.md +3 -0
- package/.codex/skills/cloudflare/references/waf/configuration.md +44 -0
- package/.codex/skills/cloudflare/references/waf/gotchas.md +24 -0
- package/.codex/skills/cloudflare/references/waf/patterns.md +29 -0
- package/.codex/skills/cloudflare/references/web-analytics/README.md +19 -0
- package/.codex/skills/cloudflare/references/web-analytics/api.md +52 -0
- package/.codex/skills/cloudflare/references/web-analytics/configuration.md +31 -0
- package/.codex/skills/cloudflare/references/web-analytics/gotchas.md +28 -0
- package/.codex/skills/cloudflare/references/web-analytics/patterns.md +52 -0
- package/.codex/skills/cloudflare/references/workerd/README.md +47 -0
- package/.codex/skills/cloudflare/references/workerd/api.md +199 -0
- package/.codex/skills/cloudflare/references/workerd/configuration.md +185 -0
- package/.codex/skills/cloudflare/references/workerd/gotchas.md +203 -0
- package/.codex/skills/cloudflare/references/workerd/patterns.md +216 -0
- package/.codex/skills/cloudflare/references/workers/README.md +96 -0
- package/.codex/skills/cloudflare/references/workers/api.md +137 -0
- package/.codex/skills/cloudflare/references/workers/configuration.md +147 -0
- package/.codex/skills/cloudflare/references/workers/gotchas.md +99 -0
- package/.codex/skills/cloudflare/references/workers/patterns.md +149 -0
- package/.codex/skills/cloudflare/references/workers-ai/README.md +116 -0
- package/.codex/skills/cloudflare/references/workers-for-platforms/README.md +48 -0
- package/.codex/skills/cloudflare/references/workers-for-platforms/api.md +169 -0
- package/.codex/skills/cloudflare/references/workers-for-platforms/configuration.md +136 -0
- package/.codex/skills/cloudflare/references/workers-for-platforms/gotchas.md +130 -0
- package/.codex/skills/cloudflare/references/workers-for-platforms/patterns.md +170 -0
- package/.codex/skills/cloudflare/references/workers-playground/README.md +16 -0
- package/.codex/skills/cloudflare/references/workers-playground/api.md +20 -0
- package/.codex/skills/cloudflare/references/workers-playground/configuration.md +3 -0
- package/.codex/skills/cloudflare/references/workers-playground/gotchas.md +35 -0
- package/.codex/skills/cloudflare/references/workers-playground/patterns.md +42 -0
- package/.codex/skills/cloudflare/references/workers-vpc/README.md +579 -0
- package/.codex/skills/cloudflare/references/workflows/README.md +62 -0
- package/.codex/skills/cloudflare/references/workflows/api.md +125 -0
- package/.codex/skills/cloudflare/references/workflows/configuration.md +177 -0
- package/.codex/skills/cloudflare/references/workflows/gotchas.md +136 -0
- package/.codex/skills/cloudflare/references/workflows/patterns.md +132 -0
- package/.codex/skills/cloudflare/references/wrangler/README.md +90 -0
- package/.codex/skills/cloudflare/references/wrangler/api.md +140 -0
- package/.codex/skills/cloudflare/references/wrangler/configuration.md +128 -0
- package/.codex/skills/cloudflare/references/wrangler/gotchas.md +93 -0
- package/.codex/skills/cloudflare/references/wrangler/patterns.md +150 -0
- package/.codex/skills/cloudflare/references/zaraz/README.md +360 -0
- package/.codex/skills/code-navigation/SKILL.md +130 -0
- package/.codex/skills/code-review/SKILL.md +208 -0
- package/.codex/skills/compaction/SKILL.md +317 -0
- package/.codex/skills/condition-based-waiting/SKILL.md +123 -0
- package/.codex/skills/condition-based-waiting/example.ts +158 -0
- package/.codex/skills/context-engineering/SKILL.md +176 -0
- package/.codex/skills/context-initialization/SKILL.md +70 -0
- package/.codex/skills/context-management/SKILL.md +163 -0
- package/.codex/skills/core-data-expert/SKILL.md +93 -0
- package/.codex/skills/core-data-expert/references/batch-operations.md +543 -0
- package/.codex/skills/core-data-expert/references/cloudkit-integration.md +259 -0
- package/.codex/skills/core-data-expert/references/concurrency.md +522 -0
- package/.codex/skills/core-data-expert/references/fetch-requests.md +643 -0
- package/.codex/skills/core-data-expert/references/glossary.md +233 -0
- package/.codex/skills/core-data-expert/references/migration.md +393 -0
- package/.codex/skills/core-data-expert/references/model-configuration.md +597 -0
- package/.codex/skills/core-data-expert/references/performance.md +300 -0
- package/.codex/skills/core-data-expert/references/persistent-history.md +553 -0
- package/.codex/skills/core-data-expert/references/project-audit.md +60 -0
- package/.codex/skills/core-data-expert/references/saving.md +574 -0
- package/.codex/skills/core-data-expert/references/stack-setup.md +625 -0
- package/.codex/skills/core-data-expert/references/testing.md +300 -0
- package/.codex/skills/core-data-expert/references/threading.md +589 -0
- package/.codex/skills/debugging/SKILL.md +203 -0
- package/.codex/skills/deep-research/SKILL.md +384 -0
- package/.codex/skills/defense-in-depth/SKILL.md +166 -0
- package/.codex/skills/dependency-upgrades/SKILL.md +198 -0
- package/.codex/skills/design-system-audit/SKILL.md +153 -0
- package/.codex/skills/development-lifecycle/SKILL.md +356 -0
- package/.codex/skills/dispatching-parallel-agents/SKILL.md +191 -0
- package/.codex/skills/docs-handoff/SKILL.md +175 -0
- package/.codex/skills/executing-plans/SKILL.md +247 -0
- package/.codex/skills/figma/SKILL.md +224 -0
- package/.codex/skills/figma/mcp.json +6 -0
- package/.codex/skills/finishing-a-development-branch/SKILL.md +357 -0
- package/.codex/skills/frontend-design/SKILL.md +176 -0
- package/.codex/skills/gemini-large-context/SKILL.md +216 -0
- package/.codex/skills/git-pr-prep/SKILL.md +179 -0
- package/.codex/skills/index-knowledge/SKILL.md +413 -0
- package/.codex/skills/jira/SKILL.md +283 -0
- package/.codex/skills/jira/mcp.json +6 -0
- package/.codex/skills/memory-system/SKILL.md +93 -0
- package/.codex/skills/mockup-to-code/SKILL.md +184 -0
- package/.codex/skills/mqdh/SKILL.md +171 -0
- package/.codex/skills/obsidian/SKILL.md +187 -0
- package/.codex/skills/obsidian/mcp.json +22 -0
- package/.codex/skills/opensrc/SKILL.md +127 -0
- package/.codex/skills/opensrc/references/architecture.md +176 -0
- package/.codex/skills/opensrc/references/cli-usage.md +176 -0
- package/.codex/skills/opensrc/references/registry-support.md +137 -0
- package/.codex/skills/pdf-extract/SKILL.md +438 -0
- package/.codex/skills/playwright/SKILL.md +320 -0
- package/.codex/skills/playwright/mcp.json +16 -0
- package/.codex/skills/playwriter/SKILL.md +158 -0
- package/.codex/skills/polar/SKILL.md +102 -0
- package/.codex/skills/prd/SKILL.md +146 -0
- package/.codex/skills/prd-task/SKILL.md +182 -0
- package/.codex/skills/prd-task/references/prd-schema.json +124 -0
- package/.codex/skills/prompt-leverage/SKILL.md +69 -0
- package/.codex/skills/prompt-leverage/agents/openai.yaml +4 -0
- package/.codex/skills/prompt-leverage/references/framework.md +91 -0
- package/.codex/skills/prompt-leverage/scripts/augment_prompt.py +114 -0
- package/.codex/skills/ralph/SKILL.md +296 -0
- package/.codex/skills/react-best-practices/AGENTS.md +2410 -0
- package/.codex/skills/react-best-practices/README.md +123 -0
- package/.codex/skills/react-best-practices/SKILL.md +133 -0
- package/.codex/skills/react-best-practices/metadata.json +15 -0
- package/.codex/skills/react-best-practices/rules/_sections.md +46 -0
- package/.codex/skills/react-best-practices/rules/_template.md +28 -0
- package/.codex/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/.codex/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
- package/.codex/skills/react-best-practices/rules/async-api-routes.md +38 -0
- package/.codex/skills/react-best-practices/rules/async-defer-await.md +80 -0
- package/.codex/skills/react-best-practices/rules/async-dependencies.md +36 -0
- package/.codex/skills/react-best-practices/rules/async-parallel.md +28 -0
- package/.codex/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/.codex/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/.codex/skills/react-best-practices/rules/bundle-conditional.md +31 -0
- package/.codex/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/.codex/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/.codex/skills/react-best-practices/rules/bundle-preload.md +50 -0
- package/.codex/skills/react-best-practices/rules/client-event-listeners.md +74 -0
- package/.codex/skills/react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/.codex/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/.codex/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/.codex/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
- package/.codex/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/.codex/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/.codex/skills/react-best-practices/rules/js-cache-storage.md +70 -0
- package/.codex/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/.codex/skills/react-best-practices/rules/js-early-exit.md +50 -0
- package/.codex/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/.codex/skills/react-best-practices/rules/js-index-maps.md +37 -0
- package/.codex/skills/react-best-practices/rules/js-length-check-first.md +49 -0
- package/.codex/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/.codex/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/.codex/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/.codex/skills/react-best-practices/rules/rendering-activity.md +26 -0
- package/.codex/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/.codex/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/.codex/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/.codex/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/.codex/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/.codex/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/.codex/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/.codex/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/.codex/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/.codex/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/.codex/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/.codex/skills/react-best-practices/rules/rerender-memo.md +44 -0
- package/.codex/skills/react-best-practices/rules/rerender-transitions.md +40 -0
- package/.codex/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/.codex/skills/react-best-practices/rules/server-cache-lru.md +41 -0
- package/.codex/skills/react-best-practices/rules/server-cache-react.md +76 -0
- package/.codex/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/.codex/skills/react-best-practices/rules/server-serialization.md +38 -0
- package/.codex/skills/receiving-code-review/SKILL.md +252 -0
- package/.codex/skills/refactoring/SKILL.md +217 -0
- package/.codex/skills/repo-orientation/SKILL.md +156 -0
- package/.codex/skills/requesting-code-review/SKILL.md +397 -0
- package/.codex/skills/resend/SKILL.md +177 -0
- package/.codex/skills/resend/references/react-email.md +287 -0
- package/.codex/skills/resend/references/receive-email.md +248 -0
- package/.codex/skills/resend/references/send-email.md +318 -0
- package/.codex/skills/root-cause-tracing/SKILL.md +192 -0
- package/.codex/skills/root-cause-tracing/find-polluter.sh +63 -0
- package/.codex/skills/safe-implementation/SKILL.md +205 -0
- package/.codex/skills/session-management/SKILL.md +10 -0
- package/.codex/skills/sharing-skills/SKILL.md +214 -0
- package/.codex/skills/skill-creator/SKILL.md +156 -0
- package/.codex/skills/source-code-research/SKILL.md +293 -0
- package/.codex/skills/source-code-research/references/analysis-tips.md +43 -0
- package/.codex/skills/source-code-research/references/anti-patterns.md +36 -0
- package/.codex/skills/source-code-research/references/common-patterns.md +57 -0
- package/.codex/skills/source-code-research/references/example-workflow.md +60 -0
- package/.codex/skills/source-code-research/references/further-reading.md +5 -0
- package/.codex/skills/source-code-research/references/source-structure.md +45 -0
- package/.codex/skills/stitch/SKILL.md +147 -0
- package/.codex/skills/stitch/mcp.json +9 -0
- package/.codex/skills/structured-edit/SKILL.md +181 -0
- package/.codex/skills/subagent-driven-development/SKILL.md +237 -0
- package/.codex/skills/supabase/SKILL.md +130 -0
- package/.codex/skills/supabase/mcp.json +27 -0
- package/.codex/skills/supabase-postgres-best-practices/AGENTS.md +1490 -0
- package/.codex/skills/supabase-postgres-best-practices/SKILL.md +65 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/advanced-full-text-search.md +55 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/advanced-jsonb-indexing.md +49 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/conn-idle-timeout.md +46 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/conn-limits.md +44 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/conn-pooling.md +41 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/conn-prepared-statements.md +46 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/data-batch-inserts.md +54 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/data-n-plus-one.md +53 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/data-pagination.md +50 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/data-upsert.md +50 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/lock-advisory.md +56 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/lock-deadlock-prevention.md +68 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/lock-short-transactions.md +50 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/lock-skip-locked.md +54 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/monitor-explain-analyze.md +45 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/monitor-pg-stat-statements.md +55 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/monitor-vacuum-analyze.md +55 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/query-composite-indexes.md +44 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/query-covering-indexes.md +40 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/query-index-types.md +45 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/query-missing-indexes.md +43 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/query-partial-indexes.md +45 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/schema-data-types.md +46 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/schema-foreign-key-indexes.md +59 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/schema-lowercase-identifiers.md +55 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/schema-partitioning.md +55 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/schema-primary-keys.md +61 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/security-privileges.md +54 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/security-rls-basics.md +50 -0
- package/.codex/skills/supabase-postgres-best-practices/rules/security-rls-performance.md +57 -0
- package/.codex/skills/swarm-coordination/SKILL.md +179 -0
- package/.codex/skills/swarm-coordination/references/architecture.md +39 -0
- package/.codex/skills/swarm-coordination/references/delegation-worker-protocol.md +145 -0
- package/.codex/skills/swarm-coordination/references/dependency-graph.md +50 -0
- package/.codex/skills/swarm-coordination/references/drift-check.md +90 -0
- package/.codex/skills/swarm-coordination/references/integration-beads.md +20 -0
- package/.codex/skills/swarm-coordination/references/launch-flow.md +186 -0
- package/.codex/skills/swarm-coordination/references/reconciler.md +172 -0
- package/.codex/skills/swarm-coordination/references/tier-enforcement.md +78 -0
- package/.codex/skills/swarm-coordination/references/tmux-integration.md +134 -0
- package/.codex/skills/swift-concurrency/SKILL.md +266 -0
- package/.codex/skills/swift-concurrency/references/actors.md +640 -0
- package/.codex/skills/swift-concurrency/references/async-algorithms.md +822 -0
- package/.codex/skills/swift-concurrency/references/async-await-basics.md +249 -0
- package/.codex/skills/swift-concurrency/references/async-sequences.md +670 -0
- package/.codex/skills/swift-concurrency/references/core-data.md +533 -0
- package/.codex/skills/swift-concurrency/references/glossary.md +128 -0
- package/.codex/skills/swift-concurrency/references/linting.md +142 -0
- package/.codex/skills/swift-concurrency/references/memory-management.md +542 -0
- package/.codex/skills/swift-concurrency/references/migration.md +1076 -0
- package/.codex/skills/swift-concurrency/references/performance.md +574 -0
- package/.codex/skills/swift-concurrency/references/sendable.md +578 -0
- package/.codex/skills/swift-concurrency/references/tasks.md +604 -0
- package/.codex/skills/swift-concurrency/references/testing.md +565 -0
- package/.codex/skills/swift-concurrency/references/threading.md +452 -0
- package/.codex/skills/swiftui-expert-skill/SKILL.md +329 -0
- package/.codex/skills/swiftui-expert-skill/references/animation-advanced.md +351 -0
- package/.codex/skills/swiftui-expert-skill/references/animation-basics.md +284 -0
- package/.codex/skills/swiftui-expert-skill/references/animation-transitions.md +326 -0
- package/.codex/skills/swiftui-expert-skill/references/image-optimization.md +286 -0
- package/.codex/skills/swiftui-expert-skill/references/layout-best-practices.md +312 -0
- package/.codex/skills/swiftui-expert-skill/references/liquid-glass.md +377 -0
- package/.codex/skills/swiftui-expert-skill/references/list-patterns.md +153 -0
- package/.codex/skills/swiftui-expert-skill/references/modern-apis.md +400 -0
- package/.codex/skills/swiftui-expert-skill/references/performance-patterns.md +377 -0
- package/.codex/skills/swiftui-expert-skill/references/scroll-patterns.md +305 -0
- package/.codex/skills/swiftui-expert-skill/references/sheet-navigation-patterns.md +292 -0
- package/.codex/skills/swiftui-expert-skill/references/state-management.md +447 -0
- package/.codex/skills/swiftui-expert-skill/references/text-formatting.md +285 -0
- package/.codex/skills/swiftui-expert-skill/references/view-structure.md +276 -0
- package/.codex/skills/systematic-debugging/SKILL.md +402 -0
- package/.codex/skills/task-planning/SKILL.md +205 -0
- package/.codex/skills/test-driven-development/SKILL.md +388 -0
- package/.codex/skills/test-strategy/SKILL.md +186 -0
- package/.codex/skills/testing-anti-patterns/SKILL.md +320 -0
- package/.codex/skills/testing-skills-with-subagents/SKILL.md +405 -0
- package/.codex/skills/tilth-cli/SKILL.md +180 -0
- package/.codex/skills/tool-priority/SKILL.md +299 -0
- package/.codex/skills/ui-inspiration-scout/SKILL.md +203 -0
- package/.codex/skills/ui-ux-research/SKILL.md +35 -0
- package/.codex/skills/using-git-worktrees/SKILL.md +259 -0
- package/.codex/skills/using-skills/SKILL.md +117 -0
- package/.codex/skills/v0/SKILL.md +158 -0
- package/.codex/skills/v0/mcp.json +6 -0
- package/.codex/skills/v1-run/SKILL.md +175 -0
- package/.codex/skills/v1-run/mcp.json +6 -0
- package/.codex/skills/vercel-deploy-claimable/SKILL.md +124 -0
- package/.codex/skills/vercel-deploy-claimable/scripts/deploy.sh +249 -0
- package/.codex/skills/verification/SKILL.md +191 -0
- package/.codex/skills/verification-before-completion/SKILL.md +236 -0
- package/.codex/skills/visual-analysis/SKILL.md +154 -0
- package/.codex/skills/web-design-guidelines/SKILL.md +46 -0
- package/.codex/skills/writing-plans/SKILL.md +320 -0
- package/.codex/skills/writing-skills/SKILL.md +287 -0
- package/.codex/skills/writing-skills/anthropic-best-practices.md +1173 -0
- package/.codex/skills/writing-skills/graphviz-conventions.dot +172 -0
- package/.codex/skills/writing-skills/persuasion-principles.md +220 -0
- package/.codex/skills/writing-skills/references/anti-patterns.md +25 -0
- package/.codex/skills/writing-skills/references/claude-search-optimization.md +140 -0
- package/.codex/skills/writing-skills/references/discovery-workflow.md +11 -0
- package/.codex/skills/writing-skills/references/file-organization.md +32 -0
- package/.codex/skills/writing-skills/references/flowcharts-and-examples.md +57 -0
- package/.codex/skills/writing-skills/references/rationalization-hardening.md +75 -0
- package/.codex/skills/writing-skills/references/testing-skill-types.md +52 -0
- package/.template-manifest.json +631 -0
- package/AGENTS.md +719 -0
- package/AGENTS.override.md.example +7 -0
- package/CHANGELOG.md +28 -0
- package/LICENSE +21 -0
- package/README.md +641 -0
- package/bin/codexkit +148 -0
- package/install/bead-close.sh +20 -0
- package/install/bead-search.sh +18 -0
- package/install/bead-start.sh +20 -0
- package/install/bead-sync.sh +19 -0
- package/install/bead-verify.sh +20 -0
- package/install/generate-manifest.sh +55 -0
- package/install/install-global.sh +150 -0
- package/install/install-project.sh +704 -0
- package/install/install-remote.sh +152 -0
- package/install/patch.sh +478 -0
- package/install/plugin.sh +565 -0
- package/install/run-codex.sh +68 -0
- package/install/template.sh +620 -0
- package/install/validate.sh +653 -0
- package/package.json +39 -0
- package/templates/global/.codex-config-template.toml +87 -0
- package/templates/global/AGENTS.override.md +18 -0
- package/templates/global/README.md +29 -0
- package/templates/project/.codex-config-template.toml +26 -0
- package/templates/project/AGENTS.md.template +27 -0
- package/templates/project/README.md +24 -0
|
@@ -0,0 +1,822 @@
|
|
|
1
|
+
# AsyncAlgorithms Package
|
|
2
|
+
|
|
3
|
+
Patterns for combining, transforming, and managing asynchronous sequences beyond standard library. Provides time-based operators, stream combination tools, and multi-consumer primitives for Swift Concurrency.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
Top 5 most common operators:
|
|
10
|
+
|
|
11
|
+
```swift
|
|
12
|
+
import AsyncAlgorithms
|
|
13
|
+
|
|
14
|
+
// 1. Debounce rapid inputs
|
|
15
|
+
for await query in searchQueryStream.debounce(for: .milliseconds(500)) {
|
|
16
|
+
await performSearch(query)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// 2. Throttle repeated actions
|
|
20
|
+
for await _ in buttonClicks.throttle(for: .seconds(1)) {
|
|
21
|
+
await performAction()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 3. Merge multiple independent streams
|
|
25
|
+
for await message in chat1Messages.merge(chat2Messages) {
|
|
26
|
+
display(message)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 4. Combine dependent values
|
|
30
|
+
for await (username, email) in usernameStream.combineLatest(emailStream) {
|
|
31
|
+
validateForm(username: username, email: email)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 5. Zip paired operations
|
|
35
|
+
for await (image, metadata) in imageStream.zip(metadataStream) {
|
|
36
|
+
await cache(image: image, metadata: metadata)
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
> **See**: [AsyncAlgorithms on GitHub](https://github.com/apple/swift-async-algorithms)
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Overview & Installation
|
|
45
|
+
|
|
46
|
+
### What is AsyncAlgorithms?
|
|
47
|
+
|
|
48
|
+
Extends Swift's AsyncSequence with time-based operators, stream combination tools, and multi-consumer primitives.
|
|
49
|
+
|
|
50
|
+
**Use for**:
|
|
51
|
+
- Time-based operations: debounce, throttle, timers
|
|
52
|
+
- Combining streams: merge, combineLatest, zip, chain
|
|
53
|
+
- Multi-consumer scenarios: AsyncChannel for backpressure
|
|
54
|
+
- Specific operators: removeDuplicates, chunks, adjacentPairs, compacted
|
|
55
|
+
|
|
56
|
+
**Use standard library for**:
|
|
57
|
+
- Bridging callbacks: AsyncStream
|
|
58
|
+
- Simple iteration: for await in sequence
|
|
59
|
+
- Single-value operations: async/await
|
|
60
|
+
|
|
61
|
+
### Installation
|
|
62
|
+
|
|
63
|
+
```swift
|
|
64
|
+
dependencies: [
|
|
65
|
+
.package(url: "https://github.com/apple/swift-async-algorithms", from: "1.0.0")
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
targets: [
|
|
69
|
+
.target(
|
|
70
|
+
name: "MyTarget",
|
|
71
|
+
dependencies: [
|
|
72
|
+
.product(name: "AsyncAlgorithms", package: "swift-async-algorithms")
|
|
73
|
+
]
|
|
74
|
+
)
|
|
75
|
+
]
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Import:
|
|
79
|
+
|
|
80
|
+
```swift
|
|
81
|
+
import AsyncAlgorithms
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Time-Based Operators
|
|
87
|
+
|
|
88
|
+
### debounce(for:tolerance:clock:)
|
|
89
|
+
|
|
90
|
+
Wait for inactivity before emitting. Use for rapid inputs like search fields.
|
|
91
|
+
|
|
92
|
+
#### Example: ArticleSearcher
|
|
93
|
+
|
|
94
|
+
```swift
|
|
95
|
+
import AsyncAlgorithms
|
|
96
|
+
|
|
97
|
+
@Observable
|
|
98
|
+
final class ArticleSearcher {
|
|
99
|
+
@MainActor private(set) var results: [Article] = []
|
|
100
|
+
private var searchQueryContinuation: AsyncStream<String>.Continuation?
|
|
101
|
+
|
|
102
|
+
private lazy var searchQueryStream: AsyncStream<String> = {
|
|
103
|
+
AsyncStream { continuation in
|
|
104
|
+
searchQueryContinuation = continuation
|
|
105
|
+
}
|
|
106
|
+
}()
|
|
107
|
+
|
|
108
|
+
func search(_ query: String) {
|
|
109
|
+
searchQueryContinuation?.yield(query)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
func startDebouncedSearch() {
|
|
113
|
+
Task { @MainActor in
|
|
114
|
+
for await query in searchQueryStream.debounce(for: .milliseconds(500)) {
|
|
115
|
+
self.results = []
|
|
116
|
+
self.results = await APIClient.searchArticles(query)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Benefits**: Automatic cancellation, backpressure, cleaner than manual Task.sleep.
|
|
124
|
+
|
|
125
|
+
#### ❌ Anti-Pattern
|
|
126
|
+
|
|
127
|
+
```swift
|
|
128
|
+
// Bad: Every keystroke spawns new task
|
|
129
|
+
func search(_ query: String) {
|
|
130
|
+
Task {
|
|
131
|
+
try? await Task.sleep(for: .milliseconds(500))
|
|
132
|
+
await performSearch(query)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Problem**: Multiple tasks execute simultaneously, causing out-of-order results.
|
|
138
|
+
|
|
139
|
+
**Solution**: Use `debounce()` for automatic backpressure.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
### throttle(for:clock:reducing:)
|
|
144
|
+
|
|
145
|
+
Emit at most one value per interval. Use for repeated actions like button taps.
|
|
146
|
+
|
|
147
|
+
#### Example: Like Button
|
|
148
|
+
|
|
149
|
+
```swift
|
|
150
|
+
import AsyncAlgorithms
|
|
151
|
+
|
|
152
|
+
struct LikeButton: View {
|
|
153
|
+
@State private var tapStream = AsyncStream<Void> { continuation in
|
|
154
|
+
// Continuation stored externally
|
|
155
|
+
}
|
|
156
|
+
@State private var isLiked = false
|
|
157
|
+
|
|
158
|
+
var body: some View {
|
|
159
|
+
Button(action: {
|
|
160
|
+
tapStream.continuation?.yield()
|
|
161
|
+
}) {
|
|
162
|
+
Image(systemName: isLiked ? "heart.fill" : "heart")
|
|
163
|
+
}
|
|
164
|
+
.task {
|
|
165
|
+
await handleThrottledTaps()
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private func handleThrottledTaps() async {
|
|
170
|
+
for await _ in tapStream.throttle(for: .seconds(1)) {
|
|
171
|
+
await toggleLike()
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
private func toggleLike() async {
|
|
176
|
+
isLiked.toggle()
|
|
177
|
+
await APIClient.updateLikeStatus(isLiked: isLiked)
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
#### Understanding reducing Parameter
|
|
183
|
+
|
|
184
|
+
```swift
|
|
185
|
+
// .latest (default): Keep most recent value
|
|
186
|
+
for await value in events.throttle(for: .seconds(1)) {
|
|
187
|
+
process(value)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// .oldest: Keep first value
|
|
191
|
+
for await value in events.throttle(for: .seconds(1), reducing: .oldest) {
|
|
192
|
+
process(value)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Custom: Sum all values
|
|
196
|
+
for await value in events.throttle(for: .seconds(1)) { $0 + $1 } {
|
|
197
|
+
process(value)
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
### AsyncTimerSequence
|
|
204
|
+
|
|
205
|
+
Emit values at regular intervals. Use for periodic refresh or countdown timers.
|
|
206
|
+
|
|
207
|
+
#### Example: Feed Refresh
|
|
208
|
+
|
|
209
|
+
```swift
|
|
210
|
+
import AsyncAlgorithms
|
|
211
|
+
|
|
212
|
+
@MainActor @Observable
|
|
213
|
+
final class FeedViewModel {
|
|
214
|
+
private(set) var articles: [Article] = []
|
|
215
|
+
private var refreshTask: Task<Void, Never>?
|
|
216
|
+
|
|
217
|
+
func startAutoRefresh() {
|
|
218
|
+
refreshTask = Task {
|
|
219
|
+
for await _ in AsyncTimerSequence(interval: .seconds(30)) {
|
|
220
|
+
await refreshFeed()
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
private func refreshFeed() async {
|
|
226
|
+
articles = await APIClient.fetchLatestArticles()
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
#### ❌ Anti-Pattern
|
|
232
|
+
|
|
233
|
+
```swift
|
|
234
|
+
// Bad: Manual timer implementation
|
|
235
|
+
func startTimer() {
|
|
236
|
+
Task {
|
|
237
|
+
while !Task.isCancelled {
|
|
238
|
+
performAction()
|
|
239
|
+
try? await Task.sleep(for: .seconds(1))
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
**Solution**: Use `AsyncTimerSequence`.
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Combining Operators
|
|
250
|
+
|
|
251
|
+
### merge(_:...)
|
|
252
|
+
|
|
253
|
+
Combine sequences into one, emitting as they arrive. **Stable operator ✅**
|
|
254
|
+
|
|
255
|
+
Use for independent data sources that don't depend on each other.
|
|
256
|
+
|
|
257
|
+
#### Example: Multi-Room Chat
|
|
258
|
+
|
|
259
|
+
```swift
|
|
260
|
+
import AsyncAlgorithms
|
|
261
|
+
|
|
262
|
+
actor ChatManager {
|
|
263
|
+
private var messageContinuations: [String: AsyncStream<ChatMessage>.Continuation] = [:]
|
|
264
|
+
|
|
265
|
+
func getMessagesStream(roomID: String) -> AsyncStream<ChatMessage> {
|
|
266
|
+
AsyncStream { continuation in
|
|
267
|
+
messageContinuations[roomID] = continuation
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
func receiveMessage(_ message: ChatMessage) {
|
|
272
|
+
messageContinuations[message.roomID]?.yield(message)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
func startMonitoring(rooms: [String]) -> AsyncStream<ChatMessage> {
|
|
276
|
+
let streams = rooms.map { getMessagesStream(roomID: $0) }
|
|
277
|
+
return streams.merge()
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Usage
|
|
282
|
+
let manager = ChatManager()
|
|
283
|
+
let mergedMessages = await manager.startMonitoring(rooms: ["general", "random"])
|
|
284
|
+
|
|
285
|
+
for await message in mergedMessages {
|
|
286
|
+
print("[\(message.roomID)] \(message.text)")
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**Behavior**: Values emit as they arrive from any source. Order interleaved by timing. Cancellation propagates to all sources.
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
### combineLatest(_:...)
|
|
295
|
+
|
|
296
|
+
Combine sequences, emitting tuple when any source emits. Always uses latest values. **Stable operator ✅**
|
|
297
|
+
|
|
298
|
+
Use for dependent values that need synchronization.
|
|
299
|
+
|
|
300
|
+
#### Example: Form Validation
|
|
301
|
+
|
|
302
|
+
```swift
|
|
303
|
+
import AsyncAlgorithms
|
|
304
|
+
|
|
305
|
+
struct SignupForm: View {
|
|
306
|
+
@State private var usernameStream = AsyncStream<String> { /* ... */ }
|
|
307
|
+
@State private var emailStream = AsyncStream<String> { /* ... */ }
|
|
308
|
+
@State private var passwordStream = AsyncStream<String> { /* ... */ }
|
|
309
|
+
@State private var formState = FormState.incomplete
|
|
310
|
+
|
|
311
|
+
var body: some View {
|
|
312
|
+
Form {
|
|
313
|
+
TextField("Username", text: $username)
|
|
314
|
+
TextField("Email", text: $email)
|
|
315
|
+
SecureField("Password", text: $password)
|
|
316
|
+
}
|
|
317
|
+
.task {
|
|
318
|
+
await validateForm()
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
private func validateForm() async {
|
|
323
|
+
for await (username, email, password) in
|
|
324
|
+
usernameStream.combineLatest(emailStream, passwordStream)
|
|
325
|
+
{
|
|
326
|
+
formState = await validate(
|
|
327
|
+
username: username,
|
|
328
|
+
email: email,
|
|
329
|
+
password: password
|
|
330
|
+
)
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
#### ❌ Anti-Pattern
|
|
337
|
+
|
|
338
|
+
```swift
|
|
339
|
+
// Bad: Manual value combining
|
|
340
|
+
actor FormValidator {
|
|
341
|
+
private var currentUsername: String = ""
|
|
342
|
+
private var currentEmail: String = ""
|
|
343
|
+
|
|
344
|
+
func updateUsername(_ username: String) {
|
|
345
|
+
currentUsername = username
|
|
346
|
+
checkForm()
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
**Solution**: Use `combineLatest()`.
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
### zip(_:...)
|
|
356
|
+
|
|
357
|
+
Combine sequences by pairing elements in order. **Stable operator ✅**
|
|
358
|
+
|
|
359
|
+
#### Example: Image + Metadata
|
|
360
|
+
|
|
361
|
+
```swift
|
|
362
|
+
import AsyncAlgorithms
|
|
363
|
+
|
|
364
|
+
struct ImageLoader {
|
|
365
|
+
func loadImagesWithMetadata(urls: [URL]) async throws -> [LoadedImage] {
|
|
366
|
+
let imageStream = AsyncThrowingStream<UIImage, Error> { continuation in
|
|
367
|
+
Task {
|
|
368
|
+
for url in urls {
|
|
369
|
+
let image = try await downloadImage(from: url)
|
|
370
|
+
continuation.yield(image)
|
|
371
|
+
}
|
|
372
|
+
continuation.finish()
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
let metadataStream = AsyncThrowingStream<ImageMetadata, Error> { continuation in
|
|
377
|
+
Task {
|
|
378
|
+
for url in urls {
|
|
379
|
+
let metadata = try await fetchMetadata(for: url)
|
|
380
|
+
continuation.yield(metadata)
|
|
381
|
+
}
|
|
382
|
+
continuation.finish()
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
var results: [LoadedImage] = []
|
|
387
|
+
for try await (image, metadata) in imageStream.zip(metadataStream) {
|
|
388
|
+
results.append(LoadedImage(image: image, metadata: metadata))
|
|
389
|
+
}
|
|
390
|
+
return results
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
**Behavior**: Emits tuple when all sequences emit. Maintains order. Finishes when shortest sequence finishes.
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
### chain(_:...)
|
|
400
|
+
|
|
401
|
+
Concatenate sequences sequentially. **Stable operator ✅**
|
|
402
|
+
|
|
403
|
+
#### Example: Paginated Loading
|
|
404
|
+
|
|
405
|
+
```swift
|
|
406
|
+
import AsyncAlgorithms
|
|
407
|
+
|
|
408
|
+
struct ArticlePaginator {
|
|
409
|
+
func loadAllArticles() -> AsyncStream<[Article]> {
|
|
410
|
+
AsyncStream { continuation in
|
|
411
|
+
Task {
|
|
412
|
+
var page = 1
|
|
413
|
+
var hasMore = true
|
|
414
|
+
while hasMore {
|
|
415
|
+
let articles = try await fetchPage(page: page)
|
|
416
|
+
continuation.yield(articles)
|
|
417
|
+
hasMore = articles.count == 20
|
|
418
|
+
page += 1
|
|
419
|
+
}
|
|
420
|
+
continuation.finish()
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Usage: Chain cache + network
|
|
427
|
+
for await articles in loadFromCacheStream().chain(loadFromNetworkStream()) {
|
|
428
|
+
display(articles)
|
|
429
|
+
}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
**Behavior**: Emits all values from first sequence before starting second.
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
## Utility Operators
|
|
437
|
+
|
|
438
|
+
### removeDuplicates()
|
|
439
|
+
|
|
440
|
+
Remove adjacent duplicates. **Stable operator ✅**
|
|
441
|
+
|
|
442
|
+
```swift
|
|
443
|
+
import AsyncAlgorithms
|
|
444
|
+
|
|
445
|
+
actor ChatHistory {
|
|
446
|
+
private var messageStream = AsyncStream<ChatMessage> { /* ... */ }
|
|
447
|
+
|
|
448
|
+
func getUniqueMessages() -> AsyncStream<ChatMessage> {
|
|
449
|
+
messageStream.removeDuplicates()
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
---
|
|
455
|
+
|
|
456
|
+
### chunks() and chunked()
|
|
457
|
+
|
|
458
|
+
Collect values into batches. **Stable operator ✅**
|
|
459
|
+
|
|
460
|
+
```swift
|
|
461
|
+
import AsyncAlgorithms
|
|
462
|
+
|
|
463
|
+
struct BatchProcessor {
|
|
464
|
+
func processLargeDataset(dataStream: AsyncStream<DataItem>) async {
|
|
465
|
+
for await batch in dataStream.chunks(count: 100) {
|
|
466
|
+
await processBatch(batch)
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
func chunkedByTime(dataStream: AsyncStream<DataItem>) async {
|
|
471
|
+
for await batch in dataStream.chunked(by: .seconds(5)) {
|
|
472
|
+
await processBatch(batch)
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
### compacted() and adjacentPairs()
|
|
481
|
+
|
|
482
|
+
```swift
|
|
483
|
+
import AsyncAlgorithms
|
|
484
|
+
|
|
485
|
+
// Remove nil values
|
|
486
|
+
for await value in optionalValuesStream.compacted() {
|
|
487
|
+
process(value)
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Pair adjacent elements
|
|
491
|
+
for await (previous, current) in valuesStream.adjacentPairs() {
|
|
492
|
+
let difference = current - previous
|
|
493
|
+
}
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
## Multi-Consumer Scenarios
|
|
499
|
+
|
|
500
|
+
### AsyncChannel
|
|
501
|
+
|
|
502
|
+
AsyncSequence with backpressure. **Stable operator ✅**
|
|
503
|
+
|
|
504
|
+
Use for producer-consumer patterns with flow control.
|
|
505
|
+
|
|
506
|
+
#### Example: Message Queue
|
|
507
|
+
|
|
508
|
+
```swift
|
|
509
|
+
import AsyncAlgorithms
|
|
510
|
+
|
|
511
|
+
actor MessageQueue {
|
|
512
|
+
private let channel = AsyncChannel<Message>()
|
|
513
|
+
|
|
514
|
+
func getMessages() -> AsyncStream<Message> {
|
|
515
|
+
channel
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
func enqueue(_ message: Message) async {
|
|
519
|
+
await channel.send(message)
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
func startProcessing() {
|
|
523
|
+
Task {
|
|
524
|
+
for await message in channel {
|
|
525
|
+
await process(message)
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// Multiple producers
|
|
532
|
+
let queue = MessageQueue()
|
|
533
|
+
Task { await queue.enqueue(Message(type: .userAction, content: "tap")) }
|
|
534
|
+
Task { await queue.enqueue(Message(type: .network, content: "data")) }
|
|
535
|
+
queue.startProcessing()
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
#### ❌ Anti-Pattern
|
|
539
|
+
|
|
540
|
+
```swift
|
|
541
|
+
// Bad: Values split unpredictably
|
|
542
|
+
let stream = AsyncStream<Int> { continuation in
|
|
543
|
+
for i in 1...10 {
|
|
544
|
+
continuation.yield(i)
|
|
545
|
+
}
|
|
546
|
+
continuation.finish()
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
Task { for await value in stream { print("Consumer 1: \(value)") } }
|
|
550
|
+
Task { for await value in stream { print("Consumer 2: \(value)") } }
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
**Problem**: Each value goes to only one consumer.
|
|
554
|
+
|
|
555
|
+
**Solution**: Use `AsyncChannel` for multi-consumer scenarios.
|
|
556
|
+
|
|
557
|
+
---
|
|
558
|
+
|
|
559
|
+
### AsyncThrowingChannel
|
|
560
|
+
|
|
561
|
+
Like AsyncChannel but can emit errors. **Stable operator ✅**
|
|
562
|
+
|
|
563
|
+
#### Example: WebSocket
|
|
564
|
+
|
|
565
|
+
```swift
|
|
566
|
+
import AsyncAlgorithms
|
|
567
|
+
|
|
568
|
+
actor WebSocketConnection {
|
|
569
|
+
private let channel = AsyncThrowingChannel<WebSocketMessage, Error>()
|
|
570
|
+
|
|
571
|
+
func getMessages() -> AsyncThrowingStream<WebSocketMessage, Error> {
|
|
572
|
+
channel
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
func receiveMessage(_ message: WebSocketMessage) async {
|
|
576
|
+
await channel.send(message)
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
func reportError(_ error: Error) async {
|
|
580
|
+
await channel.finish(throwing: error)
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// Usage
|
|
585
|
+
do {
|
|
586
|
+
for await message in connection.getMessages() {
|
|
587
|
+
handle(message)
|
|
588
|
+
}
|
|
589
|
+
} catch {
|
|
590
|
+
print("WebSocket error: \(error)")
|
|
591
|
+
}
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
---
|
|
595
|
+
|
|
596
|
+
## Combine Migration Guide
|
|
597
|
+
|
|
598
|
+
### Operator Mapping Table
|
|
599
|
+
|
|
600
|
+
| Combine | AsyncAlgorithms | Status | Alternative |
|
|
601
|
+
|---------|-----------------|---------|-------------|
|
|
602
|
+
| `.debounce()` | `debounce()` | ✅ Stable | - |
|
|
603
|
+
| `.throttle()` | `throttle()` | ✅ Stable | - |
|
|
604
|
+
| `.merge()` | `merge()` | ✅ Stable | - |
|
|
605
|
+
| `.combineLatest()` | `combineLatest()` | ✅ Stable | - |
|
|
606
|
+
| `.zip()` | `zip()` | ✅ Stable | - |
|
|
607
|
+
| `.concat()` | `chain()` | ✅ Stable | - |
|
|
608
|
+
| `.removeDuplicates()` | `removeDuplicates()` | ✅ Stable | - |
|
|
609
|
+
| `.timer()` | `AsyncTimerSequence` | ✅ Stable | - |
|
|
610
|
+
| `.share()` | - | - | `AsyncChannel` |
|
|
611
|
+
| `.flatMap()` | - | - | `TaskGroup` |
|
|
612
|
+
| `.receive(on:)` | - | - | `Task` / `@MainActor` |
|
|
613
|
+
| `.eraseToAnyPublisher()` | - | - | `any AsyncSequence` |
|
|
614
|
+
|
|
615
|
+
---
|
|
616
|
+
|
|
617
|
+
### Migration Examples
|
|
618
|
+
|
|
619
|
+
#### Example 1: ArticleSearcher
|
|
620
|
+
|
|
621
|
+
**Before: Combine**
|
|
622
|
+
|
|
623
|
+
```swift
|
|
624
|
+
import Combine
|
|
625
|
+
|
|
626
|
+
final class ArticleSearcher: ObservableObject {
|
|
627
|
+
@Published private(set) var results: [Article] = []
|
|
628
|
+
@Published var searchQuery = ""
|
|
629
|
+
|
|
630
|
+
init() {
|
|
631
|
+
$searchQuery
|
|
632
|
+
.debounce(for: .milliseconds(500), scheduler: DispatchQueue.main)
|
|
633
|
+
.removeDuplicates()
|
|
634
|
+
.flatMap { query in
|
|
635
|
+
APIClient.searchArticles(query)
|
|
636
|
+
.catch { _ in Just([]) }
|
|
637
|
+
}
|
|
638
|
+
.receive(on: DispatchQueue.main)
|
|
639
|
+
.assign(to: &$results)
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
**After: AsyncAlgorithms**
|
|
645
|
+
|
|
646
|
+
```swift
|
|
647
|
+
import AsyncAlgorithms
|
|
648
|
+
|
|
649
|
+
@Observable
|
|
650
|
+
final class ArticleSearcher {
|
|
651
|
+
@MainActor private(set) var results: [Article] = []
|
|
652
|
+
private var searchQueryContinuation: AsyncStream<String>.Continuation?
|
|
653
|
+
|
|
654
|
+
private lazy var searchQueryStream: AsyncStream<String> = {
|
|
655
|
+
AsyncStream { continuation in
|
|
656
|
+
searchQueryContinuation = continuation
|
|
657
|
+
}
|
|
658
|
+
}()
|
|
659
|
+
|
|
660
|
+
func search(_ query: String) {
|
|
661
|
+
searchQueryContinuation?.yield(query)
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
func startDebouncedSearch() {
|
|
665
|
+
Task { @MainActor in
|
|
666
|
+
for await query in searchQueryStream
|
|
667
|
+
.debounce(for: .milliseconds(500))
|
|
668
|
+
.removeDuplicates()
|
|
669
|
+
{
|
|
670
|
+
do {
|
|
671
|
+
self.results = try await APIClient.searchArticles(query)
|
|
672
|
+
} catch {
|
|
673
|
+
self.results = []
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
**Benefits**: Simpler error handling, no cancellables, automatic cancellation.
|
|
682
|
+
|
|
683
|
+
---
|
|
684
|
+
|
|
685
|
+
#### Example 2: Multi-Source Loading
|
|
686
|
+
|
|
687
|
+
**Before: Combine Merge**
|
|
688
|
+
|
|
689
|
+
```swift
|
|
690
|
+
import Combine
|
|
691
|
+
|
|
692
|
+
final class ArticleLoader: ObservableObject {
|
|
693
|
+
@Published private(set) var items: [Item] = []
|
|
694
|
+
|
|
695
|
+
func loadAllSources() {
|
|
696
|
+
let source1 = APIClient.fetchItems(from: .source1)
|
|
697
|
+
let source2 = APIClient.fetchItems(from: .source2)
|
|
698
|
+
|
|
699
|
+
Publishers.Merge(source1, source2)
|
|
700
|
+
.scan([]) { accumulated, new in
|
|
701
|
+
accumulated + new
|
|
702
|
+
}
|
|
703
|
+
.receive(on: DispatchQueue.main)
|
|
704
|
+
.assign(to: &$items)
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
```
|
|
708
|
+
|
|
709
|
+
**After: TaskGroup**
|
|
710
|
+
|
|
711
|
+
```swift
|
|
712
|
+
import AsyncAlgorithms
|
|
713
|
+
|
|
714
|
+
@Observable
|
|
715
|
+
final class ArticleLoader {
|
|
716
|
+
@MainActor private(set) var items: [Item] = []
|
|
717
|
+
|
|
718
|
+
func loadAllSourcesParallel() async {
|
|
719
|
+
await withTaskGroup(of: [Item].self) { group in
|
|
720
|
+
group.addTask {
|
|
721
|
+
await APIClient.fetchItems(from: .source1)
|
|
722
|
+
}
|
|
723
|
+
group.addTask {
|
|
724
|
+
await APIClient.fetchItems(from: .source2)
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
for await newItems in group {
|
|
728
|
+
items.append(contentsOf: newItems)
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
**Key difference**: For parallel execution, use `TaskGroup` instead of `flatMap`.
|
|
736
|
+
|
|
737
|
+
---
|
|
738
|
+
|
|
739
|
+
#### Example 3: Form Validation
|
|
740
|
+
|
|
741
|
+
**Before: Combine**
|
|
742
|
+
|
|
743
|
+
```swift
|
|
744
|
+
import Combine
|
|
745
|
+
|
|
746
|
+
final class FormValidator: ObservableObject {
|
|
747
|
+
@Published var username = ""
|
|
748
|
+
@Published var email = ""
|
|
749
|
+
|
|
750
|
+
@Published private(set) var formState: FormState = .incomplete
|
|
751
|
+
|
|
752
|
+
init() {
|
|
753
|
+
Publishers.CombineLatest2($username, $email)
|
|
754
|
+
.map { username, email in
|
|
755
|
+
validate(username: username, email: email)
|
|
756
|
+
}
|
|
757
|
+
.assign(to: &$formState)
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
**After: AsyncAlgorithms or async let**
|
|
763
|
+
|
|
764
|
+
```swift
|
|
765
|
+
import AsyncAlgorithms
|
|
766
|
+
|
|
767
|
+
@Observable
|
|
768
|
+
final class FormValidator {
|
|
769
|
+
var username = ""
|
|
770
|
+
var email = ""
|
|
771
|
+
|
|
772
|
+
@MainActor private(set) var formState: FormState = .incomplete
|
|
773
|
+
|
|
774
|
+
// Option 1: combineLatest for stream-based validation
|
|
775
|
+
func startStreamValidation() {
|
|
776
|
+
Task { @MainActor in
|
|
777
|
+
for await (username, email) in
|
|
778
|
+
usernameStream.combineLatest(emailStream)
|
|
779
|
+
{
|
|
780
|
+
self.formState = validate(
|
|
781
|
+
username: username,
|
|
782
|
+
email: email
|
|
783
|
+
)
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// Option 2: async let for simple validation
|
|
789
|
+
func validateForm() async {
|
|
790
|
+
let (username, email) = await (username, email)
|
|
791
|
+
formState = validate(
|
|
792
|
+
username: username,
|
|
793
|
+
email: email
|
|
794
|
+
)
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
**Choose**:
|
|
800
|
+
- `combineLatest()`: Continuous validation as fields change
|
|
801
|
+
- `async let`: One-time validation when all values available
|
|
802
|
+
|
|
803
|
+
---
|
|
804
|
+
|
|
805
|
+
## Best Practices
|
|
806
|
+
|
|
807
|
+
1. **Use time-based operators** for rapid inputs: debounce() for search, throttle() for buttons
|
|
808
|
+
2. **Combine streams** with merge/combineLatest instead of manual state management
|
|
809
|
+
3. **Use AsyncChannel** for multi-consumer scenarios with backpressure
|
|
810
|
+
4. **Ensure Sendable conformance** when using operators across isolation boundaries
|
|
811
|
+
5. **Leverage cancellation** - Task cancellation propagates through all operators
|
|
812
|
+
6. **Choose right tool**: AsyncAlgorithms for complex streams, AsyncStream for bridging callbacks
|
|
813
|
+
7. **Avoid manual sleep loops** - use AsyncTimerSequence instead
|
|
814
|
+
|
|
815
|
+
---
|
|
816
|
+
|
|
817
|
+
## Further Learning
|
|
818
|
+
|
|
819
|
+
- [AsyncAlgorithms Documentation](https://github.com/apple/swift-async-algorithms)
|
|
820
|
+
- [Combine Migration Guide](migration.md)
|
|
821
|
+
- [Async Sequences](async-sequences.md)
|
|
822
|
+
- [Tasks](tasks.md) - Task groups and structured concurrency
|