alchemy 0.85.0 → 0.85.1
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/bin/alchemy.js +32 -23
- package/lib/cloudflare/account-api-token.d.ts +5 -0
- package/lib/cloudflare/account-api-token.d.ts.map +1 -1
- package/lib/cloudflare/account-api-token.js +13 -2
- package/lib/cloudflare/account-api-token.js.map +1 -1
- package/lib/cloudflare/ai-crawler.d.ts +27 -0
- package/lib/cloudflare/ai-crawler.d.ts.map +1 -0
- package/lib/cloudflare/ai-crawler.js +75 -0
- package/lib/cloudflare/ai-crawler.js.map +1 -0
- package/lib/cloudflare/ai-search-token.d.ts +150 -0
- package/lib/cloudflare/ai-search-token.d.ts.map +1 -0
- package/lib/cloudflare/ai-search-token.js +171 -0
- package/lib/cloudflare/ai-search-token.js.map +1 -0
- package/lib/cloudflare/ai-search.d.ts +397 -0
- package/lib/cloudflare/ai-search.d.ts.map +1 -0
- package/lib/cloudflare/ai-search.js +307 -0
- package/lib/cloudflare/ai-search.js.map +1 -0
- package/lib/cloudflare/auth.d.ts +3 -2
- package/lib/cloudflare/auth.d.ts.map +1 -1
- package/lib/cloudflare/auth.js +17 -14
- package/lib/cloudflare/auth.js.map +1 -1
- package/lib/cloudflare/bucket-custom-domain.d.ts.map +1 -1
- package/lib/cloudflare/bucket-custom-domain.js +4 -2
- package/lib/cloudflare/bucket-custom-domain.js.map +1 -1
- package/lib/cloudflare/bucket.d.ts.map +1 -1
- package/lib/cloudflare/bucket.js +8 -2
- package/lib/cloudflare/bucket.js.map +1 -1
- package/lib/cloudflare/index.d.ts +3 -0
- package/lib/cloudflare/index.d.ts.map +1 -1
- package/lib/cloudflare/index.js +3 -0
- package/lib/cloudflare/index.js.map +1 -1
- package/lib/cloudflare/permission-groups.d.ts +5 -0
- package/lib/cloudflare/permission-groups.d.ts.map +1 -1
- package/lib/cloudflare/permission-groups.js +6 -0
- package/lib/cloudflare/permission-groups.js.map +1 -1
- package/lib/scope.d.ts +1 -1
- package/lib/scope.d.ts.map +1 -1
- package/lib/scope.js +10 -5
- package/lib/scope.js.map +1 -1
- package/lib/test/bun.d.ts +17 -0
- package/lib/test/bun.d.ts.map +1 -1
- package/lib/test/bun.js +1 -0
- package/lib/test/bun.js.map +1 -1
- package/lib/test/vitest.d.ts +17 -0
- package/lib/test/vitest.d.ts.map +1 -1
- package/lib/test/vitest.js +3 -0
- package/lib/test/vitest.js.map +1 -1
- package/lib/util/snake-to-camel.d.ts +21 -0
- package/lib/util/snake-to-camel.d.ts.map +1 -0
- package/lib/util/snake-to-camel.js +34 -0
- package/lib/util/snake-to-camel.js.map +1 -0
- package/package.json +1 -1
- package/src/cloudflare/account-api-token.ts +23 -6
- package/src/cloudflare/ai-crawler.ts +89 -0
- package/src/cloudflare/ai-search-token.ts +324 -0
- package/src/cloudflare/ai-search.ts +952 -0
- package/src/cloudflare/auth.ts +17 -14
- package/src/cloudflare/bucket-custom-domain.ts +4 -1
- package/src/cloudflare/bucket.ts +9 -2
- package/src/cloudflare/index.ts +3 -0
- package/src/cloudflare/permission-groups.ts +6 -0
- package/src/scope.ts +14 -5
- package/src/test/bun.ts +25 -0
- package/src/test/vitest.ts +33 -0
- package/src/util/snake-to-camel.ts +59 -0
- package/workers/tunnel-proxy.js +1 -1
package/lib/test/vitest.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vitest.d.ts","sourceRoot":"","sources":["../../src/test/vitest.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAOpC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD;;GAEG;AACH,OAAO,QAAQ,eAAe,CAAC;IAC7B,UAAU,OAAO;QACf,IAAI,EAAE,OAAO,IAAI,CAAC;KACnB;CACF;AAOD;;GAEG;AACH,KAAK,IAAI,GAAG;IACV;;;;;OAKG;IACH,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE3E;;;;;;OAMG;IACH,CACE,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,WAAW,EACpB,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,GAAG,CAAC,EAClC,OAAO,CAAC,EAAE,MAAM,GACf,IAAI,CAAC;IAER;;;OAGG;IACH,MAAM,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"vitest.d.ts","sourceRoot":"","sources":["../../src/test/vitest.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAOpC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD;;GAEG;AACH,OAAO,QAAQ,eAAe,CAAC;IAC7B,UAAU,OAAO;QACf,IAAI,EAAE,OAAO,IAAI,CAAC;KACnB;CACF;AAOD;;GAEG;AACH,KAAK,IAAI,GAAG;IACV;;;;;OAKG;IACH,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE3E;;;;;;OAMG;IACH,CACE,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,WAAW,EACpB,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,GAAG,CAAC,EAClC,OAAO,CAAC,EAAE,MAAM,GACf,IAAI,CAAC;IAER;;;OAGG;IACH,MAAM,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IACjC,IAAI,EAAE;QACJ;;;;;WAKG;QACH,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAE3E;;;;;;WAMG;QACH,CACE,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,WAAW,EACpB,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,GAAG,CAAC,EAClC,OAAO,CAAC,EAAE,MAAM,GACf,IAAI,CAAC;KACT,CAAC;IAEF,SAAS,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEvE,QAAQ,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEtE;;OAEG;IACH,KAAK,EAAE,KAAK,CAAC;CACd,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,IAAI,CAClB,IAAI,EAAE,UAAU,EAChB,cAAc,GAAE,WAEf,GACA,IAAI,CAuHN"}
|
package/lib/test/vitest.js
CHANGED
|
@@ -59,6 +59,9 @@ export function test(meta, defaultOptions = {
|
|
|
59
59
|
}
|
|
60
60
|
return test;
|
|
61
61
|
};
|
|
62
|
+
test.skip = (...args
|
|
63
|
+
// @ts-expect-error
|
|
64
|
+
) => it.skip(...args);
|
|
62
65
|
const scope = new Scope({
|
|
63
66
|
parent: undefined,
|
|
64
67
|
scopeName: `${defaultOptions.prefix ? `${defaultOptions.prefix}-` : ""}${path.basename(meta.filename)}`,
|
package/lib/test/vitest.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vitest.js","sourceRoot":"","sources":["../../src/test/vitest.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,OAAO,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EACL,oBAAoB,EACpB,YAAY,EACZ,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAY3B;;GAEG;AACH,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"vitest.js","sourceRoot":"","sources":["../../src/test/vitest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert a snake_case string to camelCase.
|
|
3
|
+
* @example "account_id" -> "accountId", "created_at" -> "createdAt"
|
|
4
|
+
*/
|
|
5
|
+
export declare function snakeToCamelString(s: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Recursively convert an object's keys from snake_case to camelCase.
|
|
8
|
+
* Arrays and nested objects are traversed; primitives, Date, and RegExp are returned as-is.
|
|
9
|
+
*/
|
|
10
|
+
export declare function snakeToCamelObjectDeep<T>(obj: T): SnakeToCamel<T>;
|
|
11
|
+
/**
|
|
12
|
+
* Convert a snake_case string to camelCase at the type level.
|
|
13
|
+
*/
|
|
14
|
+
export type SnakeToCamelString<S extends string> = S extends `${infer A}_${infer B}` ? `${A}${Capitalize<SnakeToCamelString<B>>}` : S;
|
|
15
|
+
/**
|
|
16
|
+
* Recursively convert an object type's keys from snake_case to camelCase.
|
|
17
|
+
*/
|
|
18
|
+
export type SnakeToCamel<T> = T extends object ? T extends Array<infer U> ? Array<SnakeToCamel<U>> : T extends Date | RegExp | Function ? T : {
|
|
19
|
+
[K in keyof T as K extends string ? SnakeToCamelString<K> : K]: SnakeToCamel<T[K]>;
|
|
20
|
+
} : T;
|
|
21
|
+
//# sourceMappingURL=snake-to-camel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snake-to-camel.d.ts","sourceRoot":"","sources":["../../src/util/snake-to-camel.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAuBjE;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,MAAM,IAC7C,CAAC,SAAS,GAAG,MAAM,CAAC,IAAI,MAAM,CAAC,EAAE,GAC7B,GAAG,CAAC,GAAG,UAAU,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,EAAE,GAC1C,CAAC,CAAC;AAER;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,GAC1C,CAAC,SAAS,KAAK,CAAC,MAAM,CAAC,CAAC,GACtB,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GACtB,CAAC,SAAS,IAAI,GAAG,MAAM,GAAG,QAAQ,GAChC,CAAC,GACD;KACG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,MAAM,GAC7B,kBAAkB,CAAC,CAAC,CAAC,GACrB,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC3B,GACL,CAAC,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert a snake_case string to camelCase.
|
|
3
|
+
* @example "account_id" -> "accountId", "created_at" -> "createdAt"
|
|
4
|
+
*/
|
|
5
|
+
export function snakeToCamelString(s) {
|
|
6
|
+
return s.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Recursively convert an object's keys from snake_case to camelCase.
|
|
10
|
+
* Arrays and nested objects are traversed; primitives, Date, and RegExp are returned as-is.
|
|
11
|
+
*/
|
|
12
|
+
export function snakeToCamelObjectDeep(obj) {
|
|
13
|
+
if (obj === undefined || obj === null) {
|
|
14
|
+
return obj;
|
|
15
|
+
}
|
|
16
|
+
if (typeof obj !== "object") {
|
|
17
|
+
return obj;
|
|
18
|
+
}
|
|
19
|
+
if (obj instanceof RegExp || obj instanceof Date) {
|
|
20
|
+
return obj;
|
|
21
|
+
}
|
|
22
|
+
if (Array.isArray(obj)) {
|
|
23
|
+
return obj.map(snakeToCamelObjectDeep);
|
|
24
|
+
}
|
|
25
|
+
return Object.fromEntries(Object.entries(obj).map(([key, value]) => [
|
|
26
|
+
snakeToCamelString(key),
|
|
27
|
+
typeof value === "object" && value !== null && !Array.isArray(value)
|
|
28
|
+
? snakeToCamelObjectDeep(value)
|
|
29
|
+
: Array.isArray(value)
|
|
30
|
+
? value.map(snakeToCamelObjectDeep)
|
|
31
|
+
: value,
|
|
32
|
+
]));
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=snake-to-camel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snake-to-camel.js","sourceRoot":"","sources":["../../src/util/snake-to-camel.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,CAAS;IAC1C,OAAO,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAC3D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAI,GAAM;IAC9C,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACtC,OAAO,GAAsB,CAAC;IAChC,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,GAAsB,CAAC;IAChC,CAAC;IACD,IAAI,GAAG,YAAY,MAAM,IAAI,GAAG,YAAY,IAAI,EAAE,CAAC;QACjD,OAAO,GAAsB,CAAC;IAChC,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC,GAAG,CAAC,sBAAsB,CAAoB,CAAC;IAC5D,CAAC;IACD,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC;QACxC,kBAAkB,CAAC,GAAG,CAAC;QACvB,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAClE,CAAC,CAAC,sBAAsB,CAAC,KAAK,CAAC;YAC/B,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;gBACpB,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,sBAAsB,CAAC;gBACnC,CAAC,CAAC,KAAK;KACZ,CAAC,CACgB,CAAC;AACvB,CAAC"}
|
package/package.json
CHANGED
|
@@ -109,6 +109,12 @@ export interface AccountApiTokenProps extends CloudflareApiOptions {
|
|
|
109
109
|
* Optional conditions for token use (like IP restrictions)
|
|
110
110
|
*/
|
|
111
111
|
condition?: TokenCondition;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Whether to delete the token when removed from Alchemy
|
|
115
|
+
* @default true
|
|
116
|
+
*/
|
|
117
|
+
delete?: boolean;
|
|
112
118
|
}
|
|
113
119
|
|
|
114
120
|
/**
|
|
@@ -261,7 +267,7 @@ export const AccountApiToken = Resource(
|
|
|
261
267
|
|
|
262
268
|
if (this.phase === "delete") {
|
|
263
269
|
// Delete token if we have an ID
|
|
264
|
-
if (this.output?.id) {
|
|
270
|
+
if (this.output?.id && props.delete !== false) {
|
|
265
271
|
try {
|
|
266
272
|
const deleteResponse = await api.delete(
|
|
267
273
|
`/accounts/${api.accountId}/tokens/${this.output.id}`,
|
|
@@ -360,11 +366,22 @@ export const AccountApiToken = Resource(
|
|
|
360
366
|
}));
|
|
361
367
|
|
|
362
368
|
throw new Error(
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
369
|
+
[
|
|
370
|
+
`Error ${
|
|
371
|
+
this.phase === "update" ? "updating" : "creating"
|
|
372
|
+
} token '${tokenName}' (${response.status}): ${
|
|
373
|
+
errorData.errors?.[0]?.message || response.statusText
|
|
374
|
+
}`,
|
|
375
|
+
...(api.credentials.type !== "api-key"
|
|
376
|
+
? [
|
|
377
|
+
`\nTo create an Account API Token, you must use a Global API Key or an API Token with the "Account API Tokens Write" permission.`,
|
|
378
|
+
]
|
|
379
|
+
: []),
|
|
380
|
+
...(api.credentials.type === "oauth"
|
|
381
|
+
? ["OAuth credentials are not supported."]
|
|
382
|
+
: []),
|
|
383
|
+
"See https://alchemy.run/guides/cloudflare/ for more details.",
|
|
384
|
+
].join("\n"),
|
|
368
385
|
);
|
|
369
386
|
}
|
|
370
387
|
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { AiSearchWebCrawlerSource } from "./ai-search.ts";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Parse a URL and extract the domain and path
|
|
5
|
+
*/
|
|
6
|
+
function parseUrl(url: string): { domain: string; path: string } {
|
|
7
|
+
// Handle URLs with or without protocol
|
|
8
|
+
let normalized = url;
|
|
9
|
+
if (!normalized.includes("://")) {
|
|
10
|
+
normalized = `https://${normalized}`;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const parsed = new URL(normalized);
|
|
14
|
+
return {
|
|
15
|
+
domain: parsed.hostname,
|
|
16
|
+
path: parsed.pathname,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Convert a path to a glob pattern for path filtering
|
|
22
|
+
*/
|
|
23
|
+
function pathToGlobPattern(path: string): string {
|
|
24
|
+
// Remove leading slash for pattern
|
|
25
|
+
const cleanPath = path.replace(/^\//, "");
|
|
26
|
+
|
|
27
|
+
if (!cleanPath || cleanPath === "/") {
|
|
28
|
+
// Root path - no filtering needed
|
|
29
|
+
return "**";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Create a pattern that matches this path and its children
|
|
33
|
+
return `**/${cleanPath}**`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Builds an AiSearchWebCrawlerSource configuration from URLs.
|
|
38
|
+
*
|
|
39
|
+
* This is a convenience helper that parses URLs and extracts the domain
|
|
40
|
+
* and path filters for use with AiSearch.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* // Crawl an entire domain
|
|
44
|
+
* const search = await AiSearch("docs-search", {
|
|
45
|
+
* source: AiCrawler(["https://docs.example.com"]),
|
|
46
|
+
* });
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* // Crawl specific paths on a domain
|
|
50
|
+
* const search = await AiSearch("blog-search", {
|
|
51
|
+
* source: AiCrawler([
|
|
52
|
+
* "https://example.com/blog",
|
|
53
|
+
* "https://example.com/news",
|
|
54
|
+
* ]),
|
|
55
|
+
* });
|
|
56
|
+
*
|
|
57
|
+
* @param urls - URLs to crawl. All URLs must be from the same domain.
|
|
58
|
+
* @returns An AiSearchWebCrawlerSource configuration object
|
|
59
|
+
*/
|
|
60
|
+
export function AiCrawler(urls: string[]): AiSearchWebCrawlerSource {
|
|
61
|
+
if (!urls || urls.length === 0) {
|
|
62
|
+
throw new Error("AiCrawler requires at least one URL");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Parse all URLs
|
|
66
|
+
const parsed = urls.map(parseUrl);
|
|
67
|
+
|
|
68
|
+
// Verify all URLs are from the same domain
|
|
69
|
+
const domains = new Set(parsed.map((p) => p.domain));
|
|
70
|
+
if (domains.size > 1) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`All URLs must be from the same domain. Found: ${[...domains].join(", ")}`,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const domain = parsed[0].domain;
|
|
77
|
+
|
|
78
|
+
// Build include paths from URL paths
|
|
79
|
+
// Only add path filters if we have specific paths (not just root)
|
|
80
|
+
const paths = parsed.map((p) => p.path).filter((p) => p && p !== "/");
|
|
81
|
+
const includePaths =
|
|
82
|
+
paths.length > 0 ? paths.map(pathToGlobPattern) : undefined;
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
type: "web-crawler",
|
|
86
|
+
domain,
|
|
87
|
+
includePaths,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { alchemy } from "../alchemy.ts";
|
|
2
|
+
import type { Context } from "../context.ts";
|
|
3
|
+
import { Resource, ResourceKind } from "../resource.ts";
|
|
4
|
+
import type { Secret } from "../secret.ts";
|
|
5
|
+
import { AccountApiToken } from "./account-api-token.ts";
|
|
6
|
+
import { CloudflareApiError } from "./api-error.ts";
|
|
7
|
+
import { extractCloudflareResult } from "./api-response.ts";
|
|
8
|
+
import {
|
|
9
|
+
CloudflareApi,
|
|
10
|
+
createCloudflareApi,
|
|
11
|
+
type CloudflareApiOptions,
|
|
12
|
+
} from "./api.ts";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Properties for creating an AI Search Token
|
|
16
|
+
*/
|
|
17
|
+
export interface AiSearchTokenProps extends CloudflareApiOptions {
|
|
18
|
+
/**
|
|
19
|
+
* Name of the token
|
|
20
|
+
* @default Uses the resource ID
|
|
21
|
+
*/
|
|
22
|
+
name?: string;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Whether to adopt an existing token if one with the same name exists
|
|
26
|
+
* @default false
|
|
27
|
+
*/
|
|
28
|
+
adopt?: boolean;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Whether to delete the token when removed from Alchemy
|
|
32
|
+
* @default true
|
|
33
|
+
*/
|
|
34
|
+
delete?: boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* AI Search Token output
|
|
39
|
+
*/
|
|
40
|
+
export type AiSearchToken = {
|
|
41
|
+
/**
|
|
42
|
+
* Resource type identifier for binding
|
|
43
|
+
* @internal
|
|
44
|
+
*/
|
|
45
|
+
type: "ai_search_token";
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The AI Search token ID (UUID)
|
|
49
|
+
*/
|
|
50
|
+
tokenId: string;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The underlying account API token ID (for lifecycle management)
|
|
54
|
+
*/
|
|
55
|
+
accountTokenId: string;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The account ID
|
|
59
|
+
*/
|
|
60
|
+
accountId: string;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The account tag
|
|
64
|
+
*/
|
|
65
|
+
accountTag: string;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Name of the token
|
|
69
|
+
*/
|
|
70
|
+
name: string;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The CF API ID for this token
|
|
74
|
+
*/
|
|
75
|
+
cfApiId: string;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The CF API key for this token (stored as Secret)
|
|
79
|
+
*/
|
|
80
|
+
cfApiKey: Secret;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Whether the token is enabled
|
|
84
|
+
*/
|
|
85
|
+
enabled: boolean;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* When the token was created
|
|
89
|
+
*/
|
|
90
|
+
createdAt: string;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* When the token was last modified
|
|
94
|
+
*/
|
|
95
|
+
modifiedAt: string;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* API response for AI Search token
|
|
100
|
+
* @internal
|
|
101
|
+
*/
|
|
102
|
+
interface AiSearchTokenApiResponse {
|
|
103
|
+
id: string;
|
|
104
|
+
account_id: string;
|
|
105
|
+
account_tag: string;
|
|
106
|
+
name: string;
|
|
107
|
+
cf_api_id: string;
|
|
108
|
+
cf_api_key: string;
|
|
109
|
+
enabled: boolean;
|
|
110
|
+
legacy: boolean;
|
|
111
|
+
created_at: string;
|
|
112
|
+
modified_at: string;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Type guard for AiSearchToken
|
|
117
|
+
*/
|
|
118
|
+
export function isAiSearchToken(resource: unknown): resource is AiSearchToken {
|
|
119
|
+
return (
|
|
120
|
+
typeof resource === "object" &&
|
|
121
|
+
resource !== null &&
|
|
122
|
+
((resource as any)[ResourceKind] === "cloudflare::AiSearchToken" ||
|
|
123
|
+
(resource as any).type === "ai_search_token")
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Creates an AI Search token for accessing AI Search instances.
|
|
129
|
+
*
|
|
130
|
+
* AI Search tokens are used to authenticate with the AI Search API and provide
|
|
131
|
+
* access to R2 buckets or other data sources for indexing.
|
|
132
|
+
*
|
|
133
|
+
* This resource automatically:
|
|
134
|
+
* 1. Creates an account API token with AI Search Index Engine and R2 Storage Write permissions
|
|
135
|
+
* 2. Registers that token with the AI Search service
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* // Create an AI Search token
|
|
139
|
+
* const token = await AiSearchToken("my-token", {
|
|
140
|
+
* name: "docs-search-token",
|
|
141
|
+
* });
|
|
142
|
+
*
|
|
143
|
+
* // Use the token with an AI Search instance
|
|
144
|
+
* const search = await AiSearch("docs-search", {
|
|
145
|
+
* source: {
|
|
146
|
+
* type: "r2",
|
|
147
|
+
* bucket: myBucket,
|
|
148
|
+
* token: token,
|
|
149
|
+
* },
|
|
150
|
+
* });
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* // Let AiSearch auto-create a token (recommended)
|
|
154
|
+
* const search = await AiSearch("docs-search", {
|
|
155
|
+
* source: {
|
|
156
|
+
* type: "r2",
|
|
157
|
+
* bucket: myBucket,
|
|
158
|
+
* },
|
|
159
|
+
* });
|
|
160
|
+
*/
|
|
161
|
+
export const AiSearchToken = Resource(
|
|
162
|
+
"cloudflare::AiSearchToken",
|
|
163
|
+
async function (
|
|
164
|
+
this: Context<AiSearchToken>,
|
|
165
|
+
id: string,
|
|
166
|
+
props: AiSearchTokenProps,
|
|
167
|
+
): Promise<AiSearchToken> {
|
|
168
|
+
const api = await createCloudflareApi(props);
|
|
169
|
+
const tokenName = props.name ?? this.scope.createPhysicalName(id);
|
|
170
|
+
|
|
171
|
+
if (this.phase === "delete") {
|
|
172
|
+
if (this.output?.tokenId && props.delete !== false) {
|
|
173
|
+
await deleteAiSearchToken(api, this.output.tokenId);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// The AccountApiToken will be cleaned up automatically by Alchemy's
|
|
177
|
+
// resource lifecycle management since it's a child resource
|
|
178
|
+
|
|
179
|
+
return this.destroy();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// For update, we can't really update tokens - just return existing
|
|
183
|
+
if (this.phase === "update" && this.output?.tokenId) {
|
|
184
|
+
return this.output;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Create an account API token with AI Search + R2 permissions
|
|
188
|
+
const accountToken = await AccountApiToken("account-token", {
|
|
189
|
+
name: `${tokenName} (AI Search Service Token)`,
|
|
190
|
+
policies: [
|
|
191
|
+
{
|
|
192
|
+
effect: "allow",
|
|
193
|
+
permissionGroups: [
|
|
194
|
+
"AI Search Index Engine",
|
|
195
|
+
"Workers R2 Storage Write",
|
|
196
|
+
],
|
|
197
|
+
resources: {
|
|
198
|
+
"com.cloudflare.api.account": "*",
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
],
|
|
202
|
+
baseUrl: props.baseUrl,
|
|
203
|
+
profile: props.profile,
|
|
204
|
+
apiKey: props.apiKey,
|
|
205
|
+
apiToken: props.apiToken,
|
|
206
|
+
accountId: props.accountId,
|
|
207
|
+
email: props.email,
|
|
208
|
+
delete: props.delete,
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
if (!accountToken.value) {
|
|
212
|
+
throw new Error(
|
|
213
|
+
"Failed to create account API token for AI Search - no token value returned",
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const cfApiId = accountToken.id;
|
|
218
|
+
const cfApiKey = accountToken.value.unencrypted;
|
|
219
|
+
|
|
220
|
+
// Register the token with AI Search
|
|
221
|
+
try {
|
|
222
|
+
const result = await createAiSearchToken(api, {
|
|
223
|
+
name: tokenName,
|
|
224
|
+
cf_api_id: cfApiId,
|
|
225
|
+
cf_api_key: cfApiKey,
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
return {
|
|
229
|
+
type: "ai_search_token" as const,
|
|
230
|
+
tokenId: result.id,
|
|
231
|
+
accountTokenId: accountToken.id,
|
|
232
|
+
accountId: result.account_id,
|
|
233
|
+
accountTag: result.account_tag,
|
|
234
|
+
name: result.name,
|
|
235
|
+
cfApiId: result.cf_api_id,
|
|
236
|
+
cfApiKey: alchemy.secret(cfApiKey),
|
|
237
|
+
enabled: result.enabled,
|
|
238
|
+
createdAt: result.created_at,
|
|
239
|
+
modifiedAt: result.modified_at,
|
|
240
|
+
};
|
|
241
|
+
} catch (error) {
|
|
242
|
+
// Check if token already exists and we should adopt it
|
|
243
|
+
if (error instanceof CloudflareApiError && props.adopt) {
|
|
244
|
+
// List tokens and find by name
|
|
245
|
+
const tokens = await listAiSearchTokens(api);
|
|
246
|
+
const existing = tokens.find((t) => t.name === tokenName);
|
|
247
|
+
if (existing) {
|
|
248
|
+
return {
|
|
249
|
+
type: "ai_search_token" as const,
|
|
250
|
+
tokenId: existing.id,
|
|
251
|
+
accountTokenId: accountToken.id,
|
|
252
|
+
accountId: existing.account_id,
|
|
253
|
+
accountTag: existing.account_tag,
|
|
254
|
+
name: existing.name,
|
|
255
|
+
cfApiId: existing.cf_api_id,
|
|
256
|
+
cfApiKey: alchemy.secret(cfApiKey),
|
|
257
|
+
enabled: existing.enabled,
|
|
258
|
+
createdAt: existing.created_at,
|
|
259
|
+
modifiedAt: existing.modified_at,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
throw error;
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Create an AI Search token
|
|
270
|
+
*/
|
|
271
|
+
export async function createAiSearchToken(
|
|
272
|
+
api: CloudflareApi,
|
|
273
|
+
payload: { name: string; cf_api_id: string; cf_api_key: string },
|
|
274
|
+
): Promise<AiSearchTokenApiResponse> {
|
|
275
|
+
return await extractCloudflareResult<AiSearchTokenApiResponse>(
|
|
276
|
+
`create AI Search token "${payload.name}"`,
|
|
277
|
+
api.post(`/accounts/${api.accountId}/ai-search/tokens`, payload),
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* List all AI Search tokens in an account
|
|
283
|
+
*/
|
|
284
|
+
export async function listAiSearchTokens(
|
|
285
|
+
api: CloudflareApi,
|
|
286
|
+
): Promise<AiSearchTokenApiResponse[]> {
|
|
287
|
+
return await extractCloudflareResult<AiSearchTokenApiResponse[]>(
|
|
288
|
+
`list AI Search tokens`,
|
|
289
|
+
api.get(`/accounts/${api.accountId}/ai-search/tokens`),
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Delete an AI Search token
|
|
295
|
+
*/
|
|
296
|
+
export async function deleteAiSearchToken(
|
|
297
|
+
api: CloudflareApi,
|
|
298
|
+
tokenId: string,
|
|
299
|
+
): Promise<void> {
|
|
300
|
+
try {
|
|
301
|
+
await extractCloudflareResult(
|
|
302
|
+
`delete AI Search token "${tokenId}"`,
|
|
303
|
+
api.delete(`/accounts/${api.accountId}/ai-search/tokens/${tokenId}`),
|
|
304
|
+
);
|
|
305
|
+
} catch (error) {
|
|
306
|
+
if (error instanceof CloudflareApiError && error.status === 404) {
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
throw error;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Get an AI Search token
|
|
315
|
+
*/
|
|
316
|
+
export async function getAiSearchToken(
|
|
317
|
+
api: CloudflareApi,
|
|
318
|
+
tokenId: string,
|
|
319
|
+
): Promise<AiSearchTokenApiResponse> {
|
|
320
|
+
return await extractCloudflareResult<AiSearchTokenApiResponse>(
|
|
321
|
+
`get AI Search token "${tokenId}"`,
|
|
322
|
+
api.get(`/accounts/${api.accountId}/ai-search/tokens/${tokenId}`),
|
|
323
|
+
);
|
|
324
|
+
}
|