alchemy 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) 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/data.d.ts +101 -0
  6. package/lib/ai/data.js +70 -0
  7. package/lib/ai/document.d.ts +101 -0
  8. package/lib/ai/document.js +82 -0
  9. package/lib/ai/index.d.ts +3 -0
  10. package/lib/ai/index.js +3 -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 +287 -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/data.ts +149 -0
  96. package/src/ai/document.ts +165 -0
  97. package/src/ai/index.ts +3 -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 +338 -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/lib/docs/index.d.ts +0 -1
  139. package/lib/docs/index.js +0 -1
  140. package/src/docs/document.ts +0 -225
  141. package/src/docs/index.ts +0 -1
@@ -0,0 +1,11 @@
1
+ import { type Tool as AITool, type Schema, type ToolExecutionOptions } from "ai";
2
+ import { type JsonSchema, type type } from "arktype";
3
+ export declare namespace ark {
4
+ function schema<T>(type: JsonSchema): Schema<T>;
5
+ interface Tool<Input extends type, Output> extends Omit<AITool<Schema<type.infer<Input>>>, "parameters" | "execute"> {
6
+ description?: string;
7
+ parameters: Input;
8
+ execute: (input: type.infer<Input>, options: ToolExecutionOptions) => Promise<Output>;
9
+ }
10
+ function tool<Input extends type, Output>(tool: Tool<Input, Output>): AITool<Schema<type.infer<Input>>, Output>;
11
+ }
package/lib/ai/ark.js ADDED
@@ -0,0 +1,86 @@
1
+ import { tool as aitool, jsonSchema, } from "ai";
2
+ import { ArkErrors } from "arktype";
3
+ export var ark;
4
+ (function (ark) {
5
+ function schema(type) {
6
+ const jsonSchemaObj = type.toJsonSchema();
7
+ const processedSchema = processSchema(jsonSchemaObj);
8
+ return jsonSchema(processedSchema, {
9
+ validate: (value) => {
10
+ const out = type(value);
11
+ if (out instanceof ArkErrors) {
12
+ return {
13
+ success: false,
14
+ error: new Error(out.summary),
15
+ };
16
+ }
17
+ return {
18
+ success: true,
19
+ value: out,
20
+ };
21
+ },
22
+ });
23
+ }
24
+ ark.schema = schema;
25
+ /**
26
+ * Recursively processes a JSON schema and sets additionalProperties: false
27
+ * for any object types.
28
+ *
29
+ * Structured Outputs requires additionalProperties: false
30
+ */
31
+ function processSchema(schema) {
32
+ if (!schema || typeof schema !== "object")
33
+ return schema;
34
+ // Create a copy to avoid mutating the original
35
+ const result = { ...schema };
36
+ // Convert anyOf with all const values to enum
37
+ if (result.anyOf && Array.isArray(result.anyOf)) {
38
+ const allConst = result.anyOf.every((item) => item && typeof item === "object" && "const" in item);
39
+ if (allConst) {
40
+ // Extract all const values
41
+ const enumValues = result.anyOf.map((item) => item.const);
42
+ // Determine the type based on the first const value
43
+ // Assuming all const values are of the same type
44
+ const firstType = typeof enumValues[0];
45
+ // Replace anyOf with enum
46
+ delete result.anyOf;
47
+ result.type = firstType;
48
+ result.enum = enumValues;
49
+ }
50
+ else {
51
+ // Process each item in anyOf
52
+ result.anyOf = result.anyOf.map(processSchema);
53
+ }
54
+ }
55
+ // If this is an object type, set additionalProperties: false
56
+ if (result.type === "object") {
57
+ result.additionalProperties = false;
58
+ result.properties ??= {};
59
+ }
60
+ // Process properties of objects
61
+ if (result.properties && typeof result.properties === "object") {
62
+ result.properties = Object.fromEntries(Object.entries(result.properties).map(([key, value]) => [
63
+ key,
64
+ processSchema(value),
65
+ ]));
66
+ }
67
+ // Process items in arrays
68
+ if (result.items) {
69
+ result.items = processSchema(result.items);
70
+ }
71
+ // Process allOf, oneOf
72
+ for (const key of ["allOf", "oneOf"]) {
73
+ if (Array.isArray(result[key])) {
74
+ result[key] = result[key].map(processSchema);
75
+ }
76
+ }
77
+ return result;
78
+ }
79
+ function tool(tool) {
80
+ return aitool({
81
+ ...tool,
82
+ parameters: ark.schema(tool.parameters),
83
+ });
84
+ }
85
+ ark.tool = tool;
86
+ })(ark || (ark = {}));
@@ -0,0 +1,51 @@
1
+ import type { Secret } from "../secret";
2
+ /**
3
+ * Model configuration for AI operations
4
+ */
5
+ export interface ModelConfig {
6
+ /**
7
+ * Model ID to use
8
+ * @default 'gpt-4o'
9
+ */
10
+ id?: string;
11
+ /**
12
+ * Model provider name
13
+ * @default 'openai'
14
+ */
15
+ provider?: string;
16
+ /**
17
+ * Model-specific options
18
+ */
19
+ options?: Record<string, unknown>;
20
+ }
21
+ /**
22
+ * Configuration for creating an OpenAI client
23
+ */
24
+ export interface ClientConfig {
25
+ /**
26
+ * Base URL for the OpenAI API
27
+ * @default 'https://api.openai.com/v1'
28
+ */
29
+ baseURL?: string;
30
+ /**
31
+ * OpenAI API key to use for generating content
32
+ * If not provided, will use OPENAI_API_KEY environment variable
33
+ */
34
+ apiKey?: Secret;
35
+ /**
36
+ * Model configuration
37
+ */
38
+ model?: ModelConfig;
39
+ }
40
+ /**
41
+ * Creates an OpenAI-compatible client with the given configuration
42
+ */
43
+ export declare function createClient(config: ClientConfig): import("@ai-sdk/openai-compatible").OpenAICompatibleProvider<string, string, string, string>;
44
+ /**
45
+ * Gets the model ID from the configuration or returns the default
46
+ */
47
+ export declare function getModelId(config: ClientConfig): string;
48
+ /**
49
+ * Gets the model options from the configuration
50
+ */
51
+ export declare function getModelOptions(config: ClientConfig): Record<string, unknown>;
@@ -0,0 +1,29 @@
1
+ import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
2
+ /**
3
+ * Creates an OpenAI-compatible client with the given configuration
4
+ */
5
+ export function createClient(config) {
6
+ // Get API key from props or environment
7
+ const apiKey = config.apiKey?.unencrypted || process.env.OPENAI_API_KEY;
8
+ if (!apiKey) {
9
+ throw new Error("OpenAI API key is required");
10
+ }
11
+ // Initialize OpenAI compatible provider
12
+ return createOpenAICompatible({
13
+ name: config.model?.provider || "openai",
14
+ apiKey,
15
+ baseURL: config.baseURL || "https://api.openai.com/v1",
16
+ });
17
+ }
18
+ /**
19
+ * Gets the model ID from the configuration or returns the default
20
+ */
21
+ export function getModelId(config) {
22
+ return config.model?.id || "gpt-4o";
23
+ }
24
+ /**
25
+ * Gets the model options from the configuration
26
+ */
27
+ export function getModelOptions(config) {
28
+ return config.model?.options || {};
29
+ }
@@ -0,0 +1,101 @@
1
+ import type { JsonSchema, Type, type } from "arktype";
2
+ import type { Context } from "../context";
3
+ import { Resource } from "../resource";
4
+ import type { Secret } from "../secret";
5
+ import { type ModelConfig } from "./client";
6
+ /**
7
+ * Properties for creating or updating an AI Object
8
+ */
9
+ export interface DataProps<T extends Type<any, any>> {
10
+ /**
11
+ * The ArkType schema to validate and structure the generated content
12
+ */
13
+ schema: T | JsonSchema;
14
+ /**
15
+ * Prompt for generating the content
16
+ * Use alchemy template literals to include file context:
17
+ * @example
18
+ * prompt: await alchemy`
19
+ * Generate a description for:
20
+ * ${alchemy.file("src/data.ts")}
21
+ * `
22
+ */
23
+ prompt: string;
24
+ /**
25
+ * System prompt to guide the AI's behavior
26
+ * @example
27
+ * system: "You are a technical writer tasked with describing code"
28
+ */
29
+ system?: string;
30
+ /**
31
+ * Base URL for the OpenAI API
32
+ * @default 'https://api.openai.com/v1'
33
+ */
34
+ baseURL?: string;
35
+ /**
36
+ * OpenAI API key to use for generating content
37
+ * If not provided, will use OPENAI_API_KEY environment variable
38
+ */
39
+ apiKey?: Secret;
40
+ /**
41
+ * Model configuration
42
+ */
43
+ model?: ModelConfig;
44
+ }
45
+ /**
46
+ * A resource that uses AI to generate structured content based on a schema
47
+ */
48
+ export interface Data<T> extends Resource<"ai::Object"> {
49
+ type: JsonSchema;
50
+ /**
51
+ * The generated content, typed according to the provided schema
52
+ */
53
+ object: T;
54
+ /**
55
+ * Time at which the content was generated
56
+ */
57
+ createdAt: number;
58
+ }
59
+ /**
60
+ * Resource for generating structured content using the Vercel AI SDK.
61
+ * Supports powerful context handling through the alchemy template literal tag.
62
+ *
63
+ * @example
64
+ * // Generate a product description with specific fields
65
+ * const productSchema = type({
66
+ * name: "string",
67
+ * description: "string",
68
+ * features: "string[]",
69
+ * price: "number"
70
+ * });
71
+ *
72
+ * const product = await Object("new-product", {
73
+ * schema: productSchema,
74
+ * prompt: "Generate a product description for a new smartphone",
75
+ * system: "You are a product copywriter specializing in tech products"
76
+ * });
77
+ *
78
+ * console.log(product.content); // Typed as per schema
79
+ *
80
+ * @example
81
+ * // Generate code documentation with context
82
+ * const docSchema = type({
83
+ * summary: "string",
84
+ * parameters: {
85
+ * name: "string",
86
+ * type: "string",
87
+ * description: "string"
88
+ * }[],
89
+ * returns: "string"
90
+ * });
91
+ *
92
+ * const docs = await Object("function-docs", {
93
+ * schema: docSchema,
94
+ * prompt: await alchemy`
95
+ * Generate documentation for this function:
96
+ * ${alchemy.file("src/utils/format.ts")}
97
+ * `,
98
+ * system: "You are a technical documentation writer"
99
+ * });
100
+ */
101
+ export declare const Data: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | (<const T extends Type<any, any>>(this: Context<Data<any>>, id: string, props: DataProps<T>) => Promise<Data<type.infer<T>>>);
package/lib/ai/data.js ADDED
@@ -0,0 +1,70 @@
1
+ import { generateObject } from "ai";
2
+ import { Resource } from "../resource";
3
+ import { ark } from "./ark";
4
+ import { createClient, getModelId, getModelOptions, } from "./client";
5
+ /**
6
+ * Resource for generating structured content using the Vercel AI SDK.
7
+ * Supports powerful context handling through the alchemy template literal tag.
8
+ *
9
+ * @example
10
+ * // Generate a product description with specific fields
11
+ * const productSchema = type({
12
+ * name: "string",
13
+ * description: "string",
14
+ * features: "string[]",
15
+ * price: "number"
16
+ * });
17
+ *
18
+ * const product = await Object("new-product", {
19
+ * schema: productSchema,
20
+ * prompt: "Generate a product description for a new smartphone",
21
+ * system: "You are a product copywriter specializing in tech products"
22
+ * });
23
+ *
24
+ * console.log(product.content); // Typed as per schema
25
+ *
26
+ * @example
27
+ * // Generate code documentation with context
28
+ * const docSchema = type({
29
+ * summary: "string",
30
+ * parameters: {
31
+ * name: "string",
32
+ * type: "string",
33
+ * description: "string"
34
+ * }[],
35
+ * returns: "string"
36
+ * });
37
+ *
38
+ * const docs = await Object("function-docs", {
39
+ * schema: docSchema,
40
+ * prompt: await alchemy`
41
+ * Generate documentation for this function:
42
+ * ${alchemy.file("src/utils/format.ts")}
43
+ * `,
44
+ * system: "You are a technical documentation writer"
45
+ * });
46
+ */
47
+ export const Data = Resource("ai::Object", async function (id, props) {
48
+ if (this.phase === "delete") {
49
+ return this.destroy();
50
+ }
51
+ // Initialize OpenAI compatible provider using shared client
52
+ const provider = createClient(props);
53
+ // Generate structured output using generateObject
54
+ const { object } = await generateObject({
55
+ model: provider(getModelId(props)),
56
+ // Convert ArkType schema to Zod schema for generateObject
57
+ // This is needed because generateObject expects a Zod schema
58
+ schema: ark.schema(props.schema),
59
+ system: props.system ||
60
+ "You are an AI assistant tasked with generating structured content.",
61
+ prompt: props.prompt,
62
+ ...getModelOptions(props),
63
+ });
64
+ // Return the resource with typed content
65
+ return this({
66
+ type: props.schema,
67
+ object: object,
68
+ createdAt: Date.now(),
69
+ });
70
+ });
@@ -0,0 +1,101 @@
1
+ import type { Context } from "../context";
2
+ import { Resource } from "../resource";
3
+ import type { Secret } from "../secret";
4
+ import { type ModelConfig } from "./client";
5
+ /**
6
+ * Properties for creating or updating a Document
7
+ */
8
+ export interface DocumentProps {
9
+ /**
10
+ * Title of the document
11
+ */
12
+ title: string;
13
+ /**
14
+ * Path to the markdown document
15
+ */
16
+ path: string;
17
+ /**
18
+ * Base URL for the OpenAI API
19
+ * @default 'https://api.openai.com/v1'
20
+ */
21
+ baseURL?: string;
22
+ /**
23
+ * Prompt for generating content
24
+ * Use alchemy template literals to include file context:
25
+ * @example
26
+ * prompt: await alchemy`
27
+ * Generate docs using:
28
+ * ${alchemy.file("src/api.ts")}
29
+ * `
30
+ */
31
+ prompt: string;
32
+ /**
33
+ * OpenAI API key to use for generating content
34
+ * If not provided, will use OPENAI_API_KEY environment variable
35
+ */
36
+ apiKey?: Secret;
37
+ /**
38
+ * Model configuration
39
+ */
40
+ model?: ModelConfig;
41
+ }
42
+ /**
43
+ * A markdown document that can be created, updated, and deleted
44
+ */
45
+ export interface Document extends DocumentProps, Resource<"docs::Document"> {
46
+ /**
47
+ * Content of the document
48
+ */
49
+ content: string;
50
+ /**
51
+ * Time at which the document was created
52
+ */
53
+ createdAt: number;
54
+ /**
55
+ * Time at which the document was last updated
56
+ */
57
+ updatedAt: number;
58
+ }
59
+ /**
60
+ * Resource for managing AI-generated markdown documents using the Vercel AI SDK.
61
+ * Supports powerful context handling through the alchemy template literal tag.
62
+ *
63
+ * @example
64
+ * // Create a document using alchemy template literals for context
65
+ * const apiDocs = await Document("api-docs", {
66
+ * path: "./docs/api.md",
67
+ * prompt: await alchemy`
68
+ * Generate API documentation based on these source files:
69
+ * ${alchemy.file("src/api.ts")}
70
+ * ${alchemy.file("src/types.ts")}
71
+ * `
72
+ * // The above will automatically append the file contents as code blocks:
73
+ * //
74
+ * // Generate API documentation based on these source files:
75
+ * // [api.ts](src/api.ts)
76
+ * // [types.ts](src/types.ts)
77
+ * //
78
+ * // // src/api.ts
79
+ * // ```ts
80
+ * // ... contents of api.ts ...
81
+ * // ```
82
+ * //
83
+ * // // src/types.ts
84
+ * // ```ts
85
+ * // ... contents of types.ts ...
86
+ * // ```
87
+ * });
88
+ *
89
+ * @example
90
+ * // Use alchemy template literals with file collections
91
+ * const modelDocs = await Document("models", {
92
+ * path: "./docs/models.md",
93
+ * prompt: await alchemy`
94
+ * Write documentation for these data models:
95
+ * ${alchemy.files("src/models/user.ts", "src/models/post.ts")}
96
+ * `
97
+ * // This creates a prompt with all files appended as code blocks,
98
+ * // automatically handling syntax highlighting based on file extensions
99
+ * });
100
+ */
101
+ export declare const Document: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<Document>, id: string, props: DocumentProps) => Promise<Document>);
@@ -0,0 +1,82 @@
1
+ import { generateText } from "ai";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { Resource } from "../resource";
5
+ import { createClient, getModelId, getModelOptions, } from "./client";
6
+ /**
7
+ * Resource for managing AI-generated markdown documents using the Vercel AI SDK.
8
+ * Supports powerful context handling through the alchemy template literal tag.
9
+ *
10
+ * @example
11
+ * // Create a document using alchemy template literals for context
12
+ * const apiDocs = await Document("api-docs", {
13
+ * path: "./docs/api.md",
14
+ * prompt: await alchemy`
15
+ * Generate API documentation based on these source files:
16
+ * ${alchemy.file("src/api.ts")}
17
+ * ${alchemy.file("src/types.ts")}
18
+ * `
19
+ * // The above will automatically append the file contents as code blocks:
20
+ * //
21
+ * // Generate API documentation based on these source files:
22
+ * // [api.ts](src/api.ts)
23
+ * // [types.ts](src/types.ts)
24
+ * //
25
+ * // // src/api.ts
26
+ * // ```ts
27
+ * // ... contents of api.ts ...
28
+ * // ```
29
+ * //
30
+ * // // src/types.ts
31
+ * // ```ts
32
+ * // ... contents of types.ts ...
33
+ * // ```
34
+ * });
35
+ *
36
+ * @example
37
+ * // Use alchemy template literals with file collections
38
+ * const modelDocs = await Document("models", {
39
+ * path: "./docs/models.md",
40
+ * prompt: await alchemy`
41
+ * Write documentation for these data models:
42
+ * ${alchemy.files("src/models/user.ts", "src/models/post.ts")}
43
+ * `
44
+ * // This creates a prompt with all files appended as code blocks,
45
+ * // automatically handling syntax highlighting based on file extensions
46
+ * });
47
+ */
48
+ export const Document = Resource("docs::Document", async function (id, props) {
49
+ // Ensure directory exists
50
+ await fs.mkdir(path.dirname(props.path), { recursive: true });
51
+ if (this.phase === "delete") {
52
+ try {
53
+ await fs.unlink(props.path);
54
+ }
55
+ catch (error) {
56
+ // Ignore if file doesn't exist
57
+ if (error.code !== "ENOENT") {
58
+ throw error;
59
+ }
60
+ }
61
+ return this.destroy();
62
+ }
63
+ // Initialize OpenAI compatible provider using shared client
64
+ const provider = createClient(props);
65
+ // Generate content
66
+ const { text } = await generateText({
67
+ model: provider(getModelId(props)),
68
+ prompt: props.prompt,
69
+ ...getModelOptions(props),
70
+ });
71
+ // Write content to file
72
+ await fs.writeFile(props.path, text);
73
+ // Get file stats for timestamps
74
+ const stats = await fs.stat(props.path);
75
+ // Return the resource
76
+ return this({
77
+ ...props,
78
+ content: text,
79
+ createdAt: stats.birthtimeMs,
80
+ updatedAt: stats.mtimeMs,
81
+ });
82
+ });
@@ -0,0 +1,3 @@
1
+ export * from "./ark";
2
+ export * from "./data";
3
+ export * from "./document";
@@ -0,0 +1,3 @@
1
+ export * from "./ark";
2
+ export * from "./data";
3
+ export * from "./document";
package/lib/alchemy.d.ts CHANGED
@@ -2,14 +2,70 @@ import { destroy } from "./destroy";
2
2
  import { Scope } from "./scope";
3
3
  import { secret } from "./secret";
4
4
  import type { StateStoreType } from "./state";
5
+ /**
6
+ * Type alias for semantic highlighting of `alchemy` as a type keyword
7
+ */
5
8
  export type alchemy = Alchemy;
6
9
  export declare const alchemy: Alchemy;
10
+ /**
11
+ * The Alchemy interface provides core functionality and is augmented by providers.
12
+ * Supports both application scoping with secrets and template string interpolation.
13
+ *
14
+ * @example
15
+ * // Create an application scope with stage and secret handling
16
+ * const app = alchemy("github:alchemy", {
17
+ * stage: "prod",
18
+ * phase: "up",
19
+ * // Required for encrypting/decrypting secrets
20
+ * password: process.env.SECRET_PASSPHRASE
21
+ * });
22
+ *
23
+ * // Create a resource with encrypted secrets
24
+ * const resource = await Resource("my-resource", {
25
+ * apiKey: alchemy.secret(process.env.API_KEY)
26
+ * });
27
+ *
28
+ * await app.finalize();
29
+ */
7
30
  export interface Alchemy {
8
31
  scope: typeof scope;
9
32
  run: typeof run;
10
33
  destroy: typeof destroy;
34
+ /**
35
+ * Creates an encrypted secret that can be safely stored in state files.
36
+ * Requires a password to be set either globally in the application options
37
+ * or locally in the current scope.
38
+ */
11
39
  secret: typeof secret;
40
+ /**
41
+ * Creates a new application scope with the given name and options.
42
+ * Used to create and manage resources with proper secret handling.
43
+ *
44
+ * @example
45
+ * const app = alchemy("my-app", {
46
+ * stage: "prod",
47
+ * // Required for encrypting/decrypting secrets
48
+ * password: process.env.SECRET_PASSPHRASE
49
+ * });
50
+ */
12
51
  (...parameters: Parameters<typeof scope>): ReturnType<typeof scope>;
52
+ /**
53
+ * Template literal tag that supports file interpolation for documentation.
54
+ * Automatically formats the content and appends file contents as code blocks.
55
+ *
56
+ * @example
57
+ * // Generate documentation using file contents
58
+ * await Document("api-docs", {
59
+ * prompt: await alchemy`
60
+ * Generate docs using the contents of:
61
+ * ${alchemy.file("README.md")}
62
+ * ${alchemy.file("./.cursorrules")}
63
+ *
64
+ * And here are the source files:
65
+ * ${alchemy.files(files)}
66
+ * `
67
+ * });
68
+ */
13
69
  (template: TemplateStringsArray, ...values: any[]): Promise<string>;
14
70
  }
15
71
  export interface AlchemyOptions {
@@ -51,15 +107,40 @@ export interface AlchemyOptions {
51
107
  quiet?: boolean;
52
108
  /**
53
109
  * A passphrase to use to encrypt/decrypt secrets.
110
+ * Required if using alchemy.secret() in this scope.
54
111
  */
55
112
  password?: string;
56
113
  }
57
114
  /**
58
115
  * Enter a new scope synchronously.
59
- * @param options
60
- * @returns
116
+ *
117
+ * @example
118
+ * // Create a scope with a password for secret handling
119
+ * await using scope = alchemy.scope("my-scope", {
120
+ * password: process.env.SECRET_PASSPHRASE
121
+ * });
122
+ *
123
+ * // Use secrets within the scope
124
+ * const resource = await Resource("my-resource", {
125
+ * apiKey: alchemy.secret(process.env.API_KEY)
126
+ * });
61
127
  */
62
128
  declare function scope(id: string | undefined, options?: AlchemyOptions): Scope;
129
+ /**
130
+ * Run a function in a new scope asynchronously.
131
+ * Useful for isolating secret handling with a specific password.
132
+ *
133
+ * @example
134
+ * // Run operations in a scope with its own password
135
+ * await alchemy.run("secure-scope", {
136
+ * password: process.env.SCOPE_PASSWORD
137
+ * }, async () => {
138
+ * // Secrets in this scope will use this password
139
+ * const resource = await Resource("my-resource", {
140
+ * apiKey: alchemy.secret(process.env.API_KEY)
141
+ * });
142
+ * });
143
+ */
63
144
  declare function run<T>(...args: [id: string, fn: (this: Scope, scope: Scope) => Promise<T>] | [
64
145
  id: string,
65
146
  options: AlchemyOptions,