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.
- package/lib/ai/ark.d.ts +11 -0
- package/lib/ai/ark.js +86 -0
- package/lib/ai/client.d.ts +51 -0
- package/lib/ai/client.js +29 -0
- package/lib/ai/data.d.ts +101 -0
- package/lib/ai/data.js +70 -0
- package/lib/ai/document.d.ts +101 -0
- package/lib/ai/document.js +82 -0
- package/lib/ai/index.d.ts +3 -0
- package/lib/ai/index.js +3 -0
- package/lib/alchemy.d.ts +83 -2
- package/lib/alchemy.js +31 -3
- package/lib/aws/bucket.d.ts +87 -1
- package/lib/aws/bucket.js +48 -1
- package/lib/aws/function.d.ts +186 -1
- package/lib/aws/function.js +62 -8
- package/lib/aws/oidc/github-oidc-provider.d.ts +81 -0
- package/lib/aws/oidc/github-oidc-provider.js +68 -0
- package/lib/aws/oidc/oidc-provider.d.ts +14 -6
- package/lib/aws/oidc/oidc-provider.js +26 -5
- package/lib/aws/policy-attachment.d.ts +44 -1
- package/lib/aws/policy-attachment.js +31 -0
- package/lib/aws/policy.d.ts +160 -1
- package/lib/aws/policy.js +78 -0
- package/lib/aws/queue.d.ts +83 -1
- package/lib/aws/queue.js +39 -0
- package/lib/aws/role.d.ts +162 -1
- package/lib/aws/role.js +114 -0
- package/lib/aws/ses.d.ts +57 -2
- package/lib/aws/ses.js +42 -1
- package/lib/aws/table.d.ts +96 -1
- package/lib/aws/table.js +36 -0
- package/lib/cloudflare/asset-manifest.js +0 -1
- package/lib/cloudflare/bound.js +0 -1
- package/lib/cloudflare/bucket.d.ts +37 -1
- package/lib/cloudflare/bucket.js +36 -0
- package/lib/cloudflare/durable-object-namespace.d.ts +25 -0
- package/lib/cloudflare/durable-object-namespace.js +22 -0
- package/lib/cloudflare/kv-namespace.d.ts +37 -1
- package/lib/cloudflare/kv-namespace.js +36 -0
- package/lib/cloudflare/static-site.d.ts +53 -1
- package/lib/cloudflare/static-site.js +53 -1
- package/lib/cloudflare/worker-metadata.js +0 -1
- package/lib/cloudflare/worker.d.ts +64 -1
- package/lib/cloudflare/worker.js +63 -0
- package/lib/cloudflare/wrangler.json.d.ts +1 -1
- package/lib/cloudflare/zone-settings.js +0 -1
- package/lib/cloudflare/zone.d.ts +56 -1
- package/lib/cloudflare/zone.js +55 -0
- package/lib/destroy.js +1 -1
- package/lib/esbuild/bundle.d.ts +43 -4
- package/lib/esbuild/bundle.js +16 -0
- package/lib/fs/file-collection.d.ts +16 -0
- package/lib/fs/file-collection.js +6 -0
- package/lib/fs/file-ref.d.ts +14 -0
- package/lib/fs/file-ref.js +6 -0
- package/lib/fs/file.d.ts +71 -25
- package/lib/fs/file.js +20 -44
- package/lib/fs/folder.d.ts +37 -5
- package/lib/fs/folder.js +26 -2
- package/lib/fs/index.d.ts +6 -0
- package/lib/fs/index.js +6 -0
- package/lib/fs/json-file.d.ts +16 -0
- package/lib/fs/json-file.js +7 -0
- package/lib/fs/text-file.d.ts +12 -0
- package/lib/fs/text-file.js +7 -0
- package/lib/fs/typescript-file.d.ts +19 -0
- package/lib/fs/typescript-file.js +14 -0
- package/lib/fs/yaml-file.d.ts +19 -0
- package/lib/fs/yaml-file.js +8 -0
- package/lib/github/secret.d.ts +63 -2
- package/lib/github/secret.js +61 -1
- package/lib/internal/docs.d.ts +5 -0
- package/lib/internal/docs.js +287 -0
- package/lib/resource.d.ts +1 -1
- package/lib/secret.d.ts +67 -0
- package/lib/secret.js +67 -0
- package/lib/shadcn/component.d.ts +1 -1
- package/lib/stripe/price.d.ts +51 -1
- package/lib/stripe/price.js +50 -0
- package/lib/stripe/product.d.ts +39 -1
- package/lib/stripe/product.js +38 -0
- package/lib/stripe/webhook.d.ts +46 -1
- package/lib/stripe/webhook.js +45 -0
- package/lib/test/bun.d.ts +64 -0
- package/lib/test/bun.js +35 -3
- package/lib/util/serde.js +14 -0
- package/lib/vite/vite.d.ts +1 -1
- package/lib/vitepress/dependencies.d.ts +2 -6
- package/lib/vitepress/vitepress.d.ts +12 -1
- package/lib/vitepress/vitepress.js +29 -23
- package/package.json +8 -3
- package/src/ai/ark.ts +118 -0
- package/src/ai/client.ts +78 -0
- package/src/ai/data.ts +149 -0
- package/src/ai/document.ts +165 -0
- package/src/ai/index.ts +3 -0
- package/src/alchemy.ts +88 -5
- package/src/aws/bucket.ts +111 -7
- package/src/aws/function.ts +231 -10
- package/src/aws/oidc/github-oidc-provider.ts +83 -0
- package/src/aws/oidc/oidc-provider.ts +39 -7
- package/src/aws/policy-attachment.ts +44 -1
- package/src/aws/policy.ts +177 -2
- package/src/aws/queue.ts +89 -0
- package/src/aws/role.ts +174 -2
- package/src/aws/ses.ts +56 -1
- package/src/aws/table.ts +103 -0
- package/src/cloudflare/bucket.ts +36 -0
- package/src/cloudflare/durable-object-namespace.ts +25 -0
- package/src/cloudflare/kv-namespace.ts +36 -0
- package/src/cloudflare/static-site.ts +53 -1
- package/src/cloudflare/worker.ts +63 -0
- package/src/cloudflare/zone.ts +55 -0
- package/src/destroy.ts +1 -1
- package/src/esbuild/bundle.ts +53 -3
- package/src/fs/file-collection.ts +24 -0
- package/src/fs/file-ref.ts +22 -0
- package/src/fs/file.ts +70 -77
- package/src/fs/folder.ts +44 -5
- package/src/fs/index.ts +6 -0
- package/src/fs/json-file.ts +23 -0
- package/src/fs/text-file.ts +19 -0
- package/src/fs/typescript-file.ts +36 -0
- package/src/fs/yaml-file.ts +26 -0
- package/src/github/secret.ts +65 -2
- package/src/internal/docs.ts +338 -0
- package/src/resource.ts +1 -1
- package/src/secret.ts +67 -0
- package/src/stripe/price.ts +50 -0
- package/src/stripe/product.ts +38 -0
- package/src/stripe/webhook.ts +45 -0
- package/src/test/bun.ts +83 -3
- package/src/util/serde.ts +17 -0
- package/src/vitepress/vitepress.ts +47 -26
- package/lib/docs/document.d.ts +0 -123
- package/lib/docs/document.js +0 -67
- package/lib/docs/index.d.ts +0 -1
- package/lib/docs/index.js +0 -1
- package/src/docs/document.ts +0 -225
- package/src/docs/index.ts +0 -1
package/src/test/bun.ts
CHANGED
|
@@ -6,35 +6,111 @@ import { alchemy } from "../alchemy";
|
|
|
6
6
|
import { destroy } from "../destroy";
|
|
7
7
|
import type { Scope } from "../scope";
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Extend the Alchemy interface to include test functionality
|
|
11
|
+
*/
|
|
9
12
|
declare module "../alchemy" {
|
|
10
13
|
interface Alchemy {
|
|
11
14
|
test: typeof test;
|
|
12
15
|
}
|
|
13
16
|
}
|
|
14
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Add test functionality to alchemy instance
|
|
20
|
+
*/
|
|
15
21
|
alchemy.test = test;
|
|
16
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Options for configuring test behavior
|
|
25
|
+
*/
|
|
17
26
|
export interface TestOptions {
|
|
27
|
+
/**
|
|
28
|
+
* Whether to automatically destroy resources after test.
|
|
29
|
+
* @default true.
|
|
30
|
+
*/
|
|
18
31
|
destroy?: boolean;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Whether to suppress logging output.
|
|
35
|
+
* @default false.
|
|
36
|
+
*/
|
|
19
37
|
quiet?: boolean;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Password to use for test resources.
|
|
41
|
+
* @default "test-password".
|
|
42
|
+
*/
|
|
20
43
|
password?: string;
|
|
21
44
|
}
|
|
22
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Global test scope for all tests
|
|
48
|
+
*/
|
|
23
49
|
const globalTestScope = alchemy.scope("test");
|
|
24
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Test function type definition with overloads
|
|
53
|
+
*/
|
|
25
54
|
type test = {
|
|
55
|
+
/**
|
|
56
|
+
* Create a test with default options
|
|
57
|
+
* @param name Test name
|
|
58
|
+
* @param fn Test function
|
|
59
|
+
* @param timeout Optional timeout in milliseconds
|
|
60
|
+
*/
|
|
26
61
|
(name: string, fn: (scope: Scope) => Promise<any>, timeout?: number): void;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Create a test with custom options
|
|
65
|
+
* @param name Test name
|
|
66
|
+
* @param options Test configuration options
|
|
67
|
+
* @param fn Test function
|
|
68
|
+
* @param timeout Optional timeout in milliseconds
|
|
69
|
+
*/
|
|
27
70
|
(
|
|
28
71
|
name: string,
|
|
29
72
|
options: TestOptions,
|
|
30
73
|
fn: (scope: Scope) => Promise<any>,
|
|
31
74
|
timeout?: number,
|
|
32
75
|
): void;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Skip test conditionally
|
|
79
|
+
* @param condition If true, test will be skipped
|
|
80
|
+
*/
|
|
33
81
|
skipIf(condition: boolean): test;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Current test scope
|
|
85
|
+
*/
|
|
34
86
|
scope: Scope;
|
|
35
87
|
};
|
|
36
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Creates a test helper function that provides scoped resource management
|
|
91
|
+
*
|
|
92
|
+
* @param meta Import meta object from the test file
|
|
93
|
+
* @param defaultOptions Default options to apply to all tests
|
|
94
|
+
* @returns Test function with scope management
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```typescript
|
|
98
|
+
* const test = alchemy.test(import.meta);
|
|
99
|
+
*
|
|
100
|
+
* describe("My Resource", () => {
|
|
101
|
+
* test("create and delete", async (scope) => {
|
|
102
|
+
* try {
|
|
103
|
+
* const resource = await MyResource("test", { ... });
|
|
104
|
+
* expect(resource.id).toBeTruthy();
|
|
105
|
+
* } finally {
|
|
106
|
+
* await alchemy.destroy(scope);
|
|
107
|
+
* }
|
|
108
|
+
* });
|
|
109
|
+
* });
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
37
112
|
export function test(meta: ImportMeta, defaultOptions?: TestOptions): test {
|
|
113
|
+
// Add skipIf functionality
|
|
38
114
|
test.skipIf = (condition: boolean) => {
|
|
39
115
|
if (condition) {
|
|
40
116
|
// TODO: proxy through to bun:test.skipIf
|
|
@@ -43,11 +119,13 @@ export function test(meta: ImportMeta, defaultOptions?: TestOptions): test {
|
|
|
43
119
|
return test;
|
|
44
120
|
};
|
|
45
121
|
|
|
122
|
+
// Create local test scope based on filename
|
|
46
123
|
const localTestScope = alchemy.scope(path.basename(meta.filename), {
|
|
47
124
|
parent: globalTestScope,
|
|
48
125
|
});
|
|
49
126
|
test.scope = localTestScope;
|
|
50
127
|
|
|
128
|
+
// Clean up test scope after all tests complete
|
|
51
129
|
afterAll(() => alchemy.destroy(test.scope));
|
|
52
130
|
|
|
53
131
|
return test as any;
|
|
@@ -71,13 +149,16 @@ export function test(meta: ImportMeta, defaultOptions?: TestOptions): test {
|
|
|
71
149
|
),
|
|
72
150
|
)
|
|
73
151
|
: {};
|
|
152
|
+
|
|
153
|
+
// Merge options with defaults
|
|
74
154
|
const options = {
|
|
75
|
-
destroy:
|
|
155
|
+
destroy: true,
|
|
76
156
|
quiet: false,
|
|
77
157
|
password: "test-password",
|
|
78
158
|
...spread(defaultOptions),
|
|
79
159
|
...spread(_options),
|
|
80
160
|
};
|
|
161
|
+
|
|
81
162
|
const fn = typeof args[1] === "function" ? args[1] : args[2]!;
|
|
82
163
|
|
|
83
164
|
return alchemy.run(
|
|
@@ -88,13 +169,12 @@ export function test(meta: ImportMeta, defaultOptions?: TestOptions): test {
|
|
|
88
169
|
},
|
|
89
170
|
async (scope) => {
|
|
90
171
|
return it(testName, async () => {
|
|
91
|
-
//
|
|
172
|
+
// Enter test scope since bun calls from different scope
|
|
92
173
|
scope.enter();
|
|
93
174
|
try {
|
|
94
175
|
await fn(scope);
|
|
95
176
|
} finally {
|
|
96
177
|
if (options.destroy !== false) {
|
|
97
|
-
// TODO: auto-destroy resources
|
|
98
178
|
await destroy(scope);
|
|
99
179
|
}
|
|
100
180
|
}
|
package/src/util/serde.ts
CHANGED
|
@@ -2,6 +2,17 @@ import { Scope } from "../scope";
|
|
|
2
2
|
import { Secret } from "../secret";
|
|
3
3
|
import { decryptWithKey, encryptWithKey } from "./encrypt";
|
|
4
4
|
|
|
5
|
+
import type { Type } from "arktype";
|
|
6
|
+
|
|
7
|
+
// zero-dependency type guard for ArkType
|
|
8
|
+
function isType(value: any): value is Type<any, any> {
|
|
9
|
+
return (
|
|
10
|
+
value &&
|
|
11
|
+
typeof value === "object" &&
|
|
12
|
+
typeof value.toJsonSchema === "function"
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
5
16
|
export async function serialize(
|
|
6
17
|
scope: Scope,
|
|
7
18
|
value: any,
|
|
@@ -21,6 +32,10 @@ export async function serialize(
|
|
|
21
32
|
? await encryptWithKey(value.unencrypted, scope.password)
|
|
22
33
|
: value.unencrypted,
|
|
23
34
|
};
|
|
35
|
+
} else if (isType(value)) {
|
|
36
|
+
return {
|
|
37
|
+
"@schema": value.toJSON(),
|
|
38
|
+
};
|
|
24
39
|
} else if (value instanceof Scope) {
|
|
25
40
|
return undefined;
|
|
26
41
|
} else if (value && typeof value === "object") {
|
|
@@ -47,6 +62,8 @@ export async function deserialize(scope: Scope, value: any): Promise<any> {
|
|
|
47
62
|
throw new Error("Cannot deserialize secret without password");
|
|
48
63
|
}
|
|
49
64
|
return new Secret(await decryptWithKey(value["@secret"], scope.password));
|
|
65
|
+
} else if ("@schema" in value) {
|
|
66
|
+
return value["@schema"];
|
|
50
67
|
} else {
|
|
51
68
|
return Object.fromEntries(
|
|
52
69
|
await Promise.all(
|
|
@@ -70,6 +70,19 @@ export interface VitePressProjectProps {
|
|
|
70
70
|
* The home page configuration
|
|
71
71
|
*/
|
|
72
72
|
home: HomePage;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Whether to delete the project folder during the delete phase
|
|
76
|
+
* @default true
|
|
77
|
+
*/
|
|
78
|
+
delete?: boolean;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The directory to generate the docs in
|
|
82
|
+
*
|
|
83
|
+
* @default {@link name}
|
|
84
|
+
*/
|
|
85
|
+
dir?: string;
|
|
73
86
|
}
|
|
74
87
|
|
|
75
88
|
export interface VitePressProject extends VitePressProjectProps, Resource {
|
|
@@ -89,11 +102,14 @@ export const VitePressProject = Resource(
|
|
|
89
102
|
id: string,
|
|
90
103
|
props: VitePressProjectProps,
|
|
91
104
|
): Promise<VitePressProject> {
|
|
105
|
+
const dir = props.dir ?? props.name;
|
|
92
106
|
if (this.phase === "delete") {
|
|
93
107
|
try {
|
|
94
|
-
if (
|
|
95
|
-
|
|
96
|
-
|
|
108
|
+
if (props.delete !== false) {
|
|
109
|
+
if (await fs.exists(dir)) {
|
|
110
|
+
// Delete the entire project directory
|
|
111
|
+
await execAsync(`rm -rf ${dir}`);
|
|
112
|
+
}
|
|
97
113
|
}
|
|
98
114
|
} catch (error) {
|
|
99
115
|
console.error(`Error deleting VitePress project ${id}:`, error);
|
|
@@ -101,7 +117,12 @@ export const VitePressProject = Resource(
|
|
|
101
117
|
return this.destroy();
|
|
102
118
|
}
|
|
103
119
|
|
|
104
|
-
const cwd = (
|
|
120
|
+
const cwd = (
|
|
121
|
+
await Folder("dir", {
|
|
122
|
+
path: dir,
|
|
123
|
+
delete: props.delete,
|
|
124
|
+
})
|
|
125
|
+
).path;
|
|
105
126
|
|
|
106
127
|
// Initialize package.json
|
|
107
128
|
await JsonFile(path.join(cwd, "package.json"), {
|
|
@@ -142,28 +163,28 @@ export const VitePressProject = Resource(
|
|
|
142
163
|
path.join(cwd, "index.md"),
|
|
143
164
|
`---\n${yaml.stringify(props.home)}---\n`,
|
|
144
165
|
),
|
|
145
|
-
TypeScriptFile(
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
import { Folder } from "alchemy/fs";
|
|
149
|
-
import { Document } from "alchemy/docs";
|
|
150
|
-
import path from "path";
|
|
151
|
-
|
|
152
|
-
await using _ = alchemy("alchemy.run", {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
const docs = await Folder(path.join("alchemy.run", "docs"));
|
|
160
|
-
|
|
161
|
-
await Document("home.md", {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
});
|
|
165
|
-
`,
|
|
166
|
-
),
|
|
166
|
+
// TypeScriptFile(
|
|
167
|
+
// path.join(cwd, "alchemy.run.ts"),
|
|
168
|
+
// `import alchemy from "alchemy";
|
|
169
|
+
// import { Folder } from "alchemy/fs";
|
|
170
|
+
// import { Document } from "alchemy/docs";
|
|
171
|
+
// import path from "path";
|
|
172
|
+
|
|
173
|
+
// await using _ = alchemy("alchemy.run", {
|
|
174
|
+
// stage: "prod",
|
|
175
|
+
// phase: process.argv.includes("--destroy") ? "destroy" : "up",
|
|
176
|
+
// password: process.env.SECRET_PASSPHRASE,
|
|
177
|
+
// quiet: !process.argv.includes("--verbose"),
|
|
178
|
+
// });
|
|
179
|
+
|
|
180
|
+
// const docs = await Folder(path.join("alchemy.run", "docs"));
|
|
181
|
+
|
|
182
|
+
// await Document("home.md", {
|
|
183
|
+
// path: path.join(docs.path, "home.md"),
|
|
184
|
+
// prompt: await alchemy\`Generate a landing page.\`,
|
|
185
|
+
// });
|
|
186
|
+
// `,
|
|
187
|
+
// ),
|
|
167
188
|
TypeScriptFile(
|
|
168
189
|
path.join(cwd, ".vitepress", "theme", "index.ts"),
|
|
169
190
|
`import TwoslashFloatingVue from "@shikijs/vitepress-twoslash/client";
|
package/lib/docs/document.d.ts
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import type { Context } from "../context";
|
|
2
|
-
import { Resource } from "../resource";
|
|
3
|
-
import type { Secret } from "../secret";
|
|
4
|
-
/**
|
|
5
|
-
* Base properties for a Document
|
|
6
|
-
*/
|
|
7
|
-
interface BaseDocumentProps {
|
|
8
|
-
/**
|
|
9
|
-
* Path to the markdown document
|
|
10
|
-
*/
|
|
11
|
-
path: string;
|
|
12
|
-
/**
|
|
13
|
-
* Base URL for the OpenAI API
|
|
14
|
-
* @default 'https://api.openai.com/v1'
|
|
15
|
-
*/
|
|
16
|
-
baseURL?: string;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Properties for creating a document with static content
|
|
20
|
-
*/
|
|
21
|
-
interface StaticDocumentProps extends BaseDocumentProps {
|
|
22
|
-
/**
|
|
23
|
-
* Static content of the document
|
|
24
|
-
*/
|
|
25
|
-
content: string;
|
|
26
|
-
/**
|
|
27
|
-
* Prompt for generating content
|
|
28
|
-
* @internal This is marked as never to ensure content and prompt are mutually exclusive
|
|
29
|
-
*/
|
|
30
|
-
prompt?: never;
|
|
31
|
-
/**
|
|
32
|
-
* OpenAI API key
|
|
33
|
-
* @internal This is marked as never since it's not needed for static content
|
|
34
|
-
*/
|
|
35
|
-
apiKey?: never;
|
|
36
|
-
/**
|
|
37
|
-
* Model configuration
|
|
38
|
-
* @internal This is marked as never since it's not needed for static content
|
|
39
|
-
*/
|
|
40
|
-
model?: never;
|
|
41
|
-
/**
|
|
42
|
-
* Context files
|
|
43
|
-
* @internal This is marked as never since it's not needed for static content
|
|
44
|
-
*/
|
|
45
|
-
context?: never;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Properties for creating a document with AI-generated content
|
|
49
|
-
*/
|
|
50
|
-
interface GeneratedDocumentProps extends BaseDocumentProps {
|
|
51
|
-
/**
|
|
52
|
-
* Static content of the document
|
|
53
|
-
* @internal This is marked as never to ensure content and prompt are mutually exclusive
|
|
54
|
-
*/
|
|
55
|
-
content?: never;
|
|
56
|
-
/**
|
|
57
|
-
* Prompt for generating content
|
|
58
|
-
* Can be either a single string or an array of strings that will be joined with newlines
|
|
59
|
-
*/
|
|
60
|
-
prompt: string | string[];
|
|
61
|
-
/**
|
|
62
|
-
* Optional context files to include in the prompt
|
|
63
|
-
* Key is the relative path to the file
|
|
64
|
-
* Value can be either the content string or another Document resource
|
|
65
|
-
*/
|
|
66
|
-
context?: {
|
|
67
|
-
[relativePath: string]: string | Document | {
|
|
68
|
-
path: string;
|
|
69
|
-
content: string;
|
|
70
|
-
};
|
|
71
|
-
};
|
|
72
|
-
/**
|
|
73
|
-
* OpenAI API key to use for generating content
|
|
74
|
-
* If not provided, will use OPENAI_API_KEY environment variable
|
|
75
|
-
*/
|
|
76
|
-
apiKey?: Secret;
|
|
77
|
-
/**
|
|
78
|
-
* Model configuration
|
|
79
|
-
*/
|
|
80
|
-
model?: {
|
|
81
|
-
/**
|
|
82
|
-
* Model ID to use
|
|
83
|
-
* @default 'gpt-4o'
|
|
84
|
-
*/
|
|
85
|
-
id?: string;
|
|
86
|
-
/**
|
|
87
|
-
* Model provider name
|
|
88
|
-
* @default 'openai'
|
|
89
|
-
*/
|
|
90
|
-
provider?: string;
|
|
91
|
-
/**
|
|
92
|
-
* Model-specific options
|
|
93
|
-
*/
|
|
94
|
-
options?: Record<string, unknown>;
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Properties for creating or updating a Document
|
|
99
|
-
* Must provide either static content or a prompt for AI generation
|
|
100
|
-
*/
|
|
101
|
-
export type DocumentProps = StaticDocumentProps | GeneratedDocumentProps;
|
|
102
|
-
/**
|
|
103
|
-
* A markdown document that can be created, updated, and deleted
|
|
104
|
-
*/
|
|
105
|
-
export interface Document extends Omit<DocumentProps, "content" | "prompt" | "context">, Resource<"docs::Document"> {
|
|
106
|
-
/**
|
|
107
|
-
* Content of the document
|
|
108
|
-
*/
|
|
109
|
-
content: string;
|
|
110
|
-
/**
|
|
111
|
-
* Time at which the document was created
|
|
112
|
-
*/
|
|
113
|
-
createdAt: number;
|
|
114
|
-
/**
|
|
115
|
-
* Time at which the document was last updated
|
|
116
|
-
*/
|
|
117
|
-
updatedAt: number;
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Resource for managing markdown documents using the Vercel AI SDK
|
|
121
|
-
*/
|
|
122
|
-
export declare const Document: ((this: Context<Document, DocumentProps>, id: string, props: DocumentProps) => Promise<Document>) | (((this: any, id: string, props?: DocumentProps | undefined) => never) & (new (_: never) => never));
|
|
123
|
-
export {};
|
package/lib/docs/document.js
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
|
|
2
|
-
import { generateText } from "ai";
|
|
3
|
-
import fs from "node:fs/promises";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import { Resource } from "../resource";
|
|
6
|
-
/**
|
|
7
|
-
* Resource for managing markdown documents using the Vercel AI SDK
|
|
8
|
-
*/
|
|
9
|
-
export const Document = Resource("docs::Document", async function (id, props) {
|
|
10
|
-
// Ensure directory exists
|
|
11
|
-
await fs.mkdir(path.dirname(props.path), { recursive: true });
|
|
12
|
-
if (this.phase === "delete") {
|
|
13
|
-
try {
|
|
14
|
-
await fs.unlink(props.path);
|
|
15
|
-
}
|
|
16
|
-
catch (error) {
|
|
17
|
-
// Ignore if file doesn't exist
|
|
18
|
-
if (error.code !== "ENOENT") {
|
|
19
|
-
throw error;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
return this.destroy();
|
|
23
|
-
}
|
|
24
|
-
let content;
|
|
25
|
-
console.log("Generating content for", props.path);
|
|
26
|
-
// Generate content if prompt is provided
|
|
27
|
-
if ("prompt" in props) {
|
|
28
|
-
// Get API key from props or environment
|
|
29
|
-
const apiKey = props.apiKey?.unencrypted || process.env.OPENAI_API_KEY;
|
|
30
|
-
if (!apiKey) {
|
|
31
|
-
throw new Error("OpenAI API key is required for content generation");
|
|
32
|
-
}
|
|
33
|
-
// Initialize OpenAI compatible provider
|
|
34
|
-
const provider = createOpenAICompatible({
|
|
35
|
-
name: props.model?.provider || "openai",
|
|
36
|
-
apiKey,
|
|
37
|
-
baseURL: props.baseURL || "https://api.openai.com/v1",
|
|
38
|
-
});
|
|
39
|
-
// Build the full prompt with context if provided
|
|
40
|
-
const fullPrompt = Array.isArray(props.prompt)
|
|
41
|
-
? props.prompt.join("\n")
|
|
42
|
-
: props.prompt;
|
|
43
|
-
// console.log(fullPrompt);
|
|
44
|
-
const { text } = await generateText({
|
|
45
|
-
model: provider(props.model?.id || "gpt-4o"),
|
|
46
|
-
prompt: fullPrompt,
|
|
47
|
-
...(props.model?.options || {}),
|
|
48
|
-
});
|
|
49
|
-
content = text;
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
// Use static content
|
|
53
|
-
content = props.content;
|
|
54
|
-
}
|
|
55
|
-
// Write content to file
|
|
56
|
-
await fs.writeFile(props.path, content);
|
|
57
|
-
// Get file stats for timestamps
|
|
58
|
-
const stats = await fs.stat(props.path);
|
|
59
|
-
// Return the resource
|
|
60
|
-
return this({
|
|
61
|
-
path: props.path,
|
|
62
|
-
baseURL: props.baseURL,
|
|
63
|
-
content,
|
|
64
|
-
createdAt: stats.birthtimeMs,
|
|
65
|
-
updatedAt: stats.mtimeMs,
|
|
66
|
-
});
|
|
67
|
-
});
|
package/lib/docs/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./document";
|
package/lib/docs/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./document";
|