@dbx-tools/appkit 0.9.118 → 0.9.120
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/README.md +27 -21
- package/index.ts +6 -1
- package/lib/index.d.ts +6 -1
- package/lib/index.js +5 -2
- package/lib/src/appkit.js +17 -20
- package/lib/src/{_cache-storage.d.ts → cache-storage.d.ts} +28 -16
- package/lib/src/cache-storage.js +276 -0
- package/lib/src/files-cache.d.ts +2 -4
- package/lib/src/files-cache.js +39 -38
- package/lib/src/identity.d.ts +12 -0
- package/lib/src/identity.js +69 -3
- package/lib/src/interceptor.js +6 -3
- package/lib/src/lakebase-resolver.d.ts +14 -0
- package/lib/src/lakebase-resolver.js +22 -3
- package/lib/src/migration.js +6 -7
- package/lib/src/plugin-execution.js +3 -3
- package/lib/src/provision.js +2 -2
- package/lib/src/tool-operations.d.ts +33 -0
- package/lib/src/tool-operations.js +43 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +25 -9
- package/src/appkit.ts +16 -21
- package/src/{_cache-storage.ts → cache-storage.ts} +138 -71
- package/src/files-cache.ts +38 -44
- package/src/identity.ts +67 -2
- package/src/interceptor.ts +5 -2
- package/src/lakebase-resolver.ts +23 -1
- package/src/migration.ts +3 -5
- package/src/plugin-execution.ts +2 -2
- package/src/provision.ts +1 -1
- package/src/tool-operations.ts +80 -0
- package/lib/src/_cache-storage.js +0 -235
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** Zod-owned operation contracts converted into native AppKit agent tools. */
|
|
2
|
+
import { defineTool } from "@databricks/appkit/beta";
|
|
3
|
+
/** Preserve operation inference while declaring an exported operation map. */
|
|
4
|
+
export function defineOperations(operations) {
|
|
5
|
+
return operations;
|
|
6
|
+
}
|
|
7
|
+
/** Convert exported Zod operation contracts into a native AppKit tool registry. */
|
|
8
|
+
export function toolRegistryFromOperations(operations) {
|
|
9
|
+
return Object.fromEntries(Object.entries(operations).flatMap(([name, operation]) => {
|
|
10
|
+
const metadata = operation.schema.meta();
|
|
11
|
+
const tool = metadata?.appkitTool ?? {};
|
|
12
|
+
if (tool.agentTool !== true)
|
|
13
|
+
return [];
|
|
14
|
+
const effect = tool.effect ?? "write";
|
|
15
|
+
const approval = tool.approval === true || effect === "destructive";
|
|
16
|
+
const description = operation.schema.description?.trim();
|
|
17
|
+
if (!description) {
|
|
18
|
+
throw new TypeError(`AppKit operation ${name} requires a Zod schema description`);
|
|
19
|
+
}
|
|
20
|
+
return [
|
|
21
|
+
[
|
|
22
|
+
name,
|
|
23
|
+
defineTool({
|
|
24
|
+
description,
|
|
25
|
+
schema: operation.schema,
|
|
26
|
+
annotations: {
|
|
27
|
+
effect,
|
|
28
|
+
...(approval ? { destructive: true } : {}),
|
|
29
|
+
...(tool.requiresUserContext === undefined
|
|
30
|
+
? {}
|
|
31
|
+
: { requiresUserContext: tool.requiresUserContext }),
|
|
32
|
+
...(tool.idempotent === undefined ? {} : { idempotent: tool.idempotent }),
|
|
33
|
+
},
|
|
34
|
+
...(tool.autoInheritable === undefined
|
|
35
|
+
? {}
|
|
36
|
+
: { autoInheritable: tool.autoInheritable }),
|
|
37
|
+
execute: (input, signal) => operation.execute(operation.schema.parse(input), signal),
|
|
38
|
+
}),
|
|
39
|
+
],
|
|
40
|
+
];
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9vbC1vcGVyYXRpb25zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Rvb2wtb3BlcmF0aW9ucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSw4RUFBOEU7QUFFOUUsT0FBTyxFQUFFLFVBQVUsRUFBcUIsTUFBTSx5QkFBeUIsQ0FBQztBQThCeEUsOEVBQThFO0FBQzlFLE1BQU0sVUFBVSxnQkFBZ0IsQ0FFOUIsVUFFRDtJQUNDLE9BQU8sVUFBVSxDQUFDO0FBQ3BCLENBQUM7QUFFRCxtRkFBbUY7QUFDbkYsTUFBTSxVQUFVLDBCQUEwQixDQUN4QyxVQUF5RTtJQUV6RSxPQUFPLE1BQU0sQ0FBQyxXQUFXLENBQ3ZCLE1BQU0sQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsU0FBUyxDQUFDLEVBQUUsRUFBRTtRQUN2RCxNQUFNLFFBQVEsR0FBRyxTQUFTLENBQUMsTUFBTSxDQUFDLElBQUksRUFBMkMsQ0FBQztRQUNsRixNQUFNLElBQUksR0FBRyxRQUFRLEVBQUUsVUFBVSxJQUFJLEVBQUUsQ0FBQztRQUN4QyxJQUFJLElBQUksQ0FBQyxTQUFTLEtBQUssSUFBSTtZQUFFLE9BQU8sRUFBRSxDQUFDO1FBQ3ZDLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxNQUFNLElBQUksT0FBTyxDQUFDO1FBQ3RDLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxRQUFRLEtBQUssSUFBSSxJQUFJLE1BQU0sS0FBSyxhQUFhLENBQUM7UUFDcEUsTUFBTSxXQUFXLEdBQUcsU0FBUyxDQUFDLE1BQU0sQ0FBQyxXQUFXLEVBQUUsSUFBSSxFQUFFLENBQUM7UUFDekQsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ2pCLE1BQU0sSUFBSSxTQUFTLENBQUMsb0JBQW9CLElBQUksb0NBQW9DLENBQUMsQ0FBQztRQUNwRixDQUFDO1FBQ0QsT0FBTztZQUNMO2dCQUNFLElBQUk7Z0JBQ0osVUFBVSxDQUFDO29CQUNULFdBQVc7b0JBQ1gsTUFBTSxFQUFFLFNBQVMsQ0FBQyxNQUFNO29CQUN4QixXQUFXLEVBQUU7d0JBQ1gsTUFBTTt3QkFDTixHQUFHLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFLFdBQVcsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO3dCQUMxQyxHQUFHLENBQUMsSUFBSSxDQUFDLG1CQUFtQixLQUFLLFNBQVM7NEJBQ3hDLENBQUMsQ0FBQyxFQUFFOzRCQUNKLENBQUMsQ0FBQyxFQUFFLG1CQUFtQixFQUFFLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO3dCQUN0RCxHQUFHLENBQUMsSUFBSSxDQUFDLFVBQVUsS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxVQUFVLEVBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO3FCQUMxRTtvQkFDRCxHQUFHLENBQUMsSUFBSSxDQUFDLGVBQWUsS0FBSyxTQUFTO3dCQUNwQyxDQUFDLENBQUMsRUFBRTt3QkFDSixDQUFDLENBQUMsRUFBRSxlQUFlLEVBQUUsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO29CQUM5QyxPQUFPLEVBQUUsQ0FBQyxLQUFLLEVBQUUsTUFBTSxFQUFFLEVBQUUsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxFQUFFLE1BQU0sQ0FBQztpQkFDckYsQ0FBQzthQUNIO1NBQ0YsQ0FBQztJQUNKLENBQUMsQ0FBQyxDQUNILENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqIFpvZC1vd25lZCBvcGVyYXRpb24gY29udHJhY3RzIGNvbnZlcnRlZCBpbnRvIG5hdGl2ZSBBcHBLaXQgYWdlbnQgdG9vbHMuICovXG5cbmltcG9ydCB7IGRlZmluZVRvb2wsIHR5cGUgVG9vbFJlZ2lzdHJ5IH0gZnJvbSBcIkBkYXRhYnJpY2tzL2FwcGtpdC9iZXRhXCI7XG5pbXBvcnQgeyB6IH0gZnJvbSBcInpvZFwiO1xuXG4vKiogTWV0YWRhdGEgc3RvcmVkIHVuZGVyIGBhcHBraXRUb29sYCBieSBhIFpvZCBzY2hlbWEncyBgLm1ldGEoKWAgdmFsdWUuICovXG5leHBvcnQgaW50ZXJmYWNlIEFwcEtpdFRvb2xNZXRhIHtcbiAgLyoqIE9wdCBpbiB0byBleHBvc2luZyB0aGlzIG9wZXJhdGlvbiBhcyBhbiBhZ2VudCB0b29sLiAqL1xuICByZWFkb25seSBhZ2VudFRvb2w/OiBib29sZWFuO1xuICAvKiogVG9vbCBzaWRlLWVmZmVjdCBjbGFzc2lmaWNhdGlvbi4gRGVmYXVsdHMgdG8gYHdyaXRlYC4gKi9cbiAgcmVhZG9ubHkgZWZmZWN0PzogXCJyZWFkXCIgfCBcIndyaXRlXCIgfCBcImRlc3RydWN0aXZlXCI7XG4gIC8qKiBSZXF1aXJlIGh1bWFuIGFwcHJvdmFsIGJlZm9yZSBleGVjdXRpb24uICovXG4gIHJlYWRvbmx5IGFwcHJvdmFsPzogYm9vbGVhbjtcbiAgLyoqIFdoZXRoZXIgZXhlY3V0aW9uIHJlcXVpcmVzIGFuIGF1dGhlbnRpY2F0ZWQgdXNlciBjb250ZXh0LiAqL1xuICByZWFkb25seSByZXF1aXJlc1VzZXJDb250ZXh0PzogYm9vbGVhbjtcbiAgLyoqIFdoZXRoZXIgcmVwZWF0ZWQgY2FsbHMgd2l0aCB0aGUgc2FtZSBpbnB1dCBhcmUgc2FmZS4gKi9cbiAgcmVhZG9ubHkgaWRlbXBvdGVudD86IGJvb2xlYW47XG4gIC8qKiBXaGV0aGVyIEFwcEtpdCBtYXkgaW5oZXJpdCB0aGUgdG9vbCBhdXRvbWF0aWNhbGx5LiAqL1xuICByZWFkb25seSBhdXRvSW5oZXJpdGFibGU/OiBib29sZWFuO1xufVxuXG4vKiogU2hhcGUgcGxhY2VkIGluIGEgWm9kIHNjaGVtYSdzIGAubWV0YSgpYCB2YWx1ZS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQXBwS2l0T3BlcmF0aW9uU2NoZW1hTWV0YSB7XG4gIHJlYWRvbmx5IGFwcGtpdFRvb2w/OiBBcHBLaXRUb29sTWV0YTtcbn1cblxuLyoqIE9uZSB0eXBlZCBvcGVyYXRpb24gYmFja2VkIGJ5IGEgc2luZ2xlIFpvZCBpbnB1dCBjb250cmFjdC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQXBwS2l0T3BlcmF0aW9uPFRTY2hlbWEgZXh0ZW5kcyB6LlpvZFR5cGUgPSB6LlpvZFR5cGUsIFRSZXN1bHQgPSB1bmtub3duPiB7XG4gIHJlYWRvbmx5IHNjaGVtYTogVFNjaGVtYTtcbiAgcmVhZG9ubHkgZXhlY3V0ZTogKGlucHV0OiB6Lm91dHB1dDxUU2NoZW1hPiwgc2lnbmFsPzogQWJvcnRTaWduYWwpID0+IFRSZXN1bHQgfCBQcm9taXNlPFRSZXN1bHQ+O1xufVxuXG4vKiogUHJlc2VydmUgb3BlcmF0aW9uIGluZmVyZW5jZSB3aGlsZSBkZWNsYXJpbmcgYW4gZXhwb3J0ZWQgb3BlcmF0aW9uIG1hcC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkZWZpbmVPcGVyYXRpb25zPFxuICBjb25zdCBUU2NoZW1hcyBleHRlbmRzIFJlYWRvbmx5PFJlY29yZDxzdHJpbmcsIHouWm9kVHlwZT4+LFxuPihvcGVyYXRpb25zOiB7XG4gIHJlYWRvbmx5IFtUTmFtZSBpbiBrZXlvZiBUU2NoZW1hc106IEFwcEtpdE9wZXJhdGlvbjxUU2NoZW1hc1tUTmFtZV0sIHVua25vd24+O1xufSk6IHR5cGVvZiBvcGVyYXRpb25zIHtcbiAgcmV0dXJuIG9wZXJhdGlvbnM7XG59XG5cbi8qKiBDb252ZXJ0IGV4cG9ydGVkIFpvZCBvcGVyYXRpb24gY29udHJhY3RzIGludG8gYSBuYXRpdmUgQXBwS2l0IHRvb2wgcmVnaXN0cnkuICovXG5leHBvcnQgZnVuY3Rpb24gdG9vbFJlZ2lzdHJ5RnJvbU9wZXJhdGlvbnMoXG4gIG9wZXJhdGlvbnM6IFJlYWRvbmx5PFJlY29yZDxzdHJpbmcsIEFwcEtpdE9wZXJhdGlvbjx6LlpvZFR5cGUsIHVua25vd24+Pj4sXG4pOiBUb29sUmVnaXN0cnkge1xuICByZXR1cm4gT2JqZWN0LmZyb21FbnRyaWVzKFxuICAgIE9iamVjdC5lbnRyaWVzKG9wZXJhdGlvbnMpLmZsYXRNYXAoKFtuYW1lLCBvcGVyYXRpb25dKSA9PiB7XG4gICAgICBjb25zdCBtZXRhZGF0YSA9IG9wZXJhdGlvbi5zY2hlbWEubWV0YSgpIGFzIEFwcEtpdE9wZXJhdGlvblNjaGVtYU1ldGEgfCB1bmRlZmluZWQ7XG4gICAgICBjb25zdCB0b29sID0gbWV0YWRhdGE/LmFwcGtpdFRvb2wgPz8ge307XG4gICAgICBpZiAodG9vbC5hZ2VudFRvb2wgIT09IHRydWUpIHJldHVybiBbXTtcbiAgICAgIGNvbnN0IGVmZmVjdCA9IHRvb2wuZWZmZWN0ID8/IFwid3JpdGVcIjtcbiAgICAgIGNvbnN0IGFwcHJvdmFsID0gdG9vbC5hcHByb3ZhbCA9PT0gdHJ1ZSB8fCBlZmZlY3QgPT09IFwiZGVzdHJ1Y3RpdmVcIjtcbiAgICAgIGNvbnN0IGRlc2NyaXB0aW9uID0gb3BlcmF0aW9uLnNjaGVtYS5kZXNjcmlwdGlvbj8udHJpbSgpO1xuICAgICAgaWYgKCFkZXNjcmlwdGlvbikge1xuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKGBBcHBLaXQgb3BlcmF0aW9uICR7bmFtZX0gcmVxdWlyZXMgYSBab2Qgc2NoZW1hIGRlc2NyaXB0aW9uYCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gW1xuICAgICAgICBbXG4gICAgICAgICAgbmFtZSxcbiAgICAgICAgICBkZWZpbmVUb29sKHtcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uLFxuICAgICAgICAgICAgc2NoZW1hOiBvcGVyYXRpb24uc2NoZW1hLFxuICAgICAgICAgICAgYW5ub3RhdGlvbnM6IHtcbiAgICAgICAgICAgICAgZWZmZWN0LFxuICAgICAgICAgICAgICAuLi4oYXBwcm92YWwgPyB7IGRlc3RydWN0aXZlOiB0cnVlIH0gOiB7fSksXG4gICAgICAgICAgICAgIC4uLih0b29sLnJlcXVpcmVzVXNlckNvbnRleHQgPT09IHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgID8ge31cbiAgICAgICAgICAgICAgICA6IHsgcmVxdWlyZXNVc2VyQ29udGV4dDogdG9vbC5yZXF1aXJlc1VzZXJDb250ZXh0IH0pLFxuICAgICAgICAgICAgICAuLi4odG9vbC5pZGVtcG90ZW50ID09PSB1bmRlZmluZWQgPyB7fSA6IHsgaWRlbXBvdGVudDogdG9vbC5pZGVtcG90ZW50IH0pLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIC4uLih0b29sLmF1dG9Jbmhlcml0YWJsZSA9PT0gdW5kZWZpbmVkXG4gICAgICAgICAgICAgID8ge31cbiAgICAgICAgICAgICAgOiB7IGF1dG9Jbmhlcml0YWJsZTogdG9vbC5hdXRvSW5oZXJpdGFibGUgfSksXG4gICAgICAgICAgICBleGVjdXRlOiAoaW5wdXQsIHNpZ25hbCkgPT4gb3BlcmF0aW9uLmV4ZWN1dGUob3BlcmF0aW9uLnNjaGVtYS5wYXJzZShpbnB1dCksIHNpZ25hbCksXG4gICAgICAgICAgfSksXG4gICAgICAgIF0sXG4gICAgICBdO1xuICAgIH0pLFxuICApO1xufVxuIl19
|
package/lib/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/_auto-configure.ts","../src/
|
|
1
|
+
{"root":["../src/_auto-configure.ts","../src/appkit.ts","../src/brand-context.ts","../src/bundle.ts","../src/cache-storage.ts","../src/child-process.ts","../src/databricks.ts","../src/files-cache.ts","../src/identity.ts","../src/interceptor.ts","../src/lakebase-resolver.ts","../src/migration.ts","../src/pgaddress.ts","../src/plugin-execution.ts","../src/plugin-registry.ts","../src/provision.ts","../src/request-tags.ts","../src/tool-operations.ts","../src/tool-provider.ts","../src/toolkit-entries.ts","../index.ts"],"version":"5.9.3"}
|
package/package.json
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@databricks/appkit": "0.81.0",
|
|
23
|
-
"@dbx-tools/projen": "^0.9.
|
|
23
|
+
"@dbx-tools/projen": "^0.9.120",
|
|
24
24
|
"@types/node": "^24.6.0",
|
|
25
25
|
"typescript": "^5.9.3",
|
|
26
26
|
"vitest": "3.2.4"
|
|
@@ -30,13 +30,13 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@databricks/sdk-experimental": "^0.17.0",
|
|
33
|
-
"@dbx-tools/auth": "^0.9.
|
|
34
|
-
"@dbx-tools/
|
|
35
|
-
"@dbx-tools/
|
|
36
|
-
"@dbx-tools/
|
|
37
|
-
"@dbx-tools/
|
|
38
|
-
"@dbx-tools/shared-
|
|
39
|
-
"
|
|
33
|
+
"@dbx-tools/auth": "^0.9.120",
|
|
34
|
+
"@dbx-tools/cache": "^0.9.120",
|
|
35
|
+
"@dbx-tools/core": "^0.9.120",
|
|
36
|
+
"@dbx-tools/lakebase": "^0.9.120",
|
|
37
|
+
"@dbx-tools/postgres": "^0.9.120",
|
|
38
|
+
"@dbx-tools/shared-core": "^0.9.120",
|
|
39
|
+
"@dbx-tools/shared-fs": "^0.9.120",
|
|
40
40
|
"zod": "4.3.6"
|
|
41
41
|
},
|
|
42
42
|
"main": "./lib/index.js",
|
|
@@ -62,6 +62,10 @@
|
|
|
62
62
|
"types": "./lib/src/bundle.d.ts",
|
|
63
63
|
"default": "./lib/src/bundle.js"
|
|
64
64
|
},
|
|
65
|
+
"./cache-storage": {
|
|
66
|
+
"types": "./lib/src/cache-storage.d.ts",
|
|
67
|
+
"default": "./lib/src/cache-storage.js"
|
|
68
|
+
},
|
|
65
69
|
"./child-process": {
|
|
66
70
|
"types": "./lib/src/child-process.d.ts",
|
|
67
71
|
"default": "./lib/src/child-process.js"
|
|
@@ -110,6 +114,10 @@
|
|
|
110
114
|
"types": "./lib/src/request-tags.d.ts",
|
|
111
115
|
"default": "./lib/src/request-tags.js"
|
|
112
116
|
},
|
|
117
|
+
"./tool-operations": {
|
|
118
|
+
"types": "./lib/src/tool-operations.d.ts",
|
|
119
|
+
"default": "./lib/src/tool-operations.js"
|
|
120
|
+
},
|
|
113
121
|
"./tool-provider": {
|
|
114
122
|
"types": "./lib/src/tool-provider.d.ts",
|
|
115
123
|
"default": "./lib/src/tool-provider.js"
|
|
@@ -125,7 +133,7 @@
|
|
|
125
133
|
"./package.json": "./package.json"
|
|
126
134
|
}
|
|
127
135
|
},
|
|
128
|
-
"version": "0.9.
|
|
136
|
+
"version": "0.9.120",
|
|
129
137
|
"types": "./lib/index.d.ts",
|
|
130
138
|
"dbxToolsConfig": {
|
|
131
139
|
"tags": [
|
|
@@ -150,6 +158,10 @@
|
|
|
150
158
|
"types": "./lib/src/bundle.d.ts",
|
|
151
159
|
"default": "./lib/src/bundle.js"
|
|
152
160
|
},
|
|
161
|
+
"./cache-storage": {
|
|
162
|
+
"types": "./lib/src/cache-storage.d.ts",
|
|
163
|
+
"default": "./lib/src/cache-storage.js"
|
|
164
|
+
},
|
|
153
165
|
"./child-process": {
|
|
154
166
|
"types": "./lib/src/child-process.d.ts",
|
|
155
167
|
"default": "./lib/src/child-process.js"
|
|
@@ -198,6 +210,10 @@
|
|
|
198
210
|
"types": "./lib/src/request-tags.d.ts",
|
|
199
211
|
"default": "./lib/src/request-tags.js"
|
|
200
212
|
},
|
|
213
|
+
"./tool-operations": {
|
|
214
|
+
"types": "./lib/src/tool-operations.d.ts",
|
|
215
|
+
"default": "./lib/src/tool-operations.js"
|
|
216
|
+
},
|
|
201
217
|
"./tool-provider": {
|
|
202
218
|
"types": "./lib/src/tool-provider.d.ts",
|
|
203
219
|
"default": "./lib/src/tool-provider.js"
|
package/src/appkit.ts
CHANGED
|
@@ -39,8 +39,8 @@ import { profile as authProfile } from "@dbx-tools/auth";
|
|
|
39
39
|
import { asyncUtils, environmentUtils, log } from "@dbx-tools/shared-core";
|
|
40
40
|
|
|
41
41
|
import { resolveAutoConfigurePolicy } from "./_auto-configure.ts";
|
|
42
|
-
import { createSoftPersistentStorage } from "./_cache-storage.ts";
|
|
43
42
|
import { loadBrandContext } from "./brand-context.ts";
|
|
43
|
+
import { createAppKitCacheStorage } from "./cache-storage.ts";
|
|
44
44
|
import {
|
|
45
45
|
createInterceptorContext,
|
|
46
46
|
type Interceptor,
|
|
@@ -48,6 +48,7 @@ import {
|
|
|
48
48
|
lifecycleBridge,
|
|
49
49
|
type ResolvedAppEnv,
|
|
50
50
|
} from "./interceptor.ts";
|
|
51
|
+
import { installAsUserDevelopmentPatch } from "./identity.ts";
|
|
51
52
|
import { applyLakebaseEnv, type LakebaseConnection } from "./lakebase-resolver.ts";
|
|
52
53
|
import { provisionCacheSchema } from "./provision.ts";
|
|
53
54
|
|
|
@@ -244,20 +245,12 @@ function applyDefaultProfile(): string | undefined {
|
|
|
244
245
|
return resolved.name;
|
|
245
246
|
}
|
|
246
247
|
|
|
247
|
-
/**
|
|
248
|
-
|
|
249
|
-
*
|
|
250
|
-
* Skips when the caller disabled the cache, already supplied a storage
|
|
251
|
-
* backend (including in-memory), or Lakebase is not in play.
|
|
252
|
-
*/
|
|
253
|
-
function shouldInjectSoftPersistentCache(
|
|
254
|
-
config: CreateAppConfig | undefined,
|
|
255
|
-
lakebase: LakebaseConnection | undefined,
|
|
256
|
-
): boolean {
|
|
248
|
+
/** Whether `createApp` should inject the default memory-first cache storage. */
|
|
249
|
+
function shouldInjectCacheStorage(config: CreateAppConfig | undefined): boolean {
|
|
257
250
|
const cache = config?.cache;
|
|
258
251
|
if (cache?.enabled === false) return false;
|
|
259
252
|
if (cache?.storage) return false;
|
|
260
|
-
return
|
|
253
|
+
return true;
|
|
261
254
|
}
|
|
262
255
|
|
|
263
256
|
function redactLakebaseConnection(resolved: LakebaseConnection): Record<string, unknown> {
|
|
@@ -306,6 +299,7 @@ function interceptorList(interceptor: CreateAppConfig["interceptor"]): Intercept
|
|
|
306
299
|
export async function createApp<T extends AppKitPlugins>(
|
|
307
300
|
config?: CreateAppConfig<T>,
|
|
308
301
|
): Promise<PluginMap<T>> {
|
|
302
|
+
installAsUserDevelopmentPatch();
|
|
309
303
|
const plugins = pluginNames(config);
|
|
310
304
|
const interceptors = interceptorList(config?.interceptor);
|
|
311
305
|
logger.debug("createApp: start", {
|
|
@@ -328,15 +322,16 @@ export async function createApp<T extends AppKitPlugins>(
|
|
|
328
322
|
delete appConfig.autoConfigure;
|
|
329
323
|
delete appConfig.interceptor;
|
|
330
324
|
|
|
331
|
-
if (
|
|
332
|
-
logger.debug("createApp: inject
|
|
333
|
-
const storage = await
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
325
|
+
if (shouldInjectCacheStorage(config)) {
|
|
326
|
+
logger.debug("createApp: inject memory-first cache storage");
|
|
327
|
+
const storage = await createAppKitCacheStorage({
|
|
328
|
+
cache: config?.cache,
|
|
329
|
+
preferLakebase: Boolean(lakebase) || usesPlugin(config, LAKEBASE_PLUGIN),
|
|
330
|
+
});
|
|
331
|
+
appConfig.cache = { ...config?.cache, storage };
|
|
332
|
+
logger.debug("createApp: memory-first cache storage ready", {
|
|
333
|
+
persistent: storage.isPersistent(),
|
|
334
|
+
});
|
|
340
335
|
}
|
|
341
336
|
|
|
342
337
|
if (interceptors.length === 0) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Memory-first AppKit cache storage with soft-fail Lakebase persistence.
|
|
3
3
|
*
|
|
4
4
|
* AppKit's `PersistentStorage.initialize()` runs DDL migrations and throws on
|
|
5
5
|
* any step failure. With `cache.strictPersistence: true` that throw makes
|
|
@@ -8,18 +8,25 @@
|
|
|
8
8
|
* usable table keeps serving.
|
|
9
9
|
*
|
|
10
10
|
* `PersistentStorage` is not on AppKit's public export map. The deep load is
|
|
11
|
-
* lazy and best-effort: if the installed AppKit layout changes,
|
|
12
|
-
*
|
|
11
|
+
* lazy and best-effort: if the installed AppKit layout changes, Lakebase is
|
|
12
|
+
* skipped and the adapter keeps its project-scoped disk persistence.
|
|
13
13
|
*
|
|
14
14
|
* @module
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import { EventEmitter } from "node:events";
|
|
17
18
|
import { createRequire } from "node:module";
|
|
18
19
|
import { dirname, join } from "node:path";
|
|
19
20
|
import { createLakebasePool, getWorkspaceClient, type CacheConfig } from "@databricks/appkit";
|
|
21
|
+
import {
|
|
22
|
+
closeCache,
|
|
23
|
+
createCache,
|
|
24
|
+
flushCache,
|
|
25
|
+
projectCache,
|
|
26
|
+
type CacheOptions,
|
|
27
|
+
} from "@dbx-tools/cache/cache";
|
|
20
28
|
import { postgresConnectionOptions } from "@dbx-tools/postgres";
|
|
21
29
|
import { errorUtils, hash, log } from "@dbx-tools/shared-core";
|
|
22
|
-
import { LRUCache } from "lru-cache";
|
|
23
30
|
import { handleOwnershipMigrationError } from "./migration.ts";
|
|
24
31
|
|
|
25
32
|
const logger = log.logger("cache-storage");
|
|
@@ -32,9 +39,17 @@ interface CacheEntry<T = unknown> {
|
|
|
32
39
|
value: T;
|
|
33
40
|
}
|
|
34
41
|
|
|
35
|
-
/**
|
|
36
|
-
export interface
|
|
37
|
-
|
|
42
|
+
/** Options for AppKit's memory-first cache storage adapter. */
|
|
43
|
+
export interface AppKitCacheStorageOptions {
|
|
44
|
+
/** Native AppKit cache configuration. */
|
|
45
|
+
cache?: CacheConfig;
|
|
46
|
+
/** Whether to attempt AppKit's Lakebase PersistentStorage. Defaults to true. */
|
|
47
|
+
preferLakebase?: boolean;
|
|
48
|
+
/** Portable disk scope used when Lakebase is unavailable. */
|
|
49
|
+
diskScope?: string;
|
|
50
|
+
/** Write-behind coalescing delay in milliseconds. */
|
|
51
|
+
writeDelayMs?: number;
|
|
52
|
+
/** Maximum entries retained in the process-local memory primary. */
|
|
38
53
|
maxEntries?: number;
|
|
39
54
|
}
|
|
40
55
|
|
|
@@ -54,95 +69,126 @@ type PersistentStorageConstructor = new (
|
|
|
54
69
|
|
|
55
70
|
let persistentStorageCtor: PersistentStorageConstructor | undefined | null = null;
|
|
56
71
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
72
|
+
class AppKitStorageLevel extends EventEmitter {
|
|
73
|
+
readonly opts = {};
|
|
74
|
+
|
|
75
|
+
constructor(private readonly storage: CacheStorage) {
|
|
76
|
+
super();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async get<T>(key: string): Promise<T | undefined> {
|
|
80
|
+
const entry = await this.storage.get<T>(key);
|
|
81
|
+
if (!entry) return undefined;
|
|
82
|
+
if (entry.expiry <= Date.now()) {
|
|
83
|
+
await this.storage.delete(key);
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
return entry.value;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async set(key: string, value: unknown, ttl?: number): Promise<void> {
|
|
90
|
+
await this.storage.set(key, {
|
|
91
|
+
value,
|
|
92
|
+
expiry: Date.now() + (ttl ?? 60_000),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async delete(key: string): Promise<boolean> {
|
|
97
|
+
await this.storage.delete(key);
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
clear(): Promise<void> {
|
|
102
|
+
return this.storage.clear();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
has(key: string): Promise<boolean> {
|
|
106
|
+
return this.storage.has(key);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
disconnect(): Promise<void> {
|
|
110
|
+
return this.storage.close();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Memory-first AppKit CacheStorage backed by @dbx-tools/cache. */
|
|
115
|
+
export class AppKitCacheStorage implements CacheStorage {
|
|
116
|
+
private readonly cache: ReturnType<typeof createCache>;
|
|
117
|
+
private readonly keys = new Set<string>();
|
|
118
|
+
private closed = false;
|
|
60
119
|
|
|
61
120
|
constructor(
|
|
62
|
-
|
|
63
|
-
|
|
121
|
+
cache: ReturnType<typeof createCache>,
|
|
122
|
+
private readonly persistent: CacheStorage | undefined,
|
|
64
123
|
) {
|
|
65
|
-
this.
|
|
66
|
-
max: positiveBound(options.maxEntries, 1_000, "maxEntries"),
|
|
67
|
-
maxSize: positiveBound(options.maxBytes, 64 * 1024 * 1024, "maxBytes"),
|
|
68
|
-
sizeCalculation: (entry, key) => retainedSize(key, entry),
|
|
69
|
-
});
|
|
124
|
+
this.cache = cache;
|
|
70
125
|
}
|
|
71
126
|
|
|
72
127
|
async get<T>(key: string): Promise<CacheEntry<T> | null> {
|
|
73
|
-
const
|
|
74
|
-
if (
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return persisted;
|
|
128
|
+
const entry = await this.cache.get<CacheEntry<T>>(key);
|
|
129
|
+
if (!entry) return null;
|
|
130
|
+
this.keys.add(key);
|
|
131
|
+
return entry;
|
|
78
132
|
}
|
|
79
133
|
|
|
80
134
|
async set<T>(key: string, entry: CacheEntry<T>): Promise<void> {
|
|
81
|
-
|
|
82
|
-
|
|
135
|
+
const ttl = entry.expiry - Date.now();
|
|
136
|
+
if (ttl <= 0) {
|
|
137
|
+
await this.delete(key);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
await this.cache.set(key, entry, { ttl });
|
|
141
|
+
this.keys.add(key);
|
|
83
142
|
}
|
|
84
143
|
|
|
85
144
|
async delete(key: string): Promise<void> {
|
|
86
|
-
await this.
|
|
87
|
-
this.
|
|
145
|
+
await this.cache.delete(key);
|
|
146
|
+
this.keys.delete(key);
|
|
88
147
|
}
|
|
89
148
|
|
|
90
149
|
async clear(): Promise<void> {
|
|
91
|
-
await this.
|
|
92
|
-
this.
|
|
150
|
+
await this.cache.clear();
|
|
151
|
+
this.keys.clear();
|
|
93
152
|
}
|
|
94
153
|
|
|
95
154
|
async has(key: string): Promise<boolean> {
|
|
96
|
-
|
|
97
|
-
return this.storage.has(key);
|
|
155
|
+
return this.cache.has(key);
|
|
98
156
|
}
|
|
99
157
|
|
|
100
|
-
size(): Promise<number> {
|
|
101
|
-
return this.
|
|
158
|
+
async size(): Promise<number> {
|
|
159
|
+
return this.persistent ? this.persistent.size() : this.keys.size;
|
|
102
160
|
}
|
|
103
161
|
|
|
104
162
|
isPersistent(): boolean {
|
|
105
|
-
return
|
|
163
|
+
return true;
|
|
106
164
|
}
|
|
107
165
|
|
|
108
|
-
healthCheck(): Promise<boolean> {
|
|
109
|
-
return this.
|
|
166
|
+
async healthCheck(): Promise<boolean> {
|
|
167
|
+
return this.persistent ? this.persistent.healthCheck() : true;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** Drain tracked write-behind persistence without closing the storage. */
|
|
171
|
+
flush(): Promise<void> {
|
|
172
|
+
return flushCache(this.cache);
|
|
110
173
|
}
|
|
111
174
|
|
|
112
175
|
async close(): Promise<void> {
|
|
113
|
-
this.
|
|
114
|
-
await this.
|
|
176
|
+
if (this.closed) return;
|
|
177
|
+
await closeCache(this.cache);
|
|
178
|
+
this.closed = true;
|
|
179
|
+
this.keys.clear();
|
|
115
180
|
}
|
|
116
181
|
|
|
117
182
|
/** Forward AppKit's runtime-only persistent cleanup hook when available. */
|
|
118
183
|
async cleanupExpired(): Promise<number> {
|
|
119
184
|
const cleanup = (
|
|
120
|
-
this.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
private retain<T>(key: string, entry: CacheEntry<T>): void {
|
|
128
|
-
const ttl = entry.expiry - Date.now();
|
|
129
|
-
if (ttl > 0) this.entries.set(key, entry, { ttl });
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function positiveBound(value: number | undefined, fallback: number, name: string): number {
|
|
134
|
-
const resolved = value ?? fallback;
|
|
135
|
-
if (!Number.isFinite(resolved) || resolved <= 0) {
|
|
136
|
-
throw new RangeError(`${name} must be a finite positive number`);
|
|
137
|
-
}
|
|
138
|
-
return Math.floor(resolved);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function retainedSize(key: string, entry: CacheEntry): number {
|
|
142
|
-
try {
|
|
143
|
-
return Buffer.byteLength(key) + Buffer.byteLength(JSON.stringify(entry));
|
|
144
|
-
} catch {
|
|
145
|
-
return Number.MAX_SAFE_INTEGER;
|
|
185
|
+
this.persistent as
|
|
186
|
+
| (CacheStorage & {
|
|
187
|
+
cleanupExpired?: () => Promise<number>;
|
|
188
|
+
})
|
|
189
|
+
| undefined
|
|
190
|
+
)?.cleanupExpired;
|
|
191
|
+
return cleanup && this.persistent ? cleanup.call(this.persistent) : 0;
|
|
146
192
|
}
|
|
147
193
|
}
|
|
148
194
|
|
|
@@ -171,7 +217,7 @@ export function loadPersistentStorage(): PersistentStorageConstructor | undefine
|
|
|
171
217
|
return loaded;
|
|
172
218
|
} catch (err) {
|
|
173
219
|
logger.debug("soft persistent cache skipped (PersistentStorage unavailable)", {
|
|
174
|
-
error: errorUtils.
|
|
220
|
+
error: errorUtils.toError(err),
|
|
175
221
|
});
|
|
176
222
|
persistentStorageCtor = undefined;
|
|
177
223
|
return undefined;
|
|
@@ -257,9 +303,9 @@ export async function probeStorage(storage: PersistentStorageBase): Promise<void
|
|
|
257
303
|
/**
|
|
258
304
|
* Build a soft-fail Lakebase cache storage when a pool can be created and
|
|
259
305
|
* AppKit's PersistentStorage can be loaded. Returns `undefined` otherwise so
|
|
260
|
-
*
|
|
306
|
+
* the caller can use portable disk persistence.
|
|
261
307
|
*/
|
|
262
|
-
|
|
308
|
+
async function createPersistentStorage(
|
|
263
309
|
cache: CacheConfig | undefined,
|
|
264
310
|
): Promise<CacheStorage | undefined> {
|
|
265
311
|
const PersistentStorage = loadPersistentStorage();
|
|
@@ -281,13 +327,10 @@ export async function createSoftPersistentStorage(
|
|
|
281
327
|
}
|
|
282
328
|
await storage.initialize();
|
|
283
329
|
await probeStorage(storage);
|
|
284
|
-
return
|
|
285
|
-
maxBytes: cache?.maxBytes,
|
|
286
|
-
maxEntries: cache?.maxSize,
|
|
287
|
-
});
|
|
330
|
+
return storage;
|
|
288
331
|
} catch (err) {
|
|
289
332
|
logger.debug("soft persistent cache unavailable", {
|
|
290
|
-
error: errorUtils.
|
|
333
|
+
error: errorUtils.toError(err),
|
|
291
334
|
});
|
|
292
335
|
if (pool) {
|
|
293
336
|
await pool.end().catch(() => {});
|
|
@@ -295,3 +338,27 @@ export async function createSoftPersistentStorage(
|
|
|
295
338
|
return undefined;
|
|
296
339
|
}
|
|
297
340
|
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Create AppKit CacheStorage with bounded memory first and tracked persistence.
|
|
344
|
+
* Lakebase remains AppKit's persistent owner when available; otherwise the
|
|
345
|
+
* shared project-scoped portable disk level is used.
|
|
346
|
+
*/
|
|
347
|
+
export async function createAppKitCacheStorage(
|
|
348
|
+
options: AppKitCacheStorageOptions = {},
|
|
349
|
+
): Promise<AppKitCacheStorage> {
|
|
350
|
+
const nativeCache = options.cache;
|
|
351
|
+
const persistent =
|
|
352
|
+
options.preferLakebase === false ? undefined : await createPersistentStorage(nativeCache);
|
|
353
|
+
const common: CacheOptions = {
|
|
354
|
+
maxEntries: options.maxEntries ?? nativeCache?.maxSize,
|
|
355
|
+
writeDelayMs: options.writeDelayMs,
|
|
356
|
+
};
|
|
357
|
+
const cache = persistent
|
|
358
|
+
? createCache({
|
|
359
|
+
...common,
|
|
360
|
+
levels: [{ name: "appkit-persistent", store: new AppKitStorageLevel(persistent) }],
|
|
361
|
+
})
|
|
362
|
+
: projectCache(options.diskScope ?? "appkit", common);
|
|
363
|
+
return new AppKitCacheStorage(cache, persistent);
|
|
364
|
+
}
|