alchemy 0.2.2 → 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 (161) 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/ai/index.d.ts +2 -0
  8. package/lib/ai/index.js +2 -0
  9. package/lib/ai/object.d.ts +101 -0
  10. package/lib/ai/object.js +70 -0
  11. package/lib/alchemy.d.ts +84 -2
  12. package/lib/alchemy.js +114 -10
  13. package/lib/apply.d.ts +1 -1
  14. package/lib/apply.js +13 -10
  15. package/lib/aws/bucket.d.ts +87 -1
  16. package/lib/aws/bucket.js +48 -1
  17. package/lib/aws/function.d.ts +186 -1
  18. package/lib/aws/function.js +62 -8
  19. package/lib/aws/oidc/github-oidc-provider.d.ts +81 -0
  20. package/lib/aws/oidc/github-oidc-provider.js +68 -0
  21. package/lib/aws/oidc/oidc-provider.d.ts +14 -6
  22. package/lib/aws/oidc/oidc-provider.js +26 -5
  23. package/lib/aws/policy-attachment.d.ts +44 -1
  24. package/lib/aws/policy-attachment.js +31 -0
  25. package/lib/aws/policy.d.ts +160 -1
  26. package/lib/aws/policy.js +78 -0
  27. package/lib/aws/queue.d.ts +83 -1
  28. package/lib/aws/queue.js +39 -0
  29. package/lib/aws/role.d.ts +162 -1
  30. package/lib/aws/role.js +114 -0
  31. package/lib/aws/ses.d.ts +57 -2
  32. package/lib/aws/ses.js +42 -1
  33. package/lib/aws/table.d.ts +96 -1
  34. package/lib/aws/table.js +36 -0
  35. package/lib/cloudflare/asset-manifest.js +0 -1
  36. package/lib/cloudflare/bound.js +0 -1
  37. package/lib/cloudflare/bucket.d.ts +37 -1
  38. package/lib/cloudflare/bucket.js +36 -0
  39. package/lib/cloudflare/durable-object-namespace.d.ts +25 -0
  40. package/lib/cloudflare/durable-object-namespace.js +22 -0
  41. package/lib/cloudflare/kv-namespace.d.ts +37 -1
  42. package/lib/cloudflare/kv-namespace.js +36 -0
  43. package/lib/cloudflare/static-site.d.ts +53 -1
  44. package/lib/cloudflare/static-site.js +53 -1
  45. package/lib/cloudflare/worker-metadata.js +0 -1
  46. package/lib/cloudflare/worker.d.ts +64 -1
  47. package/lib/cloudflare/worker.js +63 -0
  48. package/lib/cloudflare/wrangler.json.d.ts +1 -1
  49. package/lib/cloudflare/zone-settings.js +0 -1
  50. package/lib/cloudflare/zone.d.ts +56 -1
  51. package/lib/cloudflare/zone.js +55 -0
  52. package/lib/context.d.ts +9 -4
  53. package/lib/context.js +4 -2
  54. package/lib/destroy.js +9 -8
  55. package/lib/esbuild/bundle.d.ts +43 -4
  56. package/lib/esbuild/bundle.js +16 -0
  57. package/lib/fs/file-collection.d.ts +16 -0
  58. package/lib/fs/file-collection.js +6 -0
  59. package/lib/fs/file-ref.d.ts +14 -0
  60. package/lib/fs/file-ref.js +6 -0
  61. package/lib/fs/file.d.ts +78 -5
  62. package/lib/fs/file.js +39 -3
  63. package/lib/fs/folder.d.ts +37 -5
  64. package/lib/fs/folder.js +28 -3
  65. package/lib/fs/index.d.ts +6 -0
  66. package/lib/fs/index.js +6 -0
  67. package/lib/fs/json-file.d.ts +16 -0
  68. package/lib/fs/json-file.js +7 -0
  69. package/lib/fs/text-file.d.ts +12 -0
  70. package/lib/fs/text-file.js +7 -0
  71. package/lib/fs/typescript-file.d.ts +19 -0
  72. package/lib/fs/typescript-file.js +14 -0
  73. package/lib/fs/yaml-file.d.ts +19 -0
  74. package/lib/fs/yaml-file.js +8 -0
  75. package/lib/github/secret.d.ts +63 -2
  76. package/lib/github/secret.js +61 -1
  77. package/lib/internal/docs.d.ts +5 -0
  78. package/lib/internal/docs.js +324 -0
  79. package/lib/resource.d.ts +2 -2
  80. package/lib/resource.js +4 -0
  81. package/lib/scope.d.ts +1 -1
  82. package/lib/scope.js +6 -6
  83. package/lib/secret.d.ts +67 -0
  84. package/lib/secret.js +67 -0
  85. package/lib/shadcn/component.d.ts +1 -1
  86. package/lib/state.d.ts +1 -1
  87. package/lib/state.js +8 -1
  88. package/lib/stripe/price.d.ts +51 -1
  89. package/lib/stripe/price.js +50 -0
  90. package/lib/stripe/product.d.ts +39 -1
  91. package/lib/stripe/product.js +38 -0
  92. package/lib/stripe/webhook.d.ts +46 -1
  93. package/lib/stripe/webhook.js +45 -0
  94. package/lib/test/bun.d.ts +64 -0
  95. package/lib/test/bun.js +35 -3
  96. package/lib/util/serde.d.ts +3 -1
  97. package/lib/util/serde.js +20 -4
  98. package/lib/vite/vite.d.ts +1 -1
  99. package/lib/vitepress/dependencies.d.ts +12 -0
  100. package/lib/vitepress/dependencies.js +35 -0
  101. package/lib/vitepress/home-page.d.ts +133 -0
  102. package/lib/vitepress/home-page.js +11 -0
  103. package/lib/vitepress/index.d.ts +2 -0
  104. package/lib/vitepress/index.js +2 -0
  105. package/lib/vitepress/vitepress.d.ts +71 -0
  106. package/lib/vitepress/vitepress.js +266 -0
  107. package/package.json +22 -10
  108. package/src/ai/ark.ts +118 -0
  109. package/src/ai/client.ts +78 -0
  110. package/src/ai/document.ts +160 -0
  111. package/src/ai/index.ts +2 -0
  112. package/src/ai/object.ts +149 -0
  113. package/src/alchemy.ts +192 -17
  114. package/src/apply.ts +25 -13
  115. package/src/aws/bucket.ts +111 -7
  116. package/src/aws/function.ts +231 -10
  117. package/src/aws/oidc/github-oidc-provider.ts +83 -0
  118. package/src/aws/oidc/oidc-provider.ts +39 -7
  119. package/src/aws/policy-attachment.ts +44 -1
  120. package/src/aws/policy.ts +177 -2
  121. package/src/aws/queue.ts +89 -0
  122. package/src/aws/role.ts +174 -2
  123. package/src/aws/ses.ts +56 -1
  124. package/src/aws/table.ts +103 -0
  125. package/src/cloudflare/bucket.ts +36 -0
  126. package/src/cloudflare/durable-object-namespace.ts +25 -0
  127. package/src/cloudflare/kv-namespace.ts +36 -0
  128. package/src/cloudflare/static-site.ts +53 -1
  129. package/src/cloudflare/worker.ts +63 -0
  130. package/src/cloudflare/zone.ts +55 -0
  131. package/src/context.ts +30 -10
  132. package/src/destroy.ts +11 -8
  133. package/src/esbuild/bundle.ts +53 -3
  134. package/src/fs/file-collection.ts +24 -0
  135. package/src/fs/file-ref.ts +22 -0
  136. package/src/fs/file.ts +107 -6
  137. package/src/fs/folder.ts +45 -5
  138. package/src/fs/index.ts +6 -0
  139. package/src/fs/json-file.ts +23 -0
  140. package/src/fs/text-file.ts +19 -0
  141. package/src/fs/typescript-file.ts +36 -0
  142. package/src/fs/yaml-file.ts +26 -0
  143. package/src/github/secret.ts +65 -2
  144. package/src/internal/docs.ts +369 -0
  145. package/src/resource.ts +7 -2
  146. package/src/scope.ts +9 -9
  147. package/src/secret.ts +67 -0
  148. package/src/state.ts +9 -2
  149. package/src/stripe/price.ts +50 -0
  150. package/src/stripe/product.ts +38 -0
  151. package/src/stripe/webhook.ts +45 -0
  152. package/src/test/bun.ts +83 -3
  153. package/src/util/serde.ts +30 -4
  154. package/src/vitepress/dependencies.ts +68 -0
  155. package/src/vitepress/home-page.ts +166 -0
  156. package/src/vitepress/index.md +75 -0
  157. package/src/vitepress/index.ts +2 -0
  158. package/src/vitepress/vitepress.ts +382 -0
  159. package/lib/project/vite.d.ts +0 -90
  160. package/lib/project/vite.js +0 -228
  161. package/src/project/vite.ts +0 -406
@@ -7,6 +7,69 @@ import { slugify } from "../util/slugify";
7
7
  import { createCloudflareApi } from "./api";
8
8
  import { isDurableObjectNamespace, } from "./bindings";
9
9
  import { isKVNamespace } from "./kv-namespace";
10
+ /**
11
+ * A Cloudflare Worker is a serverless function that can be deployed to the Cloudflare network.
12
+ *
13
+ * @example
14
+ * // Create a basic HTTP handler worker with custom domain routing
15
+ * // and workers.dev URL:
16
+ * const api = await Worker("api", {
17
+ * name: "api-worker",
18
+ * entrypoint: "./src/api.ts",
19
+ * routes: ["api.example.com/*"],
20
+ * url: true
21
+ * });
22
+ *
23
+ * @example
24
+ * // Create a real-time chat worker using Durable Objects
25
+ * // for state management:
26
+ * const chatRooms = new DurableObjectNamespace("chat-rooms");
27
+ * const userStore = new DurableObjectNamespace("user-store");
28
+ *
29
+ * const chat = await Worker("chat", {
30
+ * name: "chat-worker",
31
+ * entrypoint: "./src/chat.ts",
32
+ * bindings: {
33
+ * ROOMS: chatRooms,
34
+ * USERS: userStore
35
+ * },
36
+ * });
37
+ *
38
+ * @example
39
+ * // Create a worker with KV namespace for caching and data storage:
40
+ * const cache = await KVNamespace("cache-store");
41
+ * const settings = await KVNamespace("user-settings");
42
+ *
43
+ * const cacheWorker = await Worker("cache", {
44
+ * name: "cache-worker",
45
+ * entrypoint: "./src/cache.ts",
46
+ * bindings: {
47
+ * CACHE: cache,
48
+ * SETTINGS: settings
49
+ * }
50
+ * });
51
+ *
52
+ * @example
53
+ * // Create a worker with R2 bucket for object storage:
54
+ * const uploads = await R2Bucket("uploads", {
55
+ * name: "user-uploads"
56
+ * });
57
+ * const assets = await R2Bucket("assets", {
58
+ * name: "static-assets",
59
+ * allowPublicAccess: true
60
+ * });
61
+ *
62
+ * const storageWorker = await Worker("storage", {
63
+ * name: "storage-worker",
64
+ * entrypoint: "./src/storage.ts",
65
+ * bindings: {
66
+ * UPLOADS: uploads,
67
+ * ASSETS: assets
68
+ * }
69
+ * });
70
+ *
71
+ * @see https://developers.cloudflare.com/workers/
72
+ */
10
73
  export const Worker = Resource("cloudflare::Worker", {
11
74
  alwaysUpdate: true,
12
75
  }, async function (id, props) {
@@ -240,4 +240,4 @@ export interface WranglerJson extends Resource<"cloudflare::WranglerJson">, Wran
240
240
  /**
241
241
  * Resource for managing wrangler.json configuration files
242
242
  */
243
- export declare const WranglerJson: ((this: Context<WranglerJson>, id: string, props: WranglerJsonProps) => Promise<WranglerJson>) | (((this: any, id: string, props: WranglerJsonProps) => never) & (new (_: never) => never));
243
+ export declare const WranglerJson: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<WranglerJson>, id: string, props: WranglerJsonProps) => Promise<WranglerJson>);
@@ -1 +0,0 @@
1
- export {};
@@ -193,4 +193,59 @@ export interface Zone extends Resource<"cloudflare::Zone"> {
193
193
  minTlsVersion: MinTLSVersionValue;
194
194
  };
195
195
  }
196
- export declare const Zone: ((this: Context<Zone>, id: string, props: ZoneProps) => Promise<Zone>) | (((this: any, id: string, props: ZoneProps) => never) & (new (_: never) => never));
196
+ /**
197
+ * A Cloudflare Zone represents a domain and its configuration settings on Cloudflare.
198
+ * Zones allow you to manage DNS, SSL/TLS, caching, security and other settings for a domain.
199
+ *
200
+ * @example
201
+ * // Create a basic zone with default settings
202
+ * const basicZone = await Zone("example.com", {
203
+ * name: "example.com",
204
+ * type: "full",
205
+ * jumpStart: true
206
+ * });
207
+ *
208
+ * @example
209
+ * // Create a zone with enhanced security settings
210
+ * const secureZone = await Zone("secure.example.com", {
211
+ * name: "secure.example.com",
212
+ * type: "full",
213
+ * settings: {
214
+ * ssl: "strict",
215
+ * alwaysUseHttps: "on",
216
+ * automaticHttpsRewrites: "on",
217
+ * minTlsVersion: "1.3",
218
+ * tls13: "zrt"
219
+ * }
220
+ * });
221
+ *
222
+ * @example
223
+ * // Create a zone with optimized performance settings
224
+ * const fastZone = await Zone("fast.example.com", {
225
+ * name: "fast.example.com",
226
+ * settings: {
227
+ * browserCacheTtl: 7200,
228
+ * brotli: "on",
229
+ * zeroRtt: "on",
230
+ * http2: "on",
231
+ * http3: "on",
232
+ * earlyHints: "on"
233
+ * }
234
+ * });
235
+ *
236
+ * @example
237
+ * // Create a development zone with specific features
238
+ * const devZone = await Zone("dev.example.com", {
239
+ * name: "dev.example.com",
240
+ * settings: {
241
+ * developmentMode: "on",
242
+ * emailObfuscation: "on",
243
+ * hotlinkProtection: "on",
244
+ * ipv6: "on",
245
+ * websockets: "on"
246
+ * }
247
+ * });
248
+ *
249
+ * @see https://developers.cloudflare.com/dns/zone-setups/
250
+ */
251
+ export declare const Zone: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<Zone>, id: string, props: ZoneProps) => Promise<Zone>);
@@ -1,5 +1,60 @@
1
1
  import { Resource } from "../resource";
2
2
  import { createCloudflareApi } from "./api";
3
+ /**
4
+ * A Cloudflare Zone represents a domain and its configuration settings on Cloudflare.
5
+ * Zones allow you to manage DNS, SSL/TLS, caching, security and other settings for a domain.
6
+ *
7
+ * @example
8
+ * // Create a basic zone with default settings
9
+ * const basicZone = await Zone("example.com", {
10
+ * name: "example.com",
11
+ * type: "full",
12
+ * jumpStart: true
13
+ * });
14
+ *
15
+ * @example
16
+ * // Create a zone with enhanced security settings
17
+ * const secureZone = await Zone("secure.example.com", {
18
+ * name: "secure.example.com",
19
+ * type: "full",
20
+ * settings: {
21
+ * ssl: "strict",
22
+ * alwaysUseHttps: "on",
23
+ * automaticHttpsRewrites: "on",
24
+ * minTlsVersion: "1.3",
25
+ * tls13: "zrt"
26
+ * }
27
+ * });
28
+ *
29
+ * @example
30
+ * // Create a zone with optimized performance settings
31
+ * const fastZone = await Zone("fast.example.com", {
32
+ * name: "fast.example.com",
33
+ * settings: {
34
+ * browserCacheTtl: 7200,
35
+ * brotli: "on",
36
+ * zeroRtt: "on",
37
+ * http2: "on",
38
+ * http3: "on",
39
+ * earlyHints: "on"
40
+ * }
41
+ * });
42
+ *
43
+ * @example
44
+ * // Create a development zone with specific features
45
+ * const devZone = await Zone("dev.example.com", {
46
+ * name: "dev.example.com",
47
+ * settings: {
48
+ * developmentMode: "on",
49
+ * emailObfuscation: "on",
50
+ * hotlinkProtection: "on",
51
+ * ipv6: "on",
52
+ * websockets: "on"
53
+ * }
54
+ * });
55
+ *
56
+ * @see https://developers.cloudflare.com/dns/zone-setups/
57
+ */
3
58
  export const Zone = Resource("cloudflare::Zone", async function (id, props) {
4
59
  // Create Cloudflare API client with automatic account discovery
5
60
  const api = await createCloudflareApi({
package/lib/context.d.ts CHANGED
@@ -1,18 +1,21 @@
1
1
  import type { Resource, ResourceFQN, ResourceID, ResourceKind, ResourceProps } from "./resource";
2
2
  import type { Scope } from "./scope";
3
3
  import type { State } from "./state";
4
- export type Context<Out extends Resource> = CreateContext<Out> | UpdateContext<Out> | DeleteContext<Out>;
4
+ export type Context<Out extends Resource, Props extends ResourceProps = ResourceProps> = CreateContext<Out> | UpdateContext<Out, Props> | DeleteContext<Out, Props>;
5
5
  export interface CreateContext<Out extends Resource> extends BaseContext<Out> {
6
6
  phase: "create";
7
7
  output?: undefined;
8
+ props?: undefined;
8
9
  }
9
- export interface UpdateContext<Out extends Resource> extends BaseContext<Out> {
10
+ export interface UpdateContext<Out extends Resource, Props extends ResourceProps = ResourceProps> extends BaseContext<Out> {
10
11
  phase: "update";
11
12
  output: Out;
13
+ props: Props;
12
14
  }
13
- export interface DeleteContext<Out extends Resource> extends BaseContext<Out> {
15
+ export interface DeleteContext<Out extends Resource, Props extends ResourceProps = ResourceProps> extends BaseContext<Out> {
14
16
  phase: "delete";
15
17
  output: Out;
18
+ props: Props;
16
19
  }
17
20
  export interface BaseContext<Out extends Resource> {
18
21
  quiet: boolean;
@@ -44,15 +47,17 @@ export interface BaseContext<Out extends Resource> {
44
47
  /**
45
48
  * Create the Resource envelope (with Alchemy + User properties)
46
49
  */
50
+ (id: string, props: Omit<Out, keyof Resource>): Out;
47
51
  (props: Omit<Out, keyof Resource>): Out;
48
52
  }
49
- export declare function context<Kind extends string, Props extends ResourceProps, Out extends Resource>({ scope, phase, kind, id, fqn, seq, state, replace, }: {
53
+ export declare function context<Kind extends string, Props extends ResourceProps | undefined, Out extends Resource>({ scope, phase, kind, id, fqn, seq, state, replace, }: {
50
54
  scope: Scope;
51
55
  phase: "create" | "update" | "delete";
52
56
  kind: ResourceKind;
53
57
  id: ResourceID;
54
58
  fqn: ResourceFQN;
55
59
  seq: number;
60
+ props: Props;
56
61
  state: State<Kind, Props, Out>;
57
62
  replace: () => void;
58
63
  }): Context<Out>;
package/lib/context.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import { DestroyedSignal } from "./destroy";
2
2
  export function context({ scope, phase, kind, id, fqn, seq, state, replace, }) {
3
- function create(props) {
3
+ function create(...args) {
4
+ const [ID, props] = typeof args[0] === "string" ? args : [id, args[0]];
4
5
  return {
5
6
  ...props,
6
7
  Kind: kind,
7
- ID: id,
8
+ ID,
8
9
  FQN: fqn,
9
10
  Scope: scope,
10
11
  Seq: seq,
@@ -17,6 +18,7 @@ export function context({ scope, phase, kind, id, fqn, seq, state, replace, }) {
17
18
  fqn: fqn,
18
19
  phase,
19
20
  output: state.output,
21
+ props: state.props,
20
22
  replace,
21
23
  get: (key) => state.data[key],
22
24
  set: async (key, value) => {
package/lib/destroy.js CHANGED
@@ -12,12 +12,13 @@ function isScopeArgs(a) {
12
12
  */
13
13
  export async function destroy(...args) {
14
14
  if (isScopeArgs(args)) {
15
- const [scope, options] = args;
16
- const strategy = options?.strategy ?? "sequential";
15
+ const [scope] = args;
16
+ const options = {
17
+ strategy: "sequential",
18
+ ...(args[1] ?? {}),
19
+ };
17
20
  // destroy all active resources
18
- await destroy.all(Array.from(scope.resources.values()), {
19
- strategy,
20
- });
21
+ await destroy.all(Array.from(scope.resources.values()), options);
21
22
  // then detect orphans and destroy them
22
23
  const orphans = await scope.state.all();
23
24
  await destroy.all(Object.values(orphans).map((orphan) => ({
@@ -34,7 +35,7 @@ export async function destroy(...args) {
34
35
  }
35
36
  const Provider = PROVIDERS.get(instance.Kind);
36
37
  if (!Provider) {
37
- throw new Error(`Cannot destroy resource type ${instance.Kind} - no provider found. You may need to import the provider in your alchemy.config.ts.`);
38
+ throw new Error(`Cannot destroy resource "${instance.FQN}" type ${instance.Kind} - no provider found. You may need to import the provider in your alchemy.config.ts.`);
38
39
  }
39
40
  const scope = instance.Scope;
40
41
  if (!scope) {
@@ -45,9 +46,8 @@ export async function destroy(...args) {
45
46
  if (!quiet) {
46
47
  console.log(`Delete: "${instance.FQN}"`);
47
48
  }
48
- const state = (await scope.state.get(instance.ID));
49
+ const state = await scope.state.get(instance.ID);
49
50
  if (state === undefined) {
50
- console.warn(`Resource "${instance.FQN}" not found`);
51
51
  return;
52
52
  }
53
53
  const ctx = context({
@@ -57,6 +57,7 @@ export async function destroy(...args) {
57
57
  id: instance.ID,
58
58
  fqn: instance.FQN,
59
59
  seq: instance.Seq,
60
+ props: state.props,
60
61
  state,
61
62
  replace: () => {
62
63
  throw new Error("Cannot replace a resource that is being deleted");
@@ -1,25 +1,35 @@
1
1
  import * as esbuild from "esbuild";
2
2
  import type { Context } from "../context";
3
3
  import { Resource } from "../resource";
4
+ /**
5
+ * Properties for creating or updating an esbuild bundle
6
+ */
4
7
  export interface BundleProps {
5
8
  /**
6
9
  * Entry point for the bundle
10
+ * Path to the source file to bundle (e.g., "src/handler.ts")
7
11
  */
8
12
  entryPoint: string;
9
13
  /**
10
14
  * Output directory for the bundle
15
+ * Directory where the bundled file will be written
11
16
  */
12
17
  outdir?: string;
13
18
  /**
14
19
  * Output filename for the bundle
20
+ * Full path to the output file, overrides outdir if specified
15
21
  */
16
22
  outfile?: string;
17
23
  /**
18
- * Bundle format (iife, cjs, esm)
24
+ * Bundle format
25
+ * iife: Immediately Invoked Function Expression
26
+ * cjs: CommonJS
27
+ * esm: ECMAScript Modules
19
28
  */
20
29
  format?: "iife" | "cjs" | "esm";
21
30
  /**
22
- * Target environment (e.g., 'node16', 'es2020')
31
+ * Target environment
32
+ * Examples: 'node16', 'node18', 'es2020'
23
33
  */
24
34
  target?: string | string[];
25
35
  /**
@@ -28,32 +38,61 @@ export interface BundleProps {
28
38
  minify?: boolean;
29
39
  /**
30
40
  * Whether to generate sourcemaps
41
+ * inline: Include sourcemap in bundle
42
+ * external: Generate separate .map file
43
+ * both: Generate both inline and external
31
44
  */
32
45
  sourcemap?: boolean | "inline" | "external" | "both";
33
46
  /**
34
47
  * External packages to exclude from bundle
48
+ * Array of package names to mark as external
35
49
  */
36
50
  external?: string[];
37
51
  /**
38
- * Platform to target (browser, node, neutral)
52
+ * Platform to target
53
+ * browser: Browser environment
54
+ * node: Node.js environment
55
+ * neutral: Platform-agnostic
39
56
  */
40
57
  platform?: "browser" | "node" | "neutral";
41
58
  /**
42
59
  * Additional esbuild options
60
+ * Any other valid esbuild BuildOptions
43
61
  */
44
62
  options?: Partial<esbuild.BuildOptions>;
45
63
  }
64
+ /**
65
+ * Output returned after bundle creation/update
66
+ */
46
67
  export interface Bundle extends Resource<"esbuild::Bundle"> {
47
68
  /**
48
69
  * Path to the bundled file
70
+ * Absolute or relative path to the generated bundle
49
71
  */
50
72
  path: string;
51
73
  /**
52
74
  * SHA-256 hash of the bundle contents
75
+ * Used for cache busting and content verification
53
76
  */
54
77
  hash: string;
55
78
  }
56
- export declare const Bundle: ((this: Context<Bundle>, id: string, props: BundleProps) => Promise<Bundle>) | (((this: any, id: string, props: BundleProps) => never) & (new (_: never) => never));
79
+ /**
80
+ * esbuild Bundle Resource
81
+ *
82
+ * Creates and manages bundled JavaScript/TypeScript files using esbuild.
83
+ * Supports various output formats, sourcemaps, and platform targets.
84
+ *
85
+ * @example
86
+ * // Bundle a TypeScript file for Node.js
87
+ * const bundle = await Bundle("handler", {
88
+ * entryPoint: "src/handler.ts",
89
+ * outdir: ".alchemy/.out",
90
+ * format: "esm",
91
+ * platform: "node",
92
+ * target: "node18"
93
+ * });
94
+ */
95
+ export declare const Bundle: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<Bundle>, id: string, props: BundleProps) => Promise<Bundle>);
57
96
  export declare function bundle(props: BundleProps): Promise<esbuild.BuildResult<{
58
97
  bundle: boolean;
59
98
  splitting?: boolean;
@@ -3,6 +3,22 @@ import crypto from "node:crypto";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
5
5
  import { Resource } from "../resource";
6
+ /**
7
+ * esbuild Bundle Resource
8
+ *
9
+ * Creates and manages bundled JavaScript/TypeScript files using esbuild.
10
+ * Supports various output formats, sourcemaps, and platform targets.
11
+ *
12
+ * @example
13
+ * // Bundle a TypeScript file for Node.js
14
+ * const bundle = await Bundle("handler", {
15
+ * entryPoint: "src/handler.ts",
16
+ * outdir: ".alchemy/.out",
17
+ * format: "esm",
18
+ * platform: "node",
19
+ * target: "node18"
20
+ * });
21
+ */
6
22
  export const Bundle = Resource("esbuild::Bundle", {
7
23
  alwaysUpdate: true,
8
24
  }, async function (id, props) {
@@ -0,0 +1,16 @@
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
+ export declare function isFileCollection(value: unknown): value is FileCollection;
@@ -0,0 +1,6 @@
1
+ export function isFileCollection(value) {
2
+ return (typeof value === "object" &&
3
+ value !== null &&
4
+ "type" in value &&
5
+ value.type === "fs::FileCollection");
6
+ }
@@ -0,0 +1,14 @@
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
+ export declare function isFileRef(value: unknown): value is FileRef;
@@ -0,0 +1,6 @@
1
+ export function isFileRef(value) {
2
+ return (typeof value === "object" &&
3
+ value !== null &&
4
+ "kind" in value &&
5
+ value.kind === "fs::FileRef");
6
+ }
package/lib/fs/file.d.ts CHANGED
@@ -1,13 +1,86 @@
1
1
  import type { Context } from "../context";
2
2
  import { Resource } from "../resource";
3
+ import type { FileCollection } from "./file-collection";
4
+ import type { FileRef } from "./file-ref";
5
+ declare module "../alchemy" {
6
+ interface Alchemy {
7
+ /**
8
+ * Creates a reference to a file in the filesystem.
9
+ * Used in template string interpolation to include file contents,
10
+ * commonly for documentation generation.
11
+ *
12
+ * @param path Path to the file
13
+ * @returns Promise resolving to a FileRef
14
+ *
15
+ * @example
16
+ * // Include a file in documentation generation
17
+ * await Document("api-docs", {
18
+ * prompt: await alchemy`
19
+ * Generate docs using the contents of:
20
+ * ${alchemy.file("./README.md")}
21
+ * `
22
+ * });
23
+ */
24
+ file(path: string): Promise<FileRef>;
25
+ /**
26
+ * Creates a collection of files with their contents.
27
+ * Used in template string interpolation to include multiple file contents,
28
+ * commonly for bulk documentation generation.
29
+ *
30
+ * @param paths Array of file paths to include in collection
31
+ * @returns Promise resolving to a FileCollection
32
+ *
33
+ * @example
34
+ * // Include multiple source files in documentation generation
35
+ * await Document("provider-docs", {
36
+ * prompt: await alchemy`
37
+ * Generate comprehensive docs for these files:
38
+ * ${alchemy.files([
39
+ * "src/types.ts",
40
+ * "src/resource.ts",
41
+ * "src/provider.ts"
42
+ * ])}
43
+ * `
44
+ * });
45
+ */
46
+ files(paths: string[]): Promise<FileCollection>;
47
+ files(path: string, ...paths: string[]): Promise<FileCollection>;
48
+ }
49
+ }
50
+ /**
51
+ * Base file resource type
52
+ */
3
53
  export interface File extends Resource<"fs::File"> {
54
+ /**
55
+ * Path to the file
56
+ */
4
57
  path: string;
58
+ /**
59
+ * Content of the file
60
+ */
5
61
  content: string;
6
62
  }
7
- export declare const File: ((this: Context<File>, id: string, { path: filePath, content, }: {
8
- path: string;
9
- content: string;
10
- }) => Promise<File>) | (((this: any, id: string, props: {
63
+ /**
64
+ * File Resource
65
+ *
66
+ * Creates and manages files in the filesystem with automatic directory creation
67
+ * and proper cleanup on deletion.
68
+ *
69
+ * @example
70
+ * // Create a simple text file
71
+ * const config = await File("config.txt", {
72
+ * path: "config.txt",
73
+ * content: "some configuration data"
74
+ * });
75
+ *
76
+ * @example
77
+ * // Create a file in a nested directory
78
+ * const log = await File("logs/app.log", {
79
+ * path: "logs/app.log",
80
+ * content: "application log entry"
81
+ * });
82
+ */
83
+ export declare const File: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<File>, id: string, props: {
11
84
  path: string;
12
85
  content: string;
13
- }) => never) & (new (_: never) => never));
86
+ }) => Promise<File>);
package/lib/fs/file.js CHANGED
@@ -2,7 +2,43 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { Resource } from "../resource";
4
4
  import { ignore } from "../util/ignore";
5
- export const File = Resource("fs::File", async function (id, { path: filePath, content, }) {
5
+ import { alchemy } from "../alchemy";
6
+ alchemy.file = async (path) => ({
7
+ kind: "fs::FileRef",
8
+ path,
9
+ });
10
+ alchemy.files = async (...args) => {
11
+ const paths = typeof args[0] === "string" ? args : args[0];
12
+ return {
13
+ type: "fs::FileCollection",
14
+ files: Object.fromEntries(await Promise.all(paths.map(async (path) => [
15
+ path,
16
+ await fs.promises.readFile(path, "utf-8"),
17
+ ]))),
18
+ };
19
+ };
20
+ /**
21
+ * File Resource
22
+ *
23
+ * Creates and manages files in the filesystem with automatic directory creation
24
+ * and proper cleanup on deletion.
25
+ *
26
+ * @example
27
+ * // Create a simple text file
28
+ * const config = await File("config.txt", {
29
+ * path: "config.txt",
30
+ * content: "some configuration data"
31
+ * });
32
+ *
33
+ * @example
34
+ * // Create a file in a nested directory
35
+ * const log = await File("logs/app.log", {
36
+ * path: "logs/app.log",
37
+ * content: "application log entry"
38
+ * });
39
+ */
40
+ export const File = Resource("fs::File", async function (id, props) {
41
+ const filePath = props?.path ?? id;
6
42
  if (this.phase === "delete") {
7
43
  await ignore("ENOENT", async () => fs.promises.unlink(filePath));
8
44
  return this.destroy();
@@ -11,10 +47,10 @@ export const File = Resource("fs::File", async function (id, { path: filePath, c
11
47
  await fs.promises.mkdir(path.dirname(filePath), {
12
48
  recursive: true,
13
49
  });
14
- await fs.promises.writeFile(filePath, content);
50
+ await fs.promises.writeFile(filePath, props.content);
15
51
  }
16
52
  return this({
17
53
  path: filePath,
18
- content,
54
+ content: props.content,
19
55
  });
20
56
  });