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
@@ -0,0 +1,71 @@
1
+ import type { DefaultTheme, ThemeOptions } from "vitepress";
2
+ import type { Context } from "../context";
3
+ import { Resource } from "../resource";
4
+ import type { HomePage } from "./home-page";
5
+ export interface VitePressProjectProps {
6
+ /**
7
+ * The name/path of the project
8
+ */
9
+ name: string;
10
+ /**
11
+ * The title of the documentation site
12
+ */
13
+ title?: string;
14
+ /**
15
+ * The description of the documentation site
16
+ */
17
+ description?: string;
18
+ /**
19
+ * Whether to use TypeScript for config and theme files
20
+ * @default true
21
+ */
22
+ typescript?: boolean;
23
+ tsconfig?: {
24
+ extends?: string;
25
+ references?: string[];
26
+ compilerOptions?: Record<string, any>;
27
+ };
28
+ /**
29
+ * Force overwrite the project config files during the update phase
30
+ * @default false
31
+ */
32
+ overwrite?: boolean;
33
+ /**
34
+ * The dependencies to install
35
+ */
36
+ dependencies?: Record<string, string>;
37
+ /**
38
+ * The dev dependencies to install
39
+ */
40
+ devDependencies?: Record<string, string>;
41
+ /**
42
+ * The theme options to use
43
+ */
44
+ theme?: ThemeOptions;
45
+ /**
46
+ * The theme config to use
47
+ */
48
+ themeConfig: DefaultTheme.Config;
49
+ /**
50
+ * The home page configuration
51
+ */
52
+ home: HomePage;
53
+ /**
54
+ * Whether to delete the project folder during the delete phase
55
+ * @default true
56
+ */
57
+ delete?: boolean;
58
+ /**
59
+ * The directory to generate the docs in
60
+ *
61
+ * @default {@link name}
62
+ */
63
+ dir?: string;
64
+ }
65
+ export interface VitePressProject extends VitePressProjectProps, Resource {
66
+ /**
67
+ * The name/path of the project
68
+ */
69
+ name: string;
70
+ }
71
+ export declare const VitePressProject: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<VitePressProject>, id: string, props: VitePressProjectProps) => Promise<VitePressProject>);
@@ -0,0 +1,266 @@
1
+ import { exec } from "child_process";
2
+ import fs from "fs/promises";
3
+ import path from "path";
4
+ import { promisify } from "util";
5
+ import yaml from "yaml";
6
+ import { Folder, JsonFile, TextFile, TypeScriptFile } from "../fs";
7
+ import { Resource } from "../resource";
8
+ import { InstallDependencies, fixedDependencies } from "./dependencies";
9
+ const execAsync = promisify(exec);
10
+ export const VitePressProject = Resource("project::VitePressProject", {
11
+ alwaysUpdate: true,
12
+ }, async function (id, props) {
13
+ const dir = props.dir ?? props.name;
14
+ if (this.phase === "delete") {
15
+ try {
16
+ if (props.delete !== false) {
17
+ if (await fs.exists(dir)) {
18
+ // Delete the entire project directory
19
+ await execAsync(`rm -rf ${dir}`);
20
+ }
21
+ }
22
+ }
23
+ catch (error) {
24
+ console.error(`Error deleting VitePress project ${id}:`, error);
25
+ }
26
+ return this.destroy();
27
+ }
28
+ const cwd = (await Folder("dir", {
29
+ path: dir,
30
+ delete: props.delete,
31
+ })).path;
32
+ // Initialize package.json
33
+ await JsonFile(path.join(cwd, "package.json"), {
34
+ name: props.name,
35
+ scripts: {
36
+ "docs:gen": "bun alchemy.run.ts",
37
+ "docs:dev": "vitepress dev",
38
+ "docs:build": "vitepress build",
39
+ "docs:preview": "vitepress preview",
40
+ },
41
+ dependencies: fixedDependencies(props.dependencies || {}),
42
+ devDependencies: fixedDependencies(props.devDependencies || {}),
43
+ });
44
+ await InstallDependencies("dependencies", {
45
+ cwd,
46
+ dependencies: props.dependencies,
47
+ devDependencies: {
48
+ vue: "latest",
49
+ vitepress: "latest",
50
+ "@shikijs/vitepress-twoslash": "latest",
51
+ "markdown-it-footnote": "latest",
52
+ ...props.devDependencies,
53
+ },
54
+ });
55
+ // Create .vitepress directory and config
56
+ await Folder(path.join(cwd, ".vitepress"));
57
+ await Folder(path.join(cwd, ".vitepress", "theme"));
58
+ await Promise.all([
59
+ TextFile(path.join(cwd, ".gitignore"), `.vitepress/cache\n`),
60
+ JsonFile(path.join(cwd, "tsconfig.json"), {
61
+ extends: props.tsconfig?.extends,
62
+ references: props.tsconfig?.references?.map((path) => ({ path })),
63
+ compilerOptions: props.tsconfig?.compilerOptions,
64
+ }),
65
+ TextFile(path.join(cwd, "index.md"), `---\n${yaml.stringify(props.home)}---\n`),
66
+ // TypeScriptFile(
67
+ // path.join(cwd, "alchemy.run.ts"),
68
+ // `import alchemy from "alchemy";
69
+ // import { Folder } from "alchemy/fs";
70
+ // import { Document } from "alchemy/docs";
71
+ // import path from "path";
72
+ // await using _ = alchemy("alchemy.run", {
73
+ // stage: "prod",
74
+ // phase: process.argv.includes("--destroy") ? "destroy" : "up",
75
+ // password: process.env.SECRET_PASSPHRASE,
76
+ // quiet: !process.argv.includes("--verbose"),
77
+ // });
78
+ // const docs = await Folder(path.join("alchemy.run", "docs"));
79
+ // await Document("home.md", {
80
+ // path: path.join(docs.path, "home.md"),
81
+ // prompt: await alchemy\`Generate a landing page.\`,
82
+ // });
83
+ // `,
84
+ // ),
85
+ TypeScriptFile(path.join(cwd, ".vitepress", "theme", "index.ts"), `import TwoslashFloatingVue from "@shikijs/vitepress-twoslash/client";
86
+ import "@shikijs/vitepress-twoslash/style.css";
87
+ import type { Theme as ThemeConfig } from "vitepress";
88
+ import Theme from "vitepress/theme-without-fonts";
89
+ import "./style.css";
90
+
91
+ export default {
92
+ extends: Theme,
93
+ enhanceApp(ctx) {
94
+ ctx.app.use(TwoslashFloatingVue);
95
+ },
96
+ } satisfies ThemeConfig;
97
+ `),
98
+ TextFile(path.join(cwd, ".vitepress", "theme", "style.css"), `/**
99
+ * Customize default theme styling by overriding CSS variables:
100
+ * https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css
101
+ */
102
+
103
+ /**
104
+ * Colors
105
+ *
106
+ * Each colors have exact same color scale system with 3 levels of solid
107
+ * colors with different brightness, and 1 soft color.
108
+ *
109
+ * - \`XXX-1\`: The most solid color used mainly for colored text. It must
110
+ * satisfy the contrast ratio against when used on top of \`XXX-soft\`.
111
+ *
112
+ * - \`XXX-2\`: The color used mainly for hover state of the button.
113
+ *
114
+ * - \`XXX-3\`: The color for solid background, such as bg color of the button.
115
+ * It must satisfy the contrast ratio with pure white (#ffffff) text on
116
+ * top of it.
117
+ *
118
+ * - \`XXX-soft\`: The color used for subtle background such as custom container
119
+ * or badges. It must satisfy the contrast ratio when putting \`XXX-1\` colors
120
+ * on top of it.
121
+ *
122
+ * The soft color must be semi transparent alpha channel. This is crucial
123
+ * because it allows adding multiple "soft" colors on top of each other
124
+ * to create a accent, such as when having inline code block inside
125
+ * custom containers.
126
+ *
127
+ * - \`default\`: The color used purely for subtle indication without any
128
+ * special meanings attached to it such as bg color for menu hover state.
129
+ *
130
+ * - \`brand\`: Used for primary brand colors, such as link text, button with
131
+ * brand theme, etc.
132
+ *
133
+ * - \`tip\`: Used to indicate useful information. The default theme uses the
134
+ * brand color for this by default.
135
+ *
136
+ * - \`warning\`: Used to indicate warning to the users. Used in custom
137
+ * container, badges, etc.
138
+ *
139
+ * - \`danger\`: Used to show error, or dangerous message to the users. Used
140
+ * in custom container, badges, etc.
141
+ * -------------------------------------------------------------------------- */
142
+
143
+ :root {
144
+ --vp-c-default-1: var(--vp-c-gray-1);
145
+ --vp-c-default-2: var(--vp-c-gray-2);
146
+ --vp-c-default-3: var(--vp-c-gray-3);
147
+ --vp-c-default-soft: var(--vp-c-gray-soft);
148
+
149
+ --vp-c-brand-1: var(--vp-c-indigo-1);
150
+ --vp-c-brand-2: var(--vp-c-indigo-2);
151
+ --vp-c-brand-3: var(--vp-c-indigo-3);
152
+ --vp-c-brand-soft: var(--vp-c-indigo-soft);
153
+
154
+ --vp-c-tip-1: var(--vp-c-brand-1);
155
+ --vp-c-tip-2: var(--vp-c-brand-2);
156
+ --vp-c-tip-3: var(--vp-c-brand-3);
157
+ --vp-c-tip-soft: var(--vp-c-brand-soft);
158
+
159
+ --vp-c-warning-1: var(--vp-c-yellow-1);
160
+ --vp-c-warning-2: var(--vp-c-yellow-2);
161
+ --vp-c-warning-3: var(--vp-c-yellow-3);
162
+ --vp-c-warning-soft: var(--vp-c-yellow-soft);
163
+
164
+ --vp-c-danger-1: var(--vp-c-red-1);
165
+ --vp-c-danger-2: var(--vp-c-red-2);
166
+ --vp-c-danger-3: var(--vp-c-red-3);
167
+ --vp-c-danger-soft: var(--vp-c-red-soft);
168
+ }
169
+
170
+ /**
171
+ * Component: Button
172
+ * -------------------------------------------------------------------------- */
173
+
174
+ :root {
175
+ --vp-button-brand-border: transparent;
176
+ --vp-button-brand-text: var(--vp-c-white);
177
+ --vp-button-brand-bg: var(--vp-c-brand-3);
178
+ --vp-button-brand-hover-border: transparent;
179
+ --vp-button-brand-hover-text: var(--vp-c-white);
180
+ --vp-button-brand-hover-bg: var(--vp-c-brand-2);
181
+ --vp-button-brand-active-border: transparent;
182
+ --vp-button-brand-active-text: var(--vp-c-white);
183
+ --vp-button-brand-active-bg: var(--vp-c-brand-1);
184
+ }
185
+
186
+ /**
187
+ * Component: Home
188
+ * -------------------------------------------------------------------------- */
189
+
190
+ :root {
191
+ --vp-home-hero-name-color: transparent;
192
+ --vp-home-hero-name-background: -webkit-linear-gradient(
193
+ 120deg,
194
+ #bd34fe 30%,
195
+ #41d1ff
196
+ );
197
+
198
+ --vp-home-hero-image-background-image: linear-gradient(
199
+ -45deg,
200
+ #bd34fe 50%,
201
+ #47caff 50%
202
+ );
203
+ --vp-home-hero-image-filter: blur(44px);
204
+ }
205
+
206
+ @media (min-width: 640px) {
207
+ :root {
208
+ --vp-home-hero-image-filter: blur(56px);
209
+ }
210
+ }
211
+
212
+ @media (min-width: 960px) {
213
+ :root {
214
+ --vp-home-hero-image-filter: blur(68px);
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Component: Custom Block
220
+ * -------------------------------------------------------------------------- */
221
+
222
+ :root {
223
+ --vp-custom-block-tip-border: transparent;
224
+ --vp-custom-block-tip-text: var(--vp-c-text-1);
225
+ --vp-custom-block-tip-bg: var(--vp-c-brand-soft);
226
+ --vp-custom-block-tip-code-bg: var(--vp-c-brand-soft);
227
+ }
228
+
229
+ /**
230
+ * Component: Algolia
231
+ * -------------------------------------------------------------------------- */
232
+
233
+ .DocSearch {
234
+ --docsearch-primary-color: var(--vp-c-brand-1) !important;
235
+ }
236
+ `),
237
+ TypeScriptFile(path.join(cwd, ".vitepress", "config.mts"), `import { transformerTwoslash } from "@shikijs/vitepress-twoslash";
238
+ import footnotePlugin from "markdown-it-footnote";
239
+ import { defineConfig } from "vitepress";
240
+
241
+ // https://vitepress.dev/reference/site-config
242
+ export default defineConfig({
243
+ title: ${JSON.stringify(props.title || "Alchemy")},
244
+ description: ${JSON.stringify(props.description || "Alchemy Docs")},
245
+ markdown: {
246
+ // @ts-ignore
247
+ codeTransformers: [transformerTwoslash()],
248
+ theme: ${JSON.stringify(props.theme ?? {
249
+ light: "light-plus",
250
+ dark: "dark-plus",
251
+ })},
252
+ config: (md) => md.use(footnotePlugin),
253
+ },
254
+ // https://vitepress.dev/reference/default-theme-config
255
+ themeConfig: ${JSON.stringify({
256
+ ...props.themeConfig,
257
+ search: props.themeConfig.search ?? { provider: "local" },
258
+ nav: props.themeConfig.nav ?? [{ text: "Home", link: "/" }],
259
+ sidebar: props.themeConfig.sidebar ?? [],
260
+ socialLinks: props.themeConfig.socialLinks ?? [],
261
+ })}
262
+ });
263
+ `),
264
+ ]);
265
+ return this(props);
266
+ });
package/package.json CHANGED
@@ -1,14 +1,16 @@
1
1
  {
2
2
  "name": "alchemy",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "type": "module",
5
5
  "module": "./lib/index.js",
6
6
  "scripts": {
7
- "publish:npm": "cp ../README.md . && rm -rf ./*.tsbuildinfo && rm -rf ./lib && tsc -b && npm publish && rm README.md"
7
+ "publish:npm": "cp ../README.md . && rm -rf ./*.tsbuildinfo && rm -rf ./lib && tsc -b && npm publish && rm README.md",
8
+ "docs:gen": "rm -rf ./docs && typedoc"
8
9
  },
9
10
  "files": ["lib", "src"],
10
11
  "exports": {
11
12
  ".": "./lib/index.js",
13
+ "./ai": "./lib/ai/index.js",
12
14
  "./aws": "./lib/aws/index.js",
13
15
  "./aws/oidc": "./lib/aws/oidc/index.js",
14
16
  "./cloudflare": "./lib/cloudflare/index.js",
@@ -22,6 +24,7 @@
22
24
  },
23
25
  "peerDependencies": {
24
26
  "@ai-sdk/openai": "^1.1.9",
27
+ "@ai-sdk/openai-compatible": "^0.2.2",
25
28
  "@aws-sdk/client-dynamodb": "^3.0.0",
26
29
  "@aws-sdk/client-iam": "^3.0.0",
27
30
  "@aws-sdk/client-lambda": "^3.0.0",
@@ -31,17 +34,20 @@
31
34
  "@aws-sdk/client-sesv2": "^3.0.0",
32
35
  "@aws-sdk/client-sqs": "^3.0.0",
33
36
  "@aws-sdk/client-sts": "^3.0.0",
37
+ "arktype": "^2.0.0",
38
+ "prettier": "^3.0.0",
34
39
  "@octokit/rest": "^21.1.1",
35
- "ai": "^4.1.16",
40
+ "ai": "^4.0.0",
36
41
  "diff": "^7.0.0",
37
- "esbuild": "^0.24.2",
38
- "glob": "^10.3.10",
39
- "hono": "^4.7.4",
42
+ "esbuild": "^0.25.1",
43
+ "glob": "^10.0.0",
44
+ "hono": "^4.0.0",
40
45
  "libsodium-wrappers": "^0.7.15",
41
46
  "jszip": "^3.0.0",
42
- "stripe": "^17.7.0",
43
- "turndown": "^7.2.0",
44
- "zod": "^3.24.1"
47
+ "stripe": "^17.0.0",
48
+ "turndown": "^7.0.0",
49
+ "yaml": "^2.0.0",
50
+ "zod": "^3.0.0"
45
51
  },
46
52
  "devDependencies": {
47
53
  "@ai-sdk/anthropic": "^1.1.6",
@@ -55,12 +61,18 @@
55
61
  "@types/node": "latest",
56
62
  "@types/turndown": "^5.0.5",
57
63
  "ai": "^4.1.16",
64
+ "arktype": "^2.1.16",
58
65
  "change-case": "^5.4.4",
59
66
  "libsodium-wrappers": "^0.7.15",
60
67
  "openpgp": "^6.1.0",
68
+ "prettier": "^3.5.3",
61
69
  "turndown": "^7.2.0",
70
+ "typedoc": "^0.28.1",
71
+ "typedoc-plugin-markdown": "^4.6.0",
62
72
  "typescript": "latest",
63
73
  "vite": "^6.0.7",
64
- "wrangler": "^3.114.0"
74
+ "vitepress": "^1.6.3",
75
+ "wrangler": "^3.114.0",
76
+ "yaml": "^2.7.1"
65
77
  }
66
78
  }
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
+ }