Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
11 changes: 10 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
**/*.ts
**/lib/**
**/node_modules
alchemy/src/aws/control/types.ts
**/*.js
**/*.md
**/*.json
**/*.html
**/*.css
examples/**
alchemy/templates/**
2 changes: 1 addition & 1 deletion .oxfmtrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"useTabs": false,
"printWidth": 80,
"endOfLine": "lf",
"experimentalTernaries": true,
"ternaries": true,
"experimental_sort_imports": {
"order": "asc"
}
Expand Down
24 changes: 24 additions & 0 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"$schema": "./node_modules/oxfmt/configuration_schema.json",
"plugins": [
"import"
],
"rules": {
"no-misused-new": "off",
"no-empty-pattern": "off",
"no-non-null-asserted-optional-chain": "off",
"no-unsafe-finally": "off",
"triple-slash-reference": "off",
"require-yield": "off",
"import/extensions": [
"error",
"ignorePackages",
{
"ts": "always",
"tsx": "always",
"js": "never",
"jsx": "never"
}
]
}
}
2 changes: 1 addition & 1 deletion alchemy-web/src/routeData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const onRequest = defineRouteMiddleware((context) => {
// Get the content collection entry for this page.
try {
route = context.locals.starlightRoute;
} catch (_) {
} catch {
// This is a non-starlight route, so we want to skip the og generation
return;
}
Expand Down
4 changes: 2 additions & 2 deletions alchemy/bin/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ async function createInitContext(options: {
if (packageJson?.name) {
projectName = sanitizeProjectName(packageJson.name);
}
} catch (_error) {}
} catch {}
}

const useTypeScript = await exists(resolve(cwd, "tsconfig.json"));
Expand Down Expand Up @@ -228,7 +228,7 @@ async function detectFrameworkFromPackageJson(
}

return "typescript";
} catch (_error) {
} catch {
return "typescript";
}
}
Expand Down
7 changes: 0 additions & 7 deletions alchemy/bin/services/github-workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,13 +229,6 @@ import { CloudflareStateStore } from "alchemy/state";`;
code = code.replace(alchemyImportRegex, `$1${githubImport}`);
}

const lastImportRegex = /import[^;]+from[^;]+;(\s*\n)*/g;
let lastImportMatch;

while ((lastImportMatch = lastImportRegex.exec(code)) !== null) {
lastImportMatch.index + lastImportMatch[0].length;
}

const appCallRegex = /const app = await alchemy\("([^"]+)"\);/;
const appMatch = code.match(appCallRegex);
if (appMatch) {
Expand Down
6 changes: 5 additions & 1 deletion alchemy/bin/services/package-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ export const PackageManager = {

export async function installDependencies(
context: ProjectContext,
{ dependencies, devDependencies, cwd }: {
{
dependencies,
devDependencies,
cwd,
}: {
dependencies?: string[];
devDependencies?: string[];
cwd?: string;
Expand Down
2 changes: 1 addition & 1 deletion alchemy/bin/services/template-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ async function handleRwsdkPostInstall(context: ProjectContext): Promise<void> {
`To complete rwsdk setup, run: cd ${context.name} && ${devInitCommand}`,
);
}
} catch (_error) {
} catch {
log.warn(
"Failed to complete rwsdk setup. You may need to run 'dev:init' manually.",
);
Expand Down
2 changes: 1 addition & 1 deletion alchemy/bin/services/vibe-rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ export async function ensureVibeRulesPostinstall(
}

await writeJson(packageJsonPath, packageJson, { spaces: 2 });
} catch (_err) {}
} catch {}
}
213 changes: 213 additions & 0 deletions alchemy/lib/alchemy.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
import { DestroyStrategy, destroy } from "./destroy.ts";
import { env } from "./env.ts";
import { type ProviderCredentials, Scope } from "./scope.ts";
import { secret } from "./secret.ts";
import type { StateStoreType } from "./state.ts";
import type { LoggerApi } from "./util/cli.ts";
/**
* Type alias for semantic highlighting of `alchemy` as a type keyword
*/
export type alchemy = Alchemy;
export declare const alchemy: Alchemy;
/**
* The Alchemy interface provides core functionality and is augmented by providers.
* Supports both application scoping with secrets and template string interpolation.
* Automatically parses CLI arguments for common options.
*
* @example
* // Simple usage with automatic CLI argument parsing
* const app = await alchemy("my-app");
* // Now supports: --destroy, --read, --quiet, --stage my-stage
* // Environment variables: PASSWORD, ALCHEMY_PASSWORD, ALCHEMY_STAGE, USER
*
* @example
* // Create an application scope with explicit options (overrides CLI args)
* const app = await alchemy("github:alchemy", {
* stage: "prod",
* phase: "up",
* // Required for encrypting/decrypting secrets
* password: process.env.SECRET_PASSPHRASE
* });
*
* // Create a resource with encrypted secrets
* const resource = await Resource("my-resource", {
* apiKey: alchemy.secret(process.env.API_KEY)
* });
*
* await app.finalize();
*/
export interface Alchemy {
run: typeof run;
destroy: typeof destroy;
/**
* Get an environment variable and error if it's not set.
*/
env: typeof env;
/**
* Creates an encrypted secret that can be safely stored in state files.
* Requires a password to be set either globally in the application options
* or locally in the current scope.
*/
secret: typeof secret;
/**
* Creates a new application scope with the given name and options.
* Used to create and manage resources with proper secret handling.
* Automatically parses CLI arguments: --destroy, --read, --quiet, --stage <name>
* Environment variables: PASSWORD, ALCHEMY_PASSWORD, ALCHEMY_STAGE, USER
*
* @example
* // Simple usage with CLI argument parsing
* const app = await alchemy("my-app");
*
* @example
* // With explicit options (overrides CLI args)
* const app = await alchemy("my-app", {
* stage: "prod",
* // Required for encrypting/decrypting secrets
* password: process.env.SECRET_PASSPHRASE
* });
*/
(appName: string, options?: Omit<AlchemyOptions, "appName">): Promise<Scope>;
}
export type Phase = "up" | "destroy" | "read";
export interface AlchemyOptions {
/**
* The name of the application.
*/
appName?: string;
/**
* Determines whether the resources will be created/updated or deleted.
*
* @default "up"
*/
phase?: Phase;
/**
* Determines if resources should be simulated locally (where possible)
*
* @default - `true` if ran with `alchemy dev` or `bun ./alchemy.run.ts --dev`
*/
local?: boolean;
/**
* Determines if local changes to resources should be reactively pushed to the local or remote environment.
*
* @default - `true` if ran with `alchemy dev`, `alchemy watch`, `bun --watch ./alchemy.run.ts`
*/
watch?: boolean;
/**
* Apply updates to resources even if there are no changes.
*
* @default false
*/
force?: boolean;
/**
* Whether to create a tunnel for supported resources.
*
* @default false
*/
tunnel?: boolean;
/**
* Name to scope the resource state under (e.g. `.alchemy/{stage}/..`).
*
* @default - your POSIX username
*/
stage?: string;
/**
* If true, will not prune resources that were dropped from the root stack.
*
* @default true
*/
destroyOrphans?: boolean;
/**
* A custom state store to use instead of the default file system store.
*/
stateStore?: StateStoreType;
/**
* A custom scope to use as a parent.
*/
parent?: Scope;
/**
* The strategy to use when destroying resources.
*
* @default "sequential"
*/
destroyStrategy?: DestroyStrategy;
/**
* If true, children of the resource will not be destroyed (but their state will be deleted).
*/
noop?: boolean;
/**
* If true, will not print any Create/Update/Delete messages.
*
* @default false
*/
quiet?: boolean;
/**
* A passphrase to use to encrypt/decrypt secrets.
* Required if using alchemy.secret() in this scope.
*/
password?: string;
/**
* Whether to stop sending anonymous telemetry data to the Alchemy team.
* You can also opt out by setting the `DO_NOT_TRACK` or `ALCHEMY_TELEMETRY_DISABLED` environment variables to a truthy value.
*
* @default false
*/
noTrack?: boolean;
/**
* A custom logger instance to use for this scope.
* If not provided, the default fallback logger will be used.
*/
logger?: LoggerApi;
/**
* Whether to adopt resources if they already exist but are not yet managed by your Alchemy app.
*
* @default false
*/
adopt?: boolean;
/**
* The root directory of the project.
*
* @default process.cwd()
*/
rootDir?: string;
/**
* The Alchemy profile to use for authoriziing requests.
*/
profile?: string;
/**
* Whether this is the application that was selected with `--app`
*
* `true` if the application was selected with `--app`
* `false` if the application was not selected with `--app`
* `undefined` if the program was not run with `--app`
*/
isSelected?: boolean;
}
export interface RunOptions extends AlchemyOptions, ProviderCredentials {
/**
* @default false
*/
isResource?: boolean;
}
/**
* Run a function in a new scope asynchronously.
* Useful for isolating secret handling with a specific password.
*
* @example
* // Run operations in a scope with its own password
* await alchemy.run("secure-scope", {
* password: process.env.SCOPE_PASSWORD
* }, async () => {
* // Secrets in this scope will use this password
* const resource = await Resource("my-resource", {
* apiKey: alchemy.secret(process.env.API_KEY)
* });
* });
*/
declare function run<T>(...args: [id: string, fn: (this: Scope, scope: Scope) => Promise<T>] | [
id: string,
options: RunOptions,
fn: (this: Scope, scope: Scope) => Promise<T>
]): Promise<T>;
export {};
//# sourceMappingURL=alchemy.d.ts.map
14 changes: 14 additions & 0 deletions alchemy/lib/apply.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { type PendingResource, type Resource, type ResourceAttributes, type ResourceProps } from "./resource.ts";
export interface ApplyOptions {
quiet?: boolean;
alwaysUpdate?: boolean;
noop?: boolean;
}
export declare function apply<Out extends ResourceAttributes>(resource: PendingResource<Out>, props: ResourceProps | undefined, options?: ApplyOptions): Promise<Awaited<Out> & Resource>;
export declare function isReplacedSignal(error: any): error is ReplacedSignal;
export declare class ReplacedSignal extends Error {
readonly kind = "ReplacedSignal";
force: boolean;
constructor(force?: boolean);
}
//# sourceMappingURL=apply.d.ts.map
Loading
Loading