alchemy 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/lib/ai/ark.d.ts +11 -0
  2. package/lib/ai/ark.js +86 -0
  3. package/lib/ai/client.d.ts +51 -0
  4. package/lib/ai/client.js +29 -0
  5. package/lib/ai/document.d.ts +97 -0
  6. package/lib/ai/document.js +82 -0
  7. package/lib/{docs → ai}/index.d.ts +1 -0
  8. package/lib/{docs → ai}/index.js +1 -0
  9. package/lib/ai/object.d.ts +101 -0
  10. package/lib/ai/object.js +70 -0
  11. package/lib/alchemy.d.ts +83 -2
  12. package/lib/alchemy.js +31 -3
  13. package/lib/aws/bucket.d.ts +87 -1
  14. package/lib/aws/bucket.js +48 -1
  15. package/lib/aws/function.d.ts +186 -1
  16. package/lib/aws/function.js +62 -8
  17. package/lib/aws/oidc/github-oidc-provider.d.ts +81 -0
  18. package/lib/aws/oidc/github-oidc-provider.js +68 -0
  19. package/lib/aws/oidc/oidc-provider.d.ts +14 -6
  20. package/lib/aws/oidc/oidc-provider.js +26 -5
  21. package/lib/aws/policy-attachment.d.ts +44 -1
  22. package/lib/aws/policy-attachment.js +31 -0
  23. package/lib/aws/policy.d.ts +160 -1
  24. package/lib/aws/policy.js +78 -0
  25. package/lib/aws/queue.d.ts +83 -1
  26. package/lib/aws/queue.js +39 -0
  27. package/lib/aws/role.d.ts +162 -1
  28. package/lib/aws/role.js +114 -0
  29. package/lib/aws/ses.d.ts +57 -2
  30. package/lib/aws/ses.js +42 -1
  31. package/lib/aws/table.d.ts +96 -1
  32. package/lib/aws/table.js +36 -0
  33. package/lib/cloudflare/asset-manifest.js +0 -1
  34. package/lib/cloudflare/bound.js +0 -1
  35. package/lib/cloudflare/bucket.d.ts +37 -1
  36. package/lib/cloudflare/bucket.js +36 -0
  37. package/lib/cloudflare/durable-object-namespace.d.ts +25 -0
  38. package/lib/cloudflare/durable-object-namespace.js +22 -0
  39. package/lib/cloudflare/kv-namespace.d.ts +37 -1
  40. package/lib/cloudflare/kv-namespace.js +36 -0
  41. package/lib/cloudflare/static-site.d.ts +53 -1
  42. package/lib/cloudflare/static-site.js +53 -1
  43. package/lib/cloudflare/worker-metadata.js +0 -1
  44. package/lib/cloudflare/worker.d.ts +64 -1
  45. package/lib/cloudflare/worker.js +63 -0
  46. package/lib/cloudflare/wrangler.json.d.ts +1 -1
  47. package/lib/cloudflare/zone-settings.js +0 -1
  48. package/lib/cloudflare/zone.d.ts +56 -1
  49. package/lib/cloudflare/zone.js +55 -0
  50. package/lib/destroy.js +1 -1
  51. package/lib/esbuild/bundle.d.ts +43 -4
  52. package/lib/esbuild/bundle.js +16 -0
  53. package/lib/fs/file-collection.d.ts +16 -0
  54. package/lib/fs/file-collection.js +6 -0
  55. package/lib/fs/file-ref.d.ts +14 -0
  56. package/lib/fs/file-ref.js +6 -0
  57. package/lib/fs/file.d.ts +71 -25
  58. package/lib/fs/file.js +20 -44
  59. package/lib/fs/folder.d.ts +37 -5
  60. package/lib/fs/folder.js +26 -2
  61. package/lib/fs/index.d.ts +6 -0
  62. package/lib/fs/index.js +6 -0
  63. package/lib/fs/json-file.d.ts +16 -0
  64. package/lib/fs/json-file.js +7 -0
  65. package/lib/fs/text-file.d.ts +12 -0
  66. package/lib/fs/text-file.js +7 -0
  67. package/lib/fs/typescript-file.d.ts +19 -0
  68. package/lib/fs/typescript-file.js +14 -0
  69. package/lib/fs/yaml-file.d.ts +19 -0
  70. package/lib/fs/yaml-file.js +8 -0
  71. package/lib/github/secret.d.ts +63 -2
  72. package/lib/github/secret.js +61 -1
  73. package/lib/internal/docs.d.ts +5 -0
  74. package/lib/internal/docs.js +324 -0
  75. package/lib/resource.d.ts +1 -1
  76. package/lib/secret.d.ts +67 -0
  77. package/lib/secret.js +67 -0
  78. package/lib/shadcn/component.d.ts +1 -1
  79. package/lib/stripe/price.d.ts +51 -1
  80. package/lib/stripe/price.js +50 -0
  81. package/lib/stripe/product.d.ts +39 -1
  82. package/lib/stripe/product.js +38 -0
  83. package/lib/stripe/webhook.d.ts +46 -1
  84. package/lib/stripe/webhook.js +45 -0
  85. package/lib/test/bun.d.ts +64 -0
  86. package/lib/test/bun.js +35 -3
  87. package/lib/util/serde.js +14 -0
  88. package/lib/vite/vite.d.ts +1 -1
  89. package/lib/vitepress/dependencies.d.ts +2 -6
  90. package/lib/vitepress/vitepress.d.ts +12 -1
  91. package/lib/vitepress/vitepress.js +29 -23
  92. package/package.json +8 -3
  93. package/src/ai/ark.ts +118 -0
  94. package/src/ai/client.ts +78 -0
  95. package/src/ai/document.ts +160 -0
  96. package/src/{docs → ai}/index.ts +1 -0
  97. package/src/ai/object.ts +149 -0
  98. package/src/alchemy.ts +88 -5
  99. package/src/aws/bucket.ts +111 -7
  100. package/src/aws/function.ts +231 -10
  101. package/src/aws/oidc/github-oidc-provider.ts +83 -0
  102. package/src/aws/oidc/oidc-provider.ts +39 -7
  103. package/src/aws/policy-attachment.ts +44 -1
  104. package/src/aws/policy.ts +177 -2
  105. package/src/aws/queue.ts +89 -0
  106. package/src/aws/role.ts +174 -2
  107. package/src/aws/ses.ts +56 -1
  108. package/src/aws/table.ts +103 -0
  109. package/src/cloudflare/bucket.ts +36 -0
  110. package/src/cloudflare/durable-object-namespace.ts +25 -0
  111. package/src/cloudflare/kv-namespace.ts +36 -0
  112. package/src/cloudflare/static-site.ts +53 -1
  113. package/src/cloudflare/worker.ts +63 -0
  114. package/src/cloudflare/zone.ts +55 -0
  115. package/src/destroy.ts +1 -1
  116. package/src/esbuild/bundle.ts +53 -3
  117. package/src/fs/file-collection.ts +24 -0
  118. package/src/fs/file-ref.ts +22 -0
  119. package/src/fs/file.ts +70 -77
  120. package/src/fs/folder.ts +44 -5
  121. package/src/fs/index.ts +6 -0
  122. package/src/fs/json-file.ts +23 -0
  123. package/src/fs/text-file.ts +19 -0
  124. package/src/fs/typescript-file.ts +36 -0
  125. package/src/fs/yaml-file.ts +26 -0
  126. package/src/github/secret.ts +65 -2
  127. package/src/internal/docs.ts +369 -0
  128. package/src/resource.ts +1 -1
  129. package/src/secret.ts +67 -0
  130. package/src/stripe/price.ts +50 -0
  131. package/src/stripe/product.ts +38 -0
  132. package/src/stripe/webhook.ts +45 -0
  133. package/src/test/bun.ts +83 -3
  134. package/src/util/serde.ts +17 -0
  135. package/src/vitepress/vitepress.ts +47 -26
  136. package/lib/docs/document.d.ts +0 -123
  137. package/lib/docs/document.js +0 -67
  138. package/src/docs/document.ts +0 -225
package/src/ai/ark.ts ADDED
@@ -0,0 +1,118 @@
1
+ import {
2
+ type Tool as AITool,
3
+ type Schema,
4
+ type ToolExecutionOptions,
5
+ tool as aitool,
6
+ jsonSchema,
7
+ } from "ai";
8
+ import { ArkErrors, type JsonSchema, type type } from "arktype";
9
+
10
+ export namespace ark {
11
+ export function schema<T>(type: JsonSchema): Schema<T>;
12
+ export function schema<T extends type>(type: T): Schema<type.infer<T>> {
13
+ const jsonSchemaObj = type.toJsonSchema() as any;
14
+ const processedSchema = processSchema(jsonSchemaObj);
15
+
16
+ return jsonSchema(processedSchema, {
17
+ validate: (value) => {
18
+ const out = type(value) as type.infer<T> | type.errors;
19
+ if (out instanceof ArkErrors) {
20
+ return {
21
+ success: false,
22
+ error: new Error(out.summary),
23
+ };
24
+ }
25
+ return {
26
+ success: true,
27
+ value: out,
28
+ };
29
+ },
30
+ });
31
+ }
32
+
33
+ /**
34
+ * Recursively processes a JSON schema and sets additionalProperties: false
35
+ * for any object types.
36
+ *
37
+ * Structured Outputs requires additionalProperties: false
38
+ */
39
+ function processSchema(schema: any): any {
40
+ if (!schema || typeof schema !== "object") return schema;
41
+
42
+ // Create a copy to avoid mutating the original
43
+ const result = { ...schema };
44
+
45
+ // Convert anyOf with all const values to enum
46
+ if (result.anyOf && Array.isArray(result.anyOf)) {
47
+ const allConst = result.anyOf.every(
48
+ (item: any) => item && typeof item === "object" && "const" in item,
49
+ );
50
+
51
+ if (allConst) {
52
+ // Extract all const values
53
+ const enumValues = result.anyOf.map((item: any) => item.const);
54
+
55
+ // Determine the type based on the first const value
56
+ // Assuming all const values are of the same type
57
+ const firstType = typeof enumValues[0];
58
+
59
+ // Replace anyOf with enum
60
+ delete result.anyOf;
61
+ result.type = firstType;
62
+ result.enum = enumValues;
63
+ } else {
64
+ // Process each item in anyOf
65
+ result.anyOf = result.anyOf.map(processSchema);
66
+ }
67
+ }
68
+
69
+ // If this is an object type, set additionalProperties: false
70
+ if (result.type === "object") {
71
+ result.additionalProperties = false;
72
+ result.properties ??= {};
73
+ }
74
+
75
+ // Process properties of objects
76
+ if (result.properties && typeof result.properties === "object") {
77
+ result.properties = Object.fromEntries(
78
+ Object.entries(result.properties).map(([key, value]) => [
79
+ key,
80
+ processSchema(value),
81
+ ]),
82
+ );
83
+ }
84
+
85
+ // Process items in arrays
86
+ if (result.items) {
87
+ result.items = processSchema(result.items);
88
+ }
89
+
90
+ // Process allOf, oneOf
91
+ for (const key of ["allOf", "oneOf"]) {
92
+ if (Array.isArray(result[key])) {
93
+ result[key] = result[key].map(processSchema);
94
+ }
95
+ }
96
+
97
+ return result;
98
+ }
99
+
100
+ export interface Tool<Input extends type, Output>
101
+ extends Omit<AITool<Schema<type.infer<Input>>>, "parameters" | "execute"> {
102
+ description?: string;
103
+ parameters: Input;
104
+ execute: (
105
+ input: type.infer<Input>,
106
+ options: ToolExecutionOptions,
107
+ ) => Promise<Output>;
108
+ }
109
+
110
+ export function tool<Input extends type, Output>(
111
+ tool: Tool<Input, Output>,
112
+ ): AITool<Schema<type.infer<Input>>, Output> {
113
+ return aitool({
114
+ ...tool,
115
+ parameters: ark.schema<Input>(tool.parameters),
116
+ } as any);
117
+ }
118
+ }
@@ -0,0 +1,78 @@
1
+ import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
2
+ import type { Secret } from "../secret";
3
+
4
+ /**
5
+ * Model configuration for AI operations
6
+ */
7
+ export interface ModelConfig {
8
+ /**
9
+ * Model ID to use
10
+ * @default 'gpt-4o'
11
+ */
12
+ id?: string;
13
+
14
+ /**
15
+ * Model provider name
16
+ * @default 'openai'
17
+ */
18
+ provider?: string;
19
+
20
+ /**
21
+ * Model-specific options
22
+ */
23
+ options?: Record<string, unknown>;
24
+ }
25
+
26
+ /**
27
+ * Configuration for creating an OpenAI client
28
+ */
29
+ export interface ClientConfig {
30
+ /**
31
+ * Base URL for the OpenAI API
32
+ * @default 'https://api.openai.com/v1'
33
+ */
34
+ baseURL?: string;
35
+
36
+ /**
37
+ * OpenAI API key to use for generating content
38
+ * If not provided, will use OPENAI_API_KEY environment variable
39
+ */
40
+ apiKey?: Secret;
41
+
42
+ /**
43
+ * Model configuration
44
+ */
45
+ model?: ModelConfig;
46
+ }
47
+
48
+ /**
49
+ * Creates an OpenAI-compatible client with the given configuration
50
+ */
51
+ export function createClient(config: ClientConfig) {
52
+ // Get API key from props or environment
53
+ const apiKey = config.apiKey?.unencrypted || process.env.OPENAI_API_KEY;
54
+ if (!apiKey) {
55
+ throw new Error("OpenAI API key is required");
56
+ }
57
+
58
+ // Initialize OpenAI compatible provider
59
+ return createOpenAICompatible({
60
+ name: config.model?.provider || "openai",
61
+ apiKey,
62
+ baseURL: config.baseURL || "https://api.openai.com/v1",
63
+ });
64
+ }
65
+
66
+ /**
67
+ * Gets the model ID from the configuration or returns the default
68
+ */
69
+ export function getModelId(config: ClientConfig): string {
70
+ return config.model?.id || "gpt-4o";
71
+ }
72
+
73
+ /**
74
+ * Gets the model options from the configuration
75
+ */
76
+ export function getModelOptions(config: ClientConfig): Record<string, unknown> {
77
+ return config.model?.options || {};
78
+ }
@@ -0,0 +1,160 @@
1
+ import { generateText } from "ai";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import type { Context } from "../context";
5
+ import { Resource } from "../resource";
6
+ import type { Secret } from "../secret";
7
+ import {
8
+ type ModelConfig,
9
+ createClient,
10
+ getModelId,
11
+ getModelOptions,
12
+ } from "./client";
13
+
14
+ /**
15
+ * Properties for creating or updating a Document
16
+ */
17
+ export interface DocumentProps {
18
+ /**
19
+ * Path to the markdown document
20
+ */
21
+ path: string;
22
+
23
+ /**
24
+ * Base URL for the OpenAI API
25
+ * @default 'https://api.openai.com/v1'
26
+ */
27
+ baseURL?: string;
28
+
29
+ /**
30
+ * Prompt for generating content
31
+ * Use alchemy template literals to include file context:
32
+ * @example
33
+ * prompt: await alchemy`
34
+ * Generate docs using:
35
+ * ${alchemy.file("src/api.ts")}
36
+ * `
37
+ */
38
+ prompt: string;
39
+
40
+ /**
41
+ * OpenAI API key to use for generating content
42
+ * If not provided, will use OPENAI_API_KEY environment variable
43
+ */
44
+ apiKey?: Secret;
45
+
46
+ /**
47
+ * Model configuration
48
+ */
49
+ model?: ModelConfig;
50
+ }
51
+
52
+ /**
53
+ * A markdown document that can be created, updated, and deleted
54
+ */
55
+ export interface Document extends DocumentProps, Resource<"docs::Document"> {
56
+ /**
57
+ * Content of the document
58
+ */
59
+ content: string;
60
+
61
+ /**
62
+ * Time at which the document was created
63
+ */
64
+ createdAt: number;
65
+
66
+ /**
67
+ * Time at which the document was last updated
68
+ */
69
+ updatedAt: number;
70
+ }
71
+
72
+ /**
73
+ * Resource for managing AI-generated markdown documents using the Vercel AI SDK.
74
+ * Supports powerful context handling through the alchemy template literal tag.
75
+ *
76
+ * @example
77
+ * // Create a document using alchemy template literals for context
78
+ * const apiDocs = await Document("api-docs", {
79
+ * path: "./docs/api.md",
80
+ * prompt: await alchemy`
81
+ * Generate API documentation based on these source files:
82
+ * ${alchemy.file("src/api.ts")}
83
+ * ${alchemy.file("src/types.ts")}
84
+ * `
85
+ * // The above will automatically append the file contents as code blocks:
86
+ * //
87
+ * // Generate API documentation based on these source files:
88
+ * // [api.ts](src/api.ts)
89
+ * // [types.ts](src/types.ts)
90
+ * //
91
+ * // // src/api.ts
92
+ * // ```ts
93
+ * // ... contents of api.ts ...
94
+ * // ```
95
+ * //
96
+ * // // src/types.ts
97
+ * // ```ts
98
+ * // ... contents of types.ts ...
99
+ * // ```
100
+ * });
101
+ *
102
+ * @example
103
+ * // Use alchemy template literals with file collections
104
+ * const modelDocs = await Document("models", {
105
+ * path: "./docs/models.md",
106
+ * prompt: await alchemy`
107
+ * Write documentation for these data models:
108
+ * ${alchemy.files("src/models/user.ts", "src/models/post.ts")}
109
+ * `
110
+ * // This creates a prompt with all files appended as code blocks,
111
+ * // automatically handling syntax highlighting based on file extensions
112
+ * });
113
+ */
114
+ export const Document = Resource(
115
+ "docs::Document",
116
+ async function (
117
+ this: Context<Document>,
118
+ id: string,
119
+ props: DocumentProps,
120
+ ): Promise<Document> {
121
+ // Ensure directory exists
122
+ await fs.mkdir(path.dirname(props.path), { recursive: true });
123
+
124
+ if (this.phase === "delete") {
125
+ try {
126
+ await fs.unlink(props.path);
127
+ } catch (error: any) {
128
+ // Ignore if file doesn't exist
129
+ if (error.code !== "ENOENT") {
130
+ throw error;
131
+ }
132
+ }
133
+ return this.destroy();
134
+ }
135
+
136
+ // Initialize OpenAI compatible provider using shared client
137
+ const provider = createClient(props);
138
+
139
+ // Generate content
140
+ const { text } = await generateText({
141
+ model: provider(getModelId(props)),
142
+ prompt: props.prompt,
143
+ ...getModelOptions(props),
144
+ });
145
+
146
+ // Write content to file
147
+ await fs.writeFile(props.path, text);
148
+
149
+ // Get file stats for timestamps
150
+ const stats = await fs.stat(props.path);
151
+
152
+ // Return the resource
153
+ return this({
154
+ ...props,
155
+ content: text,
156
+ createdAt: stats.birthtimeMs,
157
+ updatedAt: stats.mtimeMs,
158
+ });
159
+ },
160
+ );
@@ -1 +1,2 @@
1
1
  export * from "./document";
2
+ export * from "./object";
@@ -0,0 +1,149 @@
1
+ import { generateObject } from "ai";
2
+ import type { JsonSchema, Type, type } from "arktype";
3
+ import type { Context } from "../context";
4
+ import { Resource } from "../resource";
5
+ import type { Secret } from "../secret";
6
+ import { ark } from "./ark";
7
+ import {
8
+ type ModelConfig,
9
+ createClient,
10
+ getModelId,
11
+ getModelOptions,
12
+ } from "./client";
13
+
14
+ /**
15
+ * Properties for creating or updating an AI Object
16
+ */
17
+ export interface ObjectProps<T extends Type<any, any>> {
18
+ /**
19
+ * The ArkType schema to validate and structure the generated content
20
+ */
21
+ schema: T | JsonSchema;
22
+
23
+ /**
24
+ * Prompt for generating the content
25
+ * Use alchemy template literals to include file context:
26
+ * @example
27
+ * prompt: await alchemy`
28
+ * Generate a description for:
29
+ * ${alchemy.file("src/data.ts")}
30
+ * `
31
+ */
32
+ prompt: string;
33
+
34
+ /**
35
+ * System prompt to guide the AI's behavior
36
+ * @example
37
+ * system: "You are a technical writer tasked with describing code"
38
+ */
39
+ system?: string;
40
+
41
+ /**
42
+ * Base URL for the OpenAI API
43
+ * @default 'https://api.openai.com/v1'
44
+ */
45
+ baseURL?: string;
46
+
47
+ /**
48
+ * OpenAI API key to use for generating content
49
+ * If not provided, will use OPENAI_API_KEY environment variable
50
+ */
51
+ apiKey?: Secret;
52
+
53
+ /**
54
+ * Model configuration
55
+ */
56
+ model?: ModelConfig;
57
+ }
58
+
59
+ /**
60
+ * A resource that uses AI to generate structured content based on a schema
61
+ */
62
+ export interface Object<T> extends Resource<"ai::Object"> {
63
+ type: JsonSchema;
64
+
65
+ /**
66
+ * The generated content, typed according to the provided schema
67
+ */
68
+ object: T;
69
+
70
+ /**
71
+ * Time at which the content was generated
72
+ */
73
+ createdAt: number;
74
+ }
75
+
76
+ /**
77
+ * Resource for generating structured content using the Vercel AI SDK.
78
+ * Supports powerful context handling through the alchemy template literal tag.
79
+ *
80
+ * @example
81
+ * // Generate a product description with specific fields
82
+ * const productSchema = type({
83
+ * name: "string",
84
+ * description: "string",
85
+ * features: "string[]",
86
+ * price: "number"
87
+ * });
88
+ *
89
+ * const product = await Object("new-product", {
90
+ * schema: productSchema,
91
+ * prompt: "Generate a product description for a new smartphone",
92
+ * system: "You are a product copywriter specializing in tech products"
93
+ * });
94
+ *
95
+ * console.log(product.content); // Typed as per schema
96
+ *
97
+ * @example
98
+ * // Generate code documentation with context
99
+ * const docSchema = type({
100
+ * summary: "string",
101
+ * parameters: {
102
+ * name: "string",
103
+ * type: "string",
104
+ * description: "string"
105
+ * }[],
106
+ * returns: "string"
107
+ * });
108
+ *
109
+ * const docs = await Object("function-docs", {
110
+ * schema: docSchema,
111
+ * prompt: await alchemy`
112
+ * Generate documentation for this function:
113
+ * ${alchemy.file("src/utils/format.ts")}
114
+ * `,
115
+ * system: "You are a technical documentation writer"
116
+ * });
117
+ */
118
+ export const Object = Resource("ai::Object", async function <
119
+ const T extends Type<any, any>,
120
+ >(this: Context<Object<any>>, id: string, props: ObjectProps<T>): Promise<
121
+ Object<type.infer<T>>
122
+ > {
123
+ if (this.phase === "delete") {
124
+ return this.destroy();
125
+ }
126
+
127
+ // Initialize OpenAI compatible provider using shared client
128
+ const provider = createClient(props);
129
+
130
+ // Generate structured output using generateObject
131
+ const { object } = await generateObject({
132
+ model: provider(getModelId(props)),
133
+ // Convert ArkType schema to Zod schema for generateObject
134
+ // This is needed because generateObject expects a Zod schema
135
+ schema: ark.schema<type.infer<T>>(props.schema),
136
+ system:
137
+ props.system ||
138
+ "You are an AI assistant tasked with generating structured content.",
139
+ prompt: props.prompt,
140
+ ...getModelOptions(props),
141
+ });
142
+
143
+ // Return the resource with typed content
144
+ return this({
145
+ type: props.schema,
146
+ object: object,
147
+ createdAt: Date.now(),
148
+ });
149
+ });
package/src/alchemy.ts CHANGED
@@ -9,21 +9,79 @@ import type { StateStoreType } from "./state";
9
9
  // TODO: support browser
10
10
  const DEFAULT_STAGE = process.env.ALCHEMY_STAGE ?? process.env.USER ?? "dev";
11
11
 
12
- // alchemy type is to semantically highlight `alchemy` as a type (keyword)
12
+ /**
13
+ * Type alias for semantic highlighting of `alchemy` as a type keyword
14
+ */
13
15
  export type alchemy = Alchemy;
14
16
 
15
17
  export const alchemy: Alchemy = _alchemy as any;
16
18
 
17
- // Alchemy is for module augmentation
19
+ /**
20
+ * The Alchemy interface provides core functionality and is augmented by providers.
21
+ * Supports both application scoping with secrets and template string interpolation.
22
+ *
23
+ * @example
24
+ * // Create an application scope with stage and secret handling
25
+ * const app = alchemy("github:alchemy", {
26
+ * stage: "prod",
27
+ * phase: "up",
28
+ * // Required for encrypting/decrypting secrets
29
+ * password: process.env.SECRET_PASSPHRASE
30
+ * });
31
+ *
32
+ * // Create a resource with encrypted secrets
33
+ * const resource = await Resource("my-resource", {
34
+ * apiKey: alchemy.secret(process.env.API_KEY)
35
+ * });
36
+ *
37
+ * await app.finalize();
38
+ */
18
39
  export interface Alchemy {
19
40
  scope: typeof scope;
20
41
  run: typeof run;
21
42
  destroy: typeof destroy;
43
+ /**
44
+ * Creates an encrypted secret that can be safely stored in state files.
45
+ * Requires a password to be set either globally in the application options
46
+ * or locally in the current scope.
47
+ */
22
48
  secret: typeof secret;
49
+ /**
50
+ * Creates a new application scope with the given name and options.
51
+ * Used to create and manage resources with proper secret handling.
52
+ *
53
+ * @example
54
+ * const app = alchemy("my-app", {
55
+ * stage: "prod",
56
+ * // Required for encrypting/decrypting secrets
57
+ * password: process.env.SECRET_PASSPHRASE
58
+ * });
59
+ */
23
60
  (...parameters: Parameters<typeof scope>): ReturnType<typeof scope>;
61
+ /**
62
+ * Template literal tag that supports file interpolation for documentation.
63
+ * Automatically formats the content and appends file contents as code blocks.
64
+ *
65
+ * @example
66
+ * // Generate documentation using file contents
67
+ * await Document("api-docs", {
68
+ * prompt: await alchemy`
69
+ * Generate docs using the contents of:
70
+ * ${alchemy.file("README.md")}
71
+ * ${alchemy.file("./.cursorrules")}
72
+ *
73
+ * And here are the source files:
74
+ * ${alchemy.files(files)}
75
+ * `
76
+ * });
77
+ */
24
78
  (template: TemplateStringsArray, ...values: any[]): Promise<string>;
25
79
  }
26
80
 
81
+ /**
82
+ * Implementation of the alchemy function that handles both application scoping
83
+ * and template string interpolation.
84
+ */
27
85
  function _alchemy(
28
86
  ...args:
29
87
  | [template: TemplateStringsArray, ...values: any[]]
@@ -45,7 +103,7 @@ function _alchemy(
45
103
  const indent = " ".repeat(leadingSpaces);
46
104
 
47
105
  return (async () => {
48
- const { isFileCollection, isFileRef } = await import("./fs/file");
106
+ const { isFileCollection, isFileRef } = await import("./fs");
49
107
 
50
108
  const appendices: Record<string, string> = {};
51
109
 
@@ -161,14 +219,24 @@ export interface AlchemyOptions {
161
219
 
162
220
  /**
163
221
  * A passphrase to use to encrypt/decrypt secrets.
222
+ * Required if using alchemy.secret() in this scope.
164
223
  */
165
224
  password?: string;
166
225
  }
167
226
 
168
227
  /**
169
228
  * Enter a new scope synchronously.
170
- * @param options
171
- * @returns
229
+ *
230
+ * @example
231
+ * // Create a scope with a password for secret handling
232
+ * await using scope = alchemy.scope("my-scope", {
233
+ * password: process.env.SECRET_PASSPHRASE
234
+ * });
235
+ *
236
+ * // Use secrets within the scope
237
+ * const resource = await Resource("my-resource", {
238
+ * apiKey: alchemy.secret(process.env.API_KEY)
239
+ * });
172
240
  */
173
241
  function scope(
174
242
  id: string | undefined,
@@ -187,6 +255,21 @@ function scope(
187
255
  return scope;
188
256
  }
189
257
 
258
+ /**
259
+ * Run a function in a new scope asynchronously.
260
+ * Useful for isolating secret handling with a specific password.
261
+ *
262
+ * @example
263
+ * // Run operations in a scope with its own password
264
+ * await alchemy.run("secure-scope", {
265
+ * password: process.env.SCOPE_PASSWORD
266
+ * }, async () => {
267
+ * // Secrets in this scope will use this password
268
+ * const resource = await Resource("my-resource", {
269
+ * apiKey: alchemy.secret(process.env.API_KEY)
270
+ * });
271
+ * });
272
+ */
190
273
  async function run<T>(
191
274
  ...args:
192
275
  | [id: string, fn: (this: Scope, scope: Scope) => Promise<T>]