├── .cursor └── rules │ ├── cloudflare.mdc │ └── vibe-tools.mdc ├── .cursorrules ├── .github └── workflows │ ├── pkg-pr.yml │ ├── publish.yml │ ├── release.yml │ └── test.yml ├── .gitignore ├── .gitmodules ├── .vscode └── settings.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── alchemy-web ├── .gitignore ├── .vitepress │ ├── config.mts │ └── theme │ │ ├── components │ │ └── CodeSnippetHero.vue │ │ ├── fonts │ │ └── Inter.ttf │ │ ├── index.ts │ │ ├── og-generator.ts │ │ └── style.css ├── blogs │ ├── 2025-04-08-decade-long-journey.md │ └── index.md ├── docs │ ├── advanced │ │ └── serde.md │ ├── concepts │ │ ├── adoption.md │ │ ├── bindings.md │ │ ├── destroy.md │ │ ├── phase.md │ │ ├── resource.md │ │ ├── scope.md │ │ ├── secret.md │ │ ├── state.md │ │ └── testing.md │ ├── getting-started.md │ ├── guides │ │ ├── cloudflare-auth.md │ │ ├── cloudflare-durable-objects.md │ │ ├── cloudflare-nuxt-pipeline.md │ │ ├── cloudflare-queue.md │ │ ├── cloudflare-react-router.md │ │ ├── cloudflare-redwood.md │ │ ├── cloudflare-tanstack-start.md │ │ ├── cloudflare-vitejs.md │ │ ├── cloudflare-worker.md │ │ ├── cloudflare-workflows.md │ │ ├── custom-resources.md │ │ └── custom-state-store.md │ ├── index.md │ ├── providers │ │ ├── ai │ │ │ ├── astro-file.md │ │ │ ├── css-file.md │ │ │ ├── data.md │ │ │ ├── document.md │ │ │ ├── html-file.md │ │ │ ├── json-file.md │ │ │ ├── typescript-file.md │ │ │ ├── vue-file.md │ │ │ └── yaml-file.md │ │ ├── aws-control │ │ │ ├── access-analyzer │ │ │ │ └── analyzer.md │ │ │ ├── acmpca │ │ │ │ ├── certificate-authority-activation.md │ │ │ │ ├── certificate-authority.md │ │ │ │ ├── certificate.md │ │ │ │ └── permission.md │ │ │ ├── alexa │ │ │ │ └── ask.md │ │ │ ├── amazon-mq │ │ │ │ ├── broker.md │ │ │ │ ├── configuration-association.md │ │ │ │ └── configuration.md │ │ │ ├── amplify-uibuilder │ │ │ │ ├── component.md │ │ │ │ ├── form.md │ │ │ │ └── theme.md │ │ │ ├── amplify │ │ │ │ ├── app.md │ │ │ │ ├── branch.md │ │ │ │ └── domain.md │ │ │ ├── api-gateway-v2 │ │ │ │ ├── api-gateway-managed-overrides.md │ │ │ │ ├── api-mapping.md │ │ │ │ ├── api.md │ │ │ │ ├── authorizer.md │ │ │ │ ├── deployment.md │ │ │ │ ├── domain-name.md │ │ │ │ ├── integration-response.md │ │ │ │ ├── integration.md │ │ │ │ ├── model.md │ │ │ │ ├── route-response.md │ │ │ │ ├── route.md │ │ │ │ ├── stage.md │ │ │ │ └── vpc-link.md │ │ │ ├── api-gateway │ │ │ │ ├── account.md │ │ │ │ ├── api-key.md │ │ │ │ ├── authorizer.md │ │ │ │ ├── base-path-mapping-v2.md │ │ │ │ ├── base-path-mapping.md │ │ │ │ ├── client-certificate.md │ │ │ │ ├── deployment.md │ │ │ │ ├── documentation-part.md │ │ │ │ ├── documentation-version.md │ │ │ │ ├── domain-name-access-association.md │ │ │ │ ├── domain-name-v2.md │ │ │ │ ├── domain-name.md │ │ │ │ ├── gateway-response.md │ │ │ │ ├── method.md │ │ │ │ ├── model.md │ │ │ │ ├── request-validator.md │ │ │ │ ├── resource.md │ │ │ │ ├── rest-api.md │ │ │ │ ├── stage.md │ │ │ │ ├── usage-plan-key.md │ │ │ │ ├── usage-plan.md │ │ │ │ └── vpc-link.md │ │ │ ├── app-config │ │ │ │ ├── application.md │ │ │ │ ├── configuration-profile.md │ │ │ │ ├── deployment-strategy.md │ │ │ │ ├── deployment.md │ │ │ │ ├── environment.md │ │ │ │ ├── extension-association.md │ │ │ │ ├── extension.md │ │ │ │ └── hosted-configuration-version.md │ │ │ ├── app-flow │ │ │ │ ├── connector-profile.md │ │ │ │ ├── connector.md │ │ │ │ └── flow.md │ │ │ ├── app-integrations │ │ │ │ ├── application.md │ │ │ │ ├── data-integration.md │ │ │ │ └── event-integration.md │ │ │ ├── app-mesh │ │ │ │ ├── gateway-route.md │ │ │ │ ├── mesh.md │ │ │ │ ├── route.md │ │ │ │ ├── virtual-gateway.md │ │ │ │ ├── virtual-node.md │ │ │ │ ├── virtual-router.md │ │ │ │ └── virtual-service.md │ │ │ ├── app-runner │ │ │ │ ├── auto-scaling-configuration.md │ │ │ │ ├── observability-configuration.md │ │ │ │ ├── service.md │ │ │ │ ├── vpc-connector.md │ │ │ │ └── vpc-ingress-connection.md │ │ │ ├── app-stream │ │ │ │ ├── app-block-builder.md │ │ │ │ ├── app-block.md │ │ │ │ ├── application-entitlement-association.md │ │ │ │ ├── application-fleet-association.md │ │ │ │ ├── application.md │ │ │ │ ├── directory-config.md │ │ │ │ ├── entitlement.md │ │ │ │ ├── fleet.md │ │ │ │ ├── image-builder.md │ │ │ │ ├── stack-fleet-association.md │ │ │ │ ├── stack-user-association.md │ │ │ │ ├── stack.md │ │ │ │ └── user.md │ │ │ ├── app-sync │ │ │ │ ├── api-cache.md │ │ │ │ ├── api-key.md │ │ │ │ ├── api.md │ │ │ │ ├── channel-namespace.md │ │ │ │ ├── data-source.md │ │ │ │ ├── domain-name-api-association.md │ │ │ │ ├── domain-name.md │ │ │ │ ├── function-configuration.md │ │ │ │ ├── graph-qlapi.md │ │ │ │ ├── graph-qlschema.md │ │ │ │ ├── resolver.md │ │ │ │ └── source-api-association.md │ │ │ ├── app-test │ │ │ │ └── test-case.md │ │ │ ├── application-auto-scaling │ │ │ │ ├── scalable-target.md │ │ │ │ └── scaling-policy.md │ │ │ ├── application-insights │ │ │ │ └── application.md │ │ │ ├── application-signals │ │ │ │ ├── discovery.md │ │ │ │ └── service-level-objective.md │ │ │ ├── aps │ │ │ │ ├── rule-groups-namespace.md │ │ │ │ ├── scraper.md │ │ │ │ └── workspace.md │ │ │ ├── arczonal-shift │ │ │ │ ├── autoshift-observer-notification-status.md │ │ │ │ └── zonal-autoshift-configuration.md │ │ │ ├── athena │ │ │ │ ├── capacity-reservation.md │ │ │ │ ├── data-catalog.md │ │ │ │ ├── named-query.md │ │ │ │ ├── prepared-statement.md │ │ │ │ └── work-group.md │ │ │ ├── audit-manager │ │ │ │ └── assessment.md │ │ │ ├── auto-scaling-plans │ │ │ │ └── scaling-plan.md │ │ │ ├── auto-scaling │ │ │ │ ├── auto-scaling-group.md │ │ │ │ ├── launch-configuration.md │ │ │ │ ├── lifecycle-hook.md │ │ │ │ ├── scaling-policy.md │ │ │ │ ├── scheduled-action.md │ │ │ │ └── warm-pool.md │ │ │ ├── b2bi │ │ │ │ ├── capability.md │ │ │ │ ├── partnership.md │ │ │ │ ├── profile.md │ │ │ │ └── transformer.md │ │ │ ├── backup-gateway │ │ │ │ └── hypervisor.md │ │ │ ├── backup │ │ │ │ ├── backup-plan.md │ │ │ │ ├── backup-selection.md │ │ │ │ ├── backup-vault.md │ │ │ │ ├── framework.md │ │ │ │ ├── logically-air-gapped-backup-vault.md │ │ │ │ ├── report-plan.md │ │ │ │ ├── restore-testing-plan.md │ │ │ │ └── restore-testing-selection.md │ │ │ ├── batch │ │ │ │ ├── compute-environment.md │ │ │ │ ├── consumable-resource.md │ │ │ │ ├── job-definition.md │ │ │ │ ├── job-queue.md │ │ │ │ └── scheduling-policy.md │ │ │ ├── bcmdata-exports │ │ │ │ └── export.md │ │ │ ├── bedrock │ │ │ │ ├── agent-alias.md │ │ │ │ ├── agent.md │ │ │ │ ├── application-inference-profile.md │ │ │ │ ├── blueprint.md │ │ │ │ ├── data-automation-project.md │ │ │ │ ├── data-source.md │ │ │ │ ├── flow-alias.md │ │ │ │ ├── flow-version.md │ │ │ │ ├── flow.md │ │ │ │ ├── guardrail-version.md │ │ │ │ ├── guardrail.md │ │ │ │ ├── knowledge-base.md │ │ │ │ ├── prompt-version.md │ │ │ │ └── prompt.md │ │ │ ├── billing-conductor │ │ │ │ ├── billing-group.md │ │ │ │ ├── custom-line-item.md │ │ │ │ ├── pricing-plan.md │ │ │ │ └── pricing-rule.md │ │ │ ├── budgets │ │ │ │ ├── budget.md │ │ │ │ └── budgets-action.md │ │ │ ├── cassandra │ │ │ │ ├── keyspace.md │ │ │ │ ├── table.md │ │ │ │ └── type.md │ │ │ ├── ce │ │ │ │ ├── anomaly-monitor.md │ │ │ │ ├── anomaly-subscription.md │ │ │ │ └── cost-category.md │ │ │ ├── certificate-manager │ │ │ │ ├── account.md │ │ │ │ └── certificate.md │ │ │ ├── chatbot │ │ │ │ ├── custom-action.md │ │ │ │ ├── microsoft-teams-channel-configuration.md │ │ │ │ └── slack-channel-configuration.md │ │ │ ├── clean-rooms-ml │ │ │ │ └── training-dataset.md │ │ │ ├── clean-rooms │ │ │ │ ├── analysis-template.md │ │ │ │ ├── collaboration.md │ │ │ │ ├── configured-table-association.md │ │ │ │ ├── configured-table.md │ │ │ │ ├── id-mapping-table.md │ │ │ │ ├── id-namespace-association.md │ │ │ │ ├── membership.md │ │ │ │ └── privacy-budget-template.md │ │ │ ├── cloud-formation │ │ │ │ ├── custom-resource.md │ │ │ │ ├── guard-hook.md │ │ │ │ ├── hook-default-version.md │ │ │ │ ├── hook-type-config.md │ │ │ │ ├── hook-version.md │ │ │ │ ├── lambda-hook.md │ │ │ │ ├── macro.md │ │ │ │ ├── module-default-version.md │ │ │ │ ├── module-version.md │ │ │ │ ├── public-type-version.md │ │ │ │ ├── publisher.md │ │ │ │ ├── resource-default-version.md │ │ │ │ ├── resource-version.md │ │ │ │ ├── stack-set.md │ │ │ │ ├── stack.md │ │ │ │ ├── type-activation.md │ │ │ │ ├── wait-condition-handle.md │ │ │ │ └── wait-condition.md │ │ │ ├── cloud-front │ │ │ │ ├── anycast-ip-list.md │ │ │ │ ├── cache-policy.md │ │ │ │ ├── cloud-front-origin-access-identity.md │ │ │ │ ├── connection-group.md │ │ │ │ ├── continuous-deployment-policy.md │ │ │ │ ├── distribution-tenant.md │ │ │ │ ├── distribution.md │ │ │ │ ├── function.md │ │ │ │ ├── key-group.md │ │ │ │ ├── key-value-store.md │ │ │ │ ├── monitoring-subscription.md │ │ │ │ ├── origin-access-control.md │ │ │ │ ├── origin-request-policy.md │ │ │ │ ├── public-key.md │ │ │ │ ├── realtime-log-config.md │ │ │ │ ├── response-headers-policy.md │ │ │ │ ├── streaming-distribution.md │ │ │ │ └── vpc-origin.md │ │ │ ├── cloud-trail │ │ │ │ ├── channel.md │ │ │ │ ├── dashboard.md │ │ │ │ ├── event-data-store.md │ │ │ │ ├── resource-policy.md │ │ │ │ └── trail.md │ │ │ ├── cloud-watch │ │ │ │ ├── alarm.md │ │ │ │ ├── anomaly-detector.md │ │ │ │ ├── composite-alarm.md │ │ │ │ ├── dashboard.md │ │ │ │ ├── insight-rule.md │ │ │ │ └── metric-stream.md │ │ │ ├── cloud9 │ │ │ │ └── environment-ec2.md │ │ │ ├── code-artifact │ │ │ │ ├── domain.md │ │ │ │ ├── package-group.md │ │ │ │ └── repository.md │ │ │ ├── code-build │ │ │ │ ├── fleet.md │ │ │ │ ├── project.md │ │ │ │ ├── report-group.md │ │ │ │ └── source-credential.md │ │ │ ├── code-commit │ │ │ │ └── repository.md │ │ │ ├── code-connections │ │ │ │ └── connection.md │ │ │ ├── code-deploy │ │ │ │ ├── application.md │ │ │ │ ├── deployment-config.md │ │ │ │ └── deployment-group.md │ │ │ ├── code-guru-profiler │ │ │ │ └── profiling-group.md │ │ │ ├── code-guru-reviewer │ │ │ │ └── repository-association.md │ │ │ ├── code-pipeline │ │ │ │ ├── custom-action-type.md │ │ │ │ ├── pipeline.md │ │ │ │ └── webhook.md │ │ │ ├── code-star-connections │ │ │ │ ├── connection.md │ │ │ │ ├── repository-link.md │ │ │ │ └── sync-configuration.md │ │ │ ├── code-star-notifications │ │ │ │ └── notification-rule.md │ │ │ ├── code-star │ │ │ │ └── git-hub-repository.md │ │ │ ├── cognito │ │ │ │ ├── identity-pool-principal-tag.md │ │ │ │ ├── identity-pool-role-attachment.md │ │ │ │ ├── identity-pool.md │ │ │ │ ├── log-delivery-configuration.md │ │ │ │ ├── managed-login-branding.md │ │ │ │ ├── user-pool-client.md │ │ │ │ ├── user-pool-domain.md │ │ │ │ ├── user-pool-group.md │ │ │ │ ├── user-pool-identity-provider.md │ │ │ │ ├── user-pool-resource-server.md │ │ │ │ ├── user-pool-risk-configuration-attachment.md │ │ │ │ ├── user-pool-uicustomization-attachment.md │ │ │ │ ├── user-pool-user-to-group-attachment.md │ │ │ │ ├── user-pool-user.md │ │ │ │ └── user-pool.md │ │ │ ├── comprehend │ │ │ │ ├── document-classifier.md │ │ │ │ └── flywheel.md │ │ │ ├── config │ │ │ │ ├── aggregation-authorization.md │ │ │ │ ├── config-rule.md │ │ │ │ ├── configuration-aggregator.md │ │ │ │ ├── configuration-recorder.md │ │ │ │ ├── conformance-pack.md │ │ │ │ ├── delivery-channel.md │ │ │ │ ├── organization-config-rule.md │ │ │ │ ├── organization-conformance-pack.md │ │ │ │ ├── remediation-configuration.md │ │ │ │ └── stored-query.md │ │ │ ├── connect-campaigns-v2 │ │ │ │ └── campaign.md │ │ │ ├── connect-campaigns │ │ │ │ └── campaign.md │ │ │ ├── connect │ │ │ │ ├── agent-status.md │ │ │ │ ├── approved-origin.md │ │ │ │ ├── contact-flow-module.md │ │ │ │ ├── contact-flow-version.md │ │ │ │ ├── contact-flow.md │ │ │ │ ├── email-address.md │ │ │ │ ├── evaluation-form.md │ │ │ │ ├── hours-of-operation.md │ │ │ │ ├── instance-storage-config.md │ │ │ │ ├── instance.md │ │ │ │ ├── integration-association.md │ │ │ │ ├── phone-number.md │ │ │ │ ├── predefined-attribute.md │ │ │ │ ├── prompt.md │ │ │ │ ├── queue.md │ │ │ │ ├── quick-connect.md │ │ │ │ ├── routing-profile.md │ │ │ │ ├── rule.md │ │ │ │ ├── security-key.md │ │ │ │ ├── security-profile.md │ │ │ │ ├── task-template.md │ │ │ │ ├── traffic-distribution-group.md │ │ │ │ ├── user-hierarchy-group.md │ │ │ │ ├── user-hierarchy-structure.md │ │ │ │ ├── user.md │ │ │ │ ├── view-version.md │ │ │ │ └── view.md │ │ │ ├── control-tower │ │ │ │ ├── enabled-baseline.md │ │ │ │ ├── enabled-control.md │ │ │ │ └── landing-zone.md │ │ │ ├── cur │ │ │ │ └── report-definition.md │ │ │ ├── customer-profiles │ │ │ │ ├── calculated-attribute-definition.md │ │ │ │ ├── domain.md │ │ │ │ ├── event-stream.md │ │ │ │ ├── event-trigger.md │ │ │ │ ├── integration.md │ │ │ │ ├── object-type.md │ │ │ │ └── segment-definition.md │ │ │ ├── data-brew │ │ │ │ ├── dataset.md │ │ │ │ ├── job.md │ │ │ │ ├── project.md │ │ │ │ ├── recipe.md │ │ │ │ ├── ruleset.md │ │ │ │ └── schedule.md │ │ │ ├── data-pipeline │ │ │ │ └── pipeline.md │ │ │ ├── data-sync │ │ │ │ ├── agent.md │ │ │ │ ├── location-azure-blob.md │ │ │ │ ├── location-efs.md │ │ │ │ ├── location-fsx-lustre.md │ │ │ │ ├── location-fsx-ontap.md │ │ │ │ ├── location-fsx-open-zfs.md │ │ │ │ ├── location-fsx-windows.md │ │ │ │ ├── location-hdfs.md │ │ │ │ ├── location-nfs.md │ │ │ │ ├── location-object-storage.md │ │ │ │ ├── location-s3.md │ │ │ │ ├── location-smb.md │ │ │ │ ├── storage-system.md │ │ │ │ └── task.md │ │ │ ├── data-zone │ │ │ │ ├── connection.md │ │ │ │ ├── data-source.md │ │ │ │ ├── domain.md │ │ │ │ ├── environment-actions.md │ │ │ │ ├── environment-blueprint-configuration.md │ │ │ │ ├── environment-profile.md │ │ │ │ ├── environment.md │ │ │ │ ├── group-profile.md │ │ │ │ ├── project-membership.md │ │ │ │ ├── project.md │ │ │ │ ├── subscription-target.md │ │ │ │ └── user-profile.md │ │ │ ├── dax │ │ │ │ ├── cluster.md │ │ │ │ ├── parameter-group.md │ │ │ │ └── subnet-group.md │ │ │ ├── deadline │ │ │ │ ├── farm.md │ │ │ │ ├── fleet.md │ │ │ │ ├── license-endpoint.md │ │ │ │ ├── limit.md │ │ │ │ ├── metered-product.md │ │ │ │ ├── monitor.md │ │ │ │ ├── queue-environment.md │ │ │ │ ├── queue-fleet-association.md │ │ │ │ ├── queue-limit-association.md │ │ │ │ ├── queue.md │ │ │ │ └── storage-profile.md │ │ │ ├── detective │ │ │ │ ├── graph.md │ │ │ │ ├── member-invitation.md │ │ │ │ └── organization-admin.md │ │ │ ├── dev-ops-guru │ │ │ │ ├── log-anomaly-detection-integration.md │ │ │ │ ├── notification-channel.md │ │ │ │ └── resource-collection.md │ │ │ ├── directory-service │ │ │ │ ├── microsoft-ad.md │ │ │ │ └── simple-ad.md │ │ │ ├── dlm │ │ │ │ └── lifecycle-policy.md │ │ │ ├── dms │ │ │ │ ├── certificate.md │ │ │ │ ├── data-migration.md │ │ │ │ ├── data-provider.md │ │ │ │ ├── endpoint.md │ │ │ │ ├── event-subscription.md │ │ │ │ ├── instance-profile.md │ │ │ │ ├── migration-project.md │ │ │ │ ├── replication-config.md │ │ │ │ ├── replication-instance.md │ │ │ │ ├── replication-subnet-group.md │ │ │ │ └── replication-task.md │ │ │ ├── doc-db │ │ │ │ ├── dbcluster-parameter-group.md │ │ │ │ ├── dbcluster.md │ │ │ │ ├── dbinstance.md │ │ │ │ ├── dbsubnet-group.md │ │ │ │ └── event-subscription.md │ │ │ ├── doc-dbelastic │ │ │ │ └── cluster.md │ │ │ ├── dsql │ │ │ │ └── cluster.md │ │ │ ├── dynamo-db │ │ │ │ ├── global-table.md │ │ │ │ └── table.md │ │ │ ├── ec2 │ │ │ │ ├── capacity-reservation-fleet.md │ │ │ │ ├── capacity-reservation.md │ │ │ │ ├── carrier-gateway.md │ │ │ │ ├── client-vpn-authorization-rule.md │ │ │ │ ├── client-vpn-endpoint.md │ │ │ │ ├── client-vpn-route.md │ │ │ │ ├── client-vpn-target-network-association.md │ │ │ │ ├── customer-gateway.md │ │ │ │ ├── dhcpoptions.md │ │ │ │ ├── ec2fleet.md │ │ │ │ ├── egress-only-internet-gateway.md │ │ │ │ ├── eip.md │ │ │ │ ├── eipassociation.md │ │ │ │ ├── enclave-certificate-iam-role-association.md │ │ │ │ ├── flow-log.md │ │ │ │ ├── gateway-route-table-association.md │ │ │ │ ├── host.md │ │ │ │ ├── instance-connect-endpoint.md │ │ │ │ ├── instance.md │ │ │ │ ├── internet-gateway.md │ │ │ │ ├── ipam.md │ │ │ │ ├── ipamallocation.md │ │ │ │ ├── ipampool-cidr.md │ │ │ │ ├── ipampool.md │ │ │ │ ├── ipamresource-discovery-association.md │ │ │ │ ├── ipamresource-discovery.md │ │ │ │ ├── ipamscope.md │ │ │ │ ├── key-pair.md │ │ │ │ ├── launch-template.md │ │ │ │ ├── local-gateway-route-table-virtual-interface-group-association.md │ │ │ │ ├── local-gateway-route-table-vpcassociation.md │ │ │ │ ├── local-gateway-route-table.md │ │ │ │ ├── local-gateway-route.md │ │ │ │ ├── nat-gateway.md │ │ │ │ ├── network-acl-entry.md │ │ │ │ ├── network-acl.md │ │ │ │ ├── network-insights-access-scope-analysis.md │ │ │ │ ├── network-insights-access-scope.md │ │ │ │ ├── network-insights-analysis.md │ │ │ │ ├── network-insights-path.md │ │ │ │ ├── network-interface-attachment.md │ │ │ │ ├── network-interface-permission.md │ │ │ │ ├── network-interface.md │ │ │ │ ├── network-performance-metric-subscription.md │ │ │ │ ├── placement-group.md │ │ │ │ ├── prefix-list.md │ │ │ │ ├── route-server-association.md │ │ │ │ ├── route-server-endpoint.md │ │ │ │ ├── route-server-peer.md │ │ │ │ ├── route-server-propagation.md │ │ │ │ ├── route-server.md │ │ │ │ ├── route-table.md │ │ │ │ ├── route.md │ │ │ │ ├── security-group-egress.md │ │ │ │ ├── security-group-ingress.md │ │ │ │ ├── security-group-vpc-association.md │ │ │ │ ├── security-group.md │ │ │ │ ├── snapshot-block-public-access.md │ │ │ │ ├── spot-fleet.md │ │ │ │ ├── subnet-cidr-block.md │ │ │ │ ├── subnet-network-acl-association.md │ │ │ │ ├── subnet-route-table-association.md │ │ │ │ ├── subnet.md │ │ │ │ ├── traffic-mirror-filter-rule.md │ │ │ │ ├── traffic-mirror-filter.md │ │ │ │ ├── traffic-mirror-session.md │ │ │ │ ├── traffic-mirror-target.md │ │ │ │ ├── transit-gateway-attachment.md │ │ │ │ ├── transit-gateway-connect.md │ │ │ │ ├── transit-gateway-multicast-domain-association.md │ │ │ │ ├── transit-gateway-multicast-domain.md │ │ │ │ ├── transit-gateway-multicast-group-member.md │ │ │ │ ├── transit-gateway-multicast-group-source.md │ │ │ │ ├── transit-gateway-peering-attachment.md │ │ │ │ ├── transit-gateway-route-table-association.md │ │ │ │ ├── transit-gateway-route-table-propagation.md │ │ │ │ ├── transit-gateway-route-table.md │ │ │ │ ├── transit-gateway-route.md │ │ │ │ ├── transit-gateway-vpc-attachment.md │ │ │ │ ├── transit-gateway.md │ │ │ │ ├── verified-access-endpoint.md │ │ │ │ ├── verified-access-group.md │ │ │ │ ├── verified-access-instance.md │ │ │ │ ├── verified-access-trust-provider.md │ │ │ │ ├── volume-attachment.md │ │ │ │ ├── volume.md │ │ │ │ ├── vpc.md │ │ │ │ ├── vpcblock-public-access-exclusion.md │ │ │ │ ├── vpcblock-public-access-options.md │ │ │ │ ├── vpccidr-block.md │ │ │ │ ├── vpcdhcpoptions-association.md │ │ │ │ ├── vpcendpoint-connection-notification.md │ │ │ │ ├── vpcendpoint-service-permissions.md │ │ │ │ ├── vpcendpoint-service.md │ │ │ │ ├── vpcendpoint.md │ │ │ │ ├── vpcgateway-attachment.md │ │ │ │ ├── vpcpeering-connection.md │ │ │ │ ├── vpnconnection-route.md │ │ │ │ ├── vpnconnection.md │ │ │ │ ├── vpngateway-route-propagation.md │ │ │ │ └── vpngateway.md │ │ │ ├── ecr │ │ │ │ ├── public-repository.md │ │ │ │ ├── pull-through-cache-rule.md │ │ │ │ ├── registry-policy.md │ │ │ │ ├── registry-scanning-configuration.md │ │ │ │ ├── replication-configuration.md │ │ │ │ ├── repository-creation-template.md │ │ │ │ └── repository.md │ │ │ ├── ecs │ │ │ │ ├── capacity-provider.md │ │ │ │ ├── cluster-capacity-provider-associations.md │ │ │ │ ├── cluster.md │ │ │ │ ├── primary-task-set.md │ │ │ │ ├── service.md │ │ │ │ ├── task-definition.md │ │ │ │ └── task-set.md │ │ │ ├── efs │ │ │ │ ├── access-point.md │ │ │ │ ├── file-system.md │ │ │ │ └── mount-target.md │ │ │ ├── eks │ │ │ │ ├── access-entry.md │ │ │ │ ├── addon.md │ │ │ │ ├── cluster.md │ │ │ │ ├── fargate-profile.md │ │ │ │ ├── identity-provider-config.md │ │ │ │ ├── nodegroup.md │ │ │ │ └── pod-identity-association.md │ │ │ ├── elasti-cache │ │ │ │ ├── cache-cluster.md │ │ │ │ ├── global-replication-group.md │ │ │ │ ├── parameter-group.md │ │ │ │ ├── replication-group.md │ │ │ │ ├── security-group-ingress.md │ │ │ │ ├── security-group.md │ │ │ │ ├── serverless-cache.md │ │ │ │ ├── subnet-group.md │ │ │ │ ├── user-group.md │ │ │ │ └── user.md │ │ │ ├── elastic-beanstalk │ │ │ │ ├── application-version.md │ │ │ │ ├── application.md │ │ │ │ ├── configuration-template.md │ │ │ │ └── environment.md │ │ │ ├── elastic-load-balancing-v2 │ │ │ │ ├── listener-certificate.md │ │ │ │ ├── listener-rule.md │ │ │ │ ├── listener.md │ │ │ │ ├── load-balancer.md │ │ │ │ ├── target-group.md │ │ │ │ ├── trust-store-revocation.md │ │ │ │ └── trust-store.md │ │ │ ├── elastic-load-balancing │ │ │ │ └── load-balancer.md │ │ │ ├── elasticsearch │ │ │ │ └── domain.md │ │ │ ├── emr │ │ │ │ ├── cluster.md │ │ │ │ ├── instance-fleet-config.md │ │ │ │ ├── instance-group-config.md │ │ │ │ ├── security-configuration.md │ │ │ │ ├── step.md │ │ │ │ ├── studio-session-mapping.md │ │ │ │ ├── studio.md │ │ │ │ └── walworkspace.md │ │ │ ├── emrcontainers │ │ │ │ └── virtual-cluster.md │ │ │ ├── emrserverless │ │ │ │ └── application.md │ │ │ ├── entity-resolution │ │ │ │ ├── id-mapping-workflow.md │ │ │ │ ├── id-namespace.md │ │ │ │ ├── matching-workflow.md │ │ │ │ ├── policy-statement.md │ │ │ │ └── schema-mapping.md │ │ │ ├── event-schemas │ │ │ │ ├── discoverer.md │ │ │ │ ├── registry-policy.md │ │ │ │ ├── registry.md │ │ │ │ └── schema.md │ │ │ ├── events │ │ │ │ ├── api-destination.md │ │ │ │ ├── archive.md │ │ │ │ ├── connection.md │ │ │ │ ├── endpoint.md │ │ │ │ ├── event-bus-policy.md │ │ │ │ ├── event-bus.md │ │ │ │ └── rule.md │ │ │ ├── evidently │ │ │ │ ├── experiment.md │ │ │ │ ├── feature.md │ │ │ │ ├── launch.md │ │ │ │ ├── project.md │ │ │ │ └── segment.md │ │ │ ├── fin-space │ │ │ │ └── environment.md │ │ │ ├── fis │ │ │ │ ├── experiment-template.md │ │ │ │ └── target-account-configuration.md │ │ │ ├── fms │ │ │ │ ├── notification-channel.md │ │ │ │ ├── policy.md │ │ │ │ └── resource-set.md │ │ │ ├── forecast │ │ │ │ ├── dataset-group.md │ │ │ │ └── dataset.md │ │ │ ├── fraud-detector │ │ │ │ ├── detector.md │ │ │ │ ├── entity-type.md │ │ │ │ ├── event-type.md │ │ │ │ ├── label.md │ │ │ │ ├── list.md │ │ │ │ ├── outcome.md │ │ │ │ └── variable.md │ │ │ ├── fsx │ │ │ │ ├── data-repository-association.md │ │ │ │ ├── file-system.md │ │ │ │ ├── snapshot.md │ │ │ │ ├── storage-virtual-machine.md │ │ │ │ └── volume.md │ │ │ ├── game-lift │ │ │ │ ├── alias.md │ │ │ │ ├── build.md │ │ │ │ ├── container-fleet.md │ │ │ │ ├── container-group-definition.md │ │ │ │ ├── fleet.md │ │ │ │ ├── game-server-group.md │ │ │ │ ├── game-session-queue.md │ │ │ │ ├── location.md │ │ │ │ ├── matchmaking-configuration.md │ │ │ │ ├── matchmaking-rule-set.md │ │ │ │ └── script.md │ │ │ ├── global-accelerator │ │ │ │ ├── accelerator.md │ │ │ │ ├── cross-account-attachment.md │ │ │ │ ├── endpoint-group.md │ │ │ │ └── listener.md │ │ │ ├── glue │ │ │ │ ├── classifier.md │ │ │ │ ├── connection.md │ │ │ │ ├── crawler.md │ │ │ │ ├── custom-entity-type.md │ │ │ │ ├── data-catalog-encryption-settings.md │ │ │ │ ├── data-quality-ruleset.md │ │ │ │ ├── database.md │ │ │ │ ├── dev-endpoint.md │ │ │ │ ├── job.md │ │ │ │ ├── mltransform.md │ │ │ │ ├── partition.md │ │ │ │ ├── registry.md │ │ │ │ ├── schema-version-metadata.md │ │ │ │ ├── schema-version.md │ │ │ │ ├── schema.md │ │ │ │ ├── security-configuration.md │ │ │ │ ├── table-optimizer.md │ │ │ │ ├── table.md │ │ │ │ ├── trigger.md │ │ │ │ ├── usage-profile.md │ │ │ │ └── workflow.md │ │ │ ├── grafana │ │ │ │ └── workspace.md │ │ │ ├── greengrass-v2 │ │ │ │ ├── component-version.md │ │ │ │ └── deployment.md │ │ │ ├── greengrass │ │ │ │ ├── connector-definition-version.md │ │ │ │ ├── connector-definition.md │ │ │ │ ├── core-definition-version.md │ │ │ │ ├── core-definition.md │ │ │ │ ├── device-definition-version.md │ │ │ │ ├── device-definition.md │ │ │ │ ├── function-definition-version.md │ │ │ │ ├── function-definition.md │ │ │ │ ├── group-version.md │ │ │ │ ├── group.md │ │ │ │ ├── logger-definition-version.md │ │ │ │ ├── logger-definition.md │ │ │ │ ├── resource-definition-version.md │ │ │ │ ├── resource-definition.md │ │ │ │ ├── subscription-definition-version.md │ │ │ │ └── subscription-definition.md │ │ │ ├── ground-station │ │ │ │ ├── config.md │ │ │ │ ├── dataflow-endpoint-group.md │ │ │ │ └── mission-profile.md │ │ │ ├── guard-duty │ │ │ │ ├── detector.md │ │ │ │ ├── filter.md │ │ │ │ ├── ipset.md │ │ │ │ ├── malware-protection-plan.md │ │ │ │ ├── master.md │ │ │ │ ├── member.md │ │ │ │ ├── publishing-destination.md │ │ │ │ └── threat-intel-set.md │ │ │ ├── health-imaging │ │ │ │ └── datastore.md │ │ │ ├── health-lake │ │ │ │ └── fhirdatastore.md │ │ │ ├── iam │ │ │ │ ├── access-key.md │ │ │ │ ├── group-policy.md │ │ │ │ ├── group.md │ │ │ │ ├── instance-profile.md │ │ │ │ ├── managed-policy.md │ │ │ │ ├── oidcprovider.md │ │ │ │ ├── policy.md │ │ │ │ ├── role-policy.md │ │ │ │ ├── role.md │ │ │ │ ├── samlprovider.md │ │ │ │ ├── server-certificate.md │ │ │ │ ├── service-linked-role.md │ │ │ │ ├── user-policy.md │ │ │ │ ├── user-to-group-addition.md │ │ │ │ ├── user.md │ │ │ │ └── virtual-mfadevice.md │ │ │ ├── identity-store │ │ │ │ ├── group-membership.md │ │ │ │ └── group.md │ │ │ ├── image-builder │ │ │ │ ├── component.md │ │ │ │ ├── container-recipe.md │ │ │ │ ├── distribution-configuration.md │ │ │ │ ├── image-pipeline.md │ │ │ │ ├── image-recipe.md │ │ │ │ ├── image.md │ │ │ │ ├── infrastructure-configuration.md │ │ │ │ ├── lifecycle-policy.md │ │ │ │ └── workflow.md │ │ │ ├── inspector-v2 │ │ │ │ ├── cis-scan-configuration.md │ │ │ │ └── filter.md │ │ │ ├── inspector │ │ │ │ ├── assessment-target.md │ │ │ │ ├── assessment-template.md │ │ │ │ └── resource-group.md │ │ │ ├── internet-monitor │ │ │ │ └── monitor.md │ │ │ ├── invoicing │ │ │ │ └── invoice-unit.md │ │ │ ├── io-t │ │ │ │ ├── account-audit-configuration.md │ │ │ │ ├── authorizer.md │ │ │ │ ├── billing-group.md │ │ │ │ ├── cacertificate.md │ │ │ │ ├── certificate-provider.md │ │ │ │ ├── certificate.md │ │ │ │ ├── command.md │ │ │ │ ├── custom-metric.md │ │ │ │ ├── dimension.md │ │ │ │ ├── domain-configuration.md │ │ │ │ ├── fleet-metric.md │ │ │ │ ├── job-template.md │ │ │ │ ├── logging.md │ │ │ │ ├── mitigation-action.md │ │ │ │ ├── policy-principal-attachment.md │ │ │ │ ├── policy.md │ │ │ │ ├── provisioning-template.md │ │ │ │ ├── resource-specific-logging.md │ │ │ │ ├── role-alias.md │ │ │ │ ├── scheduled-audit.md │ │ │ │ ├── security-profile.md │ │ │ │ ├── software-package-version.md │ │ │ │ ├── software-package.md │ │ │ │ ├── thing-group.md │ │ │ │ ├── thing-principal-attachment.md │ │ │ │ ├── thing-type.md │ │ │ │ ├── thing.md │ │ │ │ ├── topic-rule-destination.md │ │ │ │ └── topic-rule.md │ │ │ ├── io-tanalytics │ │ │ │ ├── channel.md │ │ │ │ ├── dataset.md │ │ │ │ ├── datastore.md │ │ │ │ └── pipeline.md │ │ │ ├── io-tcore-device-advisor │ │ │ │ └── suite-definition.md │ │ │ ├── io-tevents │ │ │ │ ├── alarm-model.md │ │ │ │ ├── detector-model.md │ │ │ │ └── input.md │ │ │ ├── io-tfleet-hub │ │ │ │ └── application.md │ │ │ ├── io-tfleet-wise │ │ │ │ ├── campaign.md │ │ │ │ ├── decoder-manifest.md │ │ │ │ ├── fleet.md │ │ │ │ ├── model-manifest.md │ │ │ │ ├── signal-catalog.md │ │ │ │ ├── state-template.md │ │ │ │ └── vehicle.md │ │ │ ├── io-tsite-wise │ │ │ │ ├── access-policy.md │ │ │ │ ├── asset-model.md │ │ │ │ ├── asset.md │ │ │ │ ├── dashboard.md │ │ │ │ ├── dataset.md │ │ │ │ ├── gateway.md │ │ │ │ ├── portal.md │ │ │ │ └── project.md │ │ │ ├── io-tthings-graph │ │ │ │ └── flow-template.md │ │ │ ├── io-ttwin-maker │ │ │ │ ├── component-type.md │ │ │ │ ├── entity.md │ │ │ │ ├── scene.md │ │ │ │ ├── sync-job.md │ │ │ │ └── workspace.md │ │ │ ├── io-twireless │ │ │ │ ├── destination.md │ │ │ │ ├── device-profile.md │ │ │ │ ├── fuota-task.md │ │ │ │ ├── multicast-group.md │ │ │ │ ├── network-analyzer-configuration.md │ │ │ │ ├── partner-account.md │ │ │ │ ├── service-profile.md │ │ │ │ ├── task-definition.md │ │ │ │ ├── wireless-device-import-task.md │ │ │ │ ├── wireless-device.md │ │ │ │ └── wireless-gateway.md │ │ │ ├── ivs │ │ │ │ ├── channel.md │ │ │ │ ├── encoder-configuration.md │ │ │ │ ├── ingest-configuration.md │ │ │ │ ├── playback-key-pair.md │ │ │ │ ├── playback-restriction-policy.md │ │ │ │ ├── public-key.md │ │ │ │ ├── recording-configuration.md │ │ │ │ ├── stage.md │ │ │ │ ├── storage-configuration.md │ │ │ │ └── stream-key.md │ │ │ ├── ivschat │ │ │ │ ├── logging-configuration.md │ │ │ │ └── room.md │ │ │ ├── kafka-connect │ │ │ │ ├── connector.md │ │ │ │ ├── custom-plugin.md │ │ │ │ └── worker-configuration.md │ │ │ ├── kendra-ranking │ │ │ │ └── execution-plan.md │ │ │ ├── kendra │ │ │ │ ├── data-source.md │ │ │ │ ├── faq.md │ │ │ │ └── index.md │ │ │ ├── kinesis-analytics-v2 │ │ │ │ ├── application-cloud-watch-logging-option.md │ │ │ │ ├── application-output.md │ │ │ │ ├── application-reference-data-source.md │ │ │ │ └── application.md │ │ │ ├── kinesis-analytics │ │ │ │ ├── application-output.md │ │ │ │ ├── application-reference-data-source.md │ │ │ │ └── application.md │ │ │ ├── kinesis-firehose │ │ │ │ └── delivery-stream.md │ │ │ ├── kinesis-video │ │ │ │ ├── signaling-channel.md │ │ │ │ └── stream.md │ │ │ ├── kinesis │ │ │ │ ├── resource-policy.md │ │ │ │ ├── stream-consumer.md │ │ │ │ └── stream.md │ │ │ ├── kms │ │ │ │ ├── alias.md │ │ │ │ ├── key.md │ │ │ │ └── replica-key.md │ │ │ ├── lake-formation │ │ │ │ ├── data-cells-filter.md │ │ │ │ ├── data-lake-settings.md │ │ │ │ ├── permissions.md │ │ │ │ ├── principal-permissions.md │ │ │ │ ├── resource.md │ │ │ │ ├── tag-association.md │ │ │ │ └── tag.md │ │ │ ├── lambda │ │ │ │ ├── alias.md │ │ │ │ ├── code-signing-config.md │ │ │ │ ├── event-invoke-config.md │ │ │ │ ├── event-source-mapping.md │ │ │ │ ├── function.md │ │ │ │ ├── layer-version-permission.md │ │ │ │ ├── layer-version.md │ │ │ │ ├── permission.md │ │ │ │ ├── url.md │ │ │ │ └── version.md │ │ │ ├── launch-wizard │ │ │ │ └── deployment.md │ │ │ ├── lex │ │ │ │ ├── bot-alias.md │ │ │ │ ├── bot-version.md │ │ │ │ ├── bot.md │ │ │ │ └── resource-policy.md │ │ │ ├── license-manager │ │ │ │ ├── grant.md │ │ │ │ └── license.md │ │ │ ├── lightsail │ │ │ │ ├── alarm.md │ │ │ │ ├── bucket.md │ │ │ │ ├── certificate.md │ │ │ │ ├── container.md │ │ │ │ ├── database.md │ │ │ │ ├── disk.md │ │ │ │ ├── distribution.md │ │ │ │ ├── instance.md │ │ │ │ ├── load-balancer-tls-certificate.md │ │ │ │ ├── load-balancer.md │ │ │ │ └── static-ip.md │ │ │ ├── location │ │ │ │ ├── apikey.md │ │ │ │ ├── geofence-collection.md │ │ │ │ ├── map.md │ │ │ │ ├── place-index.md │ │ │ │ ├── route-calculator.md │ │ │ │ ├── tracker-consumer.md │ │ │ │ └── tracker.md │ │ │ ├── logs │ │ │ │ ├── account-policy.md │ │ │ │ ├── delivery-destination.md │ │ │ │ ├── delivery-source.md │ │ │ │ ├── delivery.md │ │ │ │ ├── destination.md │ │ │ │ ├── integration.md │ │ │ │ ├── log-anomaly-detector.md │ │ │ │ ├── log-group.md │ │ │ │ ├── log-stream.md │ │ │ │ ├── metric-filter.md │ │ │ │ ├── query-definition.md │ │ │ │ ├── resource-policy.md │ │ │ │ ├── subscription-filter.md │ │ │ │ └── transformer.md │ │ │ ├── lookout-equipment │ │ │ │ └── inference-scheduler.md │ │ │ ├── lookout-metrics │ │ │ │ ├── alert.md │ │ │ │ └── anomaly-detector.md │ │ │ ├── lookout-vision │ │ │ │ └── project.md │ │ │ ├── m2 │ │ │ │ ├── application.md │ │ │ │ ├── deployment.md │ │ │ │ └── environment.md │ │ │ ├── macie │ │ │ │ ├── allow-list.md │ │ │ │ ├── custom-data-identifier.md │ │ │ │ ├── findings-filter.md │ │ │ │ └── session.md │ │ │ ├── managed-blockchain │ │ │ │ ├── accessor.md │ │ │ │ ├── member.md │ │ │ │ └── node.md │ │ │ ├── media-connect │ │ │ │ ├── bridge-output.md │ │ │ │ ├── bridge-source.md │ │ │ │ ├── bridge.md │ │ │ │ ├── flow-entitlement.md │ │ │ │ ├── flow-output.md │ │ │ │ ├── flow-source.md │ │ │ │ ├── flow-vpc-interface.md │ │ │ │ ├── flow.md │ │ │ │ └── gateway.md │ │ │ ├── media-convert │ │ │ │ ├── job-template.md │ │ │ │ ├── preset.md │ │ │ │ └── queue.md │ │ │ ├── media-live │ │ │ │ ├── channel-placement-group.md │ │ │ │ ├── channel.md │ │ │ │ ├── cloud-watch-alarm-template-group.md │ │ │ │ ├── cloud-watch-alarm-template.md │ │ │ │ ├── cluster.md │ │ │ │ ├── event-bridge-rule-template-group.md │ │ │ │ ├── event-bridge-rule-template.md │ │ │ │ ├── input-security-group.md │ │ │ │ ├── input.md │ │ │ │ ├── multiplex.md │ │ │ │ ├── multiplexprogram.md │ │ │ │ ├── network.md │ │ │ │ ├── sdi-source.md │ │ │ │ └── signal-map.md │ │ │ ├── media-package-v2 │ │ │ │ ├── channel-group.md │ │ │ │ ├── channel-policy.md │ │ │ │ ├── channel.md │ │ │ │ ├── origin-endpoint-policy.md │ │ │ │ └── origin-endpoint.md │ │ │ ├── media-package │ │ │ │ ├── asset.md │ │ │ │ ├── channel.md │ │ │ │ ├── origin-endpoint.md │ │ │ │ ├── packaging-configuration.md │ │ │ │ └── packaging-group.md │ │ │ ├── media-store │ │ │ │ └── container.md │ │ │ ├── media-tailor │ │ │ │ ├── channel-policy.md │ │ │ │ ├── channel.md │ │ │ │ ├── live-source.md │ │ │ │ ├── playback-configuration.md │ │ │ │ ├── source-location.md │ │ │ │ └── vod-source.md │ │ │ ├── memory-db │ │ │ │ ├── acl.md │ │ │ │ ├── cluster.md │ │ │ │ ├── multi-region-cluster.md │ │ │ │ ├── parameter-group.md │ │ │ │ ├── subnet-group.md │ │ │ │ └── user.md │ │ │ ├── msk │ │ │ │ ├── batch-scram-secret.md │ │ │ │ ├── cluster-policy.md │ │ │ │ ├── cluster.md │ │ │ │ ├── configuration.md │ │ │ │ ├── replicator.md │ │ │ │ ├── serverless-cluster.md │ │ │ │ └── vpc-connection.md │ │ │ ├── mwaa │ │ │ │ └── environment.md │ │ │ ├── neptune-graph │ │ │ │ ├── graph.md │ │ │ │ └── private-graph-endpoint.md │ │ │ ├── neptune │ │ │ │ ├── dbcluster-parameter-group.md │ │ │ │ ├── dbcluster.md │ │ │ │ ├── dbinstance.md │ │ │ │ ├── dbparameter-group.md │ │ │ │ ├── dbsubnet-group.md │ │ │ │ └── event-subscription.md │ │ │ ├── network-firewall │ │ │ │ ├── firewall-policy.md │ │ │ │ ├── firewall.md │ │ │ │ ├── logging-configuration.md │ │ │ │ ├── rule-group.md │ │ │ │ └── tlsinspection-configuration.md │ │ │ ├── network-manager │ │ │ │ ├── connect-attachment.md │ │ │ │ ├── connect-peer.md │ │ │ │ ├── core-network.md │ │ │ │ ├── customer-gateway-association.md │ │ │ │ ├── device.md │ │ │ │ ├── direct-connect-gateway-attachment.md │ │ │ │ ├── global-network.md │ │ │ │ ├── link-association.md │ │ │ │ ├── link.md │ │ │ │ ├── site-to-site-vpn-attachment.md │ │ │ │ ├── site.md │ │ │ │ ├── transit-gateway-peering.md │ │ │ │ ├── transit-gateway-registration.md │ │ │ │ ├── transit-gateway-route-table-attachment.md │ │ │ │ └── vpc-attachment.md │ │ │ ├── notifications-contacts │ │ │ │ └── email-contact.md │ │ │ ├── notifications │ │ │ │ ├── channel-association.md │ │ │ │ ├── event-rule.md │ │ │ │ ├── managed-notification-account-contact-association.md │ │ │ │ ├── managed-notification-additional-channel-association.md │ │ │ │ ├── notification-configuration.md │ │ │ │ └── notification-hub.md │ │ │ ├── oam │ │ │ │ ├── link.md │ │ │ │ └── sink.md │ │ │ ├── omics │ │ │ │ ├── annotation-store.md │ │ │ │ ├── reference-store.md │ │ │ │ ├── run-group.md │ │ │ │ ├── sequence-store.md │ │ │ │ ├── variant-store.md │ │ │ │ └── workflow.md │ │ │ ├── open-search-serverless │ │ │ │ ├── access-policy.md │ │ │ │ ├── collection.md │ │ │ │ ├── index.md │ │ │ │ ├── lifecycle-policy.md │ │ │ │ ├── security-config.md │ │ │ │ ├── security-policy.md │ │ │ │ └── vpc-endpoint.md │ │ │ ├── open-search-service │ │ │ │ ├── application.md │ │ │ │ └── domain.md │ │ │ ├── ops-works-cm │ │ │ │ └── server.md │ │ │ ├── ops-works │ │ │ │ ├── app.md │ │ │ │ ├── elastic-load-balancer-attachment.md │ │ │ │ ├── instance.md │ │ │ │ ├── layer.md │ │ │ │ ├── stack.md │ │ │ │ ├── user-profile.md │ │ │ │ └── volume.md │ │ │ ├── organizations │ │ │ │ ├── account.md │ │ │ │ ├── organization.md │ │ │ │ ├── organizational-unit.md │ │ │ │ ├── policy.md │ │ │ │ └── resource-policy.md │ │ │ ├── osis │ │ │ │ └── pipeline.md │ │ │ ├── panorama │ │ │ │ ├── application-instance.md │ │ │ │ ├── package-version.md │ │ │ │ └── package.md │ │ │ ├── payment-cryptography │ │ │ │ ├── alias.md │ │ │ │ └── key.md │ │ │ ├── pcaconnector-ad │ │ │ │ ├── connector.md │ │ │ │ ├── directory-registration.md │ │ │ │ ├── service-principal-name.md │ │ │ │ ├── template-group-access-control-entry.md │ │ │ │ └── template.md │ │ │ ├── pcaconnector-scep │ │ │ │ ├── challenge.md │ │ │ │ └── connector.md │ │ │ ├── pcs │ │ │ │ ├── cluster.md │ │ │ │ ├── compute-node-group.md │ │ │ │ └── queue.md │ │ │ ├── personalize │ │ │ │ ├── dataset-group.md │ │ │ │ ├── dataset.md │ │ │ │ ├── schema.md │ │ │ │ └── solution.md │ │ │ ├── pinpoint-email │ │ │ │ ├── configuration-set-event-destination.md │ │ │ │ ├── configuration-set.md │ │ │ │ ├── dedicated-ip-pool.md │ │ │ │ └── identity.md │ │ │ ├── pinpoint │ │ │ │ ├── admchannel.md │ │ │ │ ├── apnschannel.md │ │ │ │ ├── apnssandbox-channel.md │ │ │ │ ├── apnsvoip-channel.md │ │ │ │ ├── apnsvoip-sandbox-channel.md │ │ │ │ ├── app.md │ │ │ │ ├── application-settings.md │ │ │ │ ├── baidu-channel.md │ │ │ │ ├── campaign.md │ │ │ │ ├── email-channel.md │ │ │ │ ├── email-template.md │ │ │ │ ├── event-stream.md │ │ │ │ ├── gcmchannel.md │ │ │ │ ├── in-app-template.md │ │ │ │ ├── push-template.md │ │ │ │ ├── segment.md │ │ │ │ ├── sms-template.md │ │ │ │ ├── smschannel.md │ │ │ │ └── voice-channel.md │ │ │ ├── pipes │ │ │ │ └── pipe.md │ │ │ ├── proton │ │ │ │ ├── environment-account-connection.md │ │ │ │ ├── environment-template.md │ │ │ │ └── service-template.md │ │ │ ├── qbusiness │ │ │ │ ├── application.md │ │ │ │ ├── data-accessor.md │ │ │ │ ├── data-source.md │ │ │ │ ├── index.md │ │ │ │ ├── permission.md │ │ │ │ ├── plugin.md │ │ │ │ ├── retriever.md │ │ │ │ └── web-experience.md │ │ │ ├── qldb │ │ │ │ ├── ledger.md │ │ │ │ └── stream.md │ │ │ ├── quick-sight │ │ │ │ ├── analysis.md │ │ │ │ ├── custom-permissions.md │ │ │ │ ├── dashboard.md │ │ │ │ ├── data-set.md │ │ │ │ ├── data-source.md │ │ │ │ ├── folder.md │ │ │ │ ├── refresh-schedule.md │ │ │ │ ├── template.md │ │ │ │ ├── theme.md │ │ │ │ ├── topic.md │ │ │ │ └── vpcconnection.md │ │ │ ├── ram │ │ │ │ ├── permission.md │ │ │ │ └── resource-share.md │ │ │ ├── rbin │ │ │ │ └── rule.md │ │ │ ├── rds │ │ │ │ ├── custom-dbengine-version.md │ │ │ │ ├── dbcluster-parameter-group.md │ │ │ │ ├── dbcluster.md │ │ │ │ ├── dbinstance.md │ │ │ │ ├── dbparameter-group.md │ │ │ │ ├── dbproxy-endpoint.md │ │ │ │ ├── dbproxy-target-group.md │ │ │ │ ├── dbproxy.md │ │ │ │ ├── dbsecurity-group-ingress.md │ │ │ │ ├── dbsecurity-group.md │ │ │ │ ├── dbshard-group.md │ │ │ │ ├── dbsubnet-group.md │ │ │ │ ├── event-subscription.md │ │ │ │ ├── global-cluster.md │ │ │ │ ├── integration.md │ │ │ │ └── option-group.md │ │ │ ├── redshift-serverless │ │ │ │ ├── namespace.md │ │ │ │ └── workgroup.md │ │ │ ├── redshift │ │ │ │ ├── cluster-parameter-group.md │ │ │ │ ├── cluster-security-group-ingress.md │ │ │ │ ├── cluster-security-group.md │ │ │ │ ├── cluster-subnet-group.md │ │ │ │ ├── cluster.md │ │ │ │ ├── endpoint-access.md │ │ │ │ ├── endpoint-authorization.md │ │ │ │ ├── event-subscription.md │ │ │ │ ├── integration.md │ │ │ │ └── scheduled-action.md │ │ │ ├── refactor-spaces │ │ │ │ ├── application.md │ │ │ │ ├── environment.md │ │ │ │ ├── route.md │ │ │ │ └── service.md │ │ │ ├── rekognition │ │ │ │ ├── collection.md │ │ │ │ ├── project.md │ │ │ │ └── stream-processor.md │ │ │ ├── resilience-hub │ │ │ │ ├── app.md │ │ │ │ └── resiliency-policy.md │ │ │ ├── resource-explorer2 │ │ │ │ ├── default-view-association.md │ │ │ │ ├── index.md │ │ │ │ └── view.md │ │ │ ├── resource-groups │ │ │ │ ├── group.md │ │ │ │ └── tag-sync-task.md │ │ │ ├── robo-maker │ │ │ │ ├── fleet.md │ │ │ │ ├── robot-application-version.md │ │ │ │ ├── robot-application.md │ │ │ │ ├── robot.md │ │ │ │ ├── simulation-application-version.md │ │ │ │ └── simulation-application.md │ │ │ ├── roles-anywhere │ │ │ │ ├── crl.md │ │ │ │ ├── profile.md │ │ │ │ └── trust-anchor.md │ │ │ ├── route53 │ │ │ │ ├── cidr-collection.md │ │ │ │ ├── dnssec.md │ │ │ │ ├── health-check.md │ │ │ │ ├── hosted-zone.md │ │ │ │ ├── key-signing-key.md │ │ │ │ ├── record-set-group.md │ │ │ │ └── record-set.md │ │ │ ├── route53profiles │ │ │ │ ├── profile-association.md │ │ │ │ ├── profile-resource-association.md │ │ │ │ └── profile.md │ │ │ ├── route53recovery-control │ │ │ │ ├── cluster.md │ │ │ │ ├── control-panel.md │ │ │ │ ├── routing-control.md │ │ │ │ └── safety-rule.md │ │ │ ├── route53recovery-readiness │ │ │ │ ├── cell.md │ │ │ │ ├── readiness-check.md │ │ │ │ ├── recovery-group.md │ │ │ │ └── resource-set.md │ │ │ ├── route53resolver │ │ │ │ ├── firewall-domain-list.md │ │ │ │ ├── firewall-rule-group-association.md │ │ │ │ ├── firewall-rule-group.md │ │ │ │ ├── outpost-resolver.md │ │ │ │ ├── resolver-config.md │ │ │ │ ├── resolver-dnssecconfig.md │ │ │ │ ├── resolver-endpoint.md │ │ │ │ ├── resolver-query-logging-config-association.md │ │ │ │ ├── resolver-query-logging-config.md │ │ │ │ ├── resolver-rule-association.md │ │ │ │ └── resolver-rule.md │ │ │ ├── rum │ │ │ │ └── app-monitor.md │ │ │ ├── s3 │ │ │ │ ├── access-grant.md │ │ │ │ ├── access-grants-instance.md │ │ │ │ ├── access-grants-location.md │ │ │ │ ├── access-point.md │ │ │ │ ├── bucket-policy.md │ │ │ │ ├── bucket.md │ │ │ │ ├── multi-region-access-point-policy.md │ │ │ │ ├── multi-region-access-point.md │ │ │ │ ├── storage-lens-group.md │ │ │ │ └── storage-lens.md │ │ │ ├── s3express │ │ │ │ ├── bucket-policy.md │ │ │ │ └── directory-bucket.md │ │ │ ├── s3object-lambda │ │ │ │ ├── access-point-policy.md │ │ │ │ └── access-point.md │ │ │ ├── s3outposts │ │ │ │ ├── access-point.md │ │ │ │ ├── bucket-policy.md │ │ │ │ ├── bucket.md │ │ │ │ └── endpoint.md │ │ │ ├── s3tables │ │ │ │ ├── table-bucket-policy.md │ │ │ │ └── table-bucket.md │ │ │ ├── sage-maker │ │ │ │ ├── app-image-config.md │ │ │ │ ├── app.md │ │ │ │ ├── cluster.md │ │ │ │ ├── code-repository.md │ │ │ │ ├── data-quality-job-definition.md │ │ │ │ ├── device-fleet.md │ │ │ │ ├── device.md │ │ │ │ ├── domain.md │ │ │ │ ├── endpoint-config.md │ │ │ │ ├── endpoint.md │ │ │ │ ├── feature-group.md │ │ │ │ ├── image-version.md │ │ │ │ ├── image.md │ │ │ │ ├── inference-component.md │ │ │ │ ├── inference-experiment.md │ │ │ │ ├── mlflow-tracking-server.md │ │ │ │ ├── model-bias-job-definition.md │ │ │ │ ├── model-card.md │ │ │ │ ├── model-explainability-job-definition.md │ │ │ │ ├── model-package-group.md │ │ │ │ ├── model-package.md │ │ │ │ ├── model-quality-job-definition.md │ │ │ │ ├── model.md │ │ │ │ ├── monitoring-schedule.md │ │ │ │ ├── notebook-instance-lifecycle-config.md │ │ │ │ ├── notebook-instance.md │ │ │ │ ├── partner-app.md │ │ │ │ ├── pipeline.md │ │ │ │ ├── project.md │ │ │ │ ├── space.md │ │ │ │ ├── studio-lifecycle-config.md │ │ │ │ ├── user-profile.md │ │ │ │ └── workteam.md │ │ │ ├── scheduler │ │ │ │ ├── schedule-group.md │ │ │ │ └── schedule.md │ │ │ ├── sdb │ │ │ │ └── domain.md │ │ │ ├── secrets-manager │ │ │ │ ├── resource-policy.md │ │ │ │ ├── rotation-schedule.md │ │ │ │ ├── secret-target-attachment.md │ │ │ │ └── secret.md │ │ │ ├── security-hub │ │ │ │ ├── automation-rule.md │ │ │ │ ├── configuration-policy.md │ │ │ │ ├── delegated-admin.md │ │ │ │ ├── finding-aggregator.md │ │ │ │ ├── hub.md │ │ │ │ ├── insight.md │ │ │ │ ├── organization-configuration.md │ │ │ │ ├── policy-association.md │ │ │ │ ├── product-subscription.md │ │ │ │ ├── security-control.md │ │ │ │ └── standard.md │ │ │ ├── security-lake │ │ │ │ ├── aws-log-source.md │ │ │ │ ├── data-lake.md │ │ │ │ ├── subscriber-notification.md │ │ │ │ └── subscriber.md │ │ │ ├── service-catalog-app-registry │ │ │ │ ├── application.md │ │ │ │ ├── attribute-group-association.md │ │ │ │ ├── attribute-group.md │ │ │ │ └── resource-association.md │ │ │ ├── service-catalog │ │ │ │ ├── accepted-portfolio-share.md │ │ │ │ ├── cloud-formation-product.md │ │ │ │ ├── cloud-formation-provisioned-product.md │ │ │ │ ├── launch-notification-constraint.md │ │ │ │ ├── launch-role-constraint.md │ │ │ │ ├── launch-template-constraint.md │ │ │ │ ├── portfolio-principal-association.md │ │ │ │ ├── portfolio-product-association.md │ │ │ │ ├── portfolio-share.md │ │ │ │ ├── portfolio.md │ │ │ │ ├── resource-update-constraint.md │ │ │ │ ├── service-action-association.md │ │ │ │ ├── service-action.md │ │ │ │ ├── stack-set-constraint.md │ │ │ │ ├── tag-option-association.md │ │ │ │ └── tag-option.md │ │ │ ├── service-discovery │ │ │ │ ├── http-namespace.md │ │ │ │ ├── instance.md │ │ │ │ ├── private-dns-namespace.md │ │ │ │ ├── public-dns-namespace.md │ │ │ │ └── service.md │ │ │ ├── ses │ │ │ │ ├── configuration-set-event-destination.md │ │ │ │ ├── configuration-set.md │ │ │ │ ├── contact-list.md │ │ │ │ ├── dedicated-ip-pool.md │ │ │ │ ├── email-identity.md │ │ │ │ ├── mail-manager-addon-instance.md │ │ │ │ ├── mail-manager-addon-subscription.md │ │ │ │ ├── mail-manager-archive.md │ │ │ │ ├── mail-manager-ingress-point.md │ │ │ │ ├── mail-manager-relay.md │ │ │ │ ├── mail-manager-rule-set.md │ │ │ │ ├── mail-manager-traffic-policy.md │ │ │ │ ├── receipt-filter.md │ │ │ │ ├── receipt-rule-set.md │ │ │ │ ├── receipt-rule.md │ │ │ │ ├── template.md │ │ │ │ └── vdm-attributes.md │ │ │ ├── shield │ │ │ │ ├── drtaccess.md │ │ │ │ ├── proactive-engagement.md │ │ │ │ ├── protection-group.md │ │ │ │ └── protection.md │ │ │ ├── signer │ │ │ │ ├── profile-permission.md │ │ │ │ └── signing-profile.md │ │ │ ├── sim-space-weaver │ │ │ │ └── simulation.md │ │ │ ├── sns │ │ │ │ ├── subscription.md │ │ │ │ ├── topic-inline-policy.md │ │ │ │ ├── topic-policy.md │ │ │ │ └── topic.md │ │ │ ├── sqs │ │ │ │ ├── queue-inline-policy.md │ │ │ │ ├── queue-policy.md │ │ │ │ └── queue.md │ │ │ ├── ssm │ │ │ │ ├── association.md │ │ │ │ ├── document.md │ │ │ │ ├── maintenance-window-target.md │ │ │ │ ├── maintenance-window-task.md │ │ │ │ ├── maintenance-window.md │ │ │ │ ├── parameter.md │ │ │ │ ├── patch-baseline.md │ │ │ │ ├── resource-data-sync.md │ │ │ │ └── resource-policy.md │ │ │ ├── ssmcontacts │ │ │ │ ├── contact-channel.md │ │ │ │ ├── contact.md │ │ │ │ ├── plan.md │ │ │ │ └── rotation.md │ │ │ ├── ssmincidents │ │ │ │ ├── replication-set.md │ │ │ │ └── response-plan.md │ │ │ ├── ssmquick-setup │ │ │ │ └── configuration-manager.md │ │ │ ├── sso │ │ │ │ ├── application-assignment.md │ │ │ │ ├── application.md │ │ │ │ ├── assignment.md │ │ │ │ ├── instance-access-control-attribute-configuration.md │ │ │ │ ├── instance.md │ │ │ │ └── permission-set.md │ │ │ ├── step-functions │ │ │ │ ├── activity.md │ │ │ │ ├── state-machine-alias.md │ │ │ │ ├── state-machine-version.md │ │ │ │ └── state-machine.md │ │ │ ├── support-app │ │ │ │ ├── account-alias.md │ │ │ │ ├── slack-channel-configuration.md │ │ │ │ └── slack-workspace-configuration.md │ │ │ ├── synthetics │ │ │ │ ├── canary.md │ │ │ │ └── group.md │ │ │ ├── systems-manager-sap │ │ │ │ └── application.md │ │ │ ├── timestream │ │ │ │ ├── database.md │ │ │ │ ├── influx-dbinstance.md │ │ │ │ ├── scheduled-query.md │ │ │ │ └── table.md │ │ │ ├── transfer │ │ │ │ ├── agreement.md │ │ │ │ ├── certificate.md │ │ │ │ ├── connector.md │ │ │ │ ├── profile.md │ │ │ │ ├── server.md │ │ │ │ ├── user.md │ │ │ │ ├── web-app.md │ │ │ │ └── workflow.md │ │ │ ├── verified-permissions │ │ │ │ ├── identity-source.md │ │ │ │ ├── policy-store.md │ │ │ │ ├── policy-template.md │ │ │ │ └── policy.md │ │ │ ├── voice-id │ │ │ │ └── domain.md │ │ │ ├── vpc-lattice │ │ │ │ ├── access-log-subscription.md │ │ │ │ ├── auth-policy.md │ │ │ │ ├── listener.md │ │ │ │ ├── resource-configuration.md │ │ │ │ ├── resource-gateway.md │ │ │ │ ├── resource-policy.md │ │ │ │ ├── rule.md │ │ │ │ ├── service-network-resource-association.md │ │ │ │ ├── service-network-service-association.md │ │ │ │ ├── service-network-vpc-association.md │ │ │ │ ├── service-network.md │ │ │ │ ├── service.md │ │ │ │ └── target-group.md │ │ │ ├── waf │ │ │ │ ├── byte-match-set.md │ │ │ │ ├── ipset.md │ │ │ │ ├── rule.md │ │ │ │ ├── size-constraint-set.md │ │ │ │ ├── sql-injection-match-set.md │ │ │ │ ├── web-acl.md │ │ │ │ └── xss-match-set.md │ │ │ ├── wafregional │ │ │ │ ├── byte-match-set.md │ │ │ │ ├── geo-match-set.md │ │ │ │ ├── ipset.md │ │ │ │ ├── rate-based-rule.md │ │ │ │ ├── regex-pattern-set.md │ │ │ │ ├── rule.md │ │ │ │ ├── size-constraint-set.md │ │ │ │ ├── sql-injection-match-set.md │ │ │ │ ├── web-acl.md │ │ │ │ ├── web-aclassociation.md │ │ │ │ └── xss-match-set.md │ │ │ ├── wafv2 │ │ │ │ ├── ipset.md │ │ │ │ ├── logging-configuration.md │ │ │ │ ├── regex-pattern-set.md │ │ │ │ ├── rule-group.md │ │ │ │ ├── web-acl.md │ │ │ │ └── web-aclassociation.md │ │ │ ├── wisdom │ │ │ │ ├── aiagent-version.md │ │ │ │ ├── aiagent.md │ │ │ │ ├── aiguardrail-version.md │ │ │ │ ├── aiguardrail.md │ │ │ │ ├── aiprompt-version.md │ │ │ │ ├── aiprompt.md │ │ │ │ ├── assistant-association.md │ │ │ │ ├── assistant.md │ │ │ │ ├── knowledge-base.md │ │ │ │ ├── message-template-version.md │ │ │ │ └── message-template.md │ │ │ ├── work-spaces-thin-client │ │ │ │ └── environment.md │ │ │ ├── work-spaces-web │ │ │ │ ├── browser-settings.md │ │ │ │ ├── data-protection-settings.md │ │ │ │ ├── identity-provider.md │ │ │ │ ├── ip-access-settings.md │ │ │ │ ├── network-settings.md │ │ │ │ ├── portal.md │ │ │ │ ├── trust-store.md │ │ │ │ ├── user-access-logging-settings.md │ │ │ │ └── user-settings.md │ │ │ ├── work-spaces │ │ │ │ ├── connection-alias.md │ │ │ │ ├── workspace.md │ │ │ │ └── workspaces-pool.md │ │ │ └── xray │ │ │ │ ├── group.md │ │ │ │ ├── resource-policy.md │ │ │ │ ├── sampling-rule.md │ │ │ │ └── transaction-search-config.md │ │ ├── aws │ │ │ ├── bucket.md │ │ │ ├── control.md │ │ │ ├── function.md │ │ │ ├── policy-attachment.md │ │ │ ├── policy.md │ │ │ ├── queue.md │ │ │ ├── role.md │ │ │ ├── ses.md │ │ │ └── table.md │ │ ├── cloudflare │ │ │ ├── account-api-token.md │ │ │ ├── account-id.md │ │ │ ├── ai-gateway.md │ │ │ ├── assets.md │ │ │ ├── bucket.md │ │ │ ├── custom-domain.md │ │ │ ├── d1-database.md │ │ │ ├── dns-records.md │ │ │ ├── durable-object-namespace.md │ │ │ ├── hyperdrive.md │ │ │ ├── kv-namespace.md │ │ │ ├── nuxt.md │ │ │ ├── permission-groups.md │ │ │ ├── pipeline.md │ │ │ ├── queue-consumer.md │ │ │ ├── queue.md │ │ │ ├── redwood.md │ │ │ ├── route.md │ │ │ ├── tanstack-start.md │ │ │ ├── vite.md │ │ │ ├── website.md │ │ │ ├── worker.md │ │ │ ├── workflow.md │ │ │ ├── wrangler.json.md │ │ │ └── zone.md │ │ ├── dns │ │ │ └── import-dns.md │ │ ├── esbuild │ │ │ └── bundle.md │ │ ├── fs │ │ │ ├── copy-file.md │ │ │ ├── file.md │ │ │ ├── folder.md │ │ │ ├── static-astro-file.md │ │ │ ├── static-css-file.md │ │ │ ├── static-html-file.md │ │ │ ├── static-json-file.md │ │ │ ├── static-text-file.md │ │ │ ├── static-typescript-file.md │ │ │ ├── static-vue-file.md │ │ │ └── static-yaml-file.md │ │ ├── github │ │ │ ├── repository-environment.md │ │ │ └── secret.md │ │ ├── neon │ │ │ └── project.md │ │ ├── os │ │ │ └── exec.md │ │ ├── sentry │ │ │ ├── client-key.md │ │ │ ├── project.md │ │ │ └── team.md │ │ ├── stripe │ │ │ ├── meter.md │ │ │ ├── price.md │ │ │ ├── product.md │ │ │ └── webhook.md │ │ ├── upstash │ │ │ └── redis.md │ │ └── vercel │ │ │ ├── project-domain.md │ │ │ └── project.md │ └── what-is-alchemy.md ├── index.md ├── package.json └── public │ ├── alchemist.webp │ ├── alchemy-flower.png │ ├── alchemy-og.png │ ├── potion-with-border.png │ └── potion.png ├── alchemy ├── package.json ├── src │ ├── ai │ │ ├── ark.ts │ │ ├── astro-file.ts │ │ ├── client.ts │ │ ├── css-file.ts │ │ ├── data.ts │ │ ├── document.ts │ │ ├── html-file.ts │ │ ├── index.ts │ │ ├── json-file.ts │ │ ├── typescript-file.ts │ │ ├── vue-file.ts │ │ └── yaml-file.ts │ ├── alchemy.ts │ ├── apply.ts │ ├── aws │ │ ├── account-id.ts │ │ ├── bucket.ts │ │ ├── control │ │ │ ├── client.ts │ │ │ ├── error.ts │ │ │ ├── index.ts │ │ │ ├── properties.ts │ │ │ ├── proxy.ts │ │ │ ├── resource.ts │ │ │ └── types.ts │ │ ├── credentials.ts │ │ ├── function.ts │ │ ├── index.ts │ │ ├── oidc │ │ │ ├── github-oidc-provider.ts │ │ │ ├── index.ts │ │ │ └── oidc-provider.ts │ │ ├── policy-attachment.ts │ │ ├── policy.ts │ │ ├── queue.ts │ │ ├── retry.ts │ │ ├── role.ts │ │ ├── ses.ts │ │ ├── ssm-parameter.ts │ │ └── table.ts │ ├── cloudflare │ │ ├── account-api-token.ts │ │ ├── account-id.ts │ │ ├── ai-gateway.ts │ │ ├── ai.ts │ │ ├── analytics-engine.ts │ │ ├── api-error.ts │ │ ├── api.ts │ │ ├── asset-manifest.ts │ │ ├── assets.ts │ │ ├── auth.ts │ │ ├── bindings.ts │ │ ├── bound.ts │ │ ├── browser-rendering.ts │ │ ├── bucket.ts │ │ ├── bundle │ │ │ ├── alias-plugin.ts │ │ │ ├── build-failures.ts │ │ │ ├── bundle-worker.ts │ │ │ ├── external.ts │ │ │ ├── local-dev-cloudflare-shim.ts │ │ │ ├── nodejs-compat-mode.ts │ │ │ ├── nodejs-compat.ts │ │ │ └── wasm-plugin.ts │ │ ├── custom-domain.ts │ │ ├── d1-clone.ts │ │ ├── d1-database.ts │ │ ├── d1-export.ts │ │ ├── d1-import.ts │ │ ├── d1-migrations.ts │ │ ├── dns-records.ts │ │ ├── durable-object-namespace.ts │ │ ├── event-source.ts │ │ ├── hyperdrive.ts │ │ ├── index.ts │ │ ├── kv-namespace.ts │ │ ├── nuxt.ts │ │ ├── permission-groups.ts │ │ ├── pipeline.ts │ │ ├── queue-consumer.ts │ │ ├── queue.ts │ │ ├── r2-rest-state-store.ts │ │ ├── react-router.ts │ │ ├── redwood.ts │ │ ├── response.ts │ │ ├── route.ts │ │ ├── tanstack-start.ts │ │ ├── types.ts │ │ ├── user.ts │ │ ├── vectorize-index.ts │ │ ├── vectorize-metadata-index.ts │ │ ├── version-metadata.ts │ │ ├── vite.ts │ │ ├── website.ts │ │ ├── worker-assets.ts │ │ ├── worker-metadata.ts │ │ ├── worker-migration.ts │ │ ├── worker-stub.ts │ │ ├── worker.ts │ │ ├── workflow.ts │ │ ├── wrangler.json.ts │ │ ├── zone-settings.ts │ │ └── zone.ts │ ├── context.ts │ ├── destroy.ts │ ├── dns │ │ ├── godaddy.ts │ │ ├── import-dns.ts │ │ ├── index.ts │ │ └── record.ts │ ├── encrypt.ts │ ├── env.ts │ ├── esbuild │ │ ├── bundle.ts │ │ └── index.ts │ ├── fs │ │ ├── copy-file.ts │ │ ├── file-collection.ts │ │ ├── file-ref.ts │ │ ├── file-system-state-store.ts │ │ ├── file.ts │ │ ├── folder.ts │ │ ├── index.ts │ │ ├── static-astro-file.ts │ │ ├── static-css-file.ts │ │ ├── static-html-file.ts │ │ ├── static-json-file.ts │ │ ├── static-text-file.ts │ │ ├── static-typescript-file.ts │ │ ├── static-vue-file.ts │ │ └── static-yaml-file.ts │ ├── github │ │ ├── client.ts │ │ ├── index.ts │ │ ├── repository-environment.ts │ │ └── secret.ts │ ├── index.ts │ ├── internal │ │ └── docs │ │ │ └── providers.ts │ ├── neon │ │ ├── api-error.ts │ │ ├── api.ts │ │ ├── index.ts │ │ └── project.ts │ ├── os │ │ ├── exec.ts │ │ └── index.ts │ ├── resource.ts │ ├── runtime │ │ ├── bind.ts │ │ ├── global.ts │ │ ├── plugin.ts │ │ ├── shims.js │ │ └── state.ts │ ├── scope.ts │ ├── secret.ts │ ├── sentry │ │ ├── api.ts │ │ ├── client-key.ts │ │ ├── index.ts │ │ ├── project.ts │ │ └── team.ts │ ├── serde.ts │ ├── state.ts │ ├── stripe │ │ ├── index.ts │ │ ├── meter.ts │ │ ├── price.ts │ │ ├── product.ts │ │ └── webhook.ts │ ├── test │ │ ├── bun.ts │ │ ├── prune.ts │ │ └── vitest.ts │ ├── type.ts │ ├── upstash │ │ ├── api.ts │ │ ├── error.ts │ │ ├── index.ts │ │ └── redis.ts │ ├── util │ │ ├── assert-never.ts │ │ ├── content-type.ts │ │ ├── dedent.ts │ │ ├── ignore.ts │ │ ├── retry.ts │ │ ├── rm.ts │ │ ├── safe-fetch.ts │ │ ├── sha256.ts │ │ ├── sleep.ts │ │ └── slugify.ts │ ├── vercel │ │ ├── api.ts │ │ ├── index.ts │ │ ├── project-domain.ts │ │ └── project.ts │ └── web │ │ ├── astro.ts │ │ ├── shadcn-component.ts │ │ ├── shadcn.ts │ │ ├── tailwind.ts │ │ ├── vite.ts │ │ └── vitepress │ │ ├── config.ts │ │ ├── custom-theme.ts │ │ ├── dependencies.ts │ │ ├── home-page.ts │ │ ├── index.ts │ │ ├── process-front-matter-files.ts │ │ └── vitepress.ts ├── test │ ├── alchemy.test.ts │ ├── aws │ │ ├── control │ │ │ ├── proxy.test.ts │ │ │ ├── resource.test.ts │ │ │ └── test-utils.ts │ │ ├── function.test.ts │ │ ├── queue.test.ts │ │ ├── role.test.ts │ │ ├── ses.test.ts │ │ ├── ssm-parameter.test.ts │ │ └── table.test.ts │ ├── cloudflare │ │ ├── account-api-token.test.ts │ │ ├── account-id.test.ts │ │ ├── ai-gateway.test.ts │ │ ├── ai.test.ts │ │ ├── browser-handler.ts │ │ ├── browser-rendering.test.ts │ │ ├── bucket.test.ts │ │ ├── bundle-handler-als.ts │ │ ├── bundle-handler.ts │ │ ├── bundle.test.ts │ │ ├── d1-clone.test.ts │ │ ├── d1-database.test.ts │ │ ├── dns-records.test.ts │ │ ├── durable-object.test.ts │ │ ├── fetch-utils.ts │ │ ├── hyperdrive.test.ts │ │ ├── kv-namespace.test.ts │ │ ├── migrations │ │ │ └── 001_create_table.sql │ │ ├── nobundle │ │ │ ├── dir │ │ │ │ └── bar.js │ │ │ ├── foo.js │ │ │ └── index.js │ │ ├── permission-groups.test.ts │ │ ├── pipeline.test.ts │ │ ├── queue-consumer.test.ts │ │ ├── queue.test.ts │ │ ├── r2-rest-state-store.test.ts │ │ ├── route.test.ts │ │ ├── unenv-handler.ts │ │ ├── unenv.test.ts │ │ ├── vectorize-index.test.ts │ │ ├── vectorize-metadata-index.test.ts │ │ ├── version-metadata-handler.ts │ │ ├── version-metadata.test.ts │ │ ├── worker.test.ts │ │ ├── workflow.test.ts │ │ ├── wrangler-json.test.ts │ │ └── zone.test.ts │ ├── esbuild.test.ts │ ├── fs │ │ └── copy-file.test.ts │ ├── github │ │ ├── repository-environment.test.ts │ │ └── secret.test.ts │ ├── handler.ts │ ├── neon │ │ └── project.test.ts │ ├── os │ │ └── exec.test.ts │ ├── run.ts │ ├── runtime │ │ ├── app.js │ │ └── app.ts │ ├── scope.test.ts │ ├── sentry │ │ ├── client-key.test.ts │ │ ├── project.test.ts │ │ └── team.test.ts │ ├── serde.test.ts │ ├── smoke.test.ts │ ├── stripe │ │ ├── meter.test.ts │ │ ├── price.test.ts │ │ ├── product.test.ts │ │ └── webhook-endpoint.test.ts │ ├── upstash │ │ └── redis.test.ts │ ├── util.ts │ ├── util │ │ └── dedent.test.ts │ └── vercel │ │ ├── project-domain.test.ts │ │ └── project.test.ts ├── tsconfig.json └── tsconfig.test.json ├── biome.json ├── bun.lock ├── examples ├── aws-app │ ├── alchemy.run.ts │ ├── package.json │ ├── src │ │ └── index.ts │ └── tsconfig.json ├── cloudflare-nuxt-pipeline │ ├── .gitignore │ ├── README.md │ ├── alchemy.run.ts │ ├── app.vue │ ├── env.d.ts │ ├── index.ts │ ├── nuxt.config.ts │ ├── package.json │ ├── pages │ │ └── index.vue │ ├── public │ │ ├── favicon.ico │ │ └── robots.txt │ ├── server │ │ ├── api │ │ │ └── pipeline.post.ts │ │ └── tsconfig.json │ └── tsconfig.json ├── cloudflare-react-router │ ├── .gitignore │ ├── README.md │ ├── alchemy.run.ts │ ├── app │ │ ├── app.css │ │ ├── entry.server.tsx │ │ ├── root.tsx │ │ ├── routes.ts │ │ ├── routes │ │ │ └── home.tsx │ │ └── welcome │ │ │ ├── logo-dark.svg │ │ │ ├── logo-light.svg │ │ │ └── welcome.tsx │ ├── bun.lock │ ├── package.json │ ├── public │ │ └── favicon.ico │ ├── react-router.config.ts │ ├── tsconfig.cloudflare.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ ├── vite.config.ts │ └── workers │ │ ├── app.ts │ │ └── env.ts ├── cloudflare-redwood │ ├── .env.example │ ├── .gitignore │ ├── .prettierrc │ ├── README.md │ ├── alchemy.run.ts │ ├── drizzle.config.ts │ ├── drizzle │ │ ├── 0000_lame_kitty_pryde.sql │ │ └── meta │ │ │ ├── 0000_snapshot.json │ │ │ └── _journal.json │ ├── package.json │ ├── public │ │ └── images │ │ │ ├── cloudflare-account-id.png │ │ │ ├── cloudflare-copy-token.png │ │ │ ├── cloudflare-custom-tokens.png │ │ │ ├── cloudflare-d1.png │ │ │ ├── cloudflare-new-token.png │ │ │ ├── cloudflare-token-summary.png │ │ │ ├── cloudflare-user-api-tokens.png │ │ │ └── new-db.png │ ├── src │ │ ├── app │ │ │ ├── Document.tsx │ │ │ ├── headers.ts │ │ │ ├── pages │ │ │ │ └── Home.tsx │ │ │ └── shared │ │ │ │ └── links.ts │ │ ├── client.tsx │ │ ├── db │ │ │ ├── schema.ts │ │ │ └── seed.ts │ │ └── worker.tsx │ ├── tsconfig.json │ ├── types │ │ ├── env.d.ts │ │ ├── rw.d.ts │ │ └── vite.d.ts │ ├── vite.config.mts │ └── worker-configuration.d.ts ├── cloudflare-tanstack-start │ ├── .gitignore │ ├── .prettierignore │ ├── .vscode │ │ └── settings.json │ ├── README.md │ ├── alchemy.run.ts │ ├── app.config.ts │ ├── bun.lock │ ├── package.json │ ├── postcss.config.mjs │ ├── public │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ ├── favicon.png │ │ └── site.webmanifest │ ├── src │ │ ├── api.ts │ │ ├── client.tsx │ │ ├── components │ │ │ ├── DefaultCatchBoundary.tsx │ │ │ ├── NotFound.tsx │ │ │ ├── PostError.tsx │ │ │ └── UserError.tsx │ │ ├── env.d.ts │ │ ├── global-middleware.ts │ │ ├── routeTree.gen.ts │ │ ├── router.tsx │ │ ├── routes │ │ │ ├── __root.tsx │ │ │ ├── _pathlessLayout.tsx │ │ │ ├── _pathlessLayout │ │ │ │ ├── _nested-layout.tsx │ │ │ │ └── _nested-layout │ │ │ │ │ ├── route-a.tsx │ │ │ │ │ └── route-b.tsx │ │ │ ├── api │ │ │ │ ├── users.$id.ts │ │ │ │ └── users.ts │ │ │ ├── deferred.tsx │ │ │ ├── index.tsx │ │ │ ├── posts.$postId.tsx │ │ │ ├── posts.index.tsx │ │ │ ├── posts.route.tsx │ │ │ ├── posts_.$postId.deep.tsx │ │ │ ├── redirect.tsx │ │ │ ├── users.$userId.tsx │ │ │ ├── users.index.tsx │ │ │ └── users.route.tsx │ │ ├── ssr.tsx │ │ ├── styles │ │ │ └── app.css │ │ └── utils │ │ │ ├── loggingMiddleware.tsx │ │ │ ├── posts.tsx │ │ │ ├── seo.ts │ │ │ └── users.tsx │ ├── tailwind.config.mjs │ └── tsconfig.json ├── cloudflare-vite │ ├── .gitignore │ ├── alchemy.run.ts │ ├── index.html │ ├── package.json │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── App.css │ │ ├── App.tsx │ │ ├── assets │ │ │ └── react.svg │ │ ├── auth │ │ │ ├── issuer.ts │ │ │ └── subjects.ts │ │ ├── env.d.ts │ │ ├── index.css │ │ ├── index.ts │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tsconfig.json │ └── vite.config.ts ├── cloudflare-worker-bootstrap │ ├── index.ts │ ├── package.json │ └── tsconfig.json └── cloudflare-worker │ ├── .gitignore │ ├── alchemy.run.ts │ ├── package.json │ ├── src │ ├── do.ts │ ├── env.ts │ ├── rpc.ts │ ├── worker.ts │ └── workflow.ts │ └── tsconfig.json ├── package.json ├── public ├── alchemist.png └── alchemist.webp ├── scripts ├── bump.ts ├── generate-aws-control-types.ts ├── generate-aws-control.ts └── shell.ts ├── stacks ├── docs.run.ts ├── env.ts ├── repo.run.ts └── website.run.ts ├── tsconfig.base.json ├── tsconfig.json ├── tsconfig.stacks.json ├── vitest.config.ts └── vitest.setup.ts /.cursor/rules/cloudflare.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: 3 | globs: alchemy/src/cloudflare/* 4 | alwaysApply: false 5 | --- 6 | When adding a new resource that can be bound to a worker, make sure to update: 7 | 8 | 1. bindings.ts - add the binding type to the union 9 | 2. bound.ts - map the Alchemy resource to the Cloudflare runtime binding type 10 | 3. worker.ts - map the binding to the cloduflare metadata api 11 | 4. {resource}.ts - add a new file for the resource alchemy/src/cloudflare/{resource}.ts 12 | 5. {resource}.test.ts - add a new file for the resource alchemy/test/cloudflare/{resource}.test.ts -------------------------------------------------------------------------------- /.github/workflows/pkg-pr.yml: -------------------------------------------------------------------------------- 1 | name: Publish Preview Package 2 | on: 3 | push: 4 | branches: [main] 5 | pull_request: 6 | 7 | jobs: 8 | pkg-pr: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v4 14 | 15 | - name: Setup Bun 16 | uses: oven-sh/setup-bun@v1 17 | with: 18 | bun-version: latest 19 | 20 | - name: Install dependencies 21 | run: bun install 22 | 23 | - name: Build 24 | run: bun run --filter alchemy build 25 | 26 | - run: bunx pkg-pr-new publish ./alchemy 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | lib/ 4 | .out/ 5 | .test/ 6 | .env 7 | *.tsbuildinfo 8 | 9 | .alchemy/ 10 | # !.alchemy/github:alchemy/ 11 | # examples/*/.alchemy 12 | 13 | .repomix-output.txt 14 | alchemy-web/public/og-images/ 15 | wrangler.jsonc -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sam-goodwin/alchemy/5ad508201ef5217e8a5ef47a9efc21e2c29b8031/.gitmodules -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.codeLens": false, 3 | "editor.formatOnSave": true, 4 | "editor.formatOnSaveMode": "file", 5 | "editor.codeActionsOnSave": { 6 | "source.fixAll.ruff": "always", 7 | "source.fixAll": "explicit", 8 | "source.organizeImports": "explicit", 9 | "source.organizeImports.biome": "explicit" 10 | }, 11 | "rewrap.autoWrap.enabled": true, 12 | "[rust]": { 13 | "editor.insertSpaces": true, 14 | "editor.tabSize": 4 15 | }, 16 | "[toml]": { 17 | "editor.defaultFormatter": "tamasfe.even-better-toml" 18 | }, 19 | "[json]": { 20 | "editor.indentSize": 2, 21 | "editor.insertSpaces": true, 22 | "editor.defaultFormatter": "biomejs.biome" 23 | }, 24 | "[markdown]": { 25 | "editor.formatOnSave": true 26 | }, 27 | "editor.inlayHints.enabled": "offUnlessPressed", 28 | "files.exclude": { 29 | "**/__pycache__": true, 30 | "**/*.pyc": true 31 | }, 32 | "vitest.disableWorkspaceWarning": true, 33 | "[typescript]": { 34 | "editor.indentSize": 2, 35 | "editor.defaultFormatter": "biomejs.biome" 36 | }, 37 | "[javascript]": { 38 | "editor.indentSize": 2, 39 | "editor.defaultFormatter": "biomejs.biome" 40 | }, 41 | "[tsx]": { 42 | "editor.indentSize": 2, 43 | "editor.defaultFormatter": "biomejs.biome" 44 | }, 45 | "[jsx]": { 46 | "editor.indentSize": 2, 47 | "editor.defaultFormatter": "biomejs.biome" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /alchemy-web/.gitignore: -------------------------------------------------------------------------------- 1 | .vitepress/cache 2 | .vitepress/.temp 3 | -------------------------------------------------------------------------------- /alchemy-web/.vitepress/theme/fonts/Inter.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sam-goodwin/alchemy/5ad508201ef5217e8a5ef47a9efc21e2c29b8031/alchemy-web/.vitepress/theme/fonts/Inter.ttf -------------------------------------------------------------------------------- /alchemy-web/blogs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Blog 4 | --- 5 | 6 | 28 | 29 | # Blog 30 | 31 | 39 | 40 |
41 |

No blog posts found. Make sure your blog posts have a date in the frontmatter.

42 |
43 | -------------------------------------------------------------------------------- /alchemy-web/docs/concepts/adoption.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 10 3 | title: Resource Adoption 4 | description: Learn how to adopt existing infrastructure with Alchemy resources instead of failing when resources already exist. 5 | --- 6 | 7 | # Resource Adoption 8 | 9 | When creating a resource, Alchemy will fail if a resource with the same name already exists. Resource adoption allows you to opt in to using the pre-existing resource instead. 10 | 11 | ## Basic Usage 12 | 13 | ```typescript 14 | // Without adoption - fails if bucket already exists 15 | const bucket = await R2Bucket("my-bucket", { 16 | name: "existing-bucket" 17 | }); 18 | 19 | // With adoption - uses existing bucket if it exists 20 | const bucket = await R2Bucket("my-bucket", { 21 | name: "existing-bucket", 22 | adopt: true 23 | }); 24 | ``` 25 | 26 | ## How It Works 27 | 28 | During the **create phase**, if a resource already exists: 29 | 30 | - **Without adoption** (default): Throws an "already exists" error 31 | - **With adoption**: Finds and adopts the existing resource 32 | 33 | ```typescript 34 | // Implementation pattern 35 | if (this.phase === "create") { 36 | try { 37 | // Try to create the resource 38 | return await createResource(props); 39 | } catch (err) { 40 | if (err.status === 409 && props.adopt) { 41 | // Adopt existing resource instead 42 | return await findExistingResource(props); 43 | } 44 | throw err; 45 | } 46 | } 47 | ``` 48 | 49 | ## Related Concepts 50 | 51 | - **[Resource](./resource.md)** - Understanding Alchemy's resource model 52 | - **[State](./state.md)** - How Alchemy tracks resource state 53 | -------------------------------------------------------------------------------- /alchemy-web/docs/guides/custom-resources.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 6 3 | title: Custom Resource 4 | description: Learn how to build your own custom infrastructure resources for Alchemy using AI-assistance. Extend Alchemy to support any cloud service or API. 5 | --- 6 | 7 | # Custom Resources 8 | 9 | In Alchemy, a Resource is "just a function". This makes it super easy to generate resources for your use-cases using Agentic IDEs like Cursor, Claude Code, Windsurf, etc. 10 | 11 | ## Cursorrules 12 | 13 | To start generating resources, copy Alchemy's [.cursorrules](https://github.com/sam-goodwin/alchemy/blob/main/.cursorrules) into your repo 14 | 15 | > [!NOTE] 16 | > All of Alchemy's "built-in" resouces are generated this way, so it is tried and tested. 17 | 18 | ## Simple Prompt Example 19 | 20 | As an example, let's show how easy it is to generate a resource for Neon's famous serverless `Database` Resource. 21 | 22 | It usually doesn't take much to get 90% of the way there - a simple prompt with a link to the API docs is a good start: 23 | 24 | > Create a Resource for managing a Neon Database 25 | > See: https://api-docs.neon.tech/reference/createprojectbranchdatabase 26 | 27 | This will generate the Resource implementation and tests. 28 | 29 | ## Resource Implememtation 30 | 31 | See the [Resource Documentation](../concepts/resource.md) for a comprehensive overview of a Resource. 32 | 33 | ## Test Suite Implementation 34 | 35 | See the [Testing Documentation](../concepts/testing.md) for a comprehensive overview of how to test your Resources. -------------------------------------------------------------------------------- /alchemy-web/docs/index.md: -------------------------------------------------------------------------------- 1 | # Alchemy 2 | 3 | Alchemy is an embeddable, zero-dependency Infrastructure-as-Code library in pure TypeScript that runs anywhere JavaScript runs. 4 | 5 | - [What is Alchemy?](./what-is-alchemy.md) 6 | - [Getting Started](./getting-started.md) 7 | 8 | -------------------------------------------------------------------------------- /alchemy-web/docs/providers/ai/html-file.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing HTML Files with AI in Alchemy 3 | description: Learn how to use Alchemy's AI provider to create, update, and manage HTML (.html) files within your projects. 4 | --- 5 | 6 | # HTMLFile 7 | 8 | The HTMLFile resource lets you generate HTML files using AI models like [OpenAI GPT-4](https://platform.openai.com/docs/models/gpt-4) or [Anthropic Claude](https://www.anthropic.com/claude). 9 | 10 | ## Minimal Example 11 | 12 | Creates a basic HTML file with AI-generated content. 13 | 14 | ```ts 15 | import { HTMLFile } from "alchemy/ai"; 16 | 17 | const page = await HTMLFile("landing", { 18 | path: "./public/index.html", 19 | prompt: "Generate a simple landing page with a hero section, features list, and contact form" 20 | }); 21 | ``` 22 | 23 | ## Generate with Context 24 | 25 | Uses file context to generate HTML that matches existing code. 26 | 27 | ```ts 28 | import { HTMLFile } from "alchemy/ai"; 29 | 30 | const component = await HTMLFile("card", { 31 | path: "./components/card.html", 32 | prompt: await alchemy` 33 | Create an HTML card component that matches the style of: 34 | ${alchemy.file("components/button.html")} 35 | ` 36 | }); 37 | ``` 38 | 39 | ## Custom Model Configuration 40 | 41 | Specifies a custom model and temperature for more controlled generation. 42 | 43 | ```ts 44 | import { HTMLFile } from "alchemy/ai"; 45 | 46 | const form = await HTMLFile("contact-form", { 47 | path: "./components/form.html", 48 | prompt: "Generate an accessible contact form with validation", 49 | model: { 50 | id: "claude-3-opus-20240229", 51 | provider: "anthropic" 52 | }, 53 | temperature: 0.2 54 | }); 55 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/aws-control/application-signals/discovery.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing AWS ApplicationSignals Discoverys with Alchemy 3 | description: Learn how to create, update, and manage AWS ApplicationSignals Discoverys using Alchemy Cloud Control. 4 | --- 5 | 6 | # Discovery 7 | 8 | The Discovery resource lets you manage [AWS ApplicationSignals Discoverys](https://docs.aws.amazon.com/applicationsignals/latest/userguide/) for tracking application performance and signals. 9 | 10 | ## Minimal Example 11 | 12 | Create a basic Discovery resource with minimal properties. 13 | 14 | ```ts 15 | import AWS from "alchemy/aws/control"; 16 | 17 | const basicDiscovery = await AWS.ApplicationSignals.Discovery("basic-discovery", { 18 | adopt: false // Default is false; it will fail if the resource already exists 19 | }); 20 | ``` 21 | 22 | ## Advanced Configuration 23 | 24 | Configure a Discovery resource with the option to adopt an existing resource. 25 | 26 | ```ts 27 | const advancedDiscovery = await AWS.ApplicationSignals.Discovery("advanced-discovery", { 28 | adopt: true // This will adopt the existing resource instead of failing 29 | }); 30 | ``` 31 | 32 | ## Monitoring Discovery Details 33 | 34 | Create a Discovery resource and monitor its properties such as ARN and timestamps. 35 | 36 | ```ts 37 | const monitoredDiscovery = await AWS.ApplicationSignals.Discovery("monitored-discovery", { 38 | adopt: false 39 | }); 40 | 41 | // Log details about the Discovery resource 42 | console.log(`ARN: ${monitoredDiscovery.Arn}`); 43 | console.log(`Creation Time: ${monitoredDiscovery.CreationTime}`); 44 | console.log(`Last Update Time: ${monitoredDiscovery.LastUpdateTime}`); 45 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/aws-control/fraud-detector/label.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing AWS FraudDetector Labels with Alchemy 3 | description: Learn how to create, update, and manage AWS FraudDetector Labels using Alchemy Cloud Control. 4 | --- 5 | 6 | # Label 7 | 8 | The Label resource lets you manage [AWS FraudDetector Labels](https://docs.aws.amazon.com/frauddetector/latest/userguide/) for identifying and categorizing events for fraud detection. 9 | 10 | ## Minimal Example 11 | 12 | Create a basic label with just the required properties and a description. 13 | 14 | ```ts 15 | import AWS from "alchemy/aws/control"; 16 | 17 | const fraudLabel = await AWS.FraudDetector.Label("fraud-label", { 18 | name: "SuspiciousTransaction", 19 | description: "Label for transactions flagged as suspicious" 20 | }); 21 | ``` 22 | 23 | ## Advanced Configuration 24 | 25 | Create a label with tags for better organization and management. 26 | 27 | ```ts 28 | const taggedLabel = await AWS.FraudDetector.Label("tagged-fraud-label", { 29 | name: "HighRiskTransaction", 30 | description: "Label for transactions identified as high risk", 31 | tags: [ 32 | { key: "Environment", value: "Production" }, 33 | { key: "Team", value: "FraudDetection" } 34 | ] 35 | }); 36 | ``` 37 | 38 | ## Update Existing Label 39 | 40 | Adopt an existing label instead of failing if it already exists. 41 | 42 | ```ts 43 | const existingLabel = await AWS.FraudDetector.Label("existing-fraud-label", { 44 | name: "ReturningCustomer", 45 | description: "Label for transactions from returning customers", 46 | adopt: true // This will adopt if the label already exists 47 | }); 48 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/aws-control/glue/registry.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing AWS Glue Registrys with Alchemy 3 | description: Learn how to create, update, and manage AWS Glue Registrys using Alchemy Cloud Control. 4 | --- 5 | 6 | # Registry 7 | 8 | The Registry resource lets you manage [AWS Glue Registrys](https://docs.aws.amazon.com/glue/latest/userguide/) for organizing and managing schemas in AWS Glue Data Catalog. 9 | 10 | ## Minimal Example 11 | 12 | Create a basic registry with a name and description. 13 | 14 | ```ts 15 | import AWS from "alchemy/aws/control"; 16 | 17 | const basicRegistry = await AWS.Glue.Registry("basic-registry", { 18 | name: "MyDataRegistry", 19 | description: "This registry holds schemas for my data assets." 20 | }); 21 | ``` 22 | 23 | ## Advanced Configuration 24 | 25 | Configure a registry with tags for better management and organization. 26 | 27 | ```ts 28 | const taggedRegistry = await AWS.Glue.Registry("tagged-registry", { 29 | name: "MyTaggedDataRegistry", 30 | description: "This registry holds schemas for my data assets with tags.", 31 | tags: [ 32 | { key: "Environment", value: "Production" }, 33 | { key: "Department", value: "Finance" } 34 | ] 35 | }); 36 | ``` 37 | 38 | ## Adoption of Existing Registry 39 | 40 | Adopt an existing registry instead of failing if it already exists. 41 | 42 | ```ts 43 | const adoptRegistry = await AWS.Glue.Registry("adopt-registry", { 44 | name: "ExistingDataRegistry", 45 | description: "This registry will adopt an existing resource.", 46 | adopt: true 47 | }); 48 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/aws-control/health-imaging/datastore.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing AWS HealthImaging Datastores with Alchemy 3 | description: Learn how to create, update, and manage AWS HealthImaging Datastores using Alchemy Cloud Control. 4 | --- 5 | 6 | # Datastore 7 | 8 | The Datastore resource lets you manage [AWS HealthImaging Datastores](https://docs.aws.amazon.com/healthimaging/latest/userguide/) for storing and retrieving medical imaging data. 9 | 10 | ## Minimal Example 11 | 12 | Create a basic HealthImaging Datastore with a specified name and an optional KMS key for encryption. 13 | 14 | ```ts 15 | import AWS from "alchemy/aws/control"; 16 | 17 | const basicDatastore = await AWS.HealthImaging.Datastore("basic-datastore", { 18 | DatastoreName: "patient-imaging-data", 19 | KmsKeyArn: "arn:aws:kms:us-west-2:123456789012:key/abcd1234-ab12-cd34-ef56-1234567890ab" 20 | }); 21 | ``` 22 | 23 | ## Advanced Configuration 24 | 25 | Configure a datastore with tags for better resource management and organization. 26 | 27 | ```ts 28 | const taggedDatastore = await AWS.HealthImaging.Datastore("tagged-datastore", { 29 | DatastoreName: "research-study-images", 30 | KmsKeyArn: "arn:aws:kms:us-west-2:123456789012:key/abcd1234-ab12-cd34-ef56-1234567890ab", 31 | Tags: { 32 | Project: "Medical Research", 33 | Environment: "Production" 34 | } 35 | }); 36 | ``` 37 | 38 | ## Adoption of Existing Resources 39 | 40 | Adopt an existing HealthImaging Datastore instead of failing if the resource already exists. 41 | 42 | ```ts 43 | const adoptExistingDatastore = await AWS.HealthImaging.Datastore("adopt-datastore", { 44 | DatastoreName: "legacy-datastore", 45 | adopt: true 46 | }); 47 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/aws-control/ivs/public-key.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing AWS IVS PublicKeys with Alchemy 3 | description: Learn how to create, update, and manage AWS IVS PublicKeys using Alchemy Cloud Control. 4 | --- 5 | 6 | # PublicKey 7 | 8 | The PublicKey resource lets you manage [AWS IVS PublicKeys](https://docs.aws.amazon.com/ivs/latest/userguide/) for securely signing video streams. This resource allows you to create and manage public keys used in the signing process of video streams. 9 | 10 | ## Minimal Example 11 | 12 | Create a basic IVS PublicKey with required properties and one optional property: 13 | 14 | ```ts 15 | import AWS from "alchemy/aws/control"; 16 | 17 | const publicKey = await AWS.IVS.PublicKey("myPublicKey", { 18 | PublicKeyMaterial: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC1...", 19 | Name: "MyIVSPublicKey" 20 | }); 21 | ``` 22 | 23 | ## Advanced Configuration 24 | 25 | Configure an IVS PublicKey with tags for better resource management: 26 | 27 | ```ts 28 | const taggedPublicKey = await AWS.IVS.PublicKey("taggedPublicKey", { 29 | PublicKeyMaterial: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC2...", 30 | Name: "TaggedIVSPublicKey", 31 | Tags: [ 32 | { Key: "Environment", Value: "Production" }, 33 | { Key: "Project", Value: "LiveStream" } 34 | ] 35 | }); 36 | ``` 37 | 38 | ## Adoption of Existing Resource 39 | 40 | Adopt an existing IVS PublicKey instead of creating a new one if it already exists: 41 | 42 | ```ts 43 | const existingPublicKey = await AWS.IVS.PublicKey("existingPublicKey", { 44 | PublicKeyMaterial: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC3...", 45 | Name: "ExistingIVSPublicKey", 46 | adopt: true 47 | }); 48 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/aws-control/macie/session.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing AWS Macie Sessions with Alchemy 3 | description: Learn how to create, update, and manage AWS Macie Sessions using Alchemy Cloud Control. 4 | --- 5 | 6 | # Session 7 | 8 | The Session resource lets you manage [AWS Macie Sessions](https://docs.aws.amazon.com/macie/latest/userguide/) for data security and compliance within your AWS environment. AWS Macie helps you discover and protect sensitive data in your AWS accounts. 9 | 10 | ## Minimal Example 11 | 12 | Create a basic Macie session with default settings. 13 | 14 | ```ts 15 | import AWS from "alchemy/aws/control"; 16 | 17 | const macieSession = await AWS.Macie.Session("basicMacieSession", { 18 | Status: "ENABLED", 19 | FindingPublishingFrequency: "FIFTEEN_MINUTES" 20 | }); 21 | ``` 22 | 23 | ## Advanced Configuration 24 | 25 | Configure a Macie session with an advanced setting for publishing findings. 26 | 27 | ```ts 28 | const advancedMacieSession = await AWS.Macie.Session("advancedMacieSession", { 29 | Status: "ENABLED", 30 | FindingPublishingFrequency: "ONE_HOUR" 31 | }); 32 | ``` 33 | 34 | ## Session with Adoption 35 | 36 | Create a Macie session and adopt it if it already exists. 37 | 38 | ```ts 39 | const adoptMacieSession = await AWS.Macie.Session("adoptMacieSession", { 40 | Status: "DISABLED", 41 | FindingPublishingFrequency: "SIX_HOURS", 42 | adopt: true 43 | }); 44 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/aws-control/route53profiles/profile.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing AWS Route53Profiles Profiles with Alchemy 3 | description: Learn how to create, update, and manage AWS Route53Profiles Profiles using Alchemy Cloud Control. 4 | --- 5 | 6 | # Profile 7 | 8 | The Profile resource lets you manage [AWS Route53Profiles Profiles](https://docs.aws.amazon.com/route53profiles/latest/userguide/) for configuring and managing DNS settings in AWS Route 53. 9 | 10 | ## Minimal Example 11 | 12 | Create a basic profile with required properties and one optional tag. 13 | 14 | ```ts 15 | import AWS from "alchemy/aws/control"; 16 | 17 | const profile = await AWS.Route53Profiles.Profile("basicProfile", { 18 | name: "BasicProfile", 19 | tags: [ 20 | { 21 | key: "Environment", 22 | value: "Development" 23 | } 24 | ] 25 | }); 26 | ``` 27 | 28 | ## Advanced Configuration 29 | 30 | Configure a profile with additional properties such as the adoption of existing resources. 31 | 32 | ```ts 33 | const advancedProfile = await AWS.Route53Profiles.Profile("advancedProfile", { 34 | name: "AdvancedProfile", 35 | adopt: true, 36 | tags: [ 37 | { 38 | key: "Project", 39 | value: "Route53Migration" 40 | }, 41 | { 42 | key: "Owner", 43 | value: "DevTeam" 44 | } 45 | ] 46 | }); 47 | ``` 48 | 49 | ## Resource Adoption 50 | 51 | Create a profile while adopting an existing resource if it already exists. 52 | 53 | ```ts 54 | const adoptedProfile = await AWS.Route53Profiles.Profile("adoptedProfile", { 55 | name: "AdoptedProfile", 56 | adopt: true 57 | }); 58 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/aws-control/security-hub/hub.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing AWS SecurityHub Hubs with Alchemy 3 | description: Learn how to create, update, and manage AWS SecurityHub Hubs using Alchemy Cloud Control. 4 | --- 5 | 6 | # Hub 7 | 8 | The Hub resource lets you manage [AWS SecurityHub Hubs](https://docs.aws.amazon.com/securityhub/latest/userguide/) for centralizing security findings and compliance checks across your AWS accounts. 9 | 10 | ## Minimal Example 11 | 12 | Create a basic SecurityHub Hub with default settings and enable default standards. 13 | 14 | ```ts 15 | import AWS from "alchemy/aws/control"; 16 | 17 | const securityHubHub = await AWS.SecurityHub.Hub("defaultSecurityHub", { 18 | EnableDefaultStandards: true, 19 | ControlFindingGenerator: "AWS" 20 | }); 21 | ``` 22 | 23 | ## Advanced Configuration 24 | 25 | Configure a SecurityHub Hub with automatic control enabling and specific tags for management. 26 | 27 | ```ts 28 | const advancedSecurityHubHub = await AWS.SecurityHub.Hub("advancedSecurityHub", { 29 | EnableDefaultStandards: true, 30 | AutoEnableControls: true, 31 | Tags: { 32 | Environment: "Production", 33 | Department: "Security" 34 | } 35 | }); 36 | ``` 37 | 38 | ## Adoption of Existing Resources 39 | 40 | If you need to adopt an existing SecurityHub Hub without failing if it already exists, you can set the `adopt` property to true. 41 | 42 | ```ts 43 | const adoptedSecurityHubHub = await AWS.SecurityHub.Hub("adoptedSecurityHub", { 44 | EnableDefaultStandards: true, 45 | adopt: true 46 | }); 47 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/aws-control/service-catalog/portfolio-share.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing AWS ServiceCatalog PortfolioShares with Alchemy 3 | description: Learn how to create, update, and manage AWS ServiceCatalog PortfolioShares using Alchemy Cloud Control. 4 | --- 5 | 6 | # PortfolioShare 7 | 8 | The PortfolioShare resource lets you manage [AWS ServiceCatalog PortfolioShares](https://docs.aws.amazon.com/servicecatalog/latest/userguide/) for sharing portfolios across AWS accounts. 9 | 10 | ## Minimal Example 11 | 12 | Create a basic PortfolioShare with required properties and one optional property. 13 | 14 | ```ts 15 | import AWS from "alchemy/aws/control"; 16 | 17 | const portfolioShare = await AWS.ServiceCatalog.PortfolioShare("basicPortfolioShare", { 18 | AccountId: "123456789012", 19 | PortfolioId: "portfolio-abc-123", 20 | AcceptLanguage: "en" 21 | }); 22 | ``` 23 | 24 | ## Advanced Configuration 25 | 26 | Configure a PortfolioShare to enable sharing of tag options. 27 | 28 | ```ts 29 | const advancedPortfolioShare = await AWS.ServiceCatalog.PortfolioShare("advancedPortfolioShare", { 30 | AccountId: "123456789013", 31 | PortfolioId: "portfolio-def-456", 32 | ShareTagOptions: true 33 | }); 34 | ``` 35 | 36 | ## Adopting Existing Resources 37 | 38 | Configure a PortfolioShare to adopt existing resources instead of failing if the resource already exists. 39 | 40 | ```ts 41 | const adoptPortfolioShare = await AWS.ServiceCatalog.PortfolioShare("adoptExistingPortfolioShare", { 42 | AccountId: "123456789014", 43 | PortfolioId: "portfolio-ghi-789", 44 | adopt: true 45 | }); 46 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/aws/bucket.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing AWS S3 Buckets with Alchemy 3 | description: Learn how to create, configure, and manage AWS S3 Buckets using Alchemy for object storage in your cloud applications. 4 | --- 5 | 6 | # Bucket 7 | 8 | The Bucket resource lets you create and manage [Amazon S3 buckets](https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html) for object storage. 9 | 10 | ## Minimal Example 11 | 12 | Create a basic S3 bucket with default settings: 13 | 14 | ```ts 15 | import { Bucket } from "alchemy/aws"; 16 | 17 | const bucket = await Bucket("storage", { 18 | bucketName: "my-app-storage", 19 | tags: { 20 | Environment: "production" 21 | } 22 | }); 23 | ``` 24 | 25 | ## Bucket with Versioning 26 | 27 | Create a bucket with versioning enabled for change tracking: 28 | 29 | ```ts 30 | import { Bucket } from "alchemy/aws"; 31 | 32 | const versionedBucket = await Bucket("document-archive", { 33 | bucketName: "document-archive", 34 | tags: { 35 | Environment: "production", 36 | Purpose: "document-storage", 37 | Versioning: "enabled" 38 | } 39 | }); 40 | ``` 41 | 42 | ## Development Bucket 43 | 44 | Create a temporary bucket for development/testing: 45 | 46 | ```ts 47 | import { Bucket } from "alchemy/aws"; 48 | 49 | const devBucket = await Bucket("dev-testing", { 50 | bucketName: "dev-testing", 51 | tags: { 52 | Environment: "development", 53 | Temporary: "true" 54 | } 55 | }); 56 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/aws/policy-attachment.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing AWS IAM Policy Attachments with Alchemy 3 | description: Learn how to attach AWS IAM Policies to Roles, Users, or Groups using Alchemy to manage permissions effectively. 4 | --- 5 | 6 | # PolicyAttachment 7 | 8 | The PolicyAttachment resource lets you attach [AWS IAM policies](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html) to IAM roles. 9 | 10 | ## Minimal Example 11 | 12 | Attach an AWS managed policy to a role: 13 | 14 | ```ts 15 | import { PolicyAttachment } from "alchemy/aws"; 16 | 17 | const adminAccess = await PolicyAttachment("admin-policy", { 18 | policyArn: "arn:aws:iam::aws:policy/AdministratorAccess", 19 | roleName: role.name 20 | }); 21 | ``` 22 | 23 | ## Attach Custom Policy 24 | 25 | Attach a custom policy created with the Policy resource: 26 | 27 | ```ts 28 | import { PolicyAttachment } from "alchemy/aws"; 29 | 30 | const customPolicy = await PolicyAttachment("custom-policy", { 31 | policyArn: policy.arn, 32 | roleName: role.name 33 | }); 34 | ``` 35 | 36 | ## Multiple Policy Attachments 37 | 38 | Attach multiple policies to a role: 39 | 40 | ```ts 41 | import { PolicyAttachment } from "alchemy/aws"; 42 | 43 | const s3Access = await PolicyAttachment("s3-access", { 44 | policyArn: "arn:aws:iam::aws:policy/AmazonS3FullAccess", 45 | roleName: role.name 46 | }); 47 | 48 | const sqsAccess = await PolicyAttachment("sqs-access", { 49 | policyArn: "arn:aws:iam::aws:policy/AmazonSQSFullAccess", 50 | roleName: role.name 51 | }); 52 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/aws/queue.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing AWS SQS Queues with Alchemy 3 | description: Learn how to create, configure, and manage AWS Simple Queue Service (SQS) queues using Alchemy for message queuing. 4 | --- 5 | 6 | # Queue 7 | 8 | The Queue resource lets you create and manage [Amazon Simple Queue Service (SQS)](https://aws.amazon.com/sqs/) queues for reliable message delivery between distributed application components. 9 | 10 | ## Minimal Example 11 | 12 | Create a standard SQS queue with default settings: 13 | 14 | ```ts 15 | import { Queue } from "alchemy/aws"; 16 | 17 | const queue = await Queue("my-queue", { 18 | queueName: "my-queue", 19 | tags: { 20 | Environment: "production" 21 | } 22 | }); 23 | ``` 24 | 25 | ## FIFO Queue 26 | 27 | Create a FIFO queue with content-based deduplication: 28 | 29 | ```ts 30 | import { Queue } from "alchemy/aws"; 31 | 32 | const fifoQueue = await Queue("orders-queue", { 33 | queueName: "orders-queue.fifo", 34 | fifo: true, 35 | contentBasedDeduplication: true, 36 | visibilityTimeout: 30 37 | }); 38 | ``` 39 | 40 | ## Custom Queue Configuration 41 | 42 | Create a queue with custom message handling settings: 43 | 44 | ```ts 45 | import { Queue } from "alchemy/aws"; 46 | 47 | const customQueue = await Queue("large-messages", { 48 | queueName: "large-messages", 49 | messageRetentionPeriod: 345600, // 4 days 50 | maximumMessageSize: 262144, // 256 KB 51 | visibilityTimeout: 60, 52 | delaySeconds: 5, 53 | receiveMessageWaitTimeSeconds: 20 54 | }); 55 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/aws/ses.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing AWS SES with Alchemy 3 | description: Learn how to configure AWS Simple Email Service (SES) for sending emails using Alchemy in your applications. 4 | --- 5 | 6 | # SES 7 | 8 | The SES resource lets you create and manage [Amazon Simple Email Service (SES)](https://docs.aws.amazon.com/ses/latest/dg/Welcome.html) configuration sets and email identities. 9 | 10 | ## Minimal Example 11 | 12 | Create a basic configuration set for sending emails: 13 | 14 | ```ts 15 | import { SES } from "alchemy/aws"; 16 | 17 | const configSet = await SES("email-config", { 18 | configurationSetName: "my-email-config", 19 | sendingOptions: { 20 | SendingEnabled: true 21 | } 22 | }); 23 | ``` 24 | 25 | ## Create Domain Identity with DKIM 26 | 27 | Create and verify a domain identity with DKIM signing enabled: 28 | 29 | ```ts 30 | const domainIdentity = await SES("domain-identity", { 31 | emailIdentity: "example.com", 32 | enableDkim: true, 33 | tags: { 34 | Environment: "production" 35 | } 36 | }); 37 | ``` 38 | 39 | ## Configure Tracking Options 40 | 41 | Set up tracking options for open and click tracking: 42 | 43 | ```ts 44 | const emailConfig = await SES("tracking-config", { 45 | configurationSetName: "tracking-config", 46 | trackingOptions: { 47 | CustomRedirectDomain: "click.example.com" 48 | }, 49 | suppressionOptions: { 50 | SuppressedReasons: ["BOUNCE", "COMPLAINT"] 51 | } 52 | }); 53 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/aws/table.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing AWS DynamoDB Tables with Alchemy 3 | description: Learn how to create, configure, and manage AWS DynamoDB Tables using Alchemy for NoSQL database solutions. 4 | --- 5 | 6 | # DynamoDB Table 7 | 8 | The Table resource lets you create and manage [Amazon DynamoDB tables](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html) for NoSQL database storage. 9 | 10 | ## Minimal Example 11 | 12 | Create a basic table with just a partition key: 13 | 14 | ```ts 15 | import { Table } from "alchemy/aws"; 16 | 17 | const table = await Table("users", { 18 | tableName: "users", 19 | partitionKey: { 20 | name: "userId", 21 | type: "S" 22 | } 23 | }); 24 | ``` 25 | 26 | ## Table with Sort Key 27 | 28 | Add a sort key to enable range queries and composite keys: 29 | 30 | ```ts 31 | const table = await Table("events", { 32 | tableName: "events", 33 | partitionKey: { 34 | name: "deviceId", 35 | type: "S" 36 | }, 37 | sortKey: { 38 | name: "timestamp", 39 | type: "N" 40 | } 41 | }); 42 | ``` 43 | 44 | ## Provisioned Capacity 45 | 46 | Configure provisioned read/write capacity for predictable workloads: 47 | 48 | ```ts 49 | const table = await Table("orders", { 50 | tableName: "orders", 51 | partitionKey: { 52 | name: "orderId", 53 | type: "S" 54 | }, 55 | billingMode: "PROVISIONED", 56 | readCapacity: 100, 57 | writeCapacity: 50, 58 | tags: { 59 | Environment: "production" 60 | } 61 | }); 62 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/cloudflare/account-id.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Getting Cloudflare Account ID with Alchemy 3 | description: Learn how to retrieve your Cloudflare Account ID programmatically using Alchemy for use in other resource configurations. 4 | --- 5 | 6 | # AccountId 7 | 8 | The AccountId resource retrieves a Cloudflare [Account ID](https://developers.cloudflare.com/fundamentals/setup/find-account-and-zone-ids/) for use with other Cloudflare resources. 9 | 10 | ## Minimal Example 11 | 12 | Get the account ID from environment variables or API token: 13 | 14 | ```ts 15 | import { AccountId } from "alchemy/cloudflare"; 16 | 17 | const accountId = await AccountId("my-account"); 18 | ``` 19 | 20 | ## With Explicit API Key 21 | 22 | Provide an API key and email directly: 23 | 24 | ```ts 25 | import { AccountId } from "alchemy/cloudflare"; 26 | 27 | const accountId = await AccountId("my-account", { 28 | apiKey: alchemy.secret(process.env.CF_API_KEY), 29 | email: "user@example.com" 30 | }); 31 | ``` 32 | 33 | ## Bind to a Worker 34 | 35 | Use the account ID with a Worker: 36 | 37 | ```ts 38 | import { Worker, AccountId } from "alchemy/cloudflare"; 39 | 40 | const accountId = await AccountId("my-account"); 41 | 42 | await Worker("my-worker", { 43 | name: "my-worker", 44 | script: "console.log('Hello, world!')", 45 | accountId: accountId 46 | }); 47 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/cloudflare/assets.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing Cloudflare Assets (Static) with Alchemy 3 | description: Learn how to deploy and manage static assets on Cloudflare using Alchemy for optimal performance and delivery. 4 | --- 5 | 6 | # Assets 7 | 8 | The Assets resource lets you add [static assets](https://developers.cloudflare.com/workers/configuration/sites/) to your Cloudflare Workers. 9 | 10 | ## Minimal Example 11 | 12 | Create a basic assets bundle from a local directory: 13 | 14 | ```ts 15 | import { Assets } from "alchemy/cloudflare"; 16 | 17 | const staticAssets = await Assets("static", { 18 | path: "./src/assets" 19 | }); 20 | ``` 21 | 22 | ## Bind to a Worker 23 | 24 | Bind the assets to a worker to serve them: 25 | 26 | ```ts 27 | import { Worker, Assets } from "alchemy/cloudflare"; 28 | 29 | const staticAssets = await Assets("static", { 30 | path: "./src/assets" 31 | }); 32 | 33 | const worker = await Worker("frontend", { 34 | name: "frontend-worker", 35 | entrypoint: "./src/worker.ts", 36 | bindings: { 37 | ASSETS: staticAssets 38 | } 39 | }); 40 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/cloudflare/custom-domain.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing Cloudflare Custom Domains with Alchemy 3 | description: Learn how to configure and manage Custom Domains for your Cloudflare services (like Pages, Workers) using Alchemy. 4 | --- 5 | 6 | # CustomDomain 7 | 8 | The CustomDomain resource lets you attach a [custom domain](https://developers.cloudflare.com/workers/configuration/routing/custom-domains/) to a Cloudflare Worker. 9 | 10 | ## Minimal Example 11 | 12 | Bind a domain to a worker: 13 | 14 | ```ts 15 | import { Worker, CustomDomain } from "alchemy/cloudflare"; 16 | 17 | const worker = await Worker("api", { 18 | name: "api-worker", 19 | entrypoint: "./src/api.ts" 20 | }); 21 | 22 | const domain = await CustomDomain("api-domain", { 23 | name: "api.example.com", 24 | zoneId: "YOUR_ZONE_ID", 25 | workerName: worker.name 26 | }); 27 | ``` 28 | 29 | ## With Environment 30 | 31 | Bind a domain to a specific worker environment: 32 | 33 | ```ts 34 | import { Worker, CustomDomain } from "alchemy/cloudflare"; 35 | 36 | const domain = await CustomDomain("staging-domain", { 37 | name: "staging.example.com", 38 | zoneId: "YOUR_ZONE_ID", 39 | workerName: "my-worker", 40 | environment: "staging" 41 | }); 42 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/cloudflare/nuxt.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Deploying Nuxt Applications to Cloudflare with Alchemy 3 | description: Learn how to deploy Nuxt.js applications to Cloudflare Pages/Workers using Alchemy for a seamless experience. 4 | --- 5 | 6 | # Nuxt 7 | 8 | Deploy a [Nuxt](https://nuxt.com) application to Cloudflare Pages with automatically configured defaults. 9 | 10 | ## Minimal Example 11 | 12 | Deploy a basic Nuxt site with default settings. 13 | 14 | ```ts 15 | import { Nuxt } from "alchemy/cloudflare"; 16 | 17 | const nuxtSite = await Nuxt("my-nuxt-app"); 18 | ``` 19 | 20 | ## Custom Bindings 21 | 22 | Add database and other bindings to your Nuxt app. 23 | 24 | ```ts 25 | import { Nuxt, D1Database } from "alchemy/cloudflare"; 26 | 27 | const db = await D1Database("my-db", { 28 | name: "my-db" 29 | }); 30 | 31 | const nuxtSiteWithDb = await Nuxt("my-nuxt-app-with-db", { 32 | command: "npm run build:cloudflare", // Custom build command 33 | bindings: { 34 | DB: db // Add custom bindings 35 | } 36 | }); 37 | ``` 38 | 39 | ## Bind to a Worker 40 | 41 | Bind a Nuxt app to a Cloudflare Worker. 42 | 43 | ```ts 44 | import { Worker, Nuxt } from "alchemy/cloudflare"; 45 | 46 | const nuxtApp = await Nuxt("my-nuxt-app", { 47 | command: "npm run build" 48 | }); 49 | 50 | await Worker("my-worker", { 51 | name: "my-worker", 52 | script: "console.log('Hello, world!')", 53 | bindings: { 54 | NUXT: nuxtApp 55 | } 56 | }); 57 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/cloudflare/permission-groups.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing Cloudflare Permission Groups with Alchemy 3 | description: Learn how to retrieve Cloudflare API Permission Groups using Alchemy to help construct API token policies. 4 | --- 5 | 6 | # PermissionGroups 7 | 8 | Lists all permission groups available for a Cloudflare account and returns a typed map of permission names to their IDs. Used when creating API tokens for Cloudflare services like R2. 9 | 10 | ## Minimal Example 11 | 12 | Get all permission groups including those for R2: 13 | 14 | ```ts 15 | import { PermissionGroups } from "alchemy/cloudflare"; 16 | 17 | const permissions = await PermissionGroups("cloudflare-permissions"); 18 | ``` 19 | 20 | ## Create API Token with Permissions 21 | 22 | Use with AccountApiToken to create a token with proper permissions: 23 | 24 | ```ts 25 | import { PermissionGroups, AccountApiToken } from "alchemy/cloudflare"; 26 | 27 | const permissions = await PermissionGroups("cloudflare-permissions"); 28 | 29 | const token = await AccountApiToken("r2-token", { 30 | name: "R2 Read-Only Token", 31 | policies: [{ 32 | effect: "allow", 33 | resources: { 34 | "com.cloudflare.edge.r2.bucket.abc123_default_my-bucket": "*" 35 | }, 36 | permissionGroups: [{ 37 | id: permissions["Workers R2 Storage Bucket Item Read"].id 38 | }] 39 | }] 40 | }); 41 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/cloudflare/vite.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Deploying Vite Applications to Cloudflare with Alchemy 3 | description: Learn how to deploy Vite.js applications to Cloudflare Pages/Workers using Alchemy for fast and efficient builds. 4 | --- 5 | 6 | # Vite 7 | 8 | Deploy a [Vite](https://vitejs.dev/) application to Cloudflare Workers with automatic configuration. 9 | 10 | ## Minimal Example 11 | 12 | Deploy a basic Vite app with default settings. 13 | 14 | ```ts 15 | import { Vite } from "alchemy/cloudflare"; 16 | 17 | const app = await Vite("my-vite-app", { 18 | name: "my-vite-app", 19 | command: "bun run build" 20 | }); 21 | ``` 22 | 23 | ## With Custom Bindings 24 | 25 | Add database and environment bindings to the Vite app. 26 | 27 | ```ts 28 | import { Vite, D1Database } from "alchemy/cloudflare"; 29 | 30 | const db = await D1Database("my-db", { 31 | name: "my-db" 32 | }); 33 | 34 | const app = await Vite("my-vite-app", { 35 | name: "my-vite-app", 36 | bindings: { 37 | DB: db, 38 | API_KEY: alchemy.secret(process.env.API_KEY) 39 | } 40 | }); 41 | ``` 42 | 43 | ## With Custom Build Configuration 44 | 45 | Customize the build command and output paths. 46 | 47 | ```ts 48 | import { Vite } from "alchemy/cloudflare"; 49 | 50 | const app = await Vite("my-vite-app", { 51 | name: "my-vite-app", 52 | command: "bun run test && bun run build:production", 53 | main: "./dist/worker.js", 54 | assets: "./dist/client" 55 | }); 56 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/cloudflare/workflow.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing Cloudflare Workflows with Alchemy 3 | description: Learn how to create and manage Cloudflare Workflows using Alchemy to orchestrate and automate tasks. 4 | --- 5 | 6 | # Workflow 7 | 8 | A [Cloudflare Workflow](https://developers.cloudflare.com/workers/configuration/workflows/) allows you to define reusable logic that can be shared across multiple Workers. 9 | 10 | ## Minimal Example 11 | 12 | Create a basic workflow that can be bound to a Worker. 13 | 14 | ```ts 15 | import { Workflow } from "alchemy/cloudflare"; 16 | 17 | const workflow = await Workflow("my-workflow", { 18 | workflowName: "my-workflow", 19 | className: "MyWorkflow" 20 | }); 21 | ``` 22 | 23 | ## Use a Workflow Defined in Another Script 24 | 25 | Reference a workflow implemented in a different worker script using `scriptName`. 26 | 27 | ```ts 28 | import { Workflow } from "alchemy/cloudflare"; 29 | 30 | const workflow = await Workflow("shared-workflow", { 31 | workflowName: "my-workflow", 32 | className: "MyWorkflow", 33 | scriptName: "shared-worker" 34 | }); 35 | ``` 36 | 37 | ## Bind to a Worker 38 | 39 | Bind a workflow to a Worker to use its functionality. 40 | 41 | ```ts 42 | import { Worker, Workflow } from "alchemy/cloudflare"; 43 | 44 | const workflow = await Workflow("my-workflow", { 45 | workflowName: "my-workflow", 46 | className: "MyWorkflow" 47 | }); 48 | 49 | await Worker("my-worker", { 50 | name: "my-worker", 51 | script: "console.log('Hello, world!')", 52 | bindings: { 53 | WORKFLOW: workflow 54 | } 55 | }); 56 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/dns/import-dns.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Importing DNS Records into Alchemy 3 | description: Learn how to import existing DNS records from your provider into Alchemy for management with Infrastructure-as-Code. 4 | --- 5 | 6 | # ImportDnsRecords 7 | 8 | The ImportDnsRecords resource lets you import DNS records from any domain using [Cloudflare's DNS-over-HTTPS API](https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-https/). 9 | 10 | ## Minimal Example 11 | 12 | Import all default DNS record types for a domain. 13 | 14 | ```ts 15 | import { ImportDnsRecords } from "alchemy/dns"; 16 | 17 | const dnsRecords = await ImportDnsRecords("example-com", { 18 | domain: "example.com" 19 | }); 20 | ``` 21 | 22 | ## Import Specific Record Types 23 | 24 | Import only specified DNS record types. 25 | 26 | ```ts 27 | import { ImportDnsRecords } from "alchemy/dns"; 28 | 29 | const records = await ImportDnsRecords("example-com", { 30 | domain: "example.com", 31 | recordTypes: ["A", "MX"] 32 | }); 33 | ``` 34 | 35 | ## Transfer Records to Cloudflare 36 | 37 | Import DNS records and transfer them to a Cloudflare zone. 38 | 39 | ```ts 40 | import { ImportDnsRecords, DnsRecords } from "alchemy/dns"; 41 | 42 | const dnsRecords = await ImportDnsRecords("dns-records", { 43 | domain: "example.com" 44 | }); 45 | 46 | await DnsRecords("transfer-records", { 47 | zoneId: zone.id, 48 | records: dnsRecords.records 49 | }); 50 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/esbuild/bundle.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Bundling Code with esbuild in Alchemy 3 | description: Learn how to use Alchemy's esbuild provider to bundle JavaScript and TypeScript code for your serverless functions and web applications. 4 | --- 5 | 6 | # Bundle 7 | 8 | The Bundle resource uses [esbuild](https://esbuild.github.io/) to bundle JavaScript and TypeScript files into optimized output. 9 | 10 | ## Minimal Example 11 | 12 | Bundle a TypeScript file into ESM format: 13 | 14 | ```ts 15 | import { Bundle } from "alchemy/esbuild"; 16 | 17 | const bundle = await Bundle("handler", { 18 | entryPoint: "src/handler.ts", 19 | format: "esm" 20 | }); 21 | ``` 22 | 23 | ## Bundle with Output Directory 24 | 25 | Specify an output directory and additional build options: 26 | 27 | ```ts 28 | const bundle = await Bundle("api", { 29 | entryPoint: "src/api.ts", 30 | outdir: ".build", 31 | format: "esm", 32 | platform: "node", 33 | target: "node18", 34 | minify: true, 35 | sourcemap: true 36 | }); 37 | ``` 38 | 39 | ## Bundle with External Dependencies 40 | 41 | Exclude packages from the bundle: 42 | 43 | ```ts 44 | const bundle = await Bundle("app", { 45 | entryPoint: "src/app.ts", 46 | format: "esm", 47 | external: ["aws-sdk", "lodash"], 48 | platform: "node" 49 | }); 50 | ``` 51 | 52 | ## Bundle for Browser 53 | 54 | Create a browser-compatible IIFE bundle: 55 | 56 | ```ts 57 | const bundle = await Bundle("web", { 58 | entryPoint: "src/main.ts", 59 | outfile: "dist/bundle.js", 60 | format: "iife", 61 | platform: "browser", 62 | minify: true, 63 | sourcemap: "external" 64 | }); 65 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/fs/copy-file.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Copying Files with Alchemy FS Provider 3 | description: Learn how to copy files and directories within your project using Alchemy's FS (File System) provider. 4 | --- 5 | 6 | # CopyFile 7 | 8 | The CopyFile resource lets you copy files from one location to another in the filesystem. 9 | 10 | ## Minimal Example 11 | 12 | Copy a file to a new location: 13 | 14 | ```ts 15 | import { CopyFile } from "alchemy/fs"; 16 | 17 | const copiedFile = await CopyFile("config-copy", { 18 | src: "config.json", 19 | dest: "backup/config.json" 20 | }); 21 | ``` 22 | 23 | ## Copy Without Overwriting 24 | 25 | Copy a file only if the destination doesn't already exist: 26 | 27 | ```ts 28 | import { CopyFile } from "alchemy/fs"; 29 | 30 | const safeCopy = await CopyFile("safe-copy", { 31 | src: "data.json", 32 | dest: "backup/data.json", 33 | overwrite: false 34 | }); 35 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/fs/folder.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing Folders (Directories) with Alchemy FS Provider 3 | description: Learn how to create, manage, and delete folders (directories) using Alchemy's FS (File System) provider. 4 | --- 5 | 6 | # Folder 7 | 8 | The Folder resource creates and manages directories in the filesystem with automatic parent directory creation and cleanup on deletion. 9 | 10 | ## Minimal Example 11 | 12 | Create a directory using the ID as the path: 13 | 14 | ```ts 15 | import { Folder } from "alchemy/fs"; 16 | 17 | const dir = await Folder("uploads"); 18 | ``` 19 | 20 | ## Custom Path 21 | 22 | Create a directory with an explicit path: 23 | 24 | ```ts 25 | import { Folder } from "alchemy/fs"; 26 | 27 | const logs = await Folder("logs", { 28 | path: "var/log/app" 29 | }); 30 | ``` 31 | 32 | ## Recursive Creation 33 | 34 | Create nested directories with recursive creation enabled (default): 35 | 36 | ```ts 37 | import { Folder } from "alchemy/fs"; 38 | 39 | const nested = await Folder("nested", { 40 | path: "path/to/nested/dir", 41 | recursive: true 42 | }); 43 | ``` 44 | 45 | ## Cleanup Options 46 | 47 | Control folder deletion behavior: 48 | 49 | ```ts 50 | import { Folder } from "alchemy/fs"; 51 | 52 | const temp = await Folder("temp", { 53 | path: "temp", 54 | delete: true, // Delete on destroy (default) 55 | clean: true // Remove contents on delete 56 | }); 57 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/fs/static-css-file.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing Static CSS Files with Alchemy FS Provider 3 | description: Learn how to create and manage static CSS (.css) files with proper formatting using Alchemy's FS provider. 4 | --- 5 | 6 | # StaticCSSFile 7 | 8 | The StaticCSSFile resource creates and manages static CSS files in your project using [Alchemy's File System](https://alchemy.run/docs/concepts/fs) capabilities. 9 | 10 | ## Minimal Example 11 | 12 | Creates a basic CSS file with styles: 13 | 14 | ```ts 15 | import { StaticCSSFile } from "alchemy/fs"; 16 | 17 | const styles = await StaticCSSFile("styles.css", ` 18 | .container { 19 | max-width: 1200px; 20 | margin: 0 auto; 21 | padding: 0 1rem; 22 | } 23 | `); 24 | ``` 25 | 26 | ## Custom Path 27 | 28 | Creates a CSS file at a specific path: 29 | 30 | ```ts 31 | import { StaticCSSFile } from "alchemy/fs"; 32 | 33 | const styles = await StaticCSSFile("main", 34 | "src/styles/main.css", 35 | `.button { 36 | background-color: #0062ff; 37 | color: white; 38 | border: none; 39 | padding: 0.5rem 1rem; 40 | border-radius: 4px; 41 | }` 42 | ); 43 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/fs/static-html-file.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing Static HTML Files with Alchemy FS Provider 3 | description: Learn how to create and manage static HTML (.html) files with proper formatting using Alchemy's FS provider. 4 | --- 5 | 6 | # StaticHTMLFile 7 | 8 | The StaticHTMLFile resource creates static HTML files with automatic directory creation and cleanup. 9 | 10 | ## Minimal Example 11 | 12 | Creates a basic HTML file: 13 | 14 | ```ts 15 | import { StaticHTMLFile } from "alchemy/fs"; 16 | 17 | const page = await StaticHTMLFile("index.html", ` 18 | 19 | 20 | My Page 21 | Hello World 22 | 23 | `); 24 | ``` 25 | 26 | ## Custom Path 27 | 28 | Creates an HTML file at a specific path: 29 | 30 | ```ts 31 | import { StaticHTMLFile } from "alchemy/fs"; 32 | 33 | const page = await StaticHTMLFile("home", "pages/index.html", ` 34 | 35 | 36 | 37 | Home 38 | 39 | 40 | 41 |

Welcome

42 |

This is my homepage.

43 | 44 | 45 | `); 46 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/fs/static-text-file.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing Static Text Files with Alchemy FS Provider 3 | description: Learn how to create and manage static text (.txt) files using Alchemy's FS provider. 4 | --- 5 | 6 | # StaticTextFile 7 | 8 | The StaticTextFile resource creates and manages plain text files in the filesystem using [Alchemy's File System](https://alchemy.run/docs/concepts/fs) capabilities. 9 | 10 | ## Minimal Example 11 | 12 | Creates a simple text file with content: 13 | 14 | ```ts 15 | import { StaticTextFile } from "alchemy/fs"; 16 | 17 | const readme = await StaticTextFile("README.md", 18 | "# Project Name\n\nProject description goes here." 19 | ); 20 | ``` 21 | 22 | ## Custom Path 23 | 24 | Creates a text file at a specific path: 25 | 26 | ```ts 27 | import { StaticTextFile } from "alchemy/fs"; 28 | 29 | const changelog = await StaticTextFile("CHANGELOG.md", 30 | "docs/CHANGELOG.md", 31 | "# Changelog\n\n## v1.0.0\n\n- Initial release" 32 | ); 33 | ``` 34 | 35 | ## Nested Directory 36 | 37 | Creates a text file in a nested directory structure (directories are created automatically): 38 | 39 | ```ts 40 | import { StaticTextFile } from "alchemy/fs"; 41 | 42 | const log = await StaticTextFile("app.log", 43 | "logs/app/app.log", 44 | "Application started successfully" 45 | ); 46 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/fs/static-vue-file.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing Static Vue Files with Alchemy FS Provider 3 | description: Learn how to create and manage static Vue (.vue) single-file components with proper formatting using Alchemy's FS provider. 4 | --- 5 | 6 | # StaticVueFile 7 | 8 | The StaticVueFile resource creates [Vue.js](https://vuejs.org/) single-file component files (.vue) with template, script and style sections. 9 | 10 | ## Minimal Example 11 | 12 | Creates a basic Vue component file with template, script and style sections. 13 | 14 | ```ts 15 | import { StaticVueFile } from "alchemy/fs"; 16 | 17 | const button = await StaticVueFile("Button.vue", ` 18 | 21 | 22 | 29 | 30 | 35 | `); 36 | ``` 37 | 38 | ## Custom Path 39 | 40 | Creates a Vue component file at a specific path. 41 | 42 | ```ts 43 | import { StaticVueFile } from "alchemy/fs"; 44 | 45 | const header = await StaticVueFile("Header", 46 | "components/Header.vue", 47 | ` 55 | 56 | 63 | `); 64 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/fs/static-yaml-file.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing Static YAML Files with Alchemy FS Provider 3 | description: Learn how to create and manage static YAML (.yaml, .yml) files with proper formatting using Alchemy's FS provider. 4 | --- 5 | 6 | # StaticYamlFile 7 | 8 | The StaticYamlFile resource creates YAML files with formatted content using the [YAML](https://yaml.org/) format. 9 | 10 | ## Minimal Example 11 | 12 | Creates a simple YAML configuration file. 13 | 14 | ```ts 15 | import { StaticYamlFile } from "alchemy/fs"; 16 | 17 | const config = await StaticYamlFile("config.yaml", { 18 | server: { 19 | host: "localhost", 20 | port: 3000 21 | } 22 | }); 23 | ``` 24 | 25 | ## Nested Configuration 26 | 27 | Creates a YAML file with nested configuration objects. 28 | 29 | ```ts 30 | import { StaticYamlFile } from "alchemy/fs"; 31 | 32 | const config = await StaticYamlFile("config.yaml", { 33 | server: { 34 | host: "localhost", 35 | port: 3000 36 | }, 37 | database: { 38 | url: "postgresql://localhost:5432/db", 39 | pool: { 40 | min: 1, 41 | max: 10 42 | } 43 | } 44 | }); 45 | ``` 46 | 47 | ## Custom Path 48 | 49 | Creates a YAML file at a specific path. 50 | 51 | ```ts 52 | import { StaticYamlFile } from "alchemy/fs"; 53 | 54 | const config = await StaticYamlFile("config", "config/app.yaml", { 55 | environment: "production", 56 | features: ["auth", "api", "storage"] 57 | }); 58 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/neon/project.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing Neon Serverless Postgres Projects with Alchemy 3 | description: Learn how to create, configure, and manage Neon serverless Postgres projects and databases using Alchemy. 4 | --- 5 | 6 | # NeonProject 7 | 8 | The NeonProject resource lets you create and manage [Neon serverless PostgreSQL](https://neon.tech) projects. 9 | 10 | ## Minimal Example 11 | 12 | Create a basic Neon project with default settings: 13 | 14 | ```ts 15 | import { NeonProject } from "alchemy/neon"; 16 | 17 | const project = await NeonProject("my-project", { 18 | name: "My Project" 19 | }); 20 | ``` 21 | 22 | ## Custom Region and Version 23 | 24 | Create a project in a specific region with a specific PostgreSQL version: 25 | 26 | ```ts 27 | import { NeonProject } from "alchemy/neon"; 28 | 29 | const project = await NeonProject("eu-project", { 30 | name: "EU Project", 31 | region_id: "aws-eu-west-1", 32 | pg_version: 16, 33 | apiKey: alchemy.secret(process.env.NEON_API_KEY) 34 | }); 35 | ``` 36 | 37 | ## Custom Branch Name 38 | 39 | Create a project with a custom default branch name: 40 | 41 | ```ts 42 | import { NeonProject } from "alchemy/neon"; 43 | 44 | const project = await NeonProject("dev-project", { 45 | name: "Development Project", 46 | default_branch_name: "development" 47 | }); 48 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/sentry/project.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing Sentry Projects with Alchemy 3 | description: Learn how to create, configure, and manage Sentry projects using Alchemy. 4 | --- 5 | 6 | # Sentry Project 7 | 8 | Create and manage Sentry projects. 9 | 10 | ## Authentication 11 | 12 | You can authenticate with Sentry in two ways: 13 | 14 | 1. Environment variable (recommended): 15 | ```bash 16 | # .env 17 | SENTRY_AUTH_TOKEN=your_auth_token 18 | ``` 19 | 20 | 2. Pass the token directly: 21 | ```typescript 22 | const project = await Project("my-project", { 23 | authToken: alchemy.secret(process.env.SENTRY_AUTH_TOKEN), 24 | name: "My Project", 25 | organization: "my-org", 26 | team: "my-team", 27 | }); 28 | ``` 29 | 30 | Get your auth token from [Sentry's API settings](https://sentry.io/settings/account/api/auth-tokens/). 31 | 32 | ## Examples 33 | 34 | ### Minimal 35 | 36 | ```typescript 37 | import { Project } from "alchemy/sentry"; 38 | 39 | const project = await Project("my-project", { 40 | name: "My Project", 41 | organization: "my-org" 42 | team: "my-team", 43 | }); 44 | ``` 45 | 46 | ### Adopt 47 | 48 | For when you have an existing Project in Sentry already. 49 | 50 | ```ts 51 | const project = await Project("my-project", { 52 | adopt: true, 53 | name: "My Project", 54 | organization: "my-org", 55 | team: "my-team", 56 | }) -------------------------------------------------------------------------------- /alchemy-web/docs/providers/sentry/team.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing Sentry Teams with Alchemy 3 | description: Learn how to create, configure, and manage Sentry teams using Alchemy. 4 | --- 5 | 6 | # Sentry Team 7 | 8 | Create and manage Sentry teams. 9 | 10 | ## Authentication 11 | 12 | You can authenticate with Sentry in two ways: 13 | 14 | 1. Environment variable (recommended): 15 | ```bash 16 | # .env 17 | SENTRY_AUTH_TOKEN=your_auth_token 18 | ``` 19 | 20 | 2. Pass the token directly: 21 | ```typescript 22 | const team = await Team("my-team", { 23 | authToken: alchemy.secret(process.env.SENTRY_AUTH_TOKEN), 24 | name: "My Team", 25 | organization: "my-org", 26 | }); 27 | ``` 28 | 29 | Get your auth token from [Sentry's API settings](https://sentry.io/settings/account/api/auth-tokens/). 30 | 31 | ## Examples 32 | 33 | ### Minimal 34 | 35 | ```typescript 36 | import { Team } from "alchemy/sentry"; 37 | 38 | const team = await Team("my-team", { 39 | name: "My Team", 40 | organization: "my-org", 41 | }); 42 | ``` 43 | 44 | ### Adopt 45 | 46 | For when you have an existing Team within Sentry: 47 | 48 | ```typescript 49 | import { Team } from "alchemy/sentry"; 50 | 51 | const team = await Team("my-team", { 52 | adopt: true, 53 | name: "My Team", 54 | organization: "my-org", 55 | }); 56 | ``` 57 | -------------------------------------------------------------------------------- /alchemy-web/docs/providers/stripe/price.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing Stripe Prices with Alchemy 3 | description: Learn how to create and manage Stripe Prices for your products and subscriptions using Alchemy. 4 | --- 5 | 6 | # Price 7 | 8 | The Price resource lets you create and manage [Stripe Prices](https://stripe.com/docs/api/prices) for products. 9 | 10 | ## Minimal Example 11 | 12 | Create a one-time fixed price for a product: 13 | 14 | ```ts 15 | import { Price } from "alchemy/stripe"; 16 | 17 | const price = await Price("basic-license", { 18 | currency: "usd", 19 | unitAmount: 2999, // $29.99 20 | product: "prod_xyz" 21 | }); 22 | ``` 23 | 24 | ## Recurring Subscription Price 25 | 26 | Create a recurring subscription price with fixed monthly billing: 27 | 28 | ```ts 29 | import { Price } from "alchemy/stripe"; 30 | 31 | const subscriptionPrice = await Price("pro-monthly", { 32 | currency: "usd", 33 | unitAmount: 1499, // $14.99/month 34 | product: "prod_xyz", 35 | recurring: { 36 | interval: "month", 37 | usageType: "licensed" 38 | } 39 | }); 40 | ``` 41 | 42 | ## Metered Usage Price 43 | 44 | Create a metered price for usage-based billing: 45 | 46 | ```ts 47 | import { Price } from "alchemy/stripe"; 48 | 49 | const meteredPrice = await Price("storage", { 50 | currency: "usd", 51 | unitAmount: 25, // $0.25 per GB 52 | product: "prod_xyz", 53 | recurring: { 54 | interval: "month", 55 | usageType: "metered", 56 | aggregateUsage: "sum" 57 | } 58 | }); 59 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/stripe/product.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing Stripe Products with Alchemy 3 | description: Learn how to create and manage Stripe Products and SKUs using Alchemy for your e-commerce or subscription service. 4 | --- 5 | 6 | # Product 7 | 8 | The Product resource lets you create and manage [Stripe Products](https://stripe.com/docs/api/products) for your Stripe account. 9 | 10 | ## Minimal Example 11 | 12 | Create a basic digital product: 13 | 14 | ```ts 15 | import { Product } from "alchemy/stripe"; 16 | 17 | const product = await Product("basic-software", { 18 | name: "Basic Software License", 19 | description: "Single-user license for basic software package" 20 | }); 21 | ``` 22 | 23 | ## Physical Product 24 | 25 | Create a physical product with shipping details: 26 | 27 | ```ts 28 | import { Product } from "alchemy/stripe"; 29 | 30 | const product = await Product("premium-hardware", { 31 | name: "Premium Hardware Kit", 32 | description: "Complete hardware kit with premium components", 33 | shippable: true, 34 | images: ["https://example.com/hardware-kit.jpg"], 35 | unitLabel: "kit", 36 | statementDescriptor: "PREMIUM HW KIT" 37 | }); 38 | ``` 39 | 40 | ## Service Product 41 | 42 | Create a service product with tax code: 43 | 44 | ```ts 45 | import { Product } from "alchemy/stripe"; 46 | 47 | const product = await Product("consulting", { 48 | name: "Professional Consulting", 49 | description: "Expert consulting services", 50 | type: "service", 51 | taxCode: "txcd_10000000", 52 | metadata: { 53 | industry: "technology", 54 | expertise: "cloud" 55 | } 56 | }); 57 | ``` -------------------------------------------------------------------------------- /alchemy-web/docs/providers/vercel/project-domain.md: -------------------------------------------------------------------------------- 1 | # ProjectDomain 2 | 3 | Add and manage domains for Vercel projects. 4 | 5 | ## Authentication 6 | 7 | To use this resource, you must authenticate with Vercel. You can do this in one of two ways: 8 | 9 | 1. **Environment Variable:** Set `VERCEL_ACCESS_TOKEN` in your `.env` file. 10 | 2. **Direct Prop:** Pass `accessToken` directly in your resource configuration. 11 | 12 | ## Examples 13 | 14 | ### Minimal 15 | 16 | ```ts 17 | const domain = await ProjectDomain("my-app.com", { 18 | name: "my-app.com", 19 | project: "prj_123", 20 | }); 21 | ``` 22 | 23 | ### With `accessToken` 24 | 25 | ```ts 26 | const domain = await ProjectDomain("my-app.com", { 27 | accessToken: alchemy.secret(process.env.VERCEL_ACCESS_TOKEN), 28 | name: "my-app.com", 29 | project: "prj_123", 30 | }); 31 | ``` 32 | 33 | ### With `redirect` 34 | 35 | ```ts 36 | const domain = await ProjectDomain("my-app.com", { 37 | name: "my-app.com", 38 | project: "prj_123", 39 | gitBranch: "main", 40 | redirect: "https://example.com", 41 | redirectStatusCode: 301, 42 | }); 43 | ``` 44 | -------------------------------------------------------------------------------- /alchemy-web/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | title: Alchemy 4 | description: TypeScript-native Infrastructure-as-Code without the dead weight. Create, Update, Delete resources with pure async TypeScript. 5 | 6 | # Custom hero component instead of the default hero 7 | --- 8 | 9 | 17 | 38 | 39 | -------------------------------------------------------------------------------- /alchemy-web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "alchemy-web", 3 | "scripts": { 4 | "docs:gen": "bun alchemy.run.ts", 5 | "docs:dev": "vitepress dev", 6 | "docs:build": "NODE_OPTIONS='--max-old-space-size=8192' vitepress build", 7 | "docs:preview": "vitepress preview" 8 | }, 9 | "dependencies": { 10 | "sharp": "^0.34.1", 11 | "vitepress-plugin-group-icons": "^1.5.2" 12 | }, 13 | "devDependencies": { 14 | "@shikijs/vitepress-twoslash": "^3.4.0", 15 | "markdown-it-footnote": "^4.0.0", 16 | "vitepress": "^1.6.3", 17 | "vue": "^3.5.13" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /alchemy-web/public/alchemist.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sam-goodwin/alchemy/5ad508201ef5217e8a5ef47a9efc21e2c29b8031/alchemy-web/public/alchemist.webp -------------------------------------------------------------------------------- /alchemy-web/public/alchemy-flower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sam-goodwin/alchemy/5ad508201ef5217e8a5ef47a9efc21e2c29b8031/alchemy-web/public/alchemy-flower.png -------------------------------------------------------------------------------- /alchemy-web/public/alchemy-og.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sam-goodwin/alchemy/5ad508201ef5217e8a5ef47a9efc21e2c29b8031/alchemy-web/public/alchemy-og.png -------------------------------------------------------------------------------- /alchemy-web/public/potion-with-border.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sam-goodwin/alchemy/5ad508201ef5217e8a5ef47a9efc21e2c29b8031/alchemy-web/public/potion-with-border.png -------------------------------------------------------------------------------- /alchemy-web/public/potion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sam-goodwin/alchemy/5ad508201ef5217e8a5ef47a9efc21e2c29b8031/alchemy-web/public/potion.png -------------------------------------------------------------------------------- /alchemy/src/ai/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./ark.ts"; 2 | export * from "./astro-file.ts"; 3 | export * from "./css-file.ts"; 4 | export * from "./data.ts"; 5 | export * from "./document.ts"; 6 | export * from "./html-file.ts"; 7 | export * from "./json-file.ts"; 8 | export * from "./typescript-file.ts"; 9 | export * from "./vue-file.ts"; 10 | export * from "./yaml-file.ts"; 11 | -------------------------------------------------------------------------------- /alchemy/src/aws/account-id.ts: -------------------------------------------------------------------------------- 1 | import { GetCallerIdentityCommand, STSClient } from "@aws-sdk/client-sts"; 2 | 3 | const sts = new STSClient({}); 4 | 5 | export type AccountId = string & { 6 | readonly __brand: "AccountId"; 7 | }; 8 | 9 | /** 10 | * Helper to get the current AWS account ID 11 | */ 12 | export async function AccountId(): Promise { 13 | const identity = await sts.send(new GetCallerIdentityCommand({})); 14 | return identity.Account! as AccountId; 15 | } 16 | -------------------------------------------------------------------------------- /alchemy/src/aws/control/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./client.ts"; 2 | export * from "./proxy.ts"; 3 | export * from "./resource.ts"; 4 | import { AWS } from "./proxy.ts"; 5 | 6 | export default AWS; 7 | -------------------------------------------------------------------------------- /alchemy/src/aws/control/proxy.ts: -------------------------------------------------------------------------------- 1 | import { createResourceType } from "./resource.ts"; 2 | 3 | /** 4 | * Proxy-based interface for dynamically accessing AWS resource handlers. 5 | * This allows for a natural, namespace-like access pattern (e.g., AWS.S3.Bucket) 6 | * while lazily creating resource handlers as needed. 7 | */ 8 | export const AWS = new Proxy( 9 | {}, 10 | { 11 | get(_, serviceName: string) { 12 | // Skip internal properties 13 | if (typeof serviceName !== "string" || serviceName.startsWith("_")) { 14 | return undefined; 15 | } 16 | 17 | // Create a nested proxy for the service namespace 18 | return new Proxy( 19 | {}, 20 | { 21 | get(_, resourceName: string) { 22 | // Skip internal properties 23 | if ( 24 | typeof resourceName !== "string" || 25 | resourceName.startsWith("_") 26 | ) { 27 | return undefined; 28 | } 29 | 30 | // Construct the CloudFormation resource type name 31 | const typeName = `AWS::${serviceName}::${resourceName}`; 32 | 33 | // Return the memoized resource handler 34 | return createResourceType(typeName); 35 | }, 36 | }, 37 | ); 38 | }, 39 | }, 40 | ) as typeof import("./types"); 41 | -------------------------------------------------------------------------------- /alchemy/src/aws/credentials.ts: -------------------------------------------------------------------------------- 1 | import type { Secret } from "../secret.ts"; 2 | 3 | export interface AwsCredentials { 4 | accessKeyId: Secret; 5 | secretAccessKey: Secret; 6 | } 7 | -------------------------------------------------------------------------------- /alchemy/src/aws/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./account-id.ts"; 2 | export * from "./bucket.ts"; 3 | export * from "./function.ts"; 4 | export * from "./policy-attachment.ts"; 5 | export * from "./policy.ts"; 6 | export * from "./queue.ts"; 7 | export * from "./role.ts"; 8 | export * from "./ses.ts"; 9 | export * from "./ssm-parameter.ts"; 10 | export * from "./table.ts"; 11 | -------------------------------------------------------------------------------- /alchemy/src/aws/oidc/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./github-oidc-provider.ts"; 2 | export * from "./oidc-provider.ts"; 3 | -------------------------------------------------------------------------------- /alchemy/src/aws/retry.ts: -------------------------------------------------------------------------------- 1 | import { withExponentialBackoff } from "../util/retry.ts"; 2 | 3 | /** 4 | * Check if an error is retryable (throttling/rate limiting) 5 | */ 6 | function isRetryableError(error: any): boolean { 7 | if (!error) return false; 8 | 9 | const errorCode = error.name || error.code || ""; 10 | const errorMessage = error.message || ""; 11 | 12 | // Check for common AWS throttling error codes and messages 13 | return ( 14 | errorCode === "Throttling" || 15 | errorCode === "ThrottlingException" || 16 | errorCode === "TooManyRequestsException" || 17 | errorCode === "RequestLimitExceeded" || 18 | errorMessage.includes("Rate exceeded") || 19 | errorMessage.includes("throttling") || 20 | errorMessage.includes("Throttling") || 21 | errorMessage.includes("Internal server error") 22 | ); 23 | } 24 | 25 | /** 26 | * Retry function with standardized parameters for AWS throttling 27 | */ 28 | export function retry( 29 | operation: () => Promise, 30 | extraIsRetryableError?: (error: any) => boolean, 31 | ): Promise { 32 | return withExponentialBackoff( 33 | operation, 34 | (err) => isRetryableError(err) || extraIsRetryableError?.(err) || false, 35 | 10, // max attempts 36 | 1000, // initial delay ms 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /alchemy/src/cloudflare/ai.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @see https://developers.cloudflare.com/workers-ai/ 3 | */ 4 | export class Ai { 5 | public readonly type = "ai"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | ///@ts-ignore 11 | _phantom: Models; 12 | } 13 | -------------------------------------------------------------------------------- /alchemy/src/cloudflare/analytics-engine.ts: -------------------------------------------------------------------------------- 1 | export interface AnalyticsEngineDatasetProps { 2 | /** 3 | * The name of the dataset to bind to - 4 | * becomes the table name to query via the api in the FROM clause 5 | */ 6 | dataset: string; 7 | } 8 | 9 | /** 10 | * @example 11 | * // Create a binding for an Analytics Engine dataset 12 | * const dataset = new AnalyticsEngineDataset("ae-dataset", { 13 | * dataset: "WEATHER", 14 | * }); 15 | */ 16 | export class AnalyticsEngineDataset { 17 | public readonly type = "analytics_engine" as const; 18 | public readonly dataset: string; 19 | 20 | constructor( 21 | public readonly id: string, 22 | input: AnalyticsEngineDatasetProps, 23 | ) { 24 | this.dataset = input.dataset; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /alchemy/src/cloudflare/asset-manifest.ts: -------------------------------------------------------------------------------- 1 | export type AssetManifest = AssetManifestEntry[]; 2 | 3 | export interface AssetManifestEntry { 4 | source: string; 5 | key: string; 6 | hash: string; 7 | cacheControl: string; 8 | contentType?: string; 9 | } 10 | 11 | export interface FileOption { 12 | files: string | string[]; 13 | cacheControl: string; 14 | contentType?: string; 15 | ignore?: string[]; 16 | } 17 | -------------------------------------------------------------------------------- /alchemy/src/cloudflare/browser-rendering.ts: -------------------------------------------------------------------------------- 1 | export class BrowserRendering { 2 | public readonly type = "browser"; 3 | } 4 | -------------------------------------------------------------------------------- /alchemy/src/cloudflare/bundle/external.ts: -------------------------------------------------------------------------------- 1 | // https://developers.cloudflare.com/workers/runtime-apis/nodejs/#supported-nodejs-apis 2 | const nodejs_compat = [ 3 | "node:async_hooks", 4 | "node:assert", 5 | "node:buffer", 6 | "node:console", 7 | "node:crypto", 8 | "node:debug", 9 | "node:diagnostics_channel", 10 | "node:dns", 11 | "node:events", 12 | "node:inspector", 13 | "node:net", 14 | "node:path", 15 | "node:perf_hooks", // partially supported 16 | "node:process", 17 | "node:querystring", 18 | "node:stream", 19 | "node:string_decoder", 20 | "node:timers", 21 | "node:tls", // partially supported 22 | "node:url", 23 | "node:util", 24 | "node:zlib", 25 | // "node:*", 26 | ]; 27 | 28 | export const external = [ 29 | ...nodejs_compat, 30 | ...nodejs_compat.map((p) => p.split(":")[1]), 31 | "cloudflare:workers", 32 | "cloudflare:workflows", 33 | "cloudflare:*", 34 | ]; 35 | 36 | export const external_als = [ 37 | // 38 | "node:async_hooks", 39 | "async_hooks", 40 | "cloudflare:*", 41 | ]; 42 | -------------------------------------------------------------------------------- /alchemy/src/cloudflare/bundle/local-dev-cloudflare-shim.ts: -------------------------------------------------------------------------------- 1 | import { dedent } from "../../util/dedent.ts"; 2 | 3 | /** 4 | * TanStackStart server functions and middleware run in Node.js intead of Miniflare when using `vite dev`. 5 | * 6 | * This plugin polyfills the cloudflare:workers module during the dev server phase. 7 | */ 8 | export function cloudflareWorkersDevEnvironmentShim() { 9 | return { 10 | name: "cloudflare-workers-dev-shim", 11 | apply: "serve", // dev‑only 12 | enforce: "pre", 13 | resolveId(id: string) { 14 | if (id === "cloudflare:workers") return id; // tell Vite we handled it 15 | }, 16 | load(id: string) { 17 | if (id === "cloudflare:workers") 18 | return dedent` 19 | import { getPlatformProxy } from "wrangler"; 20 | // TODO: should we export default cloudflare; ?? 21 | const cloudflare = await getPlatformProxy(); 22 | export const env = cloudflare.env;`; 23 | }, 24 | } as const; 25 | } 26 | -------------------------------------------------------------------------------- /alchemy/src/cloudflare/event-source.ts: -------------------------------------------------------------------------------- 1 | import type { QueueConsumerSettings } from "./queue-consumer.ts"; 2 | import type { QueueResource } from "./queue.ts"; 3 | 4 | /** 5 | * Base interface for event sources that can be bound to a Worker 6 | */ 7 | export type EventSource = QueueEventSource | QueueResource; 8 | 9 | /** 10 | * Configuration for a Queue as an event source for a Worker 11 | */ 12 | export interface QueueEventSource { 13 | /** 14 | * The queue to consume messages from 15 | */ 16 | readonly queue: QueueResource; 17 | 18 | /** 19 | * Optional settings for configuring how the Worker consumes the queue 20 | */ 21 | readonly settings?: QueueConsumerSettings; 22 | } 23 | 24 | /** 25 | * Checks if an event source is a QueueEventSource 26 | * @param eventSource - The event source to check 27 | * @returns true if the event source is a QueueEventSource, false otherwise 28 | */ 29 | export function isQueueEventSource( 30 | eventSource: any, 31 | ): eventSource is QueueEventSource { 32 | return "queue" in eventSource; 33 | } 34 | -------------------------------------------------------------------------------- /alchemy/src/cloudflare/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./account-api-token.ts"; 2 | export * from "./account-id.ts"; 3 | export * from "./ai-gateway.ts"; 4 | export * from "./ai.ts"; 5 | export * from "./analytics-engine.ts"; 6 | export * from "./api-error.ts"; 7 | export * from "./api.ts"; 8 | export * from "./assets.ts"; 9 | export * from "./bindings.ts"; 10 | export * from "./bound.ts"; 11 | export * from "./browser-rendering.ts"; 12 | export * from "./bucket.ts"; 13 | export * from "./bundle/external.ts"; 14 | export * from "./bundle/local-dev-cloudflare-shim.ts"; 15 | export * from "./custom-domain.ts"; 16 | export * from "./d1-clone.ts"; 17 | export * from "./d1-database.ts"; 18 | export * from "./d1-export.ts"; 19 | export * from "./d1-import.ts"; 20 | export * from "./dns-records.ts"; 21 | export * from "./durable-object-namespace.ts"; 22 | export * from "./hyperdrive.ts"; 23 | export * from "./kv-namespace.ts"; 24 | export * from "./nuxt.ts"; 25 | export * from "./permission-groups.ts"; 26 | export * from "./pipeline.ts"; 27 | export * from "./queue-consumer.ts"; 28 | export * from "./queue.ts"; 29 | export * from "./r2-rest-state-store.ts"; 30 | export * from "./react-router.ts"; 31 | export * from "./redwood.ts"; 32 | export * from "./route.ts"; 33 | export * from "./tanstack-start.ts"; 34 | export * from "./vectorize-index.ts"; 35 | export * from "./vectorize-metadata-index.ts"; 36 | export * from "./version-metadata.ts"; 37 | export * from "./vite.ts"; 38 | export * from "./website.ts"; 39 | export * from "./worker.ts"; 40 | export { Workflow } from "./workflow.ts"; 41 | export * from "./wrangler.json.ts"; 42 | export * from "./zone.ts"; 43 | -------------------------------------------------------------------------------- /alchemy/src/cloudflare/response.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Cloudflare API response format 3 | */ 4 | export interface CloudflareResponse { 5 | result: T; 6 | success: boolean; 7 | errors: Array<{ code: number; message: string }>; 8 | messages: string[]; 9 | } 10 | -------------------------------------------------------------------------------- /alchemy/src/cloudflare/tanstack-start.ts: -------------------------------------------------------------------------------- 1 | import type { Assets } from "./assets.ts"; 2 | import type { Bindings } from "./bindings.ts"; 3 | import { Website, type WebsiteProps } from "./website.ts"; 4 | import type { Worker } from "./worker.ts"; 5 | 6 | export interface TanStackStartProps 7 | extends WebsiteProps {} 8 | 9 | // don't allow the ASSETS to be overriden 10 | export type TanStackStart = B extends { ASSETS: any } 11 | ? never 12 | : Worker; 13 | 14 | export async function TanStackStart( 15 | id: string, 16 | props?: Partial>, 17 | ): Promise> { 18 | return Website(id, { 19 | ...props, 20 | command: props?.command ?? "bun run build", 21 | wrangler: props?.wrangler ?? true, 22 | main: props?.main ?? ".output/server/index.mjs", 23 | compatibilityFlags: ["nodejs_compat", ...(props?.compatibilityFlags ?? [])], 24 | assets: props?.assets ?? ".output/public", 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /alchemy/src/cloudflare/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Cloudflare API response format 3 | */ 4 | export interface CloudflareApiResponse { 5 | /** 6 | * API response result 7 | */ 8 | result: T; 9 | 10 | /** 11 | * Success status 12 | */ 13 | success: boolean; 14 | 15 | /** 16 | * Error details if success is false 17 | */ 18 | errors: CloudflareApiError[]; 19 | 20 | /** 21 | * Response messages 22 | */ 23 | messages: string[]; 24 | 25 | /** 26 | * Result information (typically for paginated results) 27 | */ 28 | result_info?: { 29 | page: number; 30 | per_page: number; 31 | total_pages: number; 32 | count: number; 33 | total_count: number; 34 | }; 35 | } 36 | 37 | /** 38 | * Cloudflare API error format 39 | */ 40 | export interface CloudflareApiError { 41 | /** 42 | * Error code 43 | */ 44 | code: number; 45 | 46 | /** 47 | * Error message 48 | */ 49 | message: string; 50 | } 51 | 52 | /** 53 | * Helper to extract and handle Cloudflare API errors 54 | * 55 | * @param response Fetch response object 56 | * @returns Formatted error message 57 | */ 58 | export async function extractCloudflareError( 59 | response: Response, 60 | ): Promise { 61 | try { 62 | const data = (await response.json()) as CloudflareApiResponse; 63 | if (data.errors && data.errors.length > 0) { 64 | return data.errors.map((e) => `Error ${e.code}: ${e.message}`).join(", "); 65 | } 66 | return `HTTP ${response.status}: ${response.statusText}`; 67 | } catch { 68 | return `HTTP ${response.status}: ${response.statusText}`; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /alchemy/src/cloudflare/version-metadata.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @see https://developers.cloudflare.com/workers/runtime-apis/bindings/version-metadata/ 3 | */ 4 | export class VersionMetadata { 5 | public readonly type = "version_metadata"; 6 | } 7 | -------------------------------------------------------------------------------- /alchemy/src/cloudflare/vite.ts: -------------------------------------------------------------------------------- 1 | import path from "node:path"; 2 | import type { Assets } from "./assets.ts"; 3 | import type { Bindings } from "./bindings.ts"; 4 | import { Website, type WebsiteProps } from "./website.ts"; 5 | import type { Worker } from "./worker.ts"; 6 | 7 | export interface ViteProps extends WebsiteProps {} 8 | 9 | // don't allow the ASSETS to be overriden 10 | export type Vite = B extends { ASSETS: any } 11 | ? never 12 | : Worker; 13 | 14 | export async function Vite( 15 | id: string, 16 | props: ViteProps, 17 | ): Promise> { 18 | const defaultAssets = path.join("dist", "client"); 19 | return Website(id, { 20 | ...props, 21 | assets: 22 | typeof props.assets === "object" 23 | ? { 24 | dist: props.assets.dist ?? defaultAssets, 25 | } 26 | : (props.assets ?? defaultAssets), 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /alchemy/src/dns/godaddy.ts: -------------------------------------------------------------------------------- 1 | import { safeFetch } from "../util/safe-fetch.ts"; 2 | 3 | export type UpdateNameserversOptions = { 4 | domain: string; 5 | apiKey: string; 6 | apiSecret: string; 7 | nameservers: string[]; 8 | }; 9 | 10 | export async function updateNameservers(options: UpdateNameserversOptions) { 11 | const url = `https://api.godaddy.com/v1/domains/${options.domain}/nameservers`; 12 | 13 | const response = await safeFetch(url, { 14 | method: "PUT", 15 | headers: { 16 | Authorization: `sso-key ${options.apiKey}:${options.apiSecret}`, 17 | "Content-Type": "application/json", 18 | Accept: "application/json", 19 | }, 20 | body: JSON.stringify({ 21 | nameservers: options.nameservers, 22 | }), 23 | }); 24 | 25 | if (response.ok) { 26 | console.log(`✅ Nameservers updated for ${options.domain}`); 27 | } else { 28 | const error = await response.json(); 29 | console.error("❌ Failed to update nameservers:", error); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /alchemy/src/dns/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./import-dns.ts"; 2 | export * from "./record.ts"; 3 | -------------------------------------------------------------------------------- /alchemy/src/env.ts: -------------------------------------------------------------------------------- 1 | export interface Env { 2 | [key: string]: Promise; 3 | (name: string, value?: T | undefined, error?: string): Promise; 4 | } 5 | 6 | export const env = new Proxy(_env, { 7 | get: (_, name: string) => _env(name), 8 | apply: (_, __, args: [string, any?, string?]) => _env(...args), 9 | }) as Env; 10 | 11 | async function _env( 12 | name: string, 13 | value?: T | undefined, 14 | error?: string, 15 | ): Promise { 16 | if (value !== undefined) { 17 | return value; 18 | } 19 | const env = await resolveEnv(); 20 | if (name in env) { 21 | return env[name] as T; 22 | } 23 | throw new Error(error ?? `Environment variable ${name} is not set`); 24 | } 25 | 26 | async function resolveEnv(): Promise> { 27 | if (typeof process !== "undefined") { 28 | return process.env; 29 | } 30 | try { 31 | const { env } = await import("cloudflare:workers"); 32 | return env; 33 | } catch (_error) {} 34 | if (typeof import.meta !== "undefined") { 35 | return import.meta.env; 36 | } 37 | throw new Error("No environment found"); 38 | } 39 | -------------------------------------------------------------------------------- /alchemy/src/esbuild/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./bundle.ts"; 2 | -------------------------------------------------------------------------------- /alchemy/src/fs/file-collection.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Collection of files with their contents 3 | */ 4 | export type FileCollection = { 5 | /** 6 | * Type identifier for FileCollection 7 | */ 8 | type: "fs::FileCollection"; 9 | /** 10 | * Map of relative paths to file contents 11 | */ 12 | files: { 13 | [relativePath: string]: string; 14 | }; 15 | }; 16 | 17 | export function isFileCollection(value: unknown): value is FileCollection { 18 | return ( 19 | typeof value === "object" && 20 | value !== null && 21 | "type" in value && 22 | value.type === "fs::FileCollection" 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /alchemy/src/fs/file-ref.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Reference to a file in the filesystem 3 | */ 4 | export type FileRef = { 5 | /** 6 | * Type identifier for FileRef 7 | */ 8 | kind: "fs::FileRef"; 9 | /** 10 | * Path to the file 11 | */ 12 | path: string; 13 | }; 14 | 15 | export function isFileRef(value: unknown): value is FileRef { 16 | return ( 17 | typeof value === "object" && 18 | value !== null && 19 | "kind" in value && 20 | value.kind === "fs::FileRef" 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /alchemy/src/fs/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./copy-file.ts"; 2 | export * from "./file-collection.ts"; 3 | export * from "./file-ref.ts"; 4 | export * from "./file-system-state-store.ts"; 5 | export * from "./file.ts"; 6 | export * from "./folder.ts"; 7 | export * from "./static-astro-file.ts"; 8 | export * from "./static-css-file.ts"; 9 | export * from "./static-html-file.ts"; 10 | export * from "./static-json-file.ts"; 11 | export * from "./static-text-file.ts"; 12 | export * from "./static-typescript-file.ts"; 13 | export * from "./static-vue-file.ts"; 14 | export * from "./static-yaml-file.ts"; 15 | -------------------------------------------------------------------------------- /alchemy/src/fs/static-astro-file.ts: -------------------------------------------------------------------------------- 1 | import { File } from "./file.ts"; 2 | 3 | export type StaticAstroFile = File; 4 | 5 | /** 6 | * Creates a static Astro component file 7 | * 8 | * @example 9 | * // Create an Astro component file with content 10 | * const header = await StaticAstroFile("Header.astro", 11 | * `--- 12 | * import Logo from '../components/Logo.astro'; 13 | * const navItems = ['Home', 'About', 'Contact']; 14 | * --- 15 | * 16 | *
17 | * 18 | * 25 | *
26 | * 27 | * ` 34 | * ); 35 | */ 36 | export function StaticAstroFile( 37 | id: string, 38 | ...args: [content: string] | [path: string, content: string] 39 | ): Promise { 40 | const [path, content] = args.length === 1 ? [id, args[0]] : args; 41 | return File(id, { 42 | path, 43 | content, 44 | }); 45 | } 46 | -------------------------------------------------------------------------------- /alchemy/src/fs/static-css-file.ts: -------------------------------------------------------------------------------- 1 | import { File } from "./file.ts"; 2 | 3 | export type StaticCSSFile = File; 4 | 5 | /** 6 | * Creates a static CSS file 7 | * 8 | * @example 9 | * // Create a CSS file with styles 10 | * const styles = await StaticCSSFile("styles.css", 11 | * `.container { 12 | * max-width: 1200px; 13 | * margin: 0 auto; 14 | * padding: 0 1rem; 15 | * } 16 | * 17 | * .button { 18 | * background-color: #0062ff; 19 | * color: white; 20 | * border: none; 21 | * padding: 0.5rem 1rem; 22 | * border-radius: 4px; 23 | * }` 24 | * ); 25 | */ 26 | export function StaticCSSFile( 27 | id: string, 28 | ...args: [content: string] | [path: string, content: string] 29 | ): Promise { 30 | const [path, content] = args.length === 1 ? [id, args[0]] : args; 31 | return File(id, { 32 | path, 33 | content, 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /alchemy/src/fs/static-html-file.ts: -------------------------------------------------------------------------------- 1 | import { File } from "./file.ts"; 2 | 3 | export type StaticHTMLFile = File; 4 | 5 | /** 6 | * Creates a static HTML file 7 | * 8 | * @example 9 | * // Create an HTML file with content 10 | * const page = await StaticHTMLFile("index.html", 11 | * ` 12 | * 13 | * 14 | * 15 | * 16 | * My Website 17 | * 18 | * 19 | * 20 | *
21 | *

Welcome to My Website

22 | *
23 | *
24 | *

This is the main content of the page.

25 | *
26 | *
27 | *

© 2024 My Company

28 | *
29 | * 30 | * ` 31 | * ); 32 | */ 33 | export function StaticHTMLFile( 34 | id: string, 35 | ...args: [content: string] | [path: string, content: string] 36 | ): Promise { 37 | const [path, content] = args.length === 1 ? [id, args[0]] : args; 38 | return File(id, { 39 | path, 40 | content, 41 | }); 42 | } 43 | -------------------------------------------------------------------------------- /alchemy/src/fs/static-json-file.ts: -------------------------------------------------------------------------------- 1 | import { File } from "./file.ts"; 2 | 3 | /** 4 | * Creates a JSON file with formatted content 5 | * 6 | * @example 7 | * // Create a JSON configuration file 8 | * const config = await StaticJsonFile("config.json", { 9 | * api: { 10 | * endpoint: "https://api.example.com", 11 | * version: "v1" 12 | * }, 13 | * features: ["auth", "logging"] 14 | * }); 15 | */ 16 | export type StaticJsonFile = File; 17 | 18 | export async function StaticJsonFile( 19 | id: string, 20 | ...args: [content: any] | [path: string, content: any] 21 | ): Promise { 22 | const [path, content] = args.length === 1 ? [id, args[0]] : args; 23 | return File(id, { 24 | path, 25 | content: await formatJson(content), 26 | }); 27 | } 28 | 29 | export async function formatJson(content: any) { 30 | const prettier = await import("prettier"); 31 | return prettier.format(JSON.stringify(content), { 32 | parser: "json", 33 | editor: { 34 | tabWidth: 2, 35 | indentWidth: 2, 36 | }, 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /alchemy/src/fs/static-text-file.ts: -------------------------------------------------------------------------------- 1 | import { File } from "./file.ts"; 2 | 3 | /** 4 | * Creates a plain text file 5 | * 6 | * @example 7 | * // Create a text file with content 8 | * const readme = await TextFile("README.md", 9 | * "# Project Name\n\nProject description goes here." 10 | * ); 11 | */ 12 | export type StaticTextFile = File; 13 | 14 | export function StaticTextFile( 15 | id: string, 16 | ...args: [content: string] | [path: string, content: string] 17 | ): Promise { 18 | const [path, content] = args.length === 1 ? [id, args[0]] : args; 19 | return File(id, { 20 | path, 21 | content, 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /alchemy/src/fs/static-typescript-file.ts: -------------------------------------------------------------------------------- 1 | import { File } from "./file.ts"; 2 | 3 | /** 4 | * Creates a TypeScript file with formatted content using prettier 5 | * 6 | * @example 7 | * // Create a TypeScript file 8 | * const component = await StaticTypeScriptFile("Component.ts", ` 9 | * interface Props { 10 | * name: string; 11 | * age: number; 12 | * } 13 | * 14 | * export function Component({ name, age }: Props) { 15 | * return
Hello {name}, you are {age} years old
; 16 | * } 17 | * `); 18 | */ 19 | export type StaticTypeScriptFile = File; 20 | 21 | export async function StaticTypeScriptFile( 22 | id: string, 23 | ...args: [content: string] | [path: string, content: string] 24 | ): Promise { 25 | const [path, content] = args.length === 1 ? [id, args[0]] : args; 26 | const prettier = await import("prettier"); 27 | return File(id, { 28 | path, 29 | content: await prettier.format(content, { 30 | parser: "typescript", 31 | editor: { 32 | tabWidth: 2, 33 | indentWidth: 2, 34 | }, 35 | }), 36 | }); 37 | } 38 | -------------------------------------------------------------------------------- /alchemy/src/fs/static-vue-file.ts: -------------------------------------------------------------------------------- 1 | import { File } from "./file.ts"; 2 | 3 | export type StaticVueFile = File; 4 | 5 | /** 6 | * Creates a static Vue component file 7 | * 8 | * @example 9 | * // Create a Vue component file with content 10 | * const button = await StaticVueFile("Button.vue", 11 | * ` 14 | * 15 | * 22 | * 23 | * ` 28 | * ); 29 | */ 30 | export function StaticVueFile( 31 | id: string, 32 | ...args: [content: string] | [path: string, content: string] 33 | ): Promise { 34 | const [path, content] = args.length === 1 ? [id, args[0]] : args; 35 | return File(id, { 36 | path, 37 | content, 38 | }); 39 | } 40 | -------------------------------------------------------------------------------- /alchemy/src/fs/static-yaml-file.ts: -------------------------------------------------------------------------------- 1 | import { File } from "./file.ts"; 2 | /** 3 | * Creates a YAML file with formatted content 4 | * 5 | * @example 6 | * // Create a YAML configuration file 7 | * const config = await StaticYamlFile("config.yaml", { 8 | * server: { 9 | * host: "localhost", 10 | * port: 3000 11 | * }, 12 | * database: { 13 | * url: "postgresql://localhost:5432/db", 14 | * pool: { 15 | * min: 1, 16 | * max: 10 17 | * } 18 | * } 19 | * }); 20 | */ 21 | export type StaticYamlFile = File; 22 | 23 | export async function StaticYamlFile( 24 | id: string, 25 | ...args: [content: any] | [path: string, content: any] 26 | ): Promise { 27 | const [path, content] = args.length === 1 ? [id, args[0]] : args; 28 | const yaml = await import("yaml"); 29 | return File(id, { 30 | path, 31 | content: yaml.stringify(content), 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /alchemy/src/github/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./repository-environment.ts"; 2 | export * from "./secret.ts"; 3 | -------------------------------------------------------------------------------- /alchemy/src/index.ts: -------------------------------------------------------------------------------- 1 | export type { AlchemyOptions } from "./alchemy.ts"; 2 | export type * from "./context.ts"; 3 | export * from "./resource.ts"; 4 | export type * from "./scope.ts"; 5 | export * from "./secret.ts"; 6 | export * from "./serde.ts"; 7 | export * from "./state.ts"; 8 | export * from "./type.ts"; 9 | export * from "./util/ignore.ts"; 10 | 11 | import { alchemy } from "./alchemy.ts"; 12 | export default alchemy; 13 | -------------------------------------------------------------------------------- /alchemy/src/neon/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./api-error.ts"; 2 | export * from "./api.ts"; 3 | export * from "./project.ts"; 4 | -------------------------------------------------------------------------------- /alchemy/src/os/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./exec.ts"; 2 | -------------------------------------------------------------------------------- /alchemy/src/runtime/global.ts: -------------------------------------------------------------------------------- 1 | import type { SerializedScope } from "../serde.ts"; 2 | 3 | declare global { 4 | const __ALCHEMY_WORKER_NAME__: string; 5 | const __ALCHEMY_RUNTIME__: true; 6 | const __ALCHEMY_SERIALIZED_SCOPE__: SerializedScope; 7 | } 8 | 9 | // __ALCHEMY_SERIALIZED_SCOPE__ is injected by esbuild when bundling a Worker 10 | export const isRuntime = typeof __ALCHEMY_RUNTIME__ !== "undefined"; 11 | -------------------------------------------------------------------------------- /alchemy/src/runtime/shims.js: -------------------------------------------------------------------------------- 1 | import { env } from "cloudflare:workers"; 2 | import { Scope } from "../scope.js"; 3 | import { Secret } from "../secret.js"; 4 | import { deserialize } from "../serde.js"; 5 | 6 | globalThis.process.env = env; 7 | 8 | export const __ALCHEMY_RUNTIME__ = true; 9 | 10 | export var __ALCHEMY_SERIALIZED_SCOPE__ = JSON.parse( 11 | env.__ALCHEMY_SERIALIZED_SCOPE__, 12 | ); 13 | 14 | export const STATE = { 15 | async get(id) { 16 | const fqn = globalThis.__ALCHEMY_SCOPE__.current.fqn(id); 17 | const state = __ALCHEMY_SERIALIZED_SCOPE__[fqn]; 18 | if (!state) { 19 | throw new Error( 20 | `Resource ${fqn} not found in __ALCHEMY_SERIALIZED_SCOPE__\n${JSON.stringify(__ALCHEMY_SERIALIZED_SCOPE__, null, 2)}`, 21 | ); 22 | } 23 | return await deserialize(Scope.current, state, { 24 | transform: (value) => { 25 | if (value && typeof value === "object" && value["@secret-env"]) { 26 | return { 27 | value: new Secret(env[value["@secret-env"]]), 28 | }; 29 | } 30 | }, 31 | }); 32 | }, 33 | }; 34 | // export const process = { env }; 35 | -------------------------------------------------------------------------------- /alchemy/src/runtime/state.ts: -------------------------------------------------------------------------------- 1 | import type { Resource } from "../resource.ts"; 2 | 3 | export interface RuntimeState { 4 | get(id: string): Resource; 5 | } 6 | 7 | // /** 8 | // * Runtime state injected into the environment. 9 | // */ 10 | -------------------------------------------------------------------------------- /alchemy/src/sentry/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./api.ts"; 2 | export * from "./client-key.ts"; 3 | export * from "./project.ts"; 4 | export * from "./team.ts"; 5 | -------------------------------------------------------------------------------- /alchemy/src/stripe/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./meter.ts"; 2 | export * from "./price.ts"; 3 | export * from "./product.ts"; 4 | export * from "./webhook.ts"; 5 | -------------------------------------------------------------------------------- /alchemy/src/type.ts: -------------------------------------------------------------------------------- 1 | export type type = typeof type; 2 | /** 3 | * Used to construct type-level alias information. 4 | */ 5 | export const type = ((): any => { 6 | throw new Error("Should never be called, purely for type-level aliasing"); 7 | }) as (() => T) & 8 | // we also want to make this a "class type" so that syntax highlighting is always as a type 9 | (new () => T); 10 | -------------------------------------------------------------------------------- /alchemy/src/upstash/error.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Custom error class for Upstash API errors 3 | */ 4 | export class UpstashError extends Error { 5 | /** 6 | * HTTP status code 7 | */ 8 | statusCode: number; 9 | 10 | /** 11 | * Original response object 12 | */ 13 | response: Response; 14 | 15 | /** 16 | * Create a new Upstash error 17 | * 18 | * @param message Error message 19 | * @param statusCode HTTP status code 20 | * @param response Original response object 21 | */ 22 | constructor(message: string, statusCode: number, response: Response) { 23 | super(message); 24 | this.name = "UpstashError"; 25 | this.statusCode = statusCode; 26 | this.response = response; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /alchemy/src/upstash/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./api.ts"; 2 | export * from "./error.ts"; 3 | export * from "./redis.ts"; 4 | -------------------------------------------------------------------------------- /alchemy/src/util/assert-never.ts: -------------------------------------------------------------------------------- 1 | export function assertNever(value: never): never { 2 | throw new Error(`Unexpected value: ${value}`); 3 | } 4 | -------------------------------------------------------------------------------- /alchemy/src/util/content-type.ts: -------------------------------------------------------------------------------- 1 | import path from "node:path"; 2 | 3 | // Common MIME types 4 | const mimeTypes: Record = { 5 | ".html": "text/html", 6 | ".htm": "text/html", 7 | ".css": "text/css", 8 | ".js": "application/javascript", 9 | ".mjs": "application/javascript+module", 10 | ".json": "application/json", 11 | ".xml": "application/xml", 12 | ".txt": "text/plain", 13 | ".md": "text/markdown", 14 | ".png": "image/png", 15 | ".jpg": "image/jpeg", 16 | ".jpeg": "image/jpeg", 17 | ".gif": "image/gif", 18 | ".webp": "image/webp", 19 | ".svg": "image/svg+xml", 20 | ".ico": "image/x-icon", 21 | ".pdf": "application/pdf", 22 | ".zip": "application/zip", 23 | ".woff": "font/woff", 24 | ".woff2": "font/woff2", 25 | ".ttf": "font/ttf", 26 | ".otf": "font/otf", 27 | ".eot": "application/vnd.ms-fontobject", 28 | ".mp4": "video/mp4", 29 | ".webm": "video/webm", 30 | ".mp3": "audio/mpeg", 31 | ".wav": "audio/wav", 32 | ".wasm": "application/wasm", 33 | }; 34 | 35 | /** 36 | * Gets the content type for a file based on its extension 37 | * 38 | * @param filePath Path to the file 39 | * @returns The content type for the file 40 | */ 41 | export function getContentType(filePath: string): string | undefined { 42 | return mimeTypes[path.extname(filePath).toLowerCase()]; 43 | } 44 | -------------------------------------------------------------------------------- /alchemy/src/util/ignore.ts: -------------------------------------------------------------------------------- 1 | export async function ignore( 2 | codes: string | string[], 3 | fn: () => Promise, 4 | ): Promise { 5 | try { 6 | return await fn(); 7 | } catch (error: any) { 8 | const errorCode = error.code || error.name; 9 | if ( 10 | Array.isArray(codes) ? codes.includes(errorCode) : errorCode === codes 11 | ) { 12 | return undefined; 13 | } 14 | throw error; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /alchemy/src/util/retry.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Utility function for exponential backoff retry 3 | * Retries an operation with exponential backoff when a retryable error occurs 4 | * 5 | * @param operation The async operation to execute and potentially retry 6 | * @param isRetryable Function to determine if an error should trigger a retry 7 | * @param maxAttempts Maximum number of attempts before giving up 8 | * @param initialDelayMs Initial delay in milliseconds before first retry 9 | * @returns Result of the operation 10 | * @throws The last error encountered if all retries fail 11 | */ 12 | export async function withExponentialBackoff( 13 | operation: () => Promise, 14 | isRetryable: (error: any) => boolean, 15 | maxAttempts = 5, 16 | initialDelayMs = 100, 17 | ): Promise { 18 | let attempt = 0; 19 | let delay = initialDelayMs; 20 | 21 | while (true) { 22 | try { 23 | return await operation(); 24 | } catch (error: any) { 25 | console.log(error.message); 26 | attempt++; 27 | if (attempt >= maxAttempts || !isRetryable(error)) { 28 | throw error; 29 | } 30 | 31 | // Exponential backoff with jitter 32 | const jitter = Math.random() * 0.1 * delay; 33 | await new Promise((resolve) => setTimeout(resolve, delay + jitter)); 34 | delay *= 2; // Double the delay for next attempt 35 | delay = Math.min(delay, 10000); // Cap at 10 seconds 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /alchemy/src/util/rm.ts: -------------------------------------------------------------------------------- 1 | import fs from "node:fs/promises"; 2 | 3 | export async function rm(path: string) { 4 | try { 5 | await fs.rm(path, { recursive: true, force: true }); 6 | } catch (error: any) { 7 | if (error.code !== "ENOENT") { 8 | throw error; 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /alchemy/src/util/sha256.ts: -------------------------------------------------------------------------------- 1 | import { createHash } from "node:crypto"; 2 | 3 | export function sha256(value: string): string { 4 | return createHash("sha256").update(value).digest("hex"); 5 | } 6 | -------------------------------------------------------------------------------- /alchemy/src/util/sleep.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Pauses execution for a specified number of milliseconds. 3 | * @param ms The number of milliseconds to sleep. 4 | * @returns A promise that resolves after the specified time. 5 | */ 6 | export function sleep(ms: number): Promise { 7 | return new Promise((resolve) => setTimeout(resolve, ms)); 8 | } 9 | -------------------------------------------------------------------------------- /alchemy/src/util/slugify.ts: -------------------------------------------------------------------------------- 1 | export function slugify(str: string, delimiter = "-") { 2 | return str.toLowerCase().replace(/[^a-z0-9]/gi, delimiter); 3 | } 4 | -------------------------------------------------------------------------------- /alchemy/src/vercel/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./api.ts"; 2 | export * from "./project-domain.ts"; 3 | export * from "./project.ts"; 4 | -------------------------------------------------------------------------------- /alchemy/src/web/vitepress/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./config.ts"; 2 | export * from "./custom-theme.ts"; 3 | export * from "./home-page.ts"; 4 | export * from "./process-front-matter-files.ts"; 5 | export * from "./vitepress.ts"; 6 | -------------------------------------------------------------------------------- /alchemy/test/alchemy.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect } from "vitest"; 2 | import { alchemy } from "../src/alchemy.ts"; 3 | import { BRANCH_PREFIX } from "./util.ts"; 4 | 5 | import "../src/test/vitest.ts"; 6 | 7 | const test = alchemy.test(import.meta, { 8 | prefix: BRANCH_PREFIX, 9 | }); 10 | 11 | describe("alchemy.run", async () => { 12 | describe("read mode", async () => { 13 | test("can create a scope", async (scope) => { 14 | expect(scope.phase).toBe("up"); 15 | 16 | await alchemy.run("child", { phase: "read" }, async (child) => { 17 | expect(child.phase).toBe("read"); 18 | expect(child.appName).toBeUndefined(); 19 | expect(child.scopeName).toBe("child"); 20 | expect(child.parent).toBe(scope); 21 | }); 22 | }); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /alchemy/test/aws/control/test-utils.ts: -------------------------------------------------------------------------------- 1 | import { createCloudControlClient } from "../../../src/aws/control/client.js"; 2 | 3 | const client = await createCloudControlClient(); 4 | 5 | /** 6 | * Wait for a resource to be stably deleted (not just gone once due to eventual consistency) 7 | */ 8 | export async function waitForStableDeletion( 9 | typeName: string, 10 | id: string, 11 | { 12 | maxWaitMs = 60_000, // give up after a minute 13 | stablePeriodMs = 5_000, // require this long with no re-appearance 14 | pollBaseDelayMs = 500, // first poll delay 15 | pollMaxDelayMs = 5_000, // max back-off 16 | } = {}, 17 | ) { 18 | let stableFor = 0; 19 | let delay = pollBaseDelayMs; 20 | const started = Date.now(); 21 | 22 | while (Date.now() - started < maxWaitMs) { 23 | const res = await client.getResource(typeName, id); 24 | 25 | if (res === undefined) { 26 | // resource is currently gone – keep watching until it has *stayed* gone 27 | await new Promise((r) => setTimeout(r, delay)); 28 | stableFor += delay; 29 | if (stableFor >= stablePeriodMs) return; // really gone 30 | } else { 31 | // it re-appeared – reset the stability timer 32 | stableFor = 0; 33 | await new Promise((r) => setTimeout(r, delay)); 34 | } 35 | 36 | delay = Math.min(delay * 2, pollMaxDelayMs); // exponential back-off 37 | } 38 | 39 | throw new Error( 40 | `Resource ${typeName} ${id} still exists after ${maxWaitMs} ms`, 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /alchemy/test/cloudflare/account-id.test.ts: -------------------------------------------------------------------------------- 1 | import { beforeAll, describe, expect } from "vitest"; 2 | import { alchemy } from "../../src/alchemy.ts"; 3 | import { AccountId } from "../../src/cloudflare/account-id.ts"; 4 | import { createCloudflareApi } from "../../src/cloudflare/api.ts"; 5 | import { BRANCH_PREFIX } from "../util.ts"; 6 | 7 | import { destroy } from "../../src/destroy.ts"; 8 | import "../../src/test/vitest.ts"; 9 | 10 | const test = alchemy.test(import.meta, { 11 | prefix: BRANCH_PREFIX, 12 | }); 13 | 14 | describe("Cloudflare Account ID", () => { 15 | let expectedAccountId: string; 16 | 17 | // Get the expected account ID before running tests 18 | beforeAll(async () => { 19 | const api = await createCloudflareApi(); 20 | expectedAccountId = api.accountId; 21 | }); 22 | 23 | test("AccountId function", async (scope) => { 24 | try { 25 | // Get account ID with default options 26 | const accountId = await AccountId(); 27 | 28 | // Verify account ID was retrieved correctly 29 | expect(accountId).toBeTruthy(); 30 | expect(accountId).toEqual(expectedAccountId); 31 | 32 | // Verify account ID can be retrieved with explicit options 33 | const accountIdWithOptions = await AccountId({ 34 | accountId: expectedAccountId, 35 | }); 36 | 37 | expect(accountIdWithOptions).toEqual(expectedAccountId); 38 | } finally { 39 | await destroy(scope); 40 | } 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /alchemy/test/cloudflare/browser-handler.ts: -------------------------------------------------------------------------------- 1 | import puppeteer from "@cloudflare/puppeteer"; 2 | 3 | export default { 4 | async fetch(request: Request, env: any) { 5 | const { searchParams } = new URL(request.url); 6 | let url = searchParams.get("url"); 7 | let img; 8 | 9 | if (url) { 10 | url = new URL(url).toString(); // normalize 11 | img = await env.BROWSER_KV_DEMO.get(url, { type: "arrayBuffer" }); 12 | 13 | if (img === null) { 14 | const browser = await puppeteer.launch(env.MYBROWSER); 15 | const page = await browser.newPage(); 16 | await page.goto(url); 17 | img = await page.screenshot(); 18 | 19 | await env.BROWSER_KV_DEMO.put(url, img, { 20 | expirationTtl: 60 * 60 * 24, 21 | }); 22 | 23 | await browser.close(); 24 | } 25 | 26 | return new Response(img, { 27 | headers: { 28 | "content-type": "image/jpeg", 29 | }, 30 | }); 31 | } else { 32 | return new Response("Please add an ?url=https://example.com/ parameter"); 33 | } 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /alchemy/test/cloudflare/bundle-handler-als.ts: -------------------------------------------------------------------------------- 1 | import hooks from "node:async_hooks"; 2 | 3 | export default { 4 | async fetch(): Promise { 5 | return new Response(typeof hooks.AsyncLocalStorage); 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /alchemy/test/cloudflare/bundle-handler.ts: -------------------------------------------------------------------------------- 1 | import { initLogger } from "braintrust"; 2 | // biome-ignore lint/style/useNodejsImportProtocol: we are testing `crypto` and `node:crypto` 3 | import crypto from "crypto"; 4 | import crypto2 from "node:crypto"; 5 | 6 | export default { 7 | async fetch(_request: Request, env: any): Promise { 8 | const logger = initLogger({ 9 | projectName: "My Project", 10 | apiKey: env.BRAINTRUST_API_KEY, 11 | asyncFlush: false, 12 | }); 13 | console.log(crypto.randomBytes(10)); 14 | console.log(crypto2.randomBytes(10)); 15 | console.log(logger); 16 | require("ws"); 17 | return new Response("Hello World!"); 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /alchemy/test/cloudflare/migrations/001_create_table.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE test_migrations_table ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT 4 | ); 5 | -------------------------------------------------------------------------------- /alchemy/test/cloudflare/nobundle/dir/bar.js: -------------------------------------------------------------------------------- 1 | export const bar = "bar"; -------------------------------------------------------------------------------- /alchemy/test/cloudflare/nobundle/foo.js: -------------------------------------------------------------------------------- 1 | export const foo = "foo"; -------------------------------------------------------------------------------- /alchemy/test/cloudflare/nobundle/index.js: -------------------------------------------------------------------------------- 1 | import { bar } from "./dir/bar.js"; 2 | import { foo } from "./foo.js"; 3 | 4 | export default { 5 | async fetch() { 6 | return new Response(JSON.stringify({ 7 | foo, 8 | bar 9 | })) 10 | } 11 | }; -------------------------------------------------------------------------------- /alchemy/test/cloudflare/r2-rest-state-store.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect } from "vitest"; 2 | import { alchemy } from "../../src/alchemy.ts"; 3 | import { createCloudflareApi } from "../../src/cloudflare/api.ts"; 4 | import { getBucket } from "../../src/cloudflare/bucket.ts"; 5 | import { BRANCH_PREFIX } from "../util.ts"; 6 | 7 | import { R2RestStateStore } from "../../src/cloudflare/r2-rest-state-store.ts"; 8 | import "../../src/test/vitest.ts"; 9 | 10 | describe("R2RestStateStore", async () => { 11 | const test = alchemy.test(import.meta, { 12 | // Isolate the default state store bucket from other tests' stores 13 | prefix: `${BRANCH_PREFIX}-r2-rest-state-store`, 14 | stateStore: (scope) => new R2RestStateStore(scope), 15 | }); 16 | 17 | // For public access, we still need to use the Cloudflare API 18 | // This is one feature not available through the S3 API 19 | const api = await createCloudflareApi(); 20 | 21 | test("optimistically creates alchemy-state bucket", async () => { 22 | const defaultBucketName = "alchemy-state"; 23 | const bucket = await getBucket(api, defaultBucketName); 24 | 25 | expect(bucket.result.name).toEqual(defaultBucketName); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /alchemy/test/cloudflare/unenv-handler.ts: -------------------------------------------------------------------------------- 1 | import fs from "node:fs/promises"; 2 | 3 | export default { 4 | async fetch( 5 | _request: Request, 6 | _env: any, 7 | _ctx: ExecutionContext, 8 | ): Promise { 9 | return new Response(typeof fs.readFile); 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /alchemy/test/cloudflare/unenv.test.ts: -------------------------------------------------------------------------------- 1 | import * as path from "node:path"; 2 | import { describe, expect } from "vitest"; 3 | import { alchemy } from "../../src/alchemy.ts"; 4 | import { Worker } from "../../src/cloudflare/worker.ts"; 5 | import { destroy } from "../../src/destroy.ts"; 6 | import { BRANCH_PREFIX } from "../util.ts"; 7 | 8 | import "@cloudflare/unenv-preset/node/process"; 9 | 10 | import "../../src/test/vitest.ts"; 11 | import { fetchAndExpectOK } from "./fetch-utils.ts"; 12 | 13 | const test = alchemy.test(import.meta, { 14 | prefix: BRANCH_PREFIX, 15 | }); 16 | 17 | describe("Worker Unenv Tests", () => { 18 | test("create worker with import.meta.dirname and unenv-handler", async (scope) => { 19 | try { 20 | // Create a temporary directory for the files 21 | // Create the worker using the entrypoint file 22 | const worker = await Worker(`${BRANCH_PREFIX}-test-worker-unenv`, { 23 | entrypoint: path.join(import.meta.dirname, "unenv-handler.ts"), 24 | format: "esm", 25 | url: true, // Enable workers.dev URL to test the worker 26 | compatibilityFlags: ["nodejs_compat"], 27 | }); 28 | 29 | const response = await fetchAndExpectOK(worker.url!); 30 | expect(await response.text()).toEqual("function"); 31 | } finally { 32 | // Clean up the worker 33 | await destroy(scope); 34 | } 35 | }, 120000); // Increased timeout for bundling operations 36 | }); 37 | -------------------------------------------------------------------------------- /alchemy/test/cloudflare/version-metadata-handler.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | async fetch(_request: Request, env: any): Promise { 3 | if (env.IMAGES && env.IMAGES.type === "images") { 4 | return new Response("Images binding available", { status: 200 }); 5 | } 6 | if (env.VERSION_METADATA) { 7 | return new Response("VersionMetadata binding available", { status: 200 }); 8 | } 9 | return new Response("Binding not found", { status: 500 }); 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /alchemy/test/cloudflare/version-metadata.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect } from "vitest"; 2 | import { alchemy } from "../../src/alchemy.ts"; 3 | import { VersionMetadata } from "../../src/cloudflare/version-metadata.ts"; 4 | import { Worker } from "../../src/cloudflare/worker.ts"; 5 | import { destroy } from "../../src/destroy.ts"; 6 | import { BRANCH_PREFIX } from "../util.ts"; 7 | 8 | import path from "node:path"; 9 | import "../../src/test/vitest.ts"; 10 | import { fetchAndExpectOK } from "./fetch-utils.ts"; 11 | 12 | const test = alchemy.test(import.meta, { 13 | prefix: BRANCH_PREFIX, 14 | }); 15 | 16 | describe("VersionMetadata Binding", () => { 17 | test("create worker with version metadata binding", async (scope) => { 18 | const workerName = `${BRANCH_PREFIX}-version-metadata-worker`; 19 | 20 | let worker: Worker | undefined; 21 | 22 | try { 23 | worker = await Worker(workerName, { 24 | name: workerName, 25 | entrypoint: path.join( 26 | import.meta.dirname, 27 | "version-metadata-handler.ts", 28 | ), 29 | format: "esm", 30 | url: true, 31 | bindings: { 32 | VERSION_METADATA: new VersionMetadata(), 33 | }, 34 | }); 35 | 36 | expect(worker.id).toBeTruthy(); 37 | expect(worker.name).toEqual(workerName); 38 | expect(worker.bindings).toBeDefined(); 39 | expect(worker.url).toBeTruthy(); 40 | 41 | const response = await fetchAndExpectOK(worker.url!); 42 | const text = await response.text(); 43 | expect(text).toContain("VersionMetadata binding available"); 44 | } finally { 45 | await destroy(scope); 46 | } 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /alchemy/test/esbuild.test.ts: -------------------------------------------------------------------------------- 1 | import fs from "node:fs/promises"; 2 | import path from "node:path"; 3 | import { afterAll, expect } from "vitest"; 4 | import { alchemy } from "../src/alchemy.ts"; 5 | import { Bundle } from "../src/esbuild/bundle.ts"; 6 | import { BRANCH_PREFIX, exists } from "./util.ts"; 7 | 8 | import { destroy } from "../src/destroy.ts"; 9 | import "../src/test/vitest.ts"; 10 | 11 | const test = alchemy.test(import.meta, { 12 | prefix: BRANCH_PREFIX, 13 | }); 14 | 15 | const out = path.join(".alchemy", ".out"); 16 | const outputFile = path.join(out, "handler.js"); 17 | 18 | afterAll(async () => { 19 | await fs.rmdir(out); 20 | }); 21 | 22 | test("bundle and cleanup", async (scope) => { 23 | const bundle = await Bundle("bundle", { 24 | entryPoint: path.join(import.meta.dirname, "handler.ts"), 25 | outdir: out, 26 | format: "esm", 27 | platform: "node", 28 | target: "node18", 29 | }); 30 | 31 | try { 32 | // Apply the bundle 33 | expect(bundle.path).toBe(outputFile); 34 | expect(bundle.hash).toBeTruthy(); 35 | 36 | // Verify the file exists and contains our code 37 | expect(await exists(outputFile)).toBe(true); 38 | const contents = await fs.readFile(outputFile, "utf-8"); 39 | expect(contents).toContain("Hello from bundled handler"); 40 | } finally { 41 | await destroy(scope); 42 | expect(await exists(outputFile)).toBe(false); 43 | } 44 | }); 45 | -------------------------------------------------------------------------------- /alchemy/test/handler.ts: -------------------------------------------------------------------------------- 1 | export async function handler(event: any) { 2 | console.log("Received event:", JSON.stringify(event)); 3 | 4 | // For Lambda URL, the actual payload is in the body 5 | const payload = event.body 6 | ? typeof event.body === "string" 7 | ? JSON.parse(event.body) 8 | : event.body 9 | : event; 10 | 11 | return { 12 | statusCode: 200, 13 | body: JSON.stringify({ 14 | message: "Hello from bundled handler!", 15 | event: payload, 16 | }), 17 | }; 18 | } 19 | // test case for handlers with _, 0-9, and A-Z 20 | export const _myHandler012 = handler; 21 | -------------------------------------------------------------------------------- /alchemy/test/run.ts: -------------------------------------------------------------------------------- 1 | import { runChangedTests } from "../src/test/prune.js"; 2 | 3 | /** 4 | * This script detects which tests have changed using esbuild and git and then runs only those tests. 5 | */ 6 | 7 | const sinceIdx = process.argv.findIndex((arg) => arg === "--since"); 8 | const since = 9 | (sinceIdx !== -1 ? process.argv[sinceIdx + 1] : undefined) ?? "HEAD~1"; 10 | 11 | const vitestIdx = process.argv.findIndex((arg) => arg === "--vitest"); 12 | const useVitest = vitestIdx !== -1; 13 | 14 | await runChangedTests(import.meta.dirname, since, useVitest); 15 | -------------------------------------------------------------------------------- /alchemy/test/util.ts: -------------------------------------------------------------------------------- 1 | import fs from "node:fs/promises"; 2 | import os from "node:os"; 3 | 4 | /** 5 | * Check if a file or directory exists 6 | * Uses fs.access which is available in all Node.js versions 7 | */ 8 | export async function exists(path: string): Promise { 9 | try { 10 | await fs.access(path); 11 | return true; 12 | } catch { 13 | return false; 14 | } 15 | } 16 | 17 | /** 18 | * Sanitize a string to be safe for AWS resource names 19 | * Replaces any characters that aren't alphanumeric, hyphen, or underscore 20 | */ 21 | function sanitizeForAwsResourceName(str: string): string { 22 | // Replace any character that's not alphanumeric, hyphen, or underscore with a hyphen 23 | return str.replace(/[^a-zA-Z0-9\-_]/g, "-"); 24 | } 25 | 26 | /** 27 | * Branch prefix for resource names to avoid naming conflicts in CI/CD 28 | * 29 | * Uses BRANCH_PREFIX environment variable in CI/CD environments 30 | * Falls back to current user's name in local development 31 | * Sanitizes to ensure only valid characters for AWS resource names 32 | */ 33 | export const BRANCH_PREFIX = sanitizeForAwsResourceName( 34 | process.env.BRANCH_PREFIX || os.userInfo().username, 35 | ); 36 | -------------------------------------------------------------------------------- /alchemy/test/util/dedent.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import { dedent } from "../../src/util/dedent.ts"; 3 | 4 | describe("dedent", () => { 5 | it("removes common indentation", () => { 6 | const s = dedent` 7 | line1 8 | line2 9 | line3 10 | `; 11 | expect(s).toBe("line1\n line2\nline3"); 12 | }); 13 | 14 | it("removes leading and trailing blank lines", () => { 15 | const s = dedent` 16 | 17 | line1 18 | line2 19 | 20 | `; 21 | expect(s).toBe("line1\nline2"); 22 | }); 23 | 24 | it("preserves extra indentation", () => { 25 | const s = dedent` 26 | level1 27 | level2 28 | level3 29 | `; 30 | expect(s).toBe("level1\n level2\n level3"); 31 | }); 32 | 33 | it("handles empty template", () => { 34 | const s = dedent``; 35 | expect(s).toBe(""); 36 | }); 37 | 38 | it("handles single line", () => { 39 | const s = dedent`single line`; 40 | expect(s).toBe("single line"); 41 | }); 42 | 43 | it("interpolates values correctly", () => { 44 | const value = "world"; 45 | const s = dedent` 46 | hello ${value} 47 | bye 48 | `; 49 | expect(s).toBe("hello world\nbye"); 50 | }); 51 | 52 | it("preserves blank lines in between", () => { 53 | const s = dedent` 54 | line1 55 | 56 | line3 57 | `; 58 | expect(s).toBe("line1\n\nline3"); 59 | }); 60 | 61 | it("returns empty for only whitespace lines", () => { 62 | const s = dedent` 63 | 64 | 65 | `; 66 | expect(s).toBe(""); 67 | }); 68 | }); 69 | -------------------------------------------------------------------------------- /alchemy/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base.json", 3 | "include": ["src/**/*.ts", "src/**/*.js"], 4 | "compilerOptions": { 5 | "composite": true, 6 | "noEmit": false, 7 | "outDir": "./lib", 8 | "rootDir": "./src", 9 | "sourceMap": true, 10 | "declarationMap": true, 11 | "module": "Preserve", 12 | "moduleResolution": "Bundler", 13 | "target": "ESNext", 14 | "allowJs": true, 15 | "allowImportingTsExtensions": true, 16 | "rewriteRelativeImportExtensions": true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /alchemy/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["src/**/*.ts", "test/**/*.ts", "src/runtime/shims.js"], 4 | "compilerOptions": { 5 | "rootDir": ".", 6 | "noEmit": true, 7 | "types": ["bun-types", "@cloudflare/workers-types"] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /examples/aws-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aws-app", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "bun run index.ts", 7 | "deploy": "bun run --env-file ../../.env ./alchemy.run.ts", 8 | "destroy": "bun run --env-file ../../.env ./alchemy.run.ts --destroy" 9 | }, 10 | "dependencies": { 11 | "alchemy": "workspace:*" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/aws-app/src/index.ts: -------------------------------------------------------------------------------- 1 | export function handler(_event: any, _context: any) { 2 | console.log("Hello, World!"); 3 | } 4 | -------------------------------------------------------------------------------- /examples/aws-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "include": ["src/**/*.ts", "alchemy.run.ts"], 4 | "compilerOptions": { 5 | "composite": true, 6 | "resolveJsonModule": true 7 | }, 8 | "references": [{ "path": "../../alchemy/tsconfig.json" }] 9 | } 10 | -------------------------------------------------------------------------------- /examples/cloudflare-nuxt-pipeline/.gitignore: -------------------------------------------------------------------------------- 1 | # Nuxt dev/build outputs 2 | .output 3 | .data 4 | .nuxt 5 | .nitro 6 | .cache 7 | dist 8 | 9 | # Node dependencies 10 | node_modules 11 | 12 | # Logs 13 | logs 14 | *.log 15 | 16 | # Misc 17 | .DS_Store 18 | .fleet 19 | .idea 20 | 21 | # Local env files 22 | .env 23 | .env.* 24 | !.env.example 25 | wrangler.jsonc 26 | -------------------------------------------------------------------------------- /examples/cloudflare-nuxt-pipeline/app.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /examples/cloudflare-nuxt-pipeline/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import type { worker } from "./alchemy.run.js"; 3 | 4 | export type WorkerEnv = typeof worker.Env; 5 | 6 | declare module "cloudflare:workers" { 7 | namespace Cloudflare { 8 | export interface Env extends WorkerEnv {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/cloudflare-nuxt-pipeline/index.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import type { WorkerEnv } from "./env.ts"; 3 | // @ts-ignore - Suppress type errors if the module isn't found during editing/linting 4 | import nitroApp from "./.output/server/index.mjs"; 5 | 6 | export default { 7 | async fetch( 8 | request: Request, 9 | environment: WorkerEnv, 10 | ctx: ExecutionContext, 11 | ): Promise { 12 | const url = new URL(request.url); 13 | 14 | if (url.pathname.startsWith("/api/")) { 15 | return nitroApp.fetch(request, environment, ctx); 16 | } 17 | 18 | return environment.ASSETS.fetch(request); 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /examples/cloudflare-nuxt-pipeline/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | // https://nuxt.com/docs/api/configuration/nuxt-config 2 | export default defineNuxtConfig({ 3 | compatibilityDate: "2025-04-21", 4 | devtools: { enabled: true }, 5 | nitro: { 6 | preset: "cloudflare-module", 7 | prerender: { 8 | routes: ["/"], 9 | autoSubfolderIndex: false, 10 | }, 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /examples/cloudflare-nuxt-pipeline/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nuxt-pipeline", 3 | "private": true, 4 | "type": "module", 5 | "scripts": { 6 | "build": "nuxt build", 7 | "dev": "nuxt dev", 8 | "generate": "nuxt generate", 9 | "preview": "nuxt preview", 10 | "postinstall": "nuxt prepare", 11 | "deploy": "bun run --env-file ../../.env ./alchemy.run.ts", 12 | "destroy": "bun run --env-file ../../.env ./alchemy.run.ts --destroy" 13 | }, 14 | "dependencies": { 15 | "@cloudflare/workers-types": "^4.20250421.0", 16 | "alchemy": "workspace:*", 17 | "cloudflare": "^4.2.0", 18 | "nuxt": "^3.16.2", 19 | "vue": "^3.5.13", 20 | "vue-router": "^4.5.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/cloudflare-nuxt-pipeline/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sam-goodwin/alchemy/5ad508201ef5217e8a5ef47a9efc21e2c29b8031/examples/cloudflare-nuxt-pipeline/public/favicon.ico -------------------------------------------------------------------------------- /examples/cloudflare-nuxt-pipeline/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-Agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /examples/cloudflare-nuxt-pipeline/server/api/pipeline.post.ts: -------------------------------------------------------------------------------- 1 | import { env } from "cloudflare:workers"; 2 | 3 | export default defineEventHandler(async (event) => { 4 | try { 5 | const body = await readBody(event); 6 | // @ts-ignore 7 | const pipeline = env.PIPELINE; 8 | const data = body.data; 9 | 10 | if (!data) { 11 | throw new Error("Missing 'data' property in request body"); 12 | } 13 | 14 | // Always send data wrapped in an array 15 | await pipeline.send([{ value: data }]); 16 | 17 | return { success: true, message: "Data sent to pipeline." }; 18 | } catch (error) { 19 | console.error("Error sending data to pipeline:", error); 20 | throw createError({ 21 | statusCode: 500, 22 | statusMessage: error instanceof Error ? error.message : "Pipeline error", 23 | }); 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /examples/cloudflare-nuxt-pipeline/server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.nuxt/tsconfig.server.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/cloudflare-nuxt-pipeline/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // https://nuxt.com/docs/guide/concepts/typescript 3 | "extends": "./.nuxt/tsconfig.json", 4 | "compilerOptions": { 5 | "types": ["@cloudflare/workers-types", "@types/node"], 6 | "jsx": "react-jsx" 7 | }, 8 | "references": [{ "path": "../../alchemy/tsconfig.json" }] 9 | } 10 | -------------------------------------------------------------------------------- /examples/cloudflare-react-router/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /node_modules/ 3 | *.tsbuildinfo 4 | 5 | # React Router 6 | /.react-router/ 7 | /build/ 8 | 9 | # Cloudflare 10 | .mf 11 | .wrangler 12 | .dev.vars* 13 | 14 | wrangler.json* -------------------------------------------------------------------------------- /examples/cloudflare-react-router/alchemy.run.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import alchemy from "alchemy"; 4 | import { R2RestStateStore, ReactRouter } from "alchemy/cloudflare"; 5 | 6 | const BRANCH_PREFIX = process.env.BRANCH_PREFIX ?? ""; 7 | const app = await alchemy("cloudflare-react-router", { 8 | stage: process.env.USER ?? "dev", 9 | phase: process.argv.includes("--destroy") ? "destroy" : "up", 10 | quiet: !process.argv.includes("--verbose"), 11 | password: process.env.ALCHEMY_PASSWORD, 12 | stateStore: 13 | process.env.ALCHEMY_STATE_STORE === "cloudflare" 14 | ? (scope) => new R2RestStateStore(scope) 15 | : undefined, 16 | }); 17 | 18 | export const website = await ReactRouter( 19 | `cloudflare-react-router-website${BRANCH_PREFIX}`, 20 | { 21 | main: "./workers/app.ts", 22 | command: "bun run build", 23 | }, 24 | ); 25 | 26 | console.log({ 27 | url: website.url, 28 | }); 29 | 30 | await app.finalize(); 31 | -------------------------------------------------------------------------------- /examples/cloudflare-react-router/app/app.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss" source("."); 2 | 3 | @theme { 4 | --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif, 5 | "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; 6 | } 7 | 8 | html, 9 | body { 10 | @apply bg-white dark:bg-gray-950; 11 | 12 | @media (prefers-color-scheme: dark) { 13 | color-scheme: dark; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/cloudflare-react-router/app/entry.server.tsx: -------------------------------------------------------------------------------- 1 | import type { AppLoadContext, EntryContext } from "react-router"; 2 | import { ServerRouter } from "react-router"; 3 | import { isbot } from "isbot"; 4 | import { renderToReadableStream } from "react-dom/server"; 5 | 6 | export default async function handleRequest( 7 | request: Request, 8 | responseStatusCode: number, 9 | responseHeaders: Headers, 10 | routerContext: EntryContext, 11 | _loadContext: AppLoadContext 12 | ) { 13 | let shellRendered = false; 14 | const userAgent = request.headers.get("user-agent"); 15 | 16 | const body = await renderToReadableStream( 17 | , 18 | { 19 | onError(error: unknown) { 20 | responseStatusCode = 500; 21 | // Log streaming rendering errors from inside the shell. Don't log 22 | // errors encountered during initial shell rendering since they'll 23 | // reject and get logged in handleDocumentRequest. 24 | if (shellRendered) { 25 | console.error(error); 26 | } 27 | }, 28 | } 29 | ); 30 | shellRendered = true; 31 | 32 | // Ensure requests from bots and SPA Mode renders wait for all content to load before responding 33 | // https://react.dev/reference/react-dom/server/renderToPipeableStream#waiting-for-all-content-to-load-for-crawlers-and-static-generation 34 | if ((userAgent && isbot(userAgent)) || routerContext.isSpaMode) { 35 | await body.allReady; 36 | } 37 | 38 | responseHeaders.set("Content-Type", "text/html"); 39 | return new Response(body, { 40 | headers: responseHeaders, 41 | status: responseStatusCode, 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /examples/cloudflare-react-router/app/routes.ts: -------------------------------------------------------------------------------- 1 | import { type RouteConfig, index } from "@react-router/dev/routes"; 2 | 3 | export default [index("routes/home.tsx")] satisfies RouteConfig; 4 | -------------------------------------------------------------------------------- /examples/cloudflare-react-router/app/routes/home.tsx: -------------------------------------------------------------------------------- 1 | import type { Route } from "./+types/home"; 2 | import { Welcome } from "../welcome/welcome"; 3 | 4 | export function meta({}: Route.MetaArgs) { 5 | return [ 6 | { title: "New React Router App" }, 7 | { name: "description", content: "Welcome to React Router!" }, 8 | ]; 9 | } 10 | 11 | export function loader({ context }: Route.LoaderArgs) { 12 | return { message: context.cloudflare.env.VALUE_FROM_CLOUDFLARE }; 13 | } 14 | 15 | export default function Home({ loaderData }: Route.ComponentProps) { 16 | return ; 17 | } 18 | -------------------------------------------------------------------------------- /examples/cloudflare-react-router/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cloudflare-react-router", 3 | "private": true, 4 | "type": "module", 5 | "scripts": { 6 | "build": "react-router build", 7 | "deploy": "bun --env-file ../../.env ./alchemy.run.ts", 8 | "destroy": "bun --env-file ../../.env ./alchemy.run.ts --destroy", 9 | "dev": "react-router dev", 10 | "preview": "bun run build && vite preview", 11 | "types": "react-router typegen" 12 | }, 13 | "dependencies": { 14 | "cloudflare": "^4.3.0", 15 | "isbot": "^5.1.27", 16 | "react": "^19.1.0", 17 | "react-dom": "^19.1.0", 18 | "react-router": "^7.5.3" 19 | }, 20 | "devDependencies": { 21 | "@cloudflare/vite-plugin": "^1.0.12", 22 | "@cloudflare/workers-types": "^4.20250529.0", 23 | "@react-router/dev": "^7.5.3", 24 | "@tailwindcss/vite": "^4.1.4", 25 | "@types/node": "^20", 26 | "@types/react": "^19.1.2", 27 | "@types/react-dom": "^19.1.2", 28 | "tailwindcss": "^4.1.4", 29 | "typescript": "^5.8.3", 30 | "vite": "^6.3.3", 31 | "vite-tsconfig-paths": "^5.1.4", 32 | "wrangler": "^4.18.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/cloudflare-react-router/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sam-goodwin/alchemy/5ad508201ef5217e8a5ef47a9efc21e2c29b8031/examples/cloudflare-react-router/public/favicon.ico -------------------------------------------------------------------------------- /examples/cloudflare-react-router/react-router.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "@react-router/dev/config"; 2 | 3 | export default { 4 | ssr: true, 5 | future: { 6 | unstable_viteEnvironmentApi: true, 7 | }, 8 | } satisfies Config; 9 | -------------------------------------------------------------------------------- /examples/cloudflare-react-router/tsconfig.cloudflare.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": [ 4 | "./alchemy.run.ts", 5 | ".react-router/types/**/*", 6 | "app/**/*", 7 | "app/**/.server/**/*", 8 | "app/**/.client/**/*", 9 | "workers/**/*", 10 | "types/**/*.ts" 11 | ], 12 | "compilerOptions": { 13 | "composite": true, 14 | "strict": true, 15 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 16 | "types": ["vite/client", "@cloudflare/workers-types"], 17 | "target": "ES2022", 18 | "module": "ES2022", 19 | "moduleResolution": "bundler", 20 | "jsx": "react-jsx", 21 | "baseUrl": ".", 22 | "rootDirs": [".", "./.react-router/types"], 23 | "paths": { 24 | "~/*": ["./app/*"] 25 | }, 26 | "esModuleInterop": true, 27 | "resolveJsonModule": true, 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/cloudflare-react-router/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.node.json" }, 5 | { "path": "./tsconfig.cloudflare.json" } 6 | ], 7 | "compilerOptions": { 8 | "checkJs": true, 9 | "verbatimModuleSyntax": true, 10 | "skipLibCheck": true, 11 | "strict": true, 12 | "noEmit": true, 13 | "types": ["./workers/env.ts", "@cloudflare/workers-types"] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/cloudflare-react-router/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["vite.config.ts"], 4 | "compilerOptions": { 5 | "composite": true, 6 | "strict": true, 7 | "types": ["node"], 8 | "lib": ["ES2022"], 9 | "target": "ES2022", 10 | "module": "ES2022", 11 | "moduleResolution": "bundler" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/cloudflare-react-router/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { reactRouter } from "@react-router/dev/vite"; 2 | import { cloudflare } from "@cloudflare/vite-plugin"; 3 | import tailwindcss from "@tailwindcss/vite"; 4 | import { defineConfig } from "vite"; 5 | import tsconfigPaths from "vite-tsconfig-paths"; 6 | 7 | export default defineConfig({ 8 | plugins: [ 9 | cloudflare({ viteEnvironment: { name: "ssr" } }), 10 | tailwindcss(), 11 | reactRouter(), 12 | tsconfigPaths(), 13 | ], 14 | }); 15 | -------------------------------------------------------------------------------- /examples/cloudflare-react-router/workers/app.ts: -------------------------------------------------------------------------------- 1 | import { createRequestHandler } from "react-router"; 2 | 3 | declare module "react-router" { 4 | export interface AppLoadContext { 5 | cloudflare: { 6 | env: Env; 7 | ctx: ExecutionContext; 8 | }; 9 | } 10 | } 11 | 12 | const requestHandler = createRequestHandler( 13 | () => import("virtual:react-router/server-build"), 14 | import.meta.env.MODE 15 | ); 16 | 17 | export default { 18 | async fetch(request, env, ctx) { 19 | return requestHandler(request, { 20 | cloudflare: { env, ctx }, 21 | }); 22 | }, 23 | } satisfies ExportedHandler; 24 | -------------------------------------------------------------------------------- /examples/cloudflare-react-router/workers/env.ts: -------------------------------------------------------------------------------- 1 | import type { website } from "../alchemy.run.js"; 2 | 3 | export type CloudflareEnv = typeof website.Env; 4 | 5 | declare global { 6 | type Env = CloudflareEnv 7 | } 8 | 9 | declare module "cloudflare:workers" { 10 | namespace Cloudflare { 11 | export interface Env extends CloudflareEnv {} 12 | } 13 | } -------------------------------------------------------------------------------- /examples/cloudflare-redwood/.env.example: -------------------------------------------------------------------------------- 1 | CLOUDFLARE_ACCOUNT_ID=__change_me__ 2 | CLOUDFLARE_DATABASE_ID=__change_me__ 3 | CLOUDFLARE_D1_TOKEN=__change_me__ 4 | -------------------------------------------------------------------------------- /examples/cloudflare-redwood/.gitignore: -------------------------------------------------------------------------------- 1 | # Node modules 2 | node_modules 3 | 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | pnpm-debug.log* 9 | 10 | # Environment variables 11 | .env 12 | .dev.vars 13 | 14 | # Vite build output 15 | dist 16 | 17 | # TypeScript 18 | *.tsbuildinfo 19 | 20 | # IDEs and editors 21 | .vscode/ 22 | .idea/ 23 | *.suo 24 | *.ntvs* 25 | *.njsproj 26 | *.sln 27 | *.sw? 28 | 29 | # MacOS 30 | .DS_Store 31 | 32 | # Optional npm cache directory 33 | .npm 34 | 35 | # Optional eslint cache 36 | .eslintcache 37 | 38 | # Optional stylelint cache 39 | .stylelintcache 40 | 41 | # Optional REPL history 42 | .node_repl_history 43 | 44 | # Output of 'npm pack' 45 | *.tgz 46 | 47 | # pnpm store directory 48 | .pnpm-store 49 | 50 | # dotenv environment variables file 51 | .env.local 52 | .env.development.local 53 | .env.test.local 54 | .env.production.local 55 | 56 | # Vite cache 57 | .vite 58 | 59 | # Coverage directory used by tools like istanbul 60 | coverage 61 | 62 | # Temporary files 63 | *.tmp 64 | *.temp 65 | 66 | .wrangler 67 | wrangler.jsonc -------------------------------------------------------------------------------- /examples/cloudflare-redwood/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "files": "*.jsonc", 5 | "options": { 6 | "trailingComma": "none" 7 | } 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /examples/cloudflare-redwood/alchemy.run.ts: -------------------------------------------------------------------------------- 1 | import alchemy from "alchemy"; 2 | import { D1Database, R2RestStateStore, Redwood } from "alchemy/cloudflare"; 3 | 4 | const BRANCH_PREFIX = process.env.BRANCH_PREFIX ?? ""; 5 | 6 | const app = await alchemy("cloudflare-redwood", { 7 | phase: process.argv.includes("--destroy") ? "destroy" : "up", 8 | stateStore: 9 | process.env.ALCHEMY_STATE_STORE === "cloudflare" 10 | ? (scope) => new R2RestStateStore(scope) 11 | : undefined, 12 | }); 13 | 14 | const database = await D1Database(`cloudflare-redwood-db${BRANCH_PREFIX}`, { 15 | migrationsDir: "drizzle", 16 | }); 17 | 18 | export const website = await Redwood( 19 | `cloudflare-redwood-website${BRANCH_PREFIX}`, 20 | { 21 | bindings: { 22 | DB: database, 23 | }, 24 | }, 25 | ); 26 | 27 | console.log({ 28 | url: website.url, 29 | }); 30 | 31 | await app.finalize(); 32 | -------------------------------------------------------------------------------- /examples/cloudflare-redwood/drizzle.config.ts: -------------------------------------------------------------------------------- 1 | import "dotenv/config"; 2 | import { defineConfig } from "drizzle-kit"; 3 | 4 | export default defineConfig({ 5 | out: "./drizzle", 6 | schema: "./src/db/schema.ts", 7 | dialect: "sqlite", 8 | driver: "d1-http", 9 | dbCredentials: { 10 | accountId: process.env.CLOUDFLARE_ACCOUNT_ID!, 11 | databaseId: process.env.CLOUDFLARE_DATABASE_ID!, 12 | token: process.env.CLOUDFLARE_D1_TOKEN!, 13 | }, 14 | }); 15 | -------------------------------------------------------------------------------- /examples/cloudflare-redwood/drizzle/0000_lame_kitty_pryde.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `users` ( 2 | `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, 3 | `name` text NOT NULL, 4 | `email` text NOT NULL 5 | ); 6 | --> statement-breakpoint 7 | CREATE UNIQUE INDEX `users_email_unique` ON `users` (`email`); -------------------------------------------------------------------------------- /examples/cloudflare-redwood/drizzle/meta/0000_snapshot.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "6", 3 | "dialect": "sqlite", 4 | "id": "da6e7ea7-3118-455b-914c-14ff9239bd40", 5 | "prevId": "00000000-0000-0000-0000-000000000000", 6 | "tables": { 7 | "users": { 8 | "name": "users", 9 | "columns": { 10 | "id": { 11 | "name": "id", 12 | "type": "integer", 13 | "primaryKey": true, 14 | "notNull": true, 15 | "autoincrement": true 16 | }, 17 | "name": { 18 | "name": "name", 19 | "type": "text", 20 | "primaryKey": false, 21 | "notNull": true, 22 | "autoincrement": false 23 | }, 24 | "email": { 25 | "name": "email", 26 | "type": "text", 27 | "primaryKey": false, 28 | "notNull": true, 29 | "autoincrement": false 30 | } 31 | }, 32 | "indexes": { 33 | "users_email_unique": { 34 | "name": "users_email_unique", 35 | "columns": ["email"], 36 | "isUnique": true 37 | } 38 | }, 39 | "foreignKeys": {}, 40 | "compositePrimaryKeys": {}, 41 | "uniqueConstraints": {}, 42 | "checkConstraints": {} 43 | } 44 | }, 45 | "views": {}, 46 | "enums": {}, 47 | "_meta": { 48 | "schemas": {}, 49 | "tables": {}, 50 | "columns": {} 51 | }, 52 | "internal": { 53 | "indexes": {} 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /examples/cloudflare-redwood/drizzle/meta/_journal.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "7", 3 | "dialect": "sqlite", 4 | "entries": [ 5 | { 6 | "idx": 0, 7 | "version": "6", 8 | "when": 1743024718213, 9 | "tag": "0000_lame_kitty_pryde", 10 | "breakpoints": true 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /examples/cloudflare-redwood/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@redwoodjs/starter-drizzle", 3 | "version": "1.0.0", 4 | "description": "A RedwoodSDK starter for projects with a database using Drizzle", 5 | "main": "index.js", 6 | "type": "module", 7 | "keywords": [], 8 | "author": "", 9 | "license": "MIT", 10 | "private": true, 11 | "scripts": { 12 | "build": "vite build", 13 | "dev": "NODE_ENV=${NODE_ENV:-development} vite dev", 14 | "dev:init": "rw-scripts dev-init", 15 | "preview": "bun run build && bun run vite preview", 16 | "worker:run": "rw-scripts worker-run", 17 | "clean": "bun run clean:vite", 18 | "clean:vite": "rm -rf ./node_modules/.vite", 19 | "release": "rw-scripts ensure-deploy-env && bun run clean && bun run migrate:new && RWSDK_DEPLOY=1 bun run build && wrangler deploy", 20 | "format": "prettier --write ./src", 21 | "migrate:new": "drizzle-kit generate", 22 | "migrate:dev": "wrangler d1 migrations apply DB --local", 23 | "seed": "bun run worker:run ./src/db/seed.ts", 24 | "check": "bun run types", 25 | "types": "bun run tsc", 26 | "deploy": "bun run --env-file ../../.env ./alchemy.run.ts", 27 | "destroy": "bun run --env-file ../../.env ./alchemy.run.ts --destroy" 28 | }, 29 | "dependencies": { 30 | "alchemy": "workspace:*", 31 | "dotenv": "^16.5.0", 32 | "drizzle-orm": "beta", 33 | "rwsdk": "^0.0.83" 34 | }, 35 | "devDependencies": { 36 | "@types/node": "^22.14.1", 37 | "@types/react": "^19.1.2", 38 | "@types/react-dom": "^19.1.2", 39 | "drizzle-kit": "beta", 40 | "tsx": "^4.19.3", 41 | "vite": "^6.3.2", 42 | "wrangler": "^4.12.1" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /examples/cloudflare-redwood/public/images/cloudflare-account-id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sam-goodwin/alchemy/5ad508201ef5217e8a5ef47a9efc21e2c29b8031/examples/cloudflare-redwood/public/images/cloudflare-account-id.png -------------------------------------------------------------------------------- /examples/cloudflare-redwood/public/images/cloudflare-copy-token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sam-goodwin/alchemy/5ad508201ef5217e8a5ef47a9efc21e2c29b8031/examples/cloudflare-redwood/public/images/cloudflare-copy-token.png -------------------------------------------------------------------------------- /examples/cloudflare-redwood/public/images/cloudflare-custom-tokens.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sam-goodwin/alchemy/5ad508201ef5217e8a5ef47a9efc21e2c29b8031/examples/cloudflare-redwood/public/images/cloudflare-custom-tokens.png -------------------------------------------------------------------------------- /examples/cloudflare-redwood/public/images/cloudflare-d1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sam-goodwin/alchemy/5ad508201ef5217e8a5ef47a9efc21e2c29b8031/examples/cloudflare-redwood/public/images/cloudflare-d1.png -------------------------------------------------------------------------------- /examples/cloudflare-redwood/public/images/cloudflare-new-token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sam-goodwin/alchemy/5ad508201ef5217e8a5ef47a9efc21e2c29b8031/examples/cloudflare-redwood/public/images/cloudflare-new-token.png -------------------------------------------------------------------------------- /examples/cloudflare-redwood/public/images/cloudflare-token-summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sam-goodwin/alchemy/5ad508201ef5217e8a5ef47a9efc21e2c29b8031/examples/cloudflare-redwood/public/images/cloudflare-token-summary.png -------------------------------------------------------------------------------- /examples/cloudflare-redwood/public/images/cloudflare-user-api-tokens.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sam-goodwin/alchemy/5ad508201ef5217e8a5ef47a9efc21e2c29b8031/examples/cloudflare-redwood/public/images/cloudflare-user-api-tokens.png -------------------------------------------------------------------------------- /examples/cloudflare-redwood/public/images/new-db.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sam-goodwin/alchemy/5ad508201ef5217e8a5ef47a9efc21e2c29b8031/examples/cloudflare-redwood/public/images/new-db.png -------------------------------------------------------------------------------- /examples/cloudflare-redwood/src/app/Document.tsx: -------------------------------------------------------------------------------- 1 | export const Document: React.FC<{ children: React.ReactNode }> = ({ 2 | children, 3 | }) => ( 4 | 5 | 6 | 7 | 8 | @redwoodjs/starter-drizzle 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/cloudflare-vite/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite-project", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc -b && vite build", 9 | "deploy": "bun run --env-file ../../.env ./alchemy.run.ts", 10 | "destroy": "bun run --env-file ../../.env ./alchemy.run.ts --destroy", 11 | "lint": "eslint .", 12 | "preview": "vite preview" 13 | }, 14 | "dependencies": { 15 | "@openauthjs/openauth": "^0.4.3", 16 | "react": "^19.0.0", 17 | "react-dom": "^19.0.0", 18 | "valibot": "^1.0.0" 19 | }, 20 | "devDependencies": { 21 | "@cloudflare/vite-plugin": "^1.0.4", 22 | "@eslint/js": "^9.21.0", 23 | "@types/node": "^22.13.10", 24 | "@types/react": "^19.0.10", 25 | "@types/react-dom": "^19.0.4", 26 | "@vitejs/plugin-react": "^4.3.4", 27 | "alchemy": "workspace:*", 28 | "cloudflare": "^4.2.0", 29 | "dotenv": "^16.4.7", 30 | "eslint": "^9.21.0", 31 | "eslint-plugin-react-hooks": "^5.1.0", 32 | "eslint-plugin-react-refresh": "^0.4.19", 33 | "globals": "^15.15.0", 34 | "tsx": "^4.19.3", 35 | "typescript": "~5.7.2", 36 | "typescript-eslint": "^8.24.1", 37 | "vite": "^6.2.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/cloudflare-vite/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/cloudflare-vite/src/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /examples/cloudflare-vite/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import reactLogo from "./assets/react.svg"; 3 | import viteLogo from "/vite.svg"; 4 | import "./App.css"; 5 | 6 | function App() { 7 | const [count, setCount] = useState(0); 8 | 9 | return ( 10 | <> 11 | 19 |

Vite + React

20 |
21 | 24 |

25 | Edit src/App.tsx and save to test HMR 26 |

27 |
28 |

29 | Click on the Vite and React logos to learn more 30 |

31 | 32 | ); 33 | } 34 | 35 | export default App; 36 | -------------------------------------------------------------------------------- /examples/cloudflare-vite/src/auth/subjects.ts: -------------------------------------------------------------------------------- 1 | import { createSubjects } from "@openauthjs/openauth/subject"; 2 | import type { InferOutput } from "valibot"; 3 | import { object, string } from "valibot"; 4 | 5 | export type User = InferOutput; 6 | 7 | export const User = object({ 8 | id: string(), 9 | name: string(), 10 | email: string(), 11 | avatar: string(), 12 | }); 13 | 14 | export interface Subjects { 15 | user: InferOutput; 16 | } 17 | 18 | // Define our subject structure 19 | export const Subjects = createSubjects({ 20 | user: User, 21 | }); 22 | -------------------------------------------------------------------------------- /examples/cloudflare-vite/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import type { website } from "../alchemy.run.js"; 4 | 5 | export type CloudFlareEnv = typeof website.Env; 6 | 7 | declare module "cloudflare:workers" { 8 | namespace Cloudflare { 9 | export interface Env extends CloudFlareEnv {} 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/cloudflare-vite/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | a { 17 | font-weight: 500; 18 | color: #646cff; 19 | text-decoration: inherit; 20 | } 21 | a:hover { 22 | color: #535bf2; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | display: flex; 28 | place-items: center; 29 | min-width: 320px; 30 | min-height: 100vh; 31 | } 32 | 33 | h1 { 34 | font-size: 3.2em; 35 | line-height: 1.1; 36 | } 37 | 38 | button { 39 | border-radius: 8px; 40 | border: 1px solid transparent; 41 | padding: 0.6em 1.2em; 42 | font-size: 1em; 43 | font-weight: 500; 44 | font-family: inherit; 45 | background-color: #1a1a1a; 46 | cursor: pointer; 47 | transition: border-color 0.25s; 48 | } 49 | button:hover { 50 | border-color: #646cff; 51 | } 52 | button:focus, 53 | button:focus-visible { 54 | outline: 4px auto -webkit-focus-ring-color; 55 | } 56 | 57 | @media (prefers-color-scheme: light) { 58 | :root { 59 | color: #213547; 60 | background-color: #ffffff; 61 | } 62 | a:hover { 63 | color: #747bff; 64 | } 65 | button { 66 | background-color: #f9f9f9; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /examples/cloudflare-vite/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Hono } from "hono"; 2 | 3 | // TODO: looks like openauth imports node:fs ... 4 | // import { issuer } from "./auth/issuer"; 5 | 6 | export const api = new Hono(); 7 | 8 | api.get("/hello", (c) => c.text("Hello World")); 9 | 10 | export default { 11 | async fetch(request: Request): Promise { 12 | return api.fetch(request); 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /examples/cloudflare-vite/src/main.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from "react"; 2 | import { createRoot } from "react-dom/client"; 3 | import "./index.css"; 4 | import App from "./App.tsx"; 5 | 6 | createRoot(document.getElementById("root")!).render( 7 | 8 | 9 | , 10 | ); 11 | -------------------------------------------------------------------------------- /examples/cloudflare-vite/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /examples/cloudflare-vite/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "types": ["@cloudflare/workers-types"], 5 | "allowImportingTsExtensions": true, 6 | "jsx": "react-jsx" 7 | }, 8 | "include": ["vite/*.ts", "src/**/*.ts", "src/**/*.tsx", "src/env.d.ts"], 9 | "references": [{ "path": "../../alchemy/tsconfig.json" }] 10 | } 11 | -------------------------------------------------------------------------------- /examples/cloudflare-vite/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { cloudflare } from "@cloudflare/vite-plugin"; 2 | import react from "@vitejs/plugin-react"; 3 | import { defineConfig } from "vite"; 4 | 5 | // https://vite.dev/config/ 6 | export default defineConfig({ 7 | plugins: [react(), cloudflare()], 8 | }); 9 | -------------------------------------------------------------------------------- /examples/cloudflare-worker-bootstrap/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cloudflare-worker-bootstrap", 3 | "private": true, 4 | "type": "module", 5 | "scripts": { 6 | "deploy": "bun tsx --env-file ../../.env ./index.ts", 7 | "destroy": "bun tsx --env-file ../../.env ./index.ts --destroy" 8 | }, 9 | "dependencies": { 10 | "alchemy": "workspace:*" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/cloudflare-worker-bootstrap/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["index.ts"], 3 | "extends": "../../tsconfig.base.json", 4 | "compilerOptions": { 5 | "types": ["@cloudflare/workers-types", "@types/node"] 6 | }, 7 | "references": [ 8 | { 9 | "path": "../../alchemy/tsconfig.json" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /examples/cloudflare-worker/.gitignore: -------------------------------------------------------------------------------- 1 | wrangler.jsonc -------------------------------------------------------------------------------- /examples/cloudflare-worker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cloudflare-worker", 3 | "private": true, 4 | "type": "module", 5 | "scripts": { 6 | "deploy": "bun run --env-file ../../.env ./alchemy.run.ts", 7 | "destroy": "bun run --env-file ../../.env ./alchemy.run.ts --destroy" 8 | }, 9 | "dependencies": { 10 | "alchemy": "workspace:*", 11 | "braintrust": "^0.0.201", 12 | "chalk": "^5.4.1", 13 | "pluralize": "^8.0.0", 14 | "cli-progress": "^3.12.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /examples/cloudflare-worker/src/do.ts: -------------------------------------------------------------------------------- 1 | import { DurableObject } from "cloudflare:workers"; 2 | 3 | /** 4 | * A simple Hello World Durable Object 5 | */ 6 | export class HelloWorldDO extends DurableObject { 7 | async increment() { 8 | // Get the current count from storage or initialize to 0 9 | let count = (await this.ctx.storage.get("count")) || 0; 10 | 11 | // Store the updated count 12 | await this.ctx.storage.put("count", count); 13 | 14 | return count; 15 | } 16 | 17 | /** 18 | * Handle HTTP requests to the Durable Object 19 | */ 20 | async fetch(_request: Request): Promise { 21 | const count = await this.increment(); 22 | 23 | // Return a response with the count 24 | return new Response( 25 | JSON.stringify({ 26 | message: "Hello World from Durable Object!", 27 | count: count, 28 | timestamp: new Date().toISOString(), 29 | }), 30 | { 31 | headers: { 32 | "Content-Type": "application/json", 33 | }, 34 | }, 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /examples/cloudflare-worker/src/env.ts: -------------------------------------------------------------------------------- 1 | import type { worker } from "../alchemy.run.js"; 2 | 3 | declare global { 4 | export type CloudflareEnv = typeof worker.Env; 5 | } 6 | 7 | declare module "cloudflare:workers" { 8 | namespace Cloudflare { 9 | export interface Env extends CloudflareEnv {} 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/cloudflare-worker/src/rpc.ts: -------------------------------------------------------------------------------- 1 | import { WorkerEntrypoint } from "cloudflare:workers"; 2 | 3 | export default class MyRPC extends WorkerEntrypoint { 4 | /** 5 | * Hello world 6 | */ 7 | async hello(name: string) { 8 | return `Hello, ${name}!`; 9 | } 10 | async fetch() { 11 | return new Response("Hello from Worker B"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/cloudflare-worker/src/worker.ts: -------------------------------------------------------------------------------- 1 | import { env } from "cloudflare:workers"; 2 | import type { queue, worker } from "../alchemy.run.js"; 3 | export * from "./do.js"; 4 | export * from "./workflow.js"; 5 | 6 | export default { 7 | async fetch(_request: Request) { 8 | await env.QUEUE.send({ 9 | name: "John Doe", 10 | email: "john.doe@example.com", 11 | }); 12 | 13 | const obj = env.DO.get(env.DO.idFromName("foo")); 14 | await obj.increment(); 15 | async function _foo() { 16 | // @ts-expect-error - foo doesn't exist on the HelloWorldDO class 17 | await obj.foo(); 18 | } 19 | await obj.fetch(new Request("https://example.com")); 20 | 21 | await env.RPC.hello("John Doe"); 22 | 23 | return new Response("Ok"); 24 | }, 25 | async queue(batch: typeof queue.Batch, _env: typeof worker.Env) { 26 | for (const message of batch.messages) { 27 | console.log(message); 28 | message.ack(); 29 | } 30 | batch.ackAll(); 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /examples/cloudflare-worker/src/workflow.ts: -------------------------------------------------------------------------------- 1 | // Import the Workflow definition 2 | import { 3 | WorkflowEntrypoint, 4 | type WorkflowEvent, 5 | type WorkflowStep, 6 | } from "cloudflare:workers"; 7 | // just to test bundling 8 | import { NonRetryableError } from "cloudflare:workflows"; 9 | 10 | // Create your own class that implements a Workflow 11 | export class OFACWorkflow extends WorkflowEntrypoint { 12 | // Define a run() method 13 | async run(_event: WorkflowEvent, step: WorkflowStep) { 14 | // Define one or more steps that optionally return state. 15 | await step.do("my first step", async () => { 16 | console.log("OFAC WORKFLOW STEP 1"); 17 | }); 18 | await step.do("my second step", async () => { 19 | console.log("OFAC WORKFLOW STEP 2"); 20 | }); 21 | 22 | throw new NonRetryableError("test"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/cloudflare-worker/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src/*.ts"], 3 | "extends": "../../tsconfig.base.json", 4 | "compilerOptions": { 5 | "types": ["@cloudflare/workers-types", "@types/node"] 6 | }, 7 | "references": [ 8 | { 9 | "path": "../../alchemy/tsconfig.json" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "alchemy-mono", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "module": "./lib/index.js", 7 | "license": "Apache-2.0", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/sam-goodwin/alchemy" 11 | }, 12 | "scripts": { 13 | "build": "tsc -b", 14 | "check": "bun run --filter cloudflare-react-router types && tsc -b ./tsconfig.json && biome check", 15 | "fix": "biome check --write", 16 | "deploy:repo": "bun ./stacks/repo.run.ts", 17 | "deploy:website": "bun ./stacks/website.run.ts", 18 | "generate:docs": "bun ./stacks/docs.run.ts", 19 | "generate:aws-control": "bun ./scripts/generate-aws-control.ts", 20 | "publish:npm": "bun run --filter alchemy publish:npm", 21 | "test": "bun ./alchemy/test/run.ts", 22 | "test:force": "vitest run", 23 | "bump": "bun ./scripts/bump.ts" 24 | }, 25 | "workspaces": [ 26 | "alchemy", 27 | "alchemy-web", 28 | "examples/*" 29 | ], 30 | "devDependencies": { 31 | "@biomejs/biome": "beta", 32 | "@redwoodjs/sdk": "^0.0.80", 33 | "@types/bun": "latest", 34 | "@types/node": "latest", 35 | "@vitest/ui": "^3.1.4", 36 | "aws4fetch": "^1.0.20", 37 | "braintrust": "*", 38 | "changelogithub": "^13.15.0", 39 | "openai": "^4.103.0", 40 | "typescript": "latest", 41 | "vitest": "^3.1.4", 42 | "yaml": "^2.7.1" 43 | }, 44 | "dependencies": { 45 | "alchemy-mono": "." 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /public/alchemist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sam-goodwin/alchemy/5ad508201ef5217e8a5ef47a9efc21e2c29b8031/public/alchemist.png -------------------------------------------------------------------------------- /public/alchemist.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sam-goodwin/alchemy/5ad508201ef5217e8a5ef47a9efc21e2c29b8031/public/alchemist.webp -------------------------------------------------------------------------------- /scripts/shell.ts: -------------------------------------------------------------------------------- 1 | import { exec } from "../alchemy/src/os/exec.js"; 2 | import { website } from "../stacks/website.run.js"; 3 | 4 | const command = process.argv.slice(2).join(" "); 5 | 6 | if (!command) { 7 | console.error("No command provided"); 8 | process.exit(1); 9 | } 10 | 11 | await exec(command, { 12 | env: { 13 | WEBSITE_URL: website.url, 14 | }, 15 | }); 16 | -------------------------------------------------------------------------------- /stacks/env.ts: -------------------------------------------------------------------------------- 1 | import type { AlchemyOptions, Phase } from "../alchemy/src/alchemy.js"; 2 | import { R2RestStateStore } from "../alchemy/src/cloudflare/index.js"; 3 | import alchemy from "../alchemy/src/index.js"; 4 | 5 | export const CLOUDFLARE_EMAIL = await alchemy.env.CLOUDFLARE_EMAIL; 6 | 7 | export const CLOUDFLARE_ACCOUNT_ID = await alchemy.env.CLOUDFLARE_ACCOUNT_ID; 8 | 9 | export const CLOUDFLARE_API_KEY = await alchemy.secret.env.CLOUDFLARE_API_KEY; 10 | 11 | export const STRIPE_API_KEY = await alchemy.secret.env.STRIPE_API_KEY; 12 | 13 | export const OPENAI_API_KEY = await alchemy.secret.env.OPENAI_API_KEY; 14 | 15 | export const NEON_API_KEY = await alchemy.secret.env.NEON_API_KEY; 16 | 17 | export const UPSTASH_API_KEY = await alchemy.secret.env.UPSTASH_API_KEY; 18 | 19 | export default { 20 | stage: "prod", 21 | phase: 22 | (process.env.ALCHEMY_PHASE as Phase) ?? 23 | (process.argv.includes("--destroy") 24 | ? "destroy" 25 | : process.argv.includes("--read") 26 | ? "read" 27 | : "up"), 28 | // pass the password in (you can get it from anywhere, e.g. stdin) 29 | password: process.env.SECRET_PASSPHRASE, 30 | quiet: process.argv.includes("--quiet"), 31 | stateStore: 32 | process.env.ALCHEMY_STATE_STORE === "cloudflare" 33 | ? (scope) => new R2RestStateStore(scope) 34 | : undefined, 35 | } satisfies AlchemyOptions; 36 | -------------------------------------------------------------------------------- /stacks/website.run.ts: -------------------------------------------------------------------------------- 1 | // ensure providers are registered (for deletion purposes) 2 | 3 | import "../alchemy/src/cloudflare/index.js"; 4 | import "../alchemy/src/dns/index.js"; 5 | import "../alchemy/src/os/index.js"; 6 | 7 | import path from "node:path"; 8 | import { 9 | Assets, 10 | CustomDomain, 11 | Worker, 12 | Zone, 13 | } from "../alchemy/src/cloudflare/index.js"; 14 | import alchemy from "../alchemy/src/index.js"; 15 | import { Exec } from "../alchemy/src/os/index.js"; 16 | import options from "./env.js"; 17 | 18 | const app = await alchemy("alchemy:website", options); 19 | 20 | const zone = await Zone("alchemy.run", { 21 | name: "alchemy.run", 22 | type: "full", 23 | }); 24 | 25 | await Exec("build-site", { 26 | command: "bun run --filter alchemy-web docs:build", 27 | }); 28 | 29 | const staticAssets = await Assets("static-assets", { 30 | path: path.join("alchemy-web", ".vitepress", "dist"), 31 | }); 32 | 33 | export const website = await Worker("website", { 34 | name: "alchemy-website", 35 | url: true, 36 | bindings: { 37 | ASSETS: staticAssets, 38 | }, 39 | assets: { 40 | html_handling: "auto-trailing-slash", 41 | // not_found_handling: "single-page-application", 42 | run_worker_first: false, 43 | }, 44 | script: ` 45 | export default { 46 | async fetch(request, env) { 47 | // return env.ASSETS.fetch(request); 48 | return new Response("Not Found", { status: 404 }); 49 | }, 50 | }; 51 | `, 52 | }); 53 | 54 | await CustomDomain("alchemy-web-domain", { 55 | name: "alchemy.run", 56 | zoneId: zone.id, 57 | workerName: website.name, 58 | }); 59 | 60 | await app.finalize(); 61 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": ["node_modules", "dist"], 3 | "compilerOptions": { 4 | "types": ["@cloudflare/workers-types", "@types/node"], 5 | // Enable latest features 6 | "lib": ["ESNext", "DOM"], 7 | "target": "ESNext", 8 | "moduleDetection": "force", 9 | "jsx": "react-jsx", 10 | "allowJs": true, 11 | "esModuleInterop": true, 12 | "noEmit": true, 13 | 14 | // Bundler mode 15 | "module": "Preserve", 16 | "moduleResolution": "Bundler", 17 | // "allowImportingTsExtensions": true, 18 | "verbatimModuleSyntax": true, 19 | 20 | // Best practices 21 | "strict": true, 22 | "skipLibCheck": true, 23 | "noFallthroughCasesInSwitch": true, 24 | 25 | // Some stricter flags (disabled by default) 26 | "noUnusedLocals": false, 27 | "noUnusedParameters": false, 28 | "noPropertyAccessFromIndexSignature": false, 29 | 30 | "noImplicitThis": true 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "exclude": ["node_modules", "dist"], 4 | "references": [ 5 | { "path": "./tsconfig.stacks.json" }, 6 | { "path": "./alchemy/tsconfig.json" }, 7 | { "path": "./alchemy/tsconfig.test.json" }, 8 | { "path": "./examples/aws-app/tsconfig.json" }, 9 | { "path": "./examples/cloudflare-nuxt-pipeline/tsconfig.json" }, 10 | { "path": "./examples/cloudflare-react-router/tsconfig.json" }, 11 | { "path": "./examples/cloudflare-redwood/tsconfig.json" }, 12 | { "path": "./examples/cloudflare-tanstack-start/tsconfig.json" }, 13 | { "path": "./examples/cloudflare-vite/tsconfig.json" }, 14 | { "path": "./examples/cloudflare-worker-bootstrap/tsconfig.json" }, 15 | { "path": "./examples/cloudflare-worker/tsconfig.json" }, 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /tsconfig.stacks.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "include": ["./stacks/**/*.ts", "scripts/shell.ts"], 4 | "compilerOptions": { 5 | "noEmit": true 6 | }, 7 | "references": [{ "path": "./alchemy/tsconfig.json" }] 8 | } 9 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitest/config"; 2 | 3 | 4 | export default defineConfig({ 5 | test: { 6 | pool: "threads", 7 | poolOptions: { 8 | threads: { 9 | singleThread: false, 10 | maxThreads: 32, 11 | }, 12 | }, 13 | minWorkers: 16, 14 | testTimeout: 120000, 15 | hookTimeout: 120000, 16 | passWithNoTests: true, 17 | sequence: { 18 | concurrent: true, 19 | }, 20 | include: ["alchemy/test/**/*.test.ts"], 21 | exclude: [ 22 | "**/node_modules/**", 23 | "**/dist/**", 24 | "**/lib/**", 25 | "**/.{idea,git,cache,output,temp}/**", 26 | ], 27 | env: { 28 | NODE_ENV: "test", 29 | }, 30 | globals: true, 31 | // reporter: ['verbose'], 32 | coverage: { 33 | provider: "v8", 34 | reporter: ["text", "json", "html"], 35 | exclude: [ 36 | "coverage/**", 37 | "dist/**", 38 | "lib/**", 39 | "**/node_modules/**", 40 | "**/*.test.ts", 41 | "**/*.config.*", 42 | ], 43 | }, 44 | setupFiles: ["./vitest.setup.ts"], 45 | }, 46 | }); 47 | -------------------------------------------------------------------------------- /vitest.setup.ts: -------------------------------------------------------------------------------- 1 | import { config } from "dotenv"; 2 | config({ path: ".env" }); 3 | --------------------------------------------------------------------------------