@dbx-tools/appkit 0.9.79 → 0.9.95
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 +32 -0
- package/index.ts +4 -1
- package/lib/index.d.ts +4 -1
- package/lib/index.js +4 -2
- package/lib/src/_cache-storage.d.ts +3 -0
- package/lib/src/_cache-storage.js +6 -1
- package/lib/src/files-cache.d.ts +86 -0
- package/lib/src/files-cache.js +230 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +16 -7
- package/src/_cache-storage.ts +11 -0
- package/src/files-cache.ts +332 -0
package/README.md
CHANGED
|
@@ -20,6 +20,8 @@ without taking on a heavier feature package.
|
|
|
20
20
|
`Context` values.
|
|
21
21
|
- Lakebase cache-schema provisioning for deployments where the app identity must
|
|
22
22
|
be granted access before persistent cache initialization.
|
|
23
|
+
- AppKit-global filesystem caching with user-isolated bounded L1 state,
|
|
24
|
+
cross-user invalidation, and stable framework filesystem sources.
|
|
23
25
|
- An interceptor context on `createApp` (`interceptor?: Interceptor | Interceptor[]`)
|
|
24
26
|
that hands add-ons the computed env, AppKit lifecycle hooks (`onLifecycle`, using
|
|
25
27
|
AppKit's own `setup:complete` / `server:ready` / `shutdown` vocabulary).
|
|
@@ -136,6 +138,36 @@ The injected persistent storage includes a bounded process-local L1 powered by
|
|
|
136
138
|
expiry, deletion, and clear operations remain coherent with the persistent
|
|
137
139
|
store.
|
|
138
140
|
|
|
141
|
+
## Filesystem Cache Plugin
|
|
142
|
+
|
|
143
|
+
Register `filesCache()` when provider-backed filesystems should share one
|
|
144
|
+
AppKit-lifecycle cache:
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
import { filesCache } from "@dbx-tools/appkit/files-cache";
|
|
148
|
+
import { server } from "@databricks/appkit";
|
|
149
|
+
import { appkit } from "@dbx-tools/appkit";
|
|
150
|
+
|
|
151
|
+
await appkit.createApp({
|
|
152
|
+
plugins: [server(), filesCache()],
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
The plugin exposes `forScope({ host, workspaceId?, userKey, ttlMs? })`, which
|
|
157
|
+
returns the `FileSystemCache` consumed by `@dbx-tools/shared-fs` `fs.cache()`.
|
|
158
|
+
Values are isolated by host, optional workspace id, and attributed user. A
|
|
159
|
+
batched invalidation clears matching keys across active user scopes without
|
|
160
|
+
sharing authorization-sensitive values.
|
|
161
|
+
|
|
162
|
+
`forFileSystem(scope, { paths }, load)` retains one framework filesystem source
|
|
163
|
+
for the same user and actual mounted paths. This gives frameworks such as Mastra
|
|
164
|
+
a stable source identity across page refreshes and turns without introducing a
|
|
165
|
+
second parsed catalogue cache.
|
|
166
|
+
|
|
167
|
+
Values and retained filesystem sources use a bounded process-local `lru-cache`.
|
|
168
|
+
Nothing is written to Lakebase or another persistent store. App restarts and
|
|
169
|
+
replica changes begin with a cold filesystem cache.
|
|
170
|
+
|
|
139
171
|
`lakebaseResolver.resolveLakebaseConnection()` accepts:
|
|
140
172
|
|
|
141
173
|
| Option | Type | Default | Description |
|
package/index.ts
CHANGED
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
// Hand edits are overwritten on the next watch; this file is read-only.
|
|
4
4
|
|
|
5
5
|
export const PACKAGE_IDENTIFIER = "@dbx-tools/appkit";
|
|
6
|
-
export const PACKAGE_VERSION = "0.9.
|
|
6
|
+
export const PACKAGE_VERSION = "0.9.95";
|
|
7
7
|
export * as appkit from "./src/appkit.ts";
|
|
8
8
|
export * as brandContext from "./src/brand-context.ts";
|
|
9
9
|
export * as bundle from "./src/bundle.ts";
|
|
10
10
|
export * as childProcess from "./src/child-process.ts";
|
|
11
11
|
export * as databricks from "./src/databricks.ts";
|
|
12
|
+
export * as filesCache from "./src/files-cache.ts";
|
|
12
13
|
export * as identity from "./src/identity.ts";
|
|
13
14
|
export * as interceptor from "./src/interceptor.ts";
|
|
14
15
|
export * as lakebaseResolver from "./src/lakebase-resolver.ts";
|
|
@@ -26,6 +27,8 @@ export type { BundleValidateJson, ConfigFile, ConfigMapValue, ConfigSource, Reso
|
|
|
26
27
|
export { AppKitChildProcess } from "./src/child-process.ts";
|
|
27
28
|
export type { AppKitSpawnArgs, AppKitChildProcessHealthCheckContext, AppKitChildProcessHealthCheck, AppKitChildProcessOptions, AppKitChildProcessRunOptions } from "./src/child-process.ts";
|
|
28
29
|
export type { ContextLike } from "./src/databricks.ts";
|
|
30
|
+
export { FilesCacheManager, FilesCachePlugin } from "./src/files-cache.ts";
|
|
31
|
+
export type { FilesCachePluginConfig, FilesCacheScope, FilesCacheSourceIdentity, FilesCacheExports } from "./src/files-cache.ts";
|
|
29
32
|
export { ACCESS_TOKEN_HEADER, USER_ID_HEADER, USER_EMAIL_HEADER, IDENTITY_MODES, DEFAULT_IDENTITY_MODE } from "./src/identity.ts";
|
|
30
33
|
export type { IdentityMode, HeaderBearing } from "./src/identity.ts";
|
|
31
34
|
export { LifecycleBridgePlugin, lifecycleBridge } from "./src/interceptor.ts";
|
package/lib/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
export declare const PACKAGE_IDENTIFIER = "@dbx-tools/appkit";
|
|
2
|
-
export declare const PACKAGE_VERSION = "0.9.
|
|
2
|
+
export declare const PACKAGE_VERSION = "0.9.95";
|
|
3
3
|
export * as appkit from "./src/appkit.ts";
|
|
4
4
|
export * as brandContext from "./src/brand-context.ts";
|
|
5
5
|
export * as bundle from "./src/bundle.ts";
|
|
6
6
|
export * as childProcess from "./src/child-process.ts";
|
|
7
7
|
export * as databricks from "./src/databricks.ts";
|
|
8
|
+
export * as filesCache from "./src/files-cache.ts";
|
|
8
9
|
export * as identity from "./src/identity.ts";
|
|
9
10
|
export * as interceptor from "./src/interceptor.ts";
|
|
10
11
|
export * as lakebaseResolver from "./src/lakebase-resolver.ts";
|
|
@@ -22,6 +23,8 @@ export type { BundleValidateJson, ConfigFile, ConfigMapValue, ConfigSource, Reso
|
|
|
22
23
|
export { AppKitChildProcess } from "./src/child-process.ts";
|
|
23
24
|
export type { AppKitSpawnArgs, AppKitChildProcessHealthCheckContext, AppKitChildProcessHealthCheck, AppKitChildProcessOptions, AppKitChildProcessRunOptions } from "./src/child-process.ts";
|
|
24
25
|
export type { ContextLike } from "./src/databricks.ts";
|
|
26
|
+
export { FilesCacheManager, FilesCachePlugin } from "./src/files-cache.ts";
|
|
27
|
+
export type { FilesCachePluginConfig, FilesCacheScope, FilesCacheSourceIdentity, FilesCacheExports } from "./src/files-cache.ts";
|
|
25
28
|
export { ACCESS_TOKEN_HEADER, USER_ID_HEADER, USER_EMAIL_HEADER, IDENTITY_MODES, DEFAULT_IDENTITY_MODE } from "./src/identity.ts";
|
|
26
29
|
export type { IdentityMode, HeaderBearing } from "./src/identity.ts";
|
|
27
30
|
export { LifecycleBridgePlugin, lifecycleBridge } from "./src/interceptor.ts";
|
package/lib/index.js
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
// Regenerated from the exporting modules in ./src.
|
|
3
3
|
// Hand edits are overwritten on the next watch; this file is read-only.
|
|
4
4
|
export const PACKAGE_IDENTIFIER = "@dbx-tools/appkit";
|
|
5
|
-
export const PACKAGE_VERSION = "0.9.
|
|
5
|
+
export const PACKAGE_VERSION = "0.9.95";
|
|
6
6
|
export * as appkit from "./src/appkit.js";
|
|
7
7
|
export * as brandContext from "./src/brand-context.js";
|
|
8
8
|
export * as bundle from "./src/bundle.js";
|
|
9
9
|
export * as childProcess from "./src/child-process.js";
|
|
10
10
|
export * as databricks from "./src/databricks.js";
|
|
11
|
+
export * as filesCache from "./src/files-cache.js";
|
|
11
12
|
export * as identity from "./src/identity.js";
|
|
12
13
|
export * as interceptor from "./src/interceptor.js";
|
|
13
14
|
export * as lakebaseResolver from "./src/lakebase-resolver.js";
|
|
@@ -21,8 +22,9 @@ export * as toolProvider from "./src/tool-provider.js";
|
|
|
21
22
|
export * as toolkitEntries from "./src/toolkit-entries.js";
|
|
22
23
|
export { bundleAppResourceSchema, flattenAppYamlEnv, flattenAppEnv, getBundlePath } from "./src/bundle.js";
|
|
23
24
|
export { AppKitChildProcess } from "./src/child-process.js";
|
|
25
|
+
export { FilesCacheManager, FilesCachePlugin } from "./src/files-cache.js";
|
|
24
26
|
export { ACCESS_TOKEN_HEADER, USER_ID_HEADER, USER_EMAIL_HEADER, IDENTITY_MODES, DEFAULT_IDENTITY_MODE } from "./src/identity.js";
|
|
25
27
|
export { LifecycleBridgePlugin, lifecycleBridge } from "./src/interceptor.js";
|
|
26
28
|
export { SSL_MODES } from "./src/pgaddress.js";
|
|
27
29
|
export { ToolRegistryPlugin } from "./src/tool-provider.js";
|
|
28
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
30
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwyQ0FBMkM7QUFDM0MsbURBQW1EO0FBQ25ELHdFQUF3RTtBQUV4RSxNQUFNLENBQUMsTUFBTSxrQkFBa0IsR0FBRyxtQkFBbUIsQ0FBQztBQUN0RCxNQUFNLENBQUMsTUFBTSxlQUFlLEdBQUcsUUFBUSxDQUFDO0FBQ3hDLE9BQU8sS0FBSyxNQUFNLE1BQU0saUJBQWlCLENBQUM7QUFDMUMsT0FBTyxLQUFLLFlBQVksTUFBTSx3QkFBd0IsQ0FBQztBQUN2RCxPQUFPLEtBQUssTUFBTSxNQUFNLGlCQUFpQixDQUFDO0FBQzFDLE9BQU8sS0FBSyxZQUFZLE1BQU0sd0JBQXdCLENBQUM7QUFDdkQsT0FBTyxLQUFLLFVBQVUsTUFBTSxxQkFBcUIsQ0FBQztBQUNsRCxPQUFPLEtBQUssVUFBVSxNQUFNLHNCQUFzQixDQUFDO0FBQ25ELE9BQU8sS0FBSyxRQUFRLE1BQU0sbUJBQW1CLENBQUM7QUFDOUMsT0FBTyxLQUFLLFdBQVcsTUFBTSxzQkFBc0IsQ0FBQztBQUNwRCxPQUFPLEtBQUssZ0JBQWdCLE1BQU0sNEJBQTRCLENBQUM7QUFDL0QsT0FBTyxLQUFLLFNBQVMsTUFBTSxvQkFBb0IsQ0FBQztBQUNoRCxPQUFPLEtBQUssU0FBUyxNQUFNLG9CQUFvQixDQUFDO0FBQ2hELE9BQU8sS0FBSyxlQUFlLE1BQU0sMkJBQTJCLENBQUM7QUFDN0QsT0FBTyxLQUFLLGNBQWMsTUFBTSwwQkFBMEIsQ0FBQztBQUMzRCxPQUFPLEtBQUssU0FBUyxNQUFNLG9CQUFvQixDQUFDO0FBQ2hELE9BQU8sS0FBSyxXQUFXLE1BQU0sdUJBQXVCLENBQUM7QUFDckQsT0FBTyxLQUFLLFlBQVksTUFBTSx3QkFBd0IsQ0FBQztBQUN2RCxPQUFPLEtBQUssY0FBYyxNQUFNLDBCQUEwQixDQUFDO0FBRTNELE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxpQkFBaUIsRUFBRSxhQUFhLEVBQUUsYUFBYSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFM0csT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFHNUQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLGdCQUFnQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFM0UsT0FBTyxFQUFFLG1CQUFtQixFQUFFLGNBQWMsRUFBRSxpQkFBaUIsRUFBRSxjQUFjLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUVsSSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsZUFBZSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFJOUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBSy9DLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHdCQUF3QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gR0VORVJBVEVEIGJ5IHByb2plbiB3YXRjaCAtIERPIE5PVCBFRElULlxuLy8gUmVnZW5lcmF0ZWQgZnJvbSB0aGUgZXhwb3J0aW5nIG1vZHVsZXMgaW4gLi9zcmMuXG4vLyBIYW5kIGVkaXRzIGFyZSBvdmVyd3JpdHRlbiBvbiB0aGUgbmV4dCB3YXRjaDsgdGhpcyBmaWxlIGlzIHJlYWQtb25seS5cblxuZXhwb3J0IGNvbnN0IFBBQ0tBR0VfSURFTlRJRklFUiA9IFwiQGRieC10b29scy9hcHBraXRcIjtcbmV4cG9ydCBjb25zdCBQQUNLQUdFX1ZFUlNJT04gPSBcIjAuOS45NVwiO1xuZXhwb3J0ICogYXMgYXBwa2l0IGZyb20gXCIuL3NyYy9hcHBraXQudHNcIjtcbmV4cG9ydCAqIGFzIGJyYW5kQ29udGV4dCBmcm9tIFwiLi9zcmMvYnJhbmQtY29udGV4dC50c1wiO1xuZXhwb3J0ICogYXMgYnVuZGxlIGZyb20gXCIuL3NyYy9idW5kbGUudHNcIjtcbmV4cG9ydCAqIGFzIGNoaWxkUHJvY2VzcyBmcm9tIFwiLi9zcmMvY2hpbGQtcHJvY2Vzcy50c1wiO1xuZXhwb3J0ICogYXMgZGF0YWJyaWNrcyBmcm9tIFwiLi9zcmMvZGF0YWJyaWNrcy50c1wiO1xuZXhwb3J0ICogYXMgZmlsZXNDYWNoZSBmcm9tIFwiLi9zcmMvZmlsZXMtY2FjaGUudHNcIjtcbmV4cG9ydCAqIGFzIGlkZW50aXR5IGZyb20gXCIuL3NyYy9pZGVudGl0eS50c1wiO1xuZXhwb3J0ICogYXMgaW50ZXJjZXB0b3IgZnJvbSBcIi4vc3JjL2ludGVyY2VwdG9yLnRzXCI7XG5leHBvcnQgKiBhcyBsYWtlYmFzZVJlc29sdmVyIGZyb20gXCIuL3NyYy9sYWtlYmFzZS1yZXNvbHZlci50c1wiO1xuZXhwb3J0ICogYXMgbWlncmF0aW9uIGZyb20gXCIuL3NyYy9taWdyYXRpb24udHNcIjtcbmV4cG9ydCAqIGFzIHBnYWRkcmVzcyBmcm9tIFwiLi9zcmMvcGdhZGRyZXNzLnRzXCI7XG5leHBvcnQgKiBhcyBwbHVnaW5FeGVjdXRpb24gZnJvbSBcIi4vc3JjL3BsdWdpbi1leGVjdXRpb24udHNcIjtcbmV4cG9ydCAqIGFzIHBsdWdpblJlZ2lzdHJ5IGZyb20gXCIuL3NyYy9wbHVnaW4tcmVnaXN0cnkudHNcIjtcbmV4cG9ydCAqIGFzIHByb3Zpc2lvbiBmcm9tIFwiLi9zcmMvcHJvdmlzaW9uLnRzXCI7XG5leHBvcnQgKiBhcyByZXF1ZXN0VGFncyBmcm9tIFwiLi9zcmMvcmVxdWVzdC10YWdzLnRzXCI7XG5leHBvcnQgKiBhcyB0b29sUHJvdmlkZXIgZnJvbSBcIi4vc3JjL3Rvb2wtcHJvdmlkZXIudHNcIjtcbmV4cG9ydCAqIGFzIHRvb2xraXRFbnRyaWVzIGZyb20gXCIuL3NyYy90b29sa2l0LWVudHJpZXMudHNcIjtcbmV4cG9ydCB0eXBlIHsgQXV0b0NvbmZpZ3VyZU1vZGUsIENyZWF0ZUFwcENvbmZpZywgRXhlY3V0aW9uQ29udGV4dExpa2UsIFdvcmtzcGFjZUNsaWVudExpa2UgfSBmcm9tIFwiLi9zcmMvYXBwa2l0LnRzXCI7XG5leHBvcnQgeyBidW5kbGVBcHBSZXNvdXJjZVNjaGVtYSwgZmxhdHRlbkFwcFlhbWxFbnYsIGZsYXR0ZW5BcHBFbnYsIGdldEJ1bmRsZVBhdGggfSBmcm9tIFwiLi9zcmMvYnVuZGxlLnRzXCI7XG5leHBvcnQgdHlwZSB7IEJ1bmRsZVZhbGlkYXRlSnNvbiwgQ29uZmlnRmlsZSwgQ29uZmlnTWFwVmFsdWUsIENvbmZpZ1NvdXJjZSwgUmVzb2x2ZUNvbmZpZ1ZhbHVlT3B0aW9ucyB9IGZyb20gXCIuL3NyYy9idW5kbGUudHNcIjtcbmV4cG9ydCB7IEFwcEtpdENoaWxkUHJvY2VzcyB9IGZyb20gXCIuL3NyYy9jaGlsZC1wcm9jZXNzLnRzXCI7XG5leHBvcnQgdHlwZSB7IEFwcEtpdFNwYXduQXJncywgQXBwS2l0Q2hpbGRQcm9jZXNzSGVhbHRoQ2hlY2tDb250ZXh0LCBBcHBLaXRDaGlsZFByb2Nlc3NIZWFsdGhDaGVjaywgQXBwS2l0Q2hpbGRQcm9jZXNzT3B0aW9ucywgQXBwS2l0Q2hpbGRQcm9jZXNzUnVuT3B0aW9ucyB9IGZyb20gXCIuL3NyYy9jaGlsZC1wcm9jZXNzLnRzXCI7XG5leHBvcnQgdHlwZSB7IENvbnRleHRMaWtlIH0gZnJvbSBcIi4vc3JjL2RhdGFicmlja3MudHNcIjtcbmV4cG9ydCB7IEZpbGVzQ2FjaGVNYW5hZ2VyLCBGaWxlc0NhY2hlUGx1Z2luIH0gZnJvbSBcIi4vc3JjL2ZpbGVzLWNhY2hlLnRzXCI7XG5leHBvcnQgdHlwZSB7IEZpbGVzQ2FjaGVQbHVnaW5Db25maWcsIEZpbGVzQ2FjaGVTY29wZSwgRmlsZXNDYWNoZVNvdXJjZUlkZW50aXR5LCBGaWxlc0NhY2hlRXhwb3J0cyB9IGZyb20gXCIuL3NyYy9maWxlcy1jYWNoZS50c1wiO1xuZXhwb3J0IHsgQUNDRVNTX1RPS0VOX0hFQURFUiwgVVNFUl9JRF9IRUFERVIsIFVTRVJfRU1BSUxfSEVBREVSLCBJREVOVElUWV9NT0RFUywgREVGQVVMVF9JREVOVElUWV9NT0RFIH0gZnJvbSBcIi4vc3JjL2lkZW50aXR5LnRzXCI7XG5leHBvcnQgdHlwZSB7IElkZW50aXR5TW9kZSwgSGVhZGVyQmVhcmluZyB9IGZyb20gXCIuL3NyYy9pZGVudGl0eS50c1wiO1xuZXhwb3J0IHsgTGlmZWN5Y2xlQnJpZGdlUGx1Z2luLCBsaWZlY3ljbGVCcmlkZ2UgfSBmcm9tIFwiLi9zcmMvaW50ZXJjZXB0b3IudHNcIjtcbmV4cG9ydCB0eXBlIHsgTGlmZWN5Y2xlRXZlbnQsIExpZmVjeWNsZUhhbmRsZXIsIFJlc29sdmVkQXBwRW52LCBJbnRlcmNlcHRvckNvbnRleHQsIEludGVyY2VwdG9yLCBJbnRlcmNlcHRvclJ1bnRpbWUgfSBmcm9tIFwiLi9zcmMvaW50ZXJjZXB0b3IudHNcIjtcbmV4cG9ydCB0eXBlIHsgTGFrZWJhc2VSZXNvbHZlcklucHV0cywgTGFrZWJhc2VDb25uZWN0aW9uIH0gZnJvbSBcIi4vc3JjL2xha2ViYXNlLXJlc29sdmVyLnRzXCI7XG5leHBvcnQgdHlwZSB7IE93bmVyc2hpcE1pZ3JhdGlvbkVycm9yT3B0aW9ucyB9IGZyb20gXCIuL3NyYy9taWdyYXRpb24udHNcIjtcbmV4cG9ydCB7IFNTTF9NT0RFUyB9IGZyb20gXCIuL3NyYy9wZ2FkZHJlc3MudHNcIjtcbmV4cG9ydCB0eXBlIHsgU3NsTW9kZSwgUGFyc2VkQWRkcmVzcywgTGFrZWJhc2VDb25uZWN0aW9uSW5wdXRzIH0gZnJvbSBcIi4vc3JjL3BnYWRkcmVzcy50c1wiO1xuZXhwb3J0IHR5cGUgeyBSdW5QbHVnaW5FeGVjdXRpb25PcHRpb25zIH0gZnJvbSBcIi4vc3JjL3BsdWdpbi1leGVjdXRpb24udHNcIjtcbmV4cG9ydCB0eXBlIHsgUGx1Z2luQ29udGV4dExpa2UgfSBmcm9tIFwiLi9zcmMvcGx1Z2luLXJlZ2lzdHJ5LnRzXCI7XG5leHBvcnQgdHlwZSB7IFJlcXVlc3RUYWdWYWx1ZSB9IGZyb20gXCIuL3NyYy9yZXF1ZXN0LXRhZ3MudHNcIjtcbmV4cG9ydCB7IFRvb2xSZWdpc3RyeVBsdWdpbiB9IGZyb20gXCIuL3NyYy90b29sLXByb3ZpZGVyLnRzXCI7XG5leHBvcnQgdHlwZSB7IEFnZW50VG9vbEV4ZWN1dGlvbkNvbnRleHQgfSBmcm9tIFwiLi9zcmMvdG9vbC1wcm92aWRlci50c1wiO1xuIl19
|
|
@@ -27,6 +27,7 @@ export interface L1CacheStorageOptions {
|
|
|
27
27
|
}
|
|
28
28
|
/** AppKit's internal persistent storage surface. */
|
|
29
29
|
export type PersistentStorageBase = CacheStorage & {
|
|
30
|
+
cleanupExpired?(): Promise<number>;
|
|
30
31
|
initialize(): Promise<void>;
|
|
31
32
|
initialized: boolean;
|
|
32
33
|
schemaName?: string;
|
|
@@ -47,6 +48,8 @@ export declare class L1CacheStorage implements CacheStorage {
|
|
|
47
48
|
isPersistent(): boolean;
|
|
48
49
|
healthCheck(): Promise<boolean>;
|
|
49
50
|
close(): Promise<void>;
|
|
51
|
+
/** Forward AppKit's runtime-only persistent cleanup hook when available. */
|
|
52
|
+
cleanupExpired(): Promise<number>;
|
|
50
53
|
private retain;
|
|
51
54
|
}
|
|
52
55
|
/**
|
|
@@ -73,6 +73,11 @@ export class L1CacheStorage {
|
|
|
73
73
|
this.entries.clear();
|
|
74
74
|
await this.storage.close();
|
|
75
75
|
}
|
|
76
|
+
/** Forward AppKit's runtime-only persistent cleanup hook when available. */
|
|
77
|
+
async cleanupExpired() {
|
|
78
|
+
const cleanup = this.storage.cleanupExpired;
|
|
79
|
+
return cleanup ? cleanup.call(this.storage) : 0;
|
|
80
|
+
}
|
|
76
81
|
retain(key, entry) {
|
|
77
82
|
const ttl = entry.expiry - Date.now();
|
|
78
83
|
if (ttl > 0)
|
|
@@ -227,4 +232,4 @@ export async function createSoftPersistentStorage(cache) {
|
|
|
227
232
|
return undefined;
|
|
228
233
|
}
|
|
229
234
|
}
|
|
230
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX2NhY2hlLXN0b3JhZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvX2NhY2hlLXN0b3JhZ2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFFSCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQzVDLE9BQU8sRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQzFDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxrQkFBa0IsRUFBb0IsTUFBTSxvQkFBb0IsQ0FBQztBQUM5RixPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNoRSxPQUFPLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUMvRCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ3JDLE9BQU8sRUFBRSw2QkFBNkIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRS9ELE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsZUFBZSxDQUFDLENBQUM7QUE2QjNDLElBQUkscUJBQXFCLEdBQW9ELElBQUksQ0FBQztBQUVsRixnRkFBZ0Y7QUFDaEYsTUFBTSxPQUFPLGNBQWM7SUFJTjtJQUhGLE9BQU8sQ0FBK0I7SUFFdkQsWUFDbUIsT0FBcUIsRUFDdEMsVUFBaUMsRUFBRTtRQURsQixZQUFPLEdBQVAsT0FBTyxDQUFjO1FBR3RDLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxRQUFRLENBQUM7WUFDMUIsR0FBRyxFQUFFLGFBQWEsQ0FBQyxPQUFPLENBQUMsVUFBVSxFQUFFLEtBQUssRUFBRSxZQUFZLENBQUM7WUFDM0QsT0FBTyxFQUFFLGFBQWEsQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLEVBQUUsR0FBRyxJQUFJLEdBQUcsSUFBSSxFQUFFLFVBQVUsQ0FBQztZQUN0RSxlQUFlLEVB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LFFBQVE7WUFDekIsVUFBVSxFQUFFLEtBQUssRUFBRSxPQUFPO1NBQzNCLENBQUMsQ0FBQztJQUNMLENBQUM7SUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1FBQ2IsTUFBTSxDQUFDLEtBQUssQ0FBQyxtQ0FBbUMsRUFBRTtZQUNoRCxLQUFLLEVBQUUsVUFBVSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUM7U0FDcEMsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxJQUFJLEVBQUUsQ0FBQztZQUNULE1BQU0sSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsR0FBRSxDQUFDLENBQUMsQ0FBQztRQUNuQyxDQUFDO1FBQ0QsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFNvZnQtZmFpbCBMYWtlYmFzZSBjYWNoZSBzdG9yYWdlIGZvciBBcHBLaXQncyBwZXJzaXN0ZW50IGNhY2hlLlxuICpcbiAqIEFwcEtpdCdzIGBQZXJzaXN0ZW50U3RvcmFnZS5pbml0aWFsaXplKClgIHJ1bnMgRERMIG1pZ3JhdGlvbnMgYW5kIHRocm93cyBvblxuICogYW55IHN0ZXAgZmFpbHVyZS4gV2l0aCBgY2FjaGUuc3RyaWN0UGVyc2lzdGVuY2U6IHRydWVgIHRoYXQgdGhyb3cgbWFrZXNcbiAqIGBDYWNoZU1hbmFnZXJgIHNpbGVudGx5IGRpc2FibGUgdGhlIGNhY2hlLiBUaGlzIHdyYXBzIHRoZSBzYW1lIHN0b3JhZ2UsXG4gKiBzdGlsbCBydW5zIGl0cyBtaWdyYXRpb25zLCBidXQgbG9ncyBhIGZhaWxlZCBzdGVwIGluc3RlYWQgb2YgdGhyb3dpbmcgc28gYVxuICogdXNhYmxlIHRhYmxlIGtlZXBzIHNlcnZpbmcuXG4gKlxuICogYFBlcnNpc3RlbnRTdG9yYWdlYCBpcyBub3Qgb24gQXBwS2l0J3MgcHVibGljIGV4cG9ydCBtYXAuIFRoZSBkZWVwIGxvYWQgaXNcbiAqIGxhenkgYW5kIGJlc3QtZWZmb3J0OiBpZiB0aGUgaW5zdGFsbGVkIEFwcEtpdCBsYXlvdXQgY2hhbmdlcywgdGhpcyByZXR1cm5zXG4gKiBgdW5kZWZpbmVkYCBhbmQgYGNyZWF0ZUFwcGAgbGVhdmVzIEFwcEtpdCBvbiBpdHMgZGVmYXVsdCBjYWNoZSBwYXRoLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBjcmVhdGVSZXF1aXJlIH0gZnJvbSBcIm5vZGU6bW9kdWxlXCI7XG5pbXBvcnQgeyBkaXJuYW1lLCBqb2luIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuaW1wb3J0IHsgY3JlYXRlTGFrZWJhc2VQb29sLCBnZXRXb3Jrc3BhY2VDbGllbnQsIHR5cGUgQ2FjaGVDb25maWcgfSBmcm9tIFwiQGRhdGFicmlja3MvYXBwa2l0XCI7XG5pbXBvcnQgeyBwb3N0Z3Jlc0Nvbm5lY3Rpb25PcHRpb25zIH0gZnJvbSBcIkBkYngtdG9vbHMvcG9zdGdyZXNcIjtcbmltcG9ydCB7IGVycm9yVXRpbHMsIGhhc2gsIGxvZyB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5pbXBvcnQgeyBMUlVDYWNoZSB9IGZyb20gXCJscnUtY2FjaGVcIjtcbmltcG9ydCB7IGhhbmRsZU93bmVyc2hpcE1pZ3JhdGlvbkVycm9yIH0gZnJvbSBcIi4vbWlncmF0aW9uLnRzXCI7XG5cbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJjYWNoZS1zdG9yYWdlXCIpO1xuXG50eXBlIExha2ViYXNlUG9vbCA9IFJldHVyblR5cGU8dHlwZW9mIGNyZWF0ZUxha2ViYXNlUG9vbD47XG50eXBlIENhY2hlU3RvcmFnZSA9IE5vbk51bGxhYmxlPENhY2hlQ29uZmlnW1wic3RvcmFnZVwiXT47XG5cbmludGVyZmFjZSBDYWNoZUVudHJ5PFQgPSB1bmtub3duPiB7XG4gIGV4cGlyeTogbnVtYmVyO1xuICB2YWx1ZTogVDtcbn1cblxuLyoqIEJvdW5kcyBmb3IgdGhlIHByb2Nlc3MtbG9jYWwgY2FjaGUgbGF5ZXJlZCBvdmVyIHBlcnNpc3RlbnQgQXBwS2l0IHN0b3JhZ2UuICovXG5leHBvcnQgaW50ZXJmYWNlIEwxQ2FjaGVTdG9yYWdlT3B0aW9ucyB7XG4gIG1heEJ5dGVzPzogbnVtYmVyO1xuICBtYXhFbnRyaWVzPzogbnVtYmVyO1xufVxuXG4vKiogQXBwS2l0J3MgaW50ZXJuYWwgcGVyc2lzdGVudCBzdG9yYWdlIHN1cmZhY2UuICovXG5leHBvcnQgdHlwZSBQZXJzaXN0ZW50U3RvcmFnZUJhc2UgPSBDYWNoZVN0b3JhZ2UgJiB7XG4gIGluaXRpYWxpemUoKTogUHJvbWlzZTx2b2lkPjtcbiAgaW5pdGlhbGl6ZWQ6IGJvb2xlYW47XG4gIHNjaGVtYU5hbWU/OiBzdHJpbmc7XG4gIHRhYmxlTmFtZT86IHN0cmluZztcbn07XG5cbnR5cGUgUGVyc2lzdGVudFN0b3JhZ2VDb25zdHJ1Y3RvciA9IG5ldyAoXG4gIGNvbmZpZzogQ2FjaGVDb25maWcsXG4gIHBvb2w6IExha2ViYXNlUG9vbCxcbikgPT4gUGVyc2lzdGVudFN0b3JhZ2VCYXNlO1xuXG5sZXQgcGVyc2lzdGVudFN0b3JhZ2VDdG9yOiBQZXJzaXN0ZW50U3RvcmFnZUNvbnN0cnVjdG9yIHwgdW5kZWZpbmVkIHwgbnVsbCA9IG51bGw7XG5cbi8qKiBQcm9jZXNzLWxvY2FsIExSVSB0aGF0IGF2b2lkcyBhIHBlcnNpc3RlbnQgY2FjaGUgcXVlcnkgb24gZXZlcnkgd2FybSBoaXQuICovXG5leHBvcnQgY2xhc3MgTDFDYWNoZVN0b3JhZ2UgaW1wbGVtZW50cyBDYWNoZVN0b3JhZ2Uge1xuICBwcml2YXRlIHJlYWRvbmx5IGVudHJpZXM6IExSVUNhY2hlPHN0cmluZywgQ2FjaGVFbnRyeT47XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSBzdG9yYWdlOiBDYWNoZVN0b3JhZ2UsXG4gICAgb3B0aW9uczogTDFDYWNoZVN0b3JhZ2VPcHRpb25zID0ge30sXG4gICkge1xuICAgIHRoaXMuZW50cmllcyA9IG5ldyBMUlVDYWNoZSh7XG4gICAgICBtYXg6IHBvc2l0aXZlQm91bmQob3B0aW9ucy5tYXhFbnRyaWVzLCAxXzAwMCwgXCJtYXhFbnRyaWVzXCIpLFxuICAgICAgbWF4U2l6ZTogcG9zaXRpdmVCb3VuZChvcHRpb25zLm1heEJ5dGVzLCA2NCAqIDEwMjQgKiAxMDI0LCBcIm1heEJ5dGVzXCIpLFxuICAgICAgc2l6ZUNhbGN1bGF0aW9uOiAoZW50cnksIGtleSkgPT4gcmV0YWluZWRTaXplKGtleSwgZW50cnkpLFxuICAgIH0pO1xuICB9XG5cbiAgYXN5bmMgZ2V0PFQ+KGtleTogc3RyaW5nKTogUHJvbWlzZTxDYWNoZUVudHJ5PFQ+IHwgbnVsbD4ge1xuICAgIGNvbnN0IGxvY2FsID0gdGhpcy5lbnRyaWVzLmdldChrZXkpO1xuICAgIGlmIChsb2NhbCkgcmV0dXJuIGxvY2FsIGFzIENhY2hlRW50cnk8VD47XG4gICAgY29uc3QgcGVyc2lzdGVkID0gYXdhaXQgdGhpcy5zdG9yYWdlLmdldDxUPihrZXkpO1xuICAgIGlmIChwZXJzaXN0ZWQgJiYgcGVyc2lzdGVkLmV4cGlyeSA+IERhdGUubm93KCkpIHRoaXMucmV0YWluKGtleSwgcGVyc2lzdGVkKTtcbiAgICByZXR1cm4gcGVyc2lzdGVkO1xuICB9XG5cbiAgYXN5bmMgc2V0PFQ+KGtleTogc3RyaW5nLCBlbnRyeTogQ2FjaGVFbnRyeTxUPik6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMuc3RvcmFnZS5zZXQoa2V5LCBlbnRyeSk7XG4gICAgdGhpcy5yZXRhaW4oa2V5LCBlbnRyeSk7XG4gIH1cblxuICBhc3luYyBkZWxldGUoa2V5OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLnN0b3JhZ2UuZGVsZXRlKGtleSk7XG4gICAgdGhpcy5lbnRyaWVzLmRlbGV0ZShrZXkpO1xuICB9XG5cbiAgYXN5bmMgY2xlYXIoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5zdG9yYWdlLmNsZWFyKCk7XG4gICAgdGhpcy5lbnRyaWVzLmNsZWFyKCk7XG4gIH1cblxuICBhc3luYyBoYXMoa2V5OiBzdHJpbmcpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBpZiAodGhpcy5lbnRyaWVzLmhhcyhrZXkpKSByZXR1cm4gdHJ1ZTtcbiAgICByZXR1cm4gdGhpcy5zdG9yYWdlLmhhcyhrZXkpO1xuICB9XG5cbiAgc2l6ZSgpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIHJldHVybiB0aGlzLnN0b3JhZ2Uuc2l6ZSgpO1xuICB9XG5cbiAgaXNQZXJzaXN0ZW50KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnN0b3JhZ2UuaXNQZXJzaXN0ZW50KCk7XG4gIH1cblxuICBoZWFsdGhDaGVjaygpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICByZXR1cm4gdGhpcy5zdG9yYWdlLmhlYWx0aENoZWNrKCk7XG4gIH1cblxuICBhc3luYyBjbG9zZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aGlzLmVudHJpZXMuY2xlYXIoKTtcbiAgICBhd2FpdCB0aGlzLnN0b3JhZ2UuY2xvc2UoKTtcbiAgfVxuXG4gIHByaXZhdGUgcmV0YWluPFQ+KGtleTogc3RyaW5nLCBlbnRyeTogQ2FjaGVFbnRyeTxUPik6IHZvaWQge1xuICAgIGNvbnN0IHR0bCA9IGVudHJ5LmV4cGlyeSAtIERhdGUubm93KCk7XG4gICAgaWYgKHR0bCA+IDApIHRoaXMuZW50cmllcy5zZXQoa2V5LCBlbnRyeSwgeyB0dGwgfSk7XG4gIH1cbn1cblxuZnVuY3Rpb24gcG9zaXRpdmVCb3VuZCh2YWx1ZTogbnVtYmVyIHwgdW5kZWZpbmVkLCBmYWxsYmFjazogbnVtYmVyLCBuYW1lOiBzdHJpbmcpOiBudW1iZXIge1xuICBjb25zdCByZXNvbHZlZCA9IHZhbHVlID8/IGZhbGxiYWNrO1xuICBpZiAoIU51bWJlci5pc0Zpbml0ZShyZXNvbHZlZCkgfHwgcmVzb2x2ZWQgPD0gMCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKGAke25hbWV9IG11c3QgYmUgYSBmaW5pdGUgcG9zaXRpdmUgbnVtYmVyYCk7XG4gIH1cbiAgcmV0dXJuIE1hdGguZmxvb3IocmVzb2x2ZWQpO1xufVxuXG5mdW5jdGlvbiByZXRhaW5lZFNpemUoa2V5OiBzdHJpbmcsIGVudHJ5OiBDYWNoZUVudHJ5KTogbnVtYmVyIHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gQnVmZmVyLmJ5dGVMZW5ndGgoa2V5KSArIEJ1ZmZlci5ieXRlTGVuZ3RoKEpTT04uc3RyaW5naWZ5KGVudHJ5KSk7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUjtcbiAgfVxufVxuXG4vKipcbiAqIExhemlseSByZXNvbHZlIEFwcEtpdCdzIGludGVybmFsIGBQZXJzaXN0ZW50U3RvcmFnZWAgY29uc3RydWN0b3IuIGBudWxsYFxuICogbWVhbnMgbm90IGF0dGVtcHRlZCB5ZXQ7IGB1bmRlZmluZWRgIG1lYW5zIHRoZSBsb29rdXAgYWxyZWFkeSBmYWlsZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBsb2FkUGVyc2lzdGVudFN0b3JhZ2UoKTogUGVyc2lzdGVudFN0b3JhZ2VDb25zdHJ1Y3RvciB8IHVuZGVmaW5lZCB7XG4gIGlmIChwZXJzaXN0ZW50U3RvcmFnZUN0b3IgIT09IG51bGwpIHtcbiAgICByZXR1cm4gcGVyc2lzdGVudFN0b3JhZ2VDdG9yO1xuICB9XG4gIHRyeSB7XG4gICAgY29uc3QgcmVxdWlyZSA9IGNyZWF0ZVJlcXVpcmUoaW1wb3J0Lm1ldGEudXJsKTtcbiAgICBjb25zdCBtb2R1bGVQYXRoID0gam9pbihcbiAgICAgIGRpcm5hbWUocmVxdWlyZS5yZXNvbHZlKFwiQGRhdGFicmlja3MvYXBwa2l0XCIpKSxcbiAgICAgIFwiY2FjaGUvc3RvcmFnZS9wZXJzaXN0ZW50LmpzXCIsXG4gICAgKTtcbiAgICBjb25zdCBsb2FkZWQgPSByZXF1aXJlKG1vZHVsZVBhdGgpLlBlcnNpc3RlbnRTdG9yYWdlIGFzXG4gICAgICBQZXJzaXN0ZW50U3RvcmFnZUNvbnN0cnVjdG9yIHwgdW5kZWZpbmVkO1xuICAgIGlmICh0eXBlb2YgbG9hZGVkICE9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgIGxvZ2dlci5kZWJ1ZyhcInNvZnQgcGVyc2lzdGVudCBjYWNoZSBza2lwcGVkIChQZXJzaXN0ZW50U3RvcmFnZSBtaXNzaW5nKVwiKTtcbiAgICAgIHBlcnNpc3RlbnRTdG9yYWdlQ3RvciA9IHVuZGVmaW5lZDtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIHBlcnNpc3RlbnRTdG9yYWdlQ3RvciA9IGxvYWRlZDtcbiAgICByZXR1cm4gbG9hZGVkO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBsb2dnZXIuZGVidWcoXCJzb2Z0IHBlcnNpc3RlbnQgY2FjaGUgc2tpcHBlZCAoUGVyc2lzdGVudFN0b3JhZ2UgdW5hdmFpbGFibGUpXCIsIHtcbiAgICAgIGVycm9yOiBlcnJvclV0aWxzLmVycm9yTWVzc2FnZShlcnIpLFxuICAgIH0pO1xuICAgIHBlcnNpc3RlbnRTdG9yYWdlQ3RvciA9IHVuZGVmaW5lZDtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG59XG5cbi8qKlxuICogV2hldGhlciBhbiBleGlzdGluZyBjYWNoZSB0YWJsZSBiZWxvbmdzIHRvIGFub3RoZXIgcm9sZS5cbiAqXG4gKiBQb3N0Z3JlU1FMIGFsbG93cyBncmFudGVkIHJlYWRzL3dyaXRlcyBidXQgcmVzZXJ2ZXMgaW5kZXggRERMIGZvciB0aGUgdGFibGVcbiAqIG93bmVyLiBTa2lwIEFwcEtpdCBtaWdyYXRpb25zIGluIHRoYXQgY2FzZTsge0BsaW5rIHByb2JlU3RvcmFnZX0gc3RpbGwgcHJvdmVzXG4gKiB0aGUgZXhpc3RpbmcgdGFibGUgY2FuIHNlcnZlIHRoZSBjYWNoZSBiZWZvcmUgaXQgaXMgYWNjZXB0ZWQuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHRhYmxlT3duZWRCeUFub3RoZXJSb2xlKFxuICBzdG9yYWdlOiBQZXJzaXN0ZW50U3RvcmFnZUJhc2UsXG4gIHBvb2w6IExha2ViYXNlUG9vbCxcbik6IFByb21pc2U8Ym9vbGVhbj4ge1xuICBpZiAoIXN0b3JhZ2Uuc2NoZW1hTmFtZSB8fCAhc3RvcmFnZS50YWJsZU5hbWUpIHJldHVybiBmYWxzZTtcbiAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcG9vbC5xdWVyeShcbiAgICBgU0VMRUNUIHBnX2dldF91c2VyYnlpZChjLnJlbG93bmVyKSA9IGN1cnJlbnRfdXNlciBBUyBvd25lZFxuICAgICBGUk9NIHBnX2NsYXNzIGNcbiAgICAgSk9JTiBwZ19uYW1lc3BhY2UgbiBPTiBuLm9pZCA9IGMucmVsbmFtZXNwYWNlXG4gICAgIFdIRVJFIG4ubnNwbmFtZSA9ICQxIEFORCBjLnJlbG5hbWUgPSAkMiBBTkQgYy5yZWxraW5kIElOICgncicsICdwJylgLFxuICAgIFtzdG9yYWdlLnNjaGVtYU5hbWUsIHN0b3JhZ2UudGFibGVOYW1lXSxcbiAgKTtcbiAgaWYgKHJlc3VsdC5yb3dzWzBdPy5vd25lZCAhPT0gZmFsc2UpIHJldHVybiBmYWxzZTtcbiAgbG9nZ2VyLndhcm4oXCJwZXJzaXN0ZW50IGNhY2hlIG1pZ3JhdGlvbnMgc2tpcHBlZCAodGFibGUgb3duZWQgYnkgYW5vdGhlciByb2xlKVwiLCB7XG4gICAgc2NoZW1hOiBzdG9yYWdlLnNjaGVtYU5hbWUsXG4gICAgdGFibGU6IHN0b3JhZ2UudGFibGVOYW1lLFxuICB9KTtcbiAgcmV0dXJuIHRydWU7XG59XG5cbi8qKiBTb2Z0ZW4gYGluaXRpYWxpemUoKWAgc28gYW4gb3duZXJzaGlwLW9ubHkgbWlncmF0aW9uIGZhaWx1cmUgaXMgbm90IGZhdGFsLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNvZnRlbkluaXRpYWxpemUoXG4gIHN0b3JhZ2U6IFBlcnNpc3RlbnRTdG9yYWdlQmFzZSxcbiAgc2tpcE1pZ3JhdGlvbnM/OiAoKSA9PiBQcm9taXNlPGJvb2xlYW4+LFxuKTogdm9pZCB7XG4gIGNvbnN0IG9yaWdpbmFsSW5pdGlhbGl6ZSA9IHN0b3JhZ2UuaW5pdGlhbGl6ZS5iaW5kKHN0b3JhZ2UpO1xuICBsZXQgc29mdEluaXRQcm9taXNlOiBQcm9taXNlPHZvaWQ+IHwgdW5kZWZpbmVkO1xuXG4gIHN0b3JhZ2UuaW5pdGlhbGl6ZSA9IGFzeW5jICgpID0+IHtcbiAgICBpZiAoc3RvcmFnZS5pbml0aWFsaXplZCkgcmV0dXJuO1xuICAgIHNvZnRJbml0UHJvbWlzZSA/Pz0gKGFzeW5jICgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGlmICghKGF3YWl0IHNraXBNaWdyYXRpb25zPy4oKSkpIGF3YWl0IG9yaWdpbmFsSW5pdGlhbGl6ZSgpO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICAhaGFuZGxlT3duZXJzaGlwTWlncmF0aW9uRXJyb3IoZXJyLCB7XG4gICAgICAgICAgICBzY29wZTogXCJjYWNoZS1zdG9yYWdlXCIsXG4gICAgICAgICAgICBsb2dnZXIsXG4gICAgICAgICAgICBldmVudDogXCJwZXJzaXN0ZW50IGNhY2hlIG1pZ3JhdGlvbiBmYWlsZWRcIixcbiAgICAgICAgICB9KVxuICAgICAgICApIHtcbiAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KSgpO1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBzb2Z0SW5pdFByb21pc2U7XG4gICAgICBzdG9yYWdlLmluaXRpYWxpemVkID0gdHJ1ZTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHNvZnRJbml0UHJvbWlzZSA9IHVuZGVmaW5lZDtcbiAgICAgIHRocm93IGVycjtcbiAgICB9XG4gIH07XG59XG5cbi8qKiBWZXJpZnkgdGhlIG1pZ3JhdGVkIGNhY2hlIHRhYmxlIGNhbiBzZXJ2ZSB0aGUgcmVhZHMgYW5kIHdyaXRlcyBBcHBLaXQgbmVlZHMuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcHJvYmVTdG9yYWdlKHN0b3JhZ2U6IFBlcnNpc3RlbnRTdG9yYWdlQmFzZSk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBrZXkgPSBgZGJ4LXRvb2xzOmNhY2hlLXByb2JlOiR7aGFzaC5pZCgpfWA7XG4gIHRyeSB7XG4gICAgYXdhaXQgc3RvcmFnZS5zZXQoa2V5LCB7IHZhbHVlOiBrZXksIGV4cGlyeTogRGF0ZS5ub3coKSArIDYwXzAwMCB9KTtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBzdG9yYWdlLmdldChrZXkpO1xuICAgIGlmIChyZXN1bHQ/LnZhbHVlICE9PSBrZXkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcInBlcnNpc3RlbnQgY2FjaGUgcHJvYmUgcmV0dXJuZWQgYW4gdW5leHBlY3RlZCB2YWx1ZVwiKTtcbiAgICB9XG4gIH0gZmluYWxseSB7XG4gICAgYXdhaXQgc3RvcmFnZS5kZWxldGUoa2V5KS5jYXRjaCgoKSA9PiB1bmRlZmluZWQpO1xuICB9XG59XG5cbi8qKlxuICogQnVpbGQgYSBzb2Z0LWZhaWwgTGFrZWJhc2UgY2FjaGUgc3RvcmFnZSB3aGVuIGEgcG9vbCBjYW4gYmUgY3JlYXRlZCBhbmRcbiAqIEFwcEtpdCdzIFBlcnNpc3RlbnRTdG9yYWdlIGNhbiBiZSBsb2FkZWQuIFJldHVybnMgYHVuZGVmaW5lZGAgb3RoZXJ3aXNlIHNvXG4gKiBBcHBLaXQgY2FuIGZhbGwgdGhyb3VnaCB0byBpdHMgbm9ybWFsIGNhY2hlIHBhdGguXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVTb2Z0UGVyc2lzdGVudFN0b3JhZ2UoXG4gIGNhY2hlOiBDYWNoZUNvbmZpZyB8IHVuZGVmaW5lZCxcbik6IFByb21pc2U8Q2FjaGVTdG9yYWdlIHwgdW5kZWZpbmVkPiB7XG4gIGNvbnN0IFBlcnNpc3RlbnRTdG9yYWdlID0gbG9hZFBlcnNpc3RlbnRTdG9yYWdlKCk7XG4gIGlmICghUGVyc2lzdGVudFN0b3JhZ2UpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgbGV0IHBvb2w6IExha2ViYXNlUG9vbCB8IHVuZGVmaW5lZDtcbiAgdHJ5IHtcbiAgICBjb25zdCBjcmVhdGVkUG9vbCA9IGNyZWF0ZUxha2ViYXNlUG9vbChcbiAgICAgIHBvc3RncmVzQ29ubmVjdGlvbk9wdGlvbnMoeyB3b3Jrc3BhY2VDbGllbnQ6IGdldFdvcmtzcGFjZUNsaWVudCh7fSkgfSksXG4gICAgKTtcbiAgICBwb29sID0gY3JlYXRlZFBvb2w7XG4gICAgY29uc3Qgc3RvcmFnZSA9IG5ldyBQZXJzaXN0ZW50U3RvcmFnZShjYWNoZSA/PyB7fSwgY3JlYXRlZFBvb2wpO1xuICAgIHNvZnRlbkluaXRpYWxpemUoc3RvcmFnZSwgKCkgPT4gdGFibGVPd25lZEJ5QW5vdGhlclJvbGUoc3RvcmFnZSwgY3JlYXRlZFBvb2wpKTtcbiAgICBpZiAoIShhd2FpdCBzdG9yYWdlLmhlYWx0aENoZWNrKCkpKSB7XG4gICAgICBhd2FpdCBzdG9yYWdlLmNsb3NlKCkuY2F0Y2goKCkgPT4ge30pO1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgYXdhaXQgc3RvcmFnZS5pbml0aWFsaXplKCk7XG4gICAgYXdhaXQgcHJvYmVTdG9yYWdlKHN0b3JhZ2UpO1xuICAgIHJldHVybiBuZXcgTDFDYWNoZVN0b3JhZ2Uoc3RvcmFnZSwge1xuICAgICAgbWF4Qnl0ZXM6IGNhY2hlPy5tYXhCeXRlcyxcbiAgICAgIG1heEVudHJpZXM6IGNhY2hlPy5tYXhTaXplLFxuICAgIH0pO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBsb2dnZXIuZGVidWcoXCJzb2Z0IHBlcnNpc3RlbnQgY2FjaGUgdW5hdmFpbGFibGVcIiwge1xuICAgICAgZXJyb3I6IGVycm9yVXRpbHMuZXJyb3JNZXNzYWdlKGVyciksXG4gICAgfSk7XG4gICAgaWYgKHBvb2wpIHtcbiAgICAgIGF3YWl0IHBvb2wuZW5kKCkuY2F0Y2goKCkgPT4ge30pO1xuICAgIH1cbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG59XG4iXX0=
|
|
235
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX2NhY2hlLXN0b3JhZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvX2NhY2hlLXN0b3JhZ2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFFSCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQzVDLE9BQU8sRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQzFDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxrQkFBa0IsRUFBb0IsTUFBTSxvQkFBb0IsQ0FBQztBQUM5RixPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNoRSxPQUFPLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUMvRCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ3JDLE9BQU8sRUFBRSw2QkFBNkIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRS9ELE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsZUFBZSxDQUFDLENBQUM7QUE4QjNDLElBQUkscUJBQXFCLEdBQW9ELElBQUksQ0FBQztBQUVsRixnRkFBZ0Y7QUFDaEYsTUFBTSxPQUFPLGNBQWM7SUFJTjtJQUhGLE9BQU8sQ0FBK0I7SUFFdkQsWUFDbUIsT0FBcUIsRUFDdEMsVUFBaUMsRUFBRTtRQURsQixZQUFPLEdBQVAsT0FBTyxDQUFjO1FBR3RDLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxRQUFRLENBQUM7WUFDMUIsR0FBRyxFQUFFLGFBQWEsQ0FBQyxPQUFPLENBQUMsVUFBVSxFQUFFLEtBQUssRUFBRSxZQUFZLENBQUM7WUFDM0QsT0FBTyxFQUFFLGFBQWEsQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLEVBQUUsR0FBRyxJQUFJLEdBQUcsSUFBSSxFQUFFLFVBQVUsQ0FBQztZQUN0RSxlQUFlLEVB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RyxFQUFFLEdBQUUsQ0FBQyxDQUFDLENBQUM7WUFDdEMsT0FBTyxTQUFTLENBQUM7UUFDbkIsQ0FBQztRQUNELE1BQU0sT0FBTyxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQzNCLE1BQU0sWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzVCLE9BQU8sSUFBSSxjQUFjLENBQUMsT0FBTyxFQUFFO1lBQ2pDLFFBQVEsRUFBRSxLQUFLLEVBQUUsUUFBUTtZQUN6QixVQUFVLEVBQUUsS0FBSyxFQUFFLE9BQU87U0FDM0IsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDYixNQUFNLENBQUMsS0FBSyxDQUFDLG1DQUFtQyxFQUFFO1lBQ2hELEtBQUssRUFBRSxVQUFVLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQztTQUNwQyxDQUFDLENBQUM7UUFDSCxJQUFJLElBQUksRUFBRSxDQUFDO1lBQ1QsTUFBTSxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxHQUFFLENBQUMsQ0FBQyxDQUFDO1FBQ25DLENBQUM7UUFDRCxPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogU29mdC1mYWlsIExha2ViYXNlIGNhY2hlIHN0b3JhZ2UgZm9yIEFwcEtpdCdzIHBlcnNpc3RlbnQgY2FjaGUuXG4gKlxuICogQXBwS2l0J3MgYFBlcnNpc3RlbnRTdG9yYWdlLmluaXRpYWxpemUoKWAgcnVucyBEREwgbWlncmF0aW9ucyBhbmQgdGhyb3dzIG9uXG4gKiBhbnkgc3RlcCBmYWlsdXJlLiBXaXRoIGBjYWNoZS5zdHJpY3RQZXJzaXN0ZW5jZTogdHJ1ZWAgdGhhdCB0aHJvdyBtYWtlc1xuICogYENhY2hlTWFuYWdlcmAgc2lsZW50bHkgZGlzYWJsZSB0aGUgY2FjaGUuIFRoaXMgd3JhcHMgdGhlIHNhbWUgc3RvcmFnZSxcbiAqIHN0aWxsIHJ1bnMgaXRzIG1pZ3JhdGlvbnMsIGJ1dCBsb2dzIGEgZmFpbGVkIHN0ZXAgaW5zdGVhZCBvZiB0aHJvd2luZyBzbyBhXG4gKiB1c2FibGUgdGFibGUga2VlcHMgc2VydmluZy5cbiAqXG4gKiBgUGVyc2lzdGVudFN0b3JhZ2VgIGlzIG5vdCBvbiBBcHBLaXQncyBwdWJsaWMgZXhwb3J0IG1hcC4gVGhlIGRlZXAgbG9hZCBpc1xuICogbGF6eSBhbmQgYmVzdC1lZmZvcnQ6IGlmIHRoZSBpbnN0YWxsZWQgQXBwS2l0IGxheW91dCBjaGFuZ2VzLCB0aGlzIHJldHVybnNcbiAqIGB1bmRlZmluZWRgIGFuZCBgY3JlYXRlQXBwYCBsZWF2ZXMgQXBwS2l0IG9uIGl0cyBkZWZhdWx0IGNhY2hlIHBhdGguXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IGNyZWF0ZVJlcXVpcmUgfSBmcm9tIFwibm9kZTptb2R1bGVcIjtcbmltcG9ydCB7IGRpcm5hbWUsIGpvaW4gfSBmcm9tIFwibm9kZTpwYXRoXCI7XG5pbXBvcnQgeyBjcmVhdGVMYWtlYmFzZVBvb2wsIGdldFdvcmtzcGFjZUNsaWVudCwgdHlwZSBDYWNoZUNvbmZpZyB9IGZyb20gXCJAZGF0YWJyaWNrcy9hcHBraXRcIjtcbmltcG9ydCB7IHBvc3RncmVzQ29ubmVjdGlvbk9wdGlvbnMgfSBmcm9tIFwiQGRieC10b29scy9wb3N0Z3Jlc1wiO1xuaW1wb3J0IHsgZXJyb3JVdGlscywgaGFzaCwgbG9nIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB7IExSVUNhY2hlIH0gZnJvbSBcImxydS1jYWNoZVwiO1xuaW1wb3J0IHsgaGFuZGxlT3duZXJzaGlwTWlncmF0aW9uRXJyb3IgfSBmcm9tIFwiLi9taWdyYXRpb24udHNcIjtcblxuY29uc3QgbG9nZ2VyID0gbG9nLmxvZ2dlcihcImNhY2hlLXN0b3JhZ2VcIik7XG5cbnR5cGUgTGFrZWJhc2VQb29sID0gUmV0dXJuVHlwZTx0eXBlb2YgY3JlYXRlTGFrZWJhc2VQb29sPjtcbnR5cGUgQ2FjaGVTdG9yYWdlID0gTm9uTnVsbGFibGU8Q2FjaGVDb25maWdbXCJzdG9yYWdlXCJdPjtcblxuaW50ZXJmYWNlIENhY2hlRW50cnk8VCA9IHVua25vd24+IHtcbiAgZXhwaXJ5OiBudW1iZXI7XG4gIHZhbHVlOiBUO1xufVxuXG4vKiogQm91bmRzIGZvciB0aGUgcHJvY2Vzcy1sb2NhbCBjYWNoZSBsYXllcmVkIG92ZXIgcGVyc2lzdGVudCBBcHBLaXQgc3RvcmFnZS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTDFDYWNoZVN0b3JhZ2VPcHRpb25zIHtcbiAgbWF4Qnl0ZXM/OiBudW1iZXI7XG4gIG1heEVudHJpZXM/OiBudW1iZXI7XG59XG5cbi8qKiBBcHBLaXQncyBpbnRlcm5hbCBwZXJzaXN0ZW50IHN0b3JhZ2Ugc3VyZmFjZS4gKi9cbmV4cG9ydCB0eXBlIFBlcnNpc3RlbnRTdG9yYWdlQmFzZSA9IENhY2hlU3RvcmFnZSAmIHtcbiAgY2xlYW51cEV4cGlyZWQ/KCk6IFByb21pc2U8bnVtYmVyPjtcbiAgaW5pdGlhbGl6ZSgpOiBQcm9taXNlPHZvaWQ+O1xuICBpbml0aWFsaXplZDogYm9vbGVhbjtcbiAgc2NoZW1hTmFtZT86IHN0cmluZztcbiAgdGFibGVOYW1lPzogc3RyaW5nO1xufTtcblxudHlwZSBQZXJzaXN0ZW50U3RvcmFnZUNvbnN0cnVjdG9yID0gbmV3IChcbiAgY29uZmlnOiBDYWNoZUNvbmZpZyxcbiAgcG9vbDogTGFrZWJhc2VQb29sLFxuKSA9PiBQZXJzaXN0ZW50U3RvcmFnZUJhc2U7XG5cbmxldCBwZXJzaXN0ZW50U3RvcmFnZUN0b3I6IFBlcnNpc3RlbnRTdG9yYWdlQ29uc3RydWN0b3IgfCB1bmRlZmluZWQgfCBudWxsID0gbnVsbDtcblxuLyoqIFByb2Nlc3MtbG9jYWwgTFJVIHRoYXQgYXZvaWRzIGEgcGVyc2lzdGVudCBjYWNoZSBxdWVyeSBvbiBldmVyeSB3YXJtIGhpdC4gKi9cbmV4cG9ydCBjbGFzcyBMMUNhY2hlU3RvcmFnZSBpbXBsZW1lbnRzIENhY2hlU3RvcmFnZSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgZW50cmllczogTFJVQ2FjaGU8c3RyaW5nLCBDYWNoZUVudHJ5PjtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IHN0b3JhZ2U6IENhY2hlU3RvcmFnZSxcbiAgICBvcHRpb25zOiBMMUNhY2hlU3RvcmFnZU9wdGlvbnMgPSB7fSxcbiAgKSB7XG4gICAgdGhpcy5lbnRyaWVzID0gbmV3IExSVUNhY2hlKHtcbiAgICAgIG1heDogcG9zaXRpdmVCb3VuZChvcHRpb25zLm1heEVudHJpZXMsIDFfMDAwLCBcIm1heEVudHJpZXNcIiksXG4gICAgICBtYXhTaXplOiBwb3NpdGl2ZUJvdW5kKG9wdGlvbnMubWF4Qnl0ZXMsIDY0ICogMTAyNCAqIDEwMjQsIFwibWF4Qnl0ZXNcIiksXG4gICAgICBzaXplQ2FsY3VsYXRpb246IChlbnRyeSwga2V5KSA9PiByZXRhaW5lZFNpemUoa2V5LCBlbnRyeSksXG4gICAgfSk7XG4gIH1cblxuICBhc3luYyBnZXQ8VD4oa2V5OiBzdHJpbmcpOiBQcm9taXNlPENhY2hlRW50cnk8VD4gfCBudWxsPiB7XG4gICAgY29uc3QgbG9jYWwgPSB0aGlzLmVudHJpZXMuZ2V0KGtleSk7XG4gICAgaWYgKGxvY2FsKSByZXR1cm4gbG9jYWwgYXMgQ2FjaGVFbnRyeTxUPjtcbiAgICBjb25zdCBwZXJzaXN0ZWQgPSBhd2FpdCB0aGlzLnN0b3JhZ2UuZ2V0PFQ+KGtleSk7XG4gICAgaWYgKHBlcnNpc3RlZCAmJiBwZXJzaXN0ZWQuZXhwaXJ5ID4gRGF0ZS5ub3coKSkgdGhpcy5yZXRhaW4oa2V5LCBwZXJzaXN0ZWQpO1xuICAgIHJldHVybiBwZXJzaXN0ZWQ7XG4gIH1cblxuICBhc3luYyBzZXQ8VD4oa2V5OiBzdHJpbmcsIGVudHJ5OiBDYWNoZUVudHJ5PFQ+KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5zdG9yYWdlLnNldChrZXksIGVudHJ5KTtcbiAgICB0aGlzLnJldGFpbihrZXksIGVudHJ5KTtcbiAgfVxuXG4gIGFzeW5jIGRlbGV0ZShrZXk6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMuc3RvcmFnZS5kZWxldGUoa2V5KTtcbiAgICB0aGlzLmVudHJpZXMuZGVsZXRlKGtleSk7XG4gIH1cblxuICBhc3luYyBjbGVhcigpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLnN0b3JhZ2UuY2xlYXIoKTtcbiAgICB0aGlzLmVudHJpZXMuY2xlYXIoKTtcbiAgfVxuXG4gIGFzeW5jIGhhcyhrZXk6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGlmICh0aGlzLmVudHJpZXMuaGFzKGtleSkpIHJldHVybiB0cnVlO1xuICAgIHJldHVybiB0aGlzLnN0b3JhZ2UuaGFzKGtleSk7XG4gIH1cblxuICBzaXplKCk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgcmV0dXJuIHRoaXMuc3RvcmFnZS5zaXplKCk7XG4gIH1cblxuICBpc1BlcnNpc3RlbnQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuc3RvcmFnZS5pc1BlcnNpc3RlbnQoKTtcbiAgfVxuXG4gIGhlYWx0aENoZWNrKCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIHJldHVybiB0aGlzLnN0b3JhZ2UuaGVhbHRoQ2hlY2soKTtcbiAgfVxuXG4gIGFzeW5jIGNsb3NlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMuZW50cmllcy5jbGVhcigpO1xuICAgIGF3YWl0IHRoaXMuc3RvcmFnZS5jbG9zZSgpO1xuICB9XG5cbiAgLyoqIEZvcndhcmQgQXBwS2l0J3MgcnVudGltZS1vbmx5IHBlcnNpc3RlbnQgY2xlYW51cCBob29rIHdoZW4gYXZhaWxhYmxlLiAqL1xuICBhc3luYyBjbGVhbnVwRXhwaXJlZCgpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IGNsZWFudXAgPSAoXG4gICAgICB0aGlzLnN0b3JhZ2UgYXMgQ2FjaGVTdG9yYWdlICYge1xuICAgICAgICBjbGVhbnVwRXhwaXJlZD86ICgpID0+IFByb21pc2U8bnVtYmVyPjtcbiAgICAgIH1cbiAgICApLmNsZWFudXBFeHBpcmVkO1xuICAgIHJldHVybiBjbGVhbnVwID8gY2xlYW51cC5jYWxsKHRoaXMuc3RvcmFnZSkgOiAwO1xuICB9XG5cbiAgcHJpdmF0ZSByZXRhaW48VD4oa2V5OiBzdHJpbmcsIGVudHJ5OiBDYWNoZUVudHJ5PFQ+KTogdm9pZCB7XG4gICAgY29uc3QgdHRsID0gZW50cnkuZXhwaXJ5IC0gRGF0ZS5ub3coKTtcbiAgICBpZiAodHRsID4gMCkgdGhpcy5lbnRyaWVzLnNldChrZXksIGVudHJ5LCB7IHR0bCB9KTtcbiAgfVxufVxuXG5mdW5jdGlvbiBwb3NpdGl2ZUJvdW5kKHZhbHVlOiBudW1iZXIgfCB1bmRlZmluZWQsIGZhbGxiYWNrOiBudW1iZXIsIG5hbWU6IHN0cmluZyk6IG51bWJlciB7XG4gIGNvbnN0IHJlc29sdmVkID0gdmFsdWUgPz8gZmFsbGJhY2s7XG4gIGlmICghTnVtYmVyLmlzRmluaXRlKHJlc29sdmVkKSB8fCByZXNvbHZlZCA8PSAwKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoYCR7bmFtZX0gbXVzdCBiZSBhIGZpbml0ZSBwb3NpdGl2ZSBudW1iZXJgKTtcbiAgfVxuICByZXR1cm4gTWF0aC5mbG9vcihyZXNvbHZlZCk7XG59XG5cbmZ1bmN0aW9uIHJldGFpbmVkU2l6ZShrZXk6IHN0cmluZywgZW50cnk6IENhY2hlRW50cnkpOiBudW1iZXIge1xuICB0cnkge1xuICAgIHJldHVybiBCdWZmZXIuYnl0ZUxlbmd0aChrZXkpICsgQnVmZmVyLmJ5dGVMZW5ndGgoSlNPTi5zdHJpbmdpZnkoZW50cnkpKTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIE51bWJlci5NQVhfU0FGRV9JTlRFR0VSO1xuICB9XG59XG5cbi8qKlxuICogTGF6aWx5IHJlc29sdmUgQXBwS2l0J3MgaW50ZXJuYWwgYFBlcnNpc3RlbnRTdG9yYWdlYCBjb25zdHJ1Y3Rvci4gYG51bGxgXG4gKiBtZWFucyBub3QgYXR0ZW1wdGVkIHlldDsgYHVuZGVmaW5lZGAgbWVhbnMgdGhlIGxvb2t1cCBhbHJlYWR5IGZhaWxlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxvYWRQZXJzaXN0ZW50U3RvcmFnZSgpOiBQZXJzaXN0ZW50U3RvcmFnZUNvbnN0cnVjdG9yIHwgdW5kZWZpbmVkIHtcbiAgaWYgKHBlcnNpc3RlbnRTdG9yYWdlQ3RvciAhPT0gbnVsbCkge1xuICAgIHJldHVybiBwZXJzaXN0ZW50U3RvcmFnZUN0b3I7XG4gIH1cbiAgdHJ5IHtcbiAgICBjb25zdCByZXF1aXJlID0gY3JlYXRlUmVxdWlyZShpbXBvcnQubWV0YS51cmwpO1xuICAgIGNvbnN0IG1vZHVsZVBhdGggPSBqb2luKFxuICAgICAgZGlybmFtZShyZXF1aXJlLnJlc29sdmUoXCJAZGF0YWJyaWNrcy9hcHBraXRcIikpLFxuICAgICAgXCJjYWNoZS9zdG9yYWdlL3BlcnNpc3RlbnQuanNcIixcbiAgICApO1xuICAgIGNvbnN0IGxvYWRlZCA9IHJlcXVpcmUobW9kdWxlUGF0aCkuUGVyc2lzdGVudFN0b3JhZ2UgYXNcbiAgICAgIFBlcnNpc3RlbnRTdG9yYWdlQ29uc3RydWN0b3IgfCB1bmRlZmluZWQ7XG4gICAgaWYgKHR5cGVvZiBsb2FkZWQgIT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgbG9nZ2VyLmRlYnVnKFwic29mdCBwZXJzaXN0ZW50IGNhY2hlIHNraXBwZWQgKFBlcnNpc3RlbnRTdG9yYWdlIG1pc3NpbmcpXCIpO1xuICAgICAgcGVyc2lzdGVudFN0b3JhZ2VDdG9yID0gdW5kZWZpbmVkO1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgcGVyc2lzdGVudFN0b3JhZ2VDdG9yID0gbG9hZGVkO1xuICAgIHJldHVybiBsb2FkZWQ7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGxvZ2dlci5kZWJ1ZyhcInNvZnQgcGVyc2lzdGVudCBjYWNoZSBza2lwcGVkIChQZXJzaXN0ZW50U3RvcmFnZSB1bmF2YWlsYWJsZSlcIiwge1xuICAgICAgZXJyb3I6IGVycm9yVXRpbHMuZXJyb3JNZXNzYWdlKGVyciksXG4gICAgfSk7XG4gICAgcGVyc2lzdGVudFN0b3JhZ2VDdG9yID0gdW5kZWZpbmVkO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cblxuLyoqXG4gKiBXaGV0aGVyIGFuIGV4aXN0aW5nIGNhY2hlIHRhYmxlIGJlbG9uZ3MgdG8gYW5vdGhlciByb2xlLlxuICpcbiAqIFBvc3RncmVTUUwgYWxsb3dzIGdyYW50ZWQgcmVhZHMvd3JpdGVzIGJ1dCByZXNlcnZlcyBpbmRleCBEREwgZm9yIHRoZSB0YWJsZVxuICogb3duZXIuIFNraXAgQXBwS2l0IG1pZ3JhdGlvbnMgaW4gdGhhdCBjYXNlOyB7QGxpbmsgcHJvYmVTdG9yYWdlfSBzdGlsbCBwcm92ZXNcbiAqIHRoZSBleGlzdGluZyB0YWJsZSBjYW4gc2VydmUgdGhlIGNhY2hlIGJlZm9yZSBpdCBpcyBhY2NlcHRlZC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gdGFibGVPd25lZEJ5QW5vdGhlclJvbGUoXG4gIHN0b3JhZ2U6IFBlcnNpc3RlbnRTdG9yYWdlQmFzZSxcbiAgcG9vbDogTGFrZWJhc2VQb29sLFxuKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIGlmICghc3RvcmFnZS5zY2hlbWFOYW1lIHx8ICFzdG9yYWdlLnRhYmxlTmFtZSkgcmV0dXJuIGZhbHNlO1xuICBjb25zdCByZXN1bHQgPSBhd2FpdCBwb29sLnF1ZXJ5KFxuICAgIGBTRUxFQ1QgcGdfZ2V0X3VzZXJieWlkKGMucmVsb3duZXIpID0gY3VycmVudF91c2VyIEFTIG93bmVkXG4gICAgIEZST00gcGdfY2xhc3MgY1xuICAgICBKT0lOIHBnX25hbWVzcGFjZSBuIE9OIG4ub2lkID0gYy5yZWxuYW1lc3BhY2VcbiAgICAgV0hFUkUgbi5uc3BuYW1lID0gJDEgQU5EIGMucmVsbmFtZSA9ICQyIEFORCBjLnJlbGtpbmQgSU4gKCdyJywgJ3AnKWAsXG4gICAgW3N0b3JhZ2Uuc2NoZW1hTmFtZSwgc3RvcmFnZS50YWJsZU5hbWVdLFxuICApO1xuICBpZiAocmVzdWx0LnJvd3NbMF0/Lm93bmVkICE9PSBmYWxzZSkgcmV0dXJuIGZhbHNlO1xuICBsb2dnZXIud2FybihcInBlcnNpc3RlbnQgY2FjaGUgbWlncmF0aW9ucyBza2lwcGVkICh0YWJsZSBvd25lZCBieSBhbm90aGVyIHJvbGUpXCIsIHtcbiAgICBzY2hlbWE6IHN0b3JhZ2Uuc2NoZW1hTmFtZSxcbiAgICB0YWJsZTogc3RvcmFnZS50YWJsZU5hbWUsXG4gIH0pO1xuICByZXR1cm4gdHJ1ZTtcbn1cblxuLyoqIFNvZnRlbiBgaW5pdGlhbGl6ZSgpYCBzbyBhbiBvd25lcnNoaXAtb25seSBtaWdyYXRpb24gZmFpbHVyZSBpcyBub3QgZmF0YWwuICovXG5leHBvcnQgZnVuY3Rpb24gc29mdGVuSW5pdGlhbGl6ZShcbiAgc3RvcmFnZTogUGVyc2lzdGVudFN0b3JhZ2VCYXNlLFxuICBza2lwTWlncmF0aW9ucz86ICgpID0+IFByb21pc2U8Ym9vbGVhbj4sXG4pOiB2b2lkIHtcbiAgY29uc3Qgb3JpZ2luYWxJbml0aWFsaXplID0gc3RvcmFnZS5pbml0aWFsaXplLmJpbmQoc3RvcmFnZSk7XG4gIGxldCBzb2Z0SW5pdFByb21pc2U6IFByb21pc2U8dm9pZD4gfCB1bmRlZmluZWQ7XG5cbiAgc3RvcmFnZS5pbml0aWFsaXplID0gYXN5bmMgKCkgPT4ge1xuICAgIGlmIChzdG9yYWdlLmluaXRpYWxpemVkKSByZXR1cm47XG4gICAgc29mdEluaXRQcm9taXNlID8/PSAoYXN5bmMgKCkgPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgaWYgKCEoYXdhaXQgc2tpcE1pZ3JhdGlvbnM/LigpKSkgYXdhaXQgb3JpZ2luYWxJbml0aWFsaXplKCk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgaWYgKFxuICAgICAgICAgICFoYW5kbGVPd25lcnNoaXBNaWdyYXRpb25FcnJvcihlcnIsIHtcbiAgICAgICAgICAgIHNjb3BlOiBcImNhY2hlLXN0b3JhZ2VcIixcbiAgICAgICAgICAgIGxvZ2dlcixcbiAgICAgICAgICAgIGV2ZW50OiBcInBlcnNpc3RlbnQgY2FjaGUgbWlncmF0aW9uIGZhaWxlZFwiLFxuICAgICAgICAgIH0pXG4gICAgICAgICkge1xuICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pKCk7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHNvZnRJbml0UHJvbWlzZTtcbiAgICAgIHN0b3JhZ2UuaW5pdGlhbGl6ZWQgPSB0cnVlO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgc29mdEluaXRQcm9taXNlID0gdW5kZWZpbmVkO1xuICAgICAgdGhyb3cgZXJyO1xuICAgIH1cbiAgfTtcbn1cblxuLyoqIFZlcmlmeSB0aGUgbWlncmF0ZWQgY2FjaGUgdGFibGUgY2FuIHNlcnZlIHRoZSByZWFkcyBhbmQgd3JpdGVzIEFwcEtpdCBuZWVkcy4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBwcm9iZVN0b3JhZ2Uoc3RvcmFnZTogUGVyc2lzdGVudFN0b3JhZ2VCYXNlKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IGtleSA9IGBkYngtdG9vbHM6Y2FjaGUtcHJvYmU6JHtoYXNoLmlkKCl9YDtcbiAgdHJ5IHtcbiAgICBhd2FpdCBzdG9yYWdlLnNldChrZXksIHsgdmFsdWU6IGtleSwgZXhwaXJ5OiBEYXRlLm5vdygpICsgNjBfMDAwIH0pO1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHN0b3JhZ2UuZ2V0KGtleSk7XG4gICAgaWYgKHJlc3VsdD8udmFsdWUgIT09IGtleSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwicGVyc2lzdGVudCBjYWNoZSBwcm9iZSByZXR1cm5lZCBhbiB1bmV4cGVjdGVkIHZhbHVlXCIpO1xuICAgIH1cbiAgfSBmaW5hbGx5IHtcbiAgICBhd2FpdCBzdG9yYWdlLmRlbGV0ZShrZXkpLmNhdGNoKCgpID0+IHVuZGVmaW5lZCk7XG4gIH1cbn1cblxuLyoqXG4gKiBCdWlsZCBhIHNvZnQtZmFpbCBMYWtlYmFzZSBjYWNoZSBzdG9yYWdlIHdoZW4gYSBwb29sIGNhbiBiZSBjcmVhdGVkIGFuZFxuICogQXBwS2l0J3MgUGVyc2lzdGVudFN0b3JhZ2UgY2FuIGJlIGxvYWRlZC4gUmV0dXJucyBgdW5kZWZpbmVkYCBvdGhlcndpc2Ugc29cbiAqIEFwcEtpdCBjYW4gZmFsbCB0aHJvdWdoIHRvIGl0cyBub3JtYWwgY2FjaGUgcGF0aC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZVNvZnRQZXJzaXN0ZW50U3RvcmFnZShcbiAgY2FjaGU6IENhY2hlQ29uZmlnIHwgdW5kZWZpbmVkLFxuKTogUHJvbWlzZTxDYWNoZVN0b3JhZ2UgfCB1bmRlZmluZWQ+IHtcbiAgY29uc3QgUGVyc2lzdGVudFN0b3JhZ2UgPSBsb2FkUGVyc2lzdGVudFN0b3JhZ2UoKTtcbiAgaWYgKCFQZXJzaXN0ZW50U3RvcmFnZSkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICBsZXQgcG9vbDogTGFrZWJhc2VQb29sIHwgdW5kZWZpbmVkO1xuICB0cnkge1xuICAgIGNvbnN0IGNyZWF0ZWRQb29sID0gY3JlYXRlTGFrZWJhc2VQb29sKFxuICAgICAgcG9zdGdyZXNDb25uZWN0aW9uT3B0aW9ucyh7IHdvcmtzcGFjZUNsaWVudDogZ2V0V29ya3NwYWNlQ2xpZW50KHt9KSB9KSxcbiAgICApO1xuICAgIHBvb2wgPSBjcmVhdGVkUG9vbDtcbiAgICBjb25zdCBzdG9yYWdlID0gbmV3IFBlcnNpc3RlbnRTdG9yYWdlKGNhY2hlID8/IHt9LCBjcmVhdGVkUG9vbCk7XG4gICAgc29mdGVuSW5pdGlhbGl6ZShzdG9yYWdlLCAoKSA9PiB0YWJsZU93bmVkQnlBbm90aGVyUm9sZShzdG9yYWdlLCBjcmVhdGVkUG9vbCkpO1xuICAgIGlmICghKGF3YWl0IHN0b3JhZ2UuaGVhbHRoQ2hlY2soKSkpIHtcbiAgICAgIGF3YWl0IHN0b3JhZ2UuY2xvc2UoKS5jYXRjaCgoKSA9PiB7fSk7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgICBhd2FpdCBzdG9yYWdlLmluaXRpYWxpemUoKTtcbiAgICBhd2FpdCBwcm9iZVN0b3JhZ2Uoc3RvcmFnZSk7XG4gICAgcmV0dXJuIG5ldyBMMUNhY2hlU3RvcmFnZShzdG9yYWdlLCB7XG4gICAgICBtYXhCeXRlczogY2FjaGU/Lm1heEJ5dGVzLFxuICAgICAgbWF4RW50cmllczogY2FjaGU/Lm1heFNpemUsXG4gICAgfSk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGxvZ2dlci5kZWJ1ZyhcInNvZnQgcGVyc2lzdGVudCBjYWNoZSB1bmF2YWlsYWJsZVwiLCB7XG4gICAgICBlcnJvcjogZXJyb3JVdGlscy5lcnJvck1lc3NhZ2UoZXJyKSxcbiAgICB9KTtcbiAgICBpZiAocG9vbCkge1xuICAgICAgYXdhaXQgcG9vbC5lbmQoKS5jYXRjaCgoKSA9PiB7fSk7XG4gICAgfVxuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AppKit-global filesystem cache with user-isolated process-local LRU values.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { Plugin, type BasePluginConfig } from "@databricks/appkit";
|
|
7
|
+
import { type FileSystemCache } from "@dbx-tools/shared-fs";
|
|
8
|
+
/** Configuration for the AppKit files-cache plugin. */
|
|
9
|
+
export interface FilesCachePluginConfig extends BasePluginConfig {
|
|
10
|
+
/** Default entry TTL in milliseconds. Defaults to 60 seconds. */
|
|
11
|
+
ttlMs?: number;
|
|
12
|
+
/** Invalidation debounce window in milliseconds. Defaults to 25ms. */
|
|
13
|
+
invalidationBatchMs?: number;
|
|
14
|
+
/** Maximum entries retained in each user L1. Defaults to 1,000. */
|
|
15
|
+
maxEntries?: number;
|
|
16
|
+
/** Maximum retained bytes in each user L1. Defaults to 64 MiB. */
|
|
17
|
+
maxBytes?: number;
|
|
18
|
+
/** Maximum active user scopes retained by the process. Defaults to 256. */
|
|
19
|
+
maxScopes?: number;
|
|
20
|
+
}
|
|
21
|
+
/** Identity for one authorization-safe filesystem cache scope. */
|
|
22
|
+
export interface FilesCacheScope {
|
|
23
|
+
/** Databricks workspace host. */
|
|
24
|
+
host: string;
|
|
25
|
+
/** Attributed user identifier used to isolate values. */
|
|
26
|
+
userKey: string;
|
|
27
|
+
/** Optional workspace identifier included in shared invalidation scope. */
|
|
28
|
+
workspaceId?: string;
|
|
29
|
+
/** Optional per-scope entry TTL override in milliseconds. */
|
|
30
|
+
ttlMs?: number;
|
|
31
|
+
}
|
|
32
|
+
/** Stable identity for a framework filesystem source retained within one user scope. */
|
|
33
|
+
export interface FilesCacheSourceIdentity {
|
|
34
|
+
/** Actual mounted filesystem paths represented by the source. */
|
|
35
|
+
paths: readonly string[];
|
|
36
|
+
}
|
|
37
|
+
/** Public exports from {@link FilesCachePlugin}. */
|
|
38
|
+
export interface FilesCacheExports {
|
|
39
|
+
/** Resolve one user-isolated filesystem cache. */
|
|
40
|
+
forScope(scope: FilesCacheScope): Promise<FileSystemCache>;
|
|
41
|
+
/** Resolve one app-lifetime filesystem source for a user and its actual mounted paths. */
|
|
42
|
+
forFileSystem<T extends object>(scope: FilesCacheScope, identity: FilesCacheSourceIdentity, load: () => T | Promise<T>): Promise<T>;
|
|
43
|
+
/** Flush pending invalidation batches. */
|
|
44
|
+
flush(): Promise<void>;
|
|
45
|
+
}
|
|
46
|
+
/** Process-local filesystem cache manager. */
|
|
47
|
+
export declare class FilesCacheManager {
|
|
48
|
+
private readonly config;
|
|
49
|
+
private readonly groups;
|
|
50
|
+
private readonly scopes;
|
|
51
|
+
constructor(config?: FilesCachePluginConfig);
|
|
52
|
+
/** Return one user-isolated cache within a host/workspace invalidation group. */
|
|
53
|
+
forScope(input: FilesCacheScope): Promise<FileSystemCache>;
|
|
54
|
+
/** Retain one stable framework filesystem source for the scope and mounted paths. */
|
|
55
|
+
forFileSystem<T extends object>(input: FilesCacheScope, identity: FilesCacheSourceIdentity, load: () => T | Promise<T>): Promise<T>;
|
|
56
|
+
private resolveScopeState;
|
|
57
|
+
/** Flush every pending invalidation batch. */
|
|
58
|
+
flush(): Promise<void>;
|
|
59
|
+
/** Flush state and release all process-local entries and timers. */
|
|
60
|
+
close(): Promise<void>;
|
|
61
|
+
private group;
|
|
62
|
+
private createScope;
|
|
63
|
+
private read;
|
|
64
|
+
private keys;
|
|
65
|
+
private queueInvalidation;
|
|
66
|
+
private flushInvalidations;
|
|
67
|
+
}
|
|
68
|
+
/** AppKit plugin that owns process-local filesystem LRU caches. */
|
|
69
|
+
export declare class FilesCachePlugin extends Plugin<FilesCachePluginConfig> {
|
|
70
|
+
static manifest: {
|
|
71
|
+
name: "files-cache";
|
|
72
|
+
displayName: string;
|
|
73
|
+
description: string;
|
|
74
|
+
stability: "beta";
|
|
75
|
+
resources: {
|
|
76
|
+
required: never[];
|
|
77
|
+
optional: never[];
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
private manager?;
|
|
81
|
+
setup(): Promise<void>;
|
|
82
|
+
exports(): FilesCacheExports;
|
|
83
|
+
private requireManager;
|
|
84
|
+
}
|
|
85
|
+
/** AppKit registration factory for {@link FilesCachePlugin}. */
|
|
86
|
+
export declare const filesCache: import("@databricks/appkit").ToPlugin<typeof FilesCachePlugin, FilesCachePluginConfig, "files-cache">;
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AppKit-global filesystem cache with user-isolated process-local LRU values.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { Plugin, toPlugin } from "@databricks/appkit";
|
|
7
|
+
import { posixPath } from "@dbx-tools/shared-fs";
|
|
8
|
+
import { errorUtils, log, object } from "@dbx-tools/shared-core";
|
|
9
|
+
import { LRUCache } from "lru-cache";
|
|
10
|
+
const DEFAULT_TTL_MS = 60_000;
|
|
11
|
+
const DEFAULT_INVALIDATION_BATCH_MS = 25;
|
|
12
|
+
const DEFAULT_MAX_ENTRIES = 1_000;
|
|
13
|
+
const DEFAULT_MAX_BYTES = 64 * 1024 * 1024;
|
|
14
|
+
const DEFAULT_MAX_SCOPES = 256;
|
|
15
|
+
const logger = log.logger("files-cache");
|
|
16
|
+
/** Process-local filesystem cache manager. */
|
|
17
|
+
export class FilesCacheManager {
|
|
18
|
+
config;
|
|
19
|
+
groups = new Map();
|
|
20
|
+
scopes;
|
|
21
|
+
constructor(config = {}) {
|
|
22
|
+
this.config = {
|
|
23
|
+
ttlMs: positiveDuration(config.ttlMs, DEFAULT_TTL_MS, "ttlMs"),
|
|
24
|
+
invalidationBatchMs: positiveDuration(config.invalidationBatchMs, DEFAULT_INVALIDATION_BATCH_MS, "invalidationBatchMs"),
|
|
25
|
+
maxEntries: positiveInteger(config.maxEntries, DEFAULT_MAX_ENTRIES, "maxEntries"),
|
|
26
|
+
maxBytes: positiveInteger(config.maxBytes, DEFAULT_MAX_BYTES, "maxBytes"),
|
|
27
|
+
maxScopes: positiveInteger(config.maxScopes, DEFAULT_MAX_SCOPES, "maxScopes"),
|
|
28
|
+
};
|
|
29
|
+
this.scopes = new LRUCache({
|
|
30
|
+
max: this.config.maxScopes,
|
|
31
|
+
dispose: (state) => {
|
|
32
|
+
state.group.scopes.delete(state);
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/** Return one user-isolated cache within a host/workspace invalidation group. */
|
|
37
|
+
async forScope(input) {
|
|
38
|
+
return (await this.resolveScopeState(input)).cache;
|
|
39
|
+
}
|
|
40
|
+
/** Retain one stable framework filesystem source for the scope and mounted paths. */
|
|
41
|
+
async forFileSystem(input, identity, load) {
|
|
42
|
+
const state = await this.resolveScopeState(input);
|
|
43
|
+
const paths = identity.paths.map((path) => posixPath.normalizeRoot(path));
|
|
44
|
+
if (paths.length === 0)
|
|
45
|
+
throw new TypeError("Filesystem source paths must not be empty");
|
|
46
|
+
const sourceKey = object.toStableKey({ paths });
|
|
47
|
+
let source = state.sources.get(sourceKey);
|
|
48
|
+
if (!source) {
|
|
49
|
+
source = Promise.resolve(load());
|
|
50
|
+
state.sources.set(sourceKey, source);
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
return (await source);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (state.sources.get(sourceKey) === source)
|
|
57
|
+
state.sources.delete(sourceKey);
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async resolveScopeState(input) {
|
|
62
|
+
const scope = resolveScope(input, this.config.ttlMs);
|
|
63
|
+
const scopeKey = object.toStableKey({
|
|
64
|
+
host: scope.host,
|
|
65
|
+
userKey: scope.userKey,
|
|
66
|
+
workspaceId: scope.workspaceId,
|
|
67
|
+
});
|
|
68
|
+
let state = this.scopes.get(scopeKey);
|
|
69
|
+
if (!state) {
|
|
70
|
+
const group = this.group(scope);
|
|
71
|
+
state = this.createScope(scope, group);
|
|
72
|
+
group.scopes.add(state);
|
|
73
|
+
this.scopes.set(scopeKey, state);
|
|
74
|
+
}
|
|
75
|
+
return state;
|
|
76
|
+
}
|
|
77
|
+
/** Flush every pending invalidation batch. */
|
|
78
|
+
async flush() {
|
|
79
|
+
await Promise.all([...this.groups.values()].map((group) => this.flushInvalidations(group)));
|
|
80
|
+
}
|
|
81
|
+
/** Flush state and release all process-local entries and timers. */
|
|
82
|
+
async close() {
|
|
83
|
+
for (const group of this.groups.values()) {
|
|
84
|
+
if (group.timer)
|
|
85
|
+
clearTimeout(group.timer);
|
|
86
|
+
group.timer = undefined;
|
|
87
|
+
}
|
|
88
|
+
await this.flush();
|
|
89
|
+
this.scopes.clear();
|
|
90
|
+
this.groups.clear();
|
|
91
|
+
}
|
|
92
|
+
group(scope) {
|
|
93
|
+
const key = object.toStableKey({
|
|
94
|
+
host: scope.host,
|
|
95
|
+
workspaceId: scope.workspaceId,
|
|
96
|
+
});
|
|
97
|
+
const existing = this.groups.get(key);
|
|
98
|
+
if (existing)
|
|
99
|
+
return existing;
|
|
100
|
+
const group = {
|
|
101
|
+
pending: new Set(),
|
|
102
|
+
scopes: new Set(),
|
|
103
|
+
};
|
|
104
|
+
this.groups.set(key, group);
|
|
105
|
+
return group;
|
|
106
|
+
}
|
|
107
|
+
createScope(scope, group) {
|
|
108
|
+
const state = {};
|
|
109
|
+
state.scope = scope;
|
|
110
|
+
state.group = group;
|
|
111
|
+
state.entries = new LRUCache({
|
|
112
|
+
max: this.config.maxEntries,
|
|
113
|
+
maxSize: this.config.maxBytes,
|
|
114
|
+
sizeCalculation: (entry, cacheKey) => retainedSize(cacheKey, entry),
|
|
115
|
+
});
|
|
116
|
+
state.sources = new Map();
|
|
117
|
+
state.cache = {
|
|
118
|
+
read: (cacheKey, load) => this.read(state, cacheKey, load),
|
|
119
|
+
invalidate: (cacheKey) => this.queueInvalidation(state, cacheKey),
|
|
120
|
+
keys: () => this.keys(state),
|
|
121
|
+
};
|
|
122
|
+
return state;
|
|
123
|
+
}
|
|
124
|
+
async read(state, key, load) {
|
|
125
|
+
if (!state.group.pending.has(key)) {
|
|
126
|
+
const retained = state.entries.get(key);
|
|
127
|
+
if (retained)
|
|
128
|
+
return retained.value;
|
|
129
|
+
}
|
|
130
|
+
const value = await load();
|
|
131
|
+
state.entries.set(key, { value }, { ttl: state.scope.ttlMs });
|
|
132
|
+
return value;
|
|
133
|
+
}
|
|
134
|
+
*keys(state) {
|
|
135
|
+
for (const key of state.entries.keys()) {
|
|
136
|
+
if (!state.group.pending.has(key))
|
|
137
|
+
yield key;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
queueInvalidation(state, key) {
|
|
141
|
+
state.group.pending.add(key);
|
|
142
|
+
if (state.group.timer)
|
|
143
|
+
return;
|
|
144
|
+
state.group.timer = setTimeout(() => {
|
|
145
|
+
state.group.timer = undefined;
|
|
146
|
+
void this.flushInvalidations(state.group).catch((error) => {
|
|
147
|
+
logger.warn("filesystem cache invalidation batch failed", {
|
|
148
|
+
error: errorUtils.errorMessage(error),
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
}, this.config.invalidationBatchMs);
|
|
152
|
+
state.group.timer.unref?.();
|
|
153
|
+
}
|
|
154
|
+
async flushInvalidations(group) {
|
|
155
|
+
if (group.timer)
|
|
156
|
+
clearTimeout(group.timer);
|
|
157
|
+
group.timer = undefined;
|
|
158
|
+
if (group.pending.size === 0)
|
|
159
|
+
return;
|
|
160
|
+
const keys = [...group.pending];
|
|
161
|
+
group.pending.clear();
|
|
162
|
+
for (const state of group.scopes) {
|
|
163
|
+
for (const key of keys)
|
|
164
|
+
state.entries.delete(key);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/** AppKit plugin that owns process-local filesystem LRU caches. */
|
|
169
|
+
export class FilesCachePlugin extends Plugin {
|
|
170
|
+
static manifest = {
|
|
171
|
+
name: "files-cache",
|
|
172
|
+
displayName: "Files Cache",
|
|
173
|
+
description: "Provides bounded user-scoped process-local filesystem caches.",
|
|
174
|
+
stability: "beta",
|
|
175
|
+
resources: { required: [], optional: [] },
|
|
176
|
+
};
|
|
177
|
+
manager;
|
|
178
|
+
async setup() {
|
|
179
|
+
this.manager = new FilesCacheManager(this.config);
|
|
180
|
+
this.context?.onLifecycle("shutdown", () => this.manager?.close());
|
|
181
|
+
}
|
|
182
|
+
exports() {
|
|
183
|
+
return {
|
|
184
|
+
forScope: (scope) => this.requireManager().forScope(scope),
|
|
185
|
+
forFileSystem: (scope, identity, load) => this.requireManager().forFileSystem(scope, identity, load),
|
|
186
|
+
flush: () => this.requireManager().flush(),
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
requireManager() {
|
|
190
|
+
if (!this.manager)
|
|
191
|
+
throw new Error("Files cache plugin has not completed setup");
|
|
192
|
+
return this.manager;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/** AppKit registration factory for {@link FilesCachePlugin}. */
|
|
196
|
+
export const filesCache = toPlugin(FilesCachePlugin);
|
|
197
|
+
function resolveScope(input, defaultTtlMs) {
|
|
198
|
+
const host = input.host.trim().replace(/\/+$/, "");
|
|
199
|
+
const userKey = input.userKey.trim();
|
|
200
|
+
const workspaceId = input.workspaceId?.trim() || undefined;
|
|
201
|
+
if (!host)
|
|
202
|
+
throw new TypeError("Files cache scope host must not be blank");
|
|
203
|
+
if (!userKey)
|
|
204
|
+
throw new TypeError("Files cache scope userKey must not be blank");
|
|
205
|
+
return {
|
|
206
|
+
host,
|
|
207
|
+
userKey,
|
|
208
|
+
...(workspaceId ? { workspaceId } : {}),
|
|
209
|
+
ttlMs: positiveDuration(input.ttlMs, defaultTtlMs, "scope.ttlMs"),
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function positiveDuration(value, fallback, name) {
|
|
213
|
+
const resolved = value ?? fallback;
|
|
214
|
+
if (!Number.isFinite(resolved) || resolved <= 0) {
|
|
215
|
+
throw new RangeError(`${name} must be a finite positive number`);
|
|
216
|
+
}
|
|
217
|
+
return resolved;
|
|
218
|
+
}
|
|
219
|
+
function positiveInteger(value, fallback, name) {
|
|
220
|
+
return Math.floor(positiveDuration(value, fallback, name));
|
|
221
|
+
}
|
|
222
|
+
function retainedSize(key, entry) {
|
|
223
|
+
try {
|
|
224
|
+
return Buffer.byteLength(key) + Buffer.byteLength(JSON.stringify(entry.value));
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
return Number.MAX_SAFE_INTEGER;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsZXMtY2FjaGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZmlsZXMtY2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7R0FJRztBQUVILE9BQU8sRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUE4QyxNQUFNLG9CQUFvQixDQUFDO0FBQ2xHLE9BQU8sRUFBRSxTQUFTLEVBQXlDLE1BQU0sc0JBQXNCLENBQUM7QUFDeEYsT0FBTyxFQUFFLFVBQVUsRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDakUsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUVyQyxNQUFNLGNBQWMsR0FBRyxNQUFNLENBQUM7QUFDOUIsTUFBTSw2QkFBNkIsR0FBRyxFQUFFLENBQUM7QUFDekMsTUFBTSxtQkFBbUIsR0FBRyxLQUFLLENBQUM7QUFDbEMsTUFBTSxpQkFBaUIsR0FBRyxFQUFFLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQztBQUMzQyxNQUFNLGtCQUFrQixHQUFHLEdBQUcsQ0FBQztBQUMvQixNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDO0FBaUZ6Qyw4Q0FBOEM7QUFDOUMsTUFBTSxPQUFPLGlCQUFpQjtJQUNYLE1BQU0sQ0FBMkI7SUFDakMsTUFBTSxHQUFHLElBQUksR0FBRyxFQUFzQixDQUFDO0lBQ3ZDLE1BQU0sQ0FBK0I7SUFFdEQsWUFBWSxTQUFpQyxFQUFFO1FBQzdDLElBQUksQ0FBQyxNQUFNLEdBQUc7WUFDWixLQUFLLEVBQUUsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxjQUFjLEVBQUUsT0FBTyxDQUFDO1lBQzlELG1CQUFtQixFQUFFLGdCQUFnQixDQUNuQyxNQUFNLENBQUMsbUJBQW1CLEVBQzFCLDZCQUE2QixFQUM3QixxQkFBcUIsQ0FDdEI7WUFDRCxVQUFVLEVBQUUsZUFBZSxDQUFDLE1BQU0s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O0lBQ2hGLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUM7QUFDN0QsQ0FBQztBQUVELFNBQVMsWUFBWSxDQUFDLEdBQVcsRUFBRSxLQUFvQjtJQUNyRCxJQUFJLENBQUM7UUFDSCxPQUFPLE1BQU0sQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBQ2pGLENBQUM7SUFBQyxNQUFNLENBQUM7UUFDUCxPQUFPLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQztJQUNqQyxDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQXBwS2l0LWdsb2JhbCBmaWxlc3lzdGVtIGNhY2hlIHdpdGggdXNlci1pc29sYXRlZCBwcm9jZXNzLWxvY2FsIExSVSB2YWx1ZXMuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IFBsdWdpbiwgdG9QbHVnaW4sIHR5cGUgQmFzZVBsdWdpbkNvbmZpZywgdHlwZSBQbHVnaW5NYW5pZmVzdCB9IGZyb20gXCJAZGF0YWJyaWNrcy9hcHBraXRcIjtcbmltcG9ydCB7IHBvc2l4UGF0aCwgdHlwZSBDYWNoZVZhbHVlLCB0eXBlIEZpbGVTeXN0ZW1DYWNoZSB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1mc1wiO1xuaW1wb3J0IHsgZXJyb3JVdGlscywgbG9nLCBvYmplY3QgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHsgTFJVQ2FjaGUgfSBmcm9tIFwibHJ1LWNhY2hlXCI7XG5cbmNvbnN0IERFRkFVTFRfVFRMX01TID0gNjBfMDAwO1xuY29uc3QgREVGQVVMVF9JTlZBTElEQVRJT05fQkFUQ0hfTVMgPSAyNTtcbmNvbnN0IERFRkFVTFRfTUFYX0VOVFJJRVMgPSAxXzAwMDtcbmNvbnN0IERFRkFVTFRfTUFYX0JZVEVTID0gNjQgKiAxMDI0ICogMTAyNDtcbmNvbnN0IERFRkFVTFRfTUFYX1NDT1BFUyA9IDI1NjtcbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJmaWxlcy1jYWNoZVwiKTtcblxuaW50ZXJmYWNlIFJldGFpbmVkRW50cnkge1xuICB2YWx1ZTogQ2FjaGVWYWx1ZTtcbn1cblxuaW50ZXJmYWNlIFNjb3BlU3RhdGUge1xuICBjYWNoZTogRmlsZVN5c3RlbUNhY2hlO1xuICBlbnRyaWVzOiBMUlVDYWNoZTxzdHJpbmcsIFJldGFpbmVkRW50cnk+O1xuICBncm91cDogR3JvdXBTdGF0ZTtcbiAgc2NvcGU6IFJlc29sdmVkRmlsZXNDYWNoZVNjb3BlO1xuICBzb3VyY2VzOiBNYXA8c3RyaW5nLCBQcm9taXNlPG9iamVjdD4+O1xufVxuXG5pbnRlcmZhY2UgR3JvdXBTdGF0ZSB7XG4gIHBlbmRpbmc6IFNldDxzdHJpbmc+O1xuICBzY29wZXM6IFNldDxTY29wZVN0YXRlPjtcbiAgdGltZXI/OiBSZXR1cm5UeXBlPHR5cGVvZiBzZXRUaW1lb3V0Pjtcbn1cblxuaW50ZXJmYWNlIFJlc29sdmVkRmlsZXNDYWNoZUNvbmZpZyB7XG4gIGludmFsaWRhdGlvbkJhdGNoTXM6IG51bWJlcjtcbiAgbWF4Qnl0ZXM6IG51bWJlcjtcbiAgbWF4RW50cmllczogbnVtYmVyO1xuICBtYXhTY29wZXM6IG51bWJlcjtcbiAgdHRsTXM6IG51bWJlcjtcbn1cblxuaW50ZXJmYWNlIFJlc29sdmVkRmlsZXNDYWNoZVNjb3BlIHtcbiAgaG9zdDogc3RyaW5nO1xuICB0dGxNczogbnVtYmVyO1xuICB1c2VyS2V5OiBzdHJpbmc7XG4gIHdvcmtzcGFjZUlkPzogc3RyaW5nO1xufVxuXG4vKiogQ29uZmlndXJhdGlvbiBmb3IgdGhlIEFwcEtpdCBmaWxlcy1jYWNoZSBwbHVnaW4uICovXG5leHBvcnQgaW50ZXJmYWNlIEZpbGVzQ2FjaGVQbHVnaW5Db25maWcgZXh0ZW5kcyBCYXNlUGx1Z2luQ29uZmlnIHtcbiAgLyoqIERlZmF1bHQgZW50cnkgVFRMIGluIG1pbGxpc2Vjb25kcy4gRGVmYXVsdHMgdG8gNjAgc2Vjb25kcy4gKi9cbiAgdHRsTXM/OiBudW1iZXI7XG4gIC8qKiBJbnZhbGlkYXRpb24gZGVib3VuY2Ugd2luZG93IGluIG1pbGxpc2Vjb25kcy4gRGVmYXVsdHMgdG8gMjVtcy4gKi9cbiAgaW52YWxpZGF0aW9uQmF0Y2hNcz86IG51bWJlcjtcbiAgLyoqIE1heGltdW0gZW50cmllcyByZXRhaW5lZCBpbiBlYWNoIHVzZXIgTDEuIERlZmF1bHRzIHRvIDEsMDAwLiAqL1xuICBtYXhFbnRyaWVzPzogbnVtYmVyO1xuICAvKiogTWF4aW11bSByZXRhaW5lZCBieXRlcyBpbiBlYWNoIHVzZXIgTDEuIERlZmF1bHRzIHRvIDY0IE1pQi4gKi9cbiAgbWF4Qnl0ZXM/OiBudW1iZXI7XG4gIC8qKiBNYXhpbXVtIGFjdGl2ZSB1c2VyIHNjb3BlcyByZXRhaW5lZCBieSB0aGUgcHJvY2Vzcy4gRGVmYXVsdHMgdG8gMjU2LiAqL1xuICBtYXhTY29wZXM/OiBudW1iZXI7XG59XG5cbi8qKiBJZGVudGl0eSBmb3Igb25lIGF1dGhvcml6YXRpb24tc2FmZSBmaWxlc3lzdGVtIGNhY2hlIHNjb3BlLiAqL1xuZXhwb3J0IGludGVyZmFjZSBGaWxlc0NhY2hlU2NvcGUge1xuICAvKiogRGF0YWJyaWNrcyB3b3Jrc3BhY2UgaG9zdC4gKi9cbiAgaG9zdDogc3RyaW5nO1xuICAvKiogQXR0cmlidXRlZCB1c2VyIGlkZW50aWZpZXIgdXNlZCB0byBpc29sYXRlIHZhbHVlcy4gKi9cbiAgdXNlcktleTogc3RyaW5nO1xuICAvKiogT3B0aW9uYWwgd29ya3NwYWNlIGlkZW50aWZpZXIgaW5jbHVkZWQgaW4gc2hhcmVkIGludmFsaWRhdGlvbiBzY29wZS4gKi9cbiAgd29ya3NwYWNlSWQ/OiBzdHJpbmc7XG4gIC8qKiBPcHRpb25hbCBwZXItc2NvcGUgZW50cnkgVFRMIG92ZXJyaWRlIGluIG1pbGxpc2Vjb25kcy4gKi9cbiAgdHRsTXM/OiBudW1iZXI7XG59XG5cbi8qKiBTdGFibGUgaWRlbnRpdHkgZm9yIGEgZnJhbWV3b3JrIGZpbGVzeXN0ZW0gc291cmNlIHJldGFpbmVkIHdpdGhpbiBvbmUgdXNlciBzY29wZS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRmlsZXNDYWNoZVNvdXJjZUlkZW50aXR5IHtcbiAgLyoqIEFjdHVhbCBtb3VudGVkIGZpbGVzeXN0ZW0gcGF0aHMgcmVwcmVzZW50ZWQgYnkgdGhlIHNvdXJjZS4gKi9cbiAgcGF0aHM6IHJlYWRvbmx5IHN0cmluZ1tdO1xufVxuXG4vKiogUHVibGljIGV4cG9ydHMgZnJvbSB7QGxpbmsgRmlsZXNDYWNoZVBsdWdpbn0uICovXG5leHBvcnQgaW50ZXJmYWNlIEZpbGVzQ2FjaGVFeHBvcnRzIHtcbiAgLyoqIFJlc29sdmUgb25lIHVzZXItaXNvbGF0ZWQgZmlsZXN5c3RlbSBjYWNoZS4gKi9cbiAgZm9yU2NvcGUoc2NvcGU6IEZpbGVzQ2FjaGVTY29wZSk6IFByb21pc2U8RmlsZVN5c3RlbUNhY2hlPjtcbiAgLyoqIFJlc29sdmUgb25lIGFwcC1saWZldGltZSBmaWxlc3lzdGVtIHNvdXJjZSBmb3IgYSB1c2VyIGFuZCBpdHMgYWN0dWFsIG1vdW50ZWQgcGF0aHMuICovXG4gIGZvckZpbGVTeXN0ZW08VCBleHRlbmRzIG9iamVjdD4oXG4gICAgc2NvcGU6IEZpbGVzQ2FjaGVTY29wZSxcbiAgICBpZGVudGl0eTogRmlsZXNDYWNoZVNvdXJjZUlkZW50aXR5LFxuICAgIGxvYWQ6ICgpID0+IFQgfCBQcm9taXNlPFQ+LFxuICApOiBQcm9taXNlPFQ+O1xuICAvKiogRmx1c2ggcGVuZGluZyBpbnZhbGlkYXRpb24gYmF0Y2hlcy4gKi9cbiAgZmx1c2goKTogUHJvbWlzZTx2b2lkPjtcbn1cblxuLyoqIFByb2Nlc3MtbG9jYWwgZmlsZXN5c3RlbSBjYWNoZSBtYW5hZ2VyLiAqL1xuZXhwb3J0IGNsYXNzIEZpbGVzQ2FjaGVNYW5hZ2VyIHtcbiAgcHJpdmF0ZSByZWFkb25seSBjb25maWc6IFJlc29sdmVkRmlsZXNDYWNoZUNvbmZpZztcbiAgcHJpdmF0ZSByZWFkb25seSBncm91cHMgPSBuZXcgTWFwPHN0cmluZywgR3JvdXBTdGF0ZT4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBzY29wZXM6IExSVUNhY2hlPHN0cmluZywgU2NvcGVTdGF0ZT47XG5cbiAgY29uc3RydWN0b3IoY29uZmlnOiBGaWxlc0NhY2hlUGx1Z2luQ29uZmlnID0ge30pIHtcbiAgICB0aGlzLmNvbmZpZyA9IHtcbiAgICAgIHR0bE1zOiBwb3NpdGl2ZUR1cmF0aW9uKGNvbmZpZy50dGxNcywgREVGQVVMVF9UVExfTVMsIFwidHRsTXNcIiksXG4gICAgICBpbnZhbGlkYXRpb25CYXRjaE1zOiBwb3NpdGl2ZUR1cmF0aW9uKFxuICAgICAgICBjb25maWcuaW52YWxpZGF0aW9uQmF0Y2hNcyxcbiAgICAgICAgREVGQVVMVF9JTlZBTElEQVRJT05fQkFUQ0hfTVMsXG4gICAgICAgIFwiaW52YWxpZGF0aW9uQmF0Y2hNc1wiLFxuICAgICAgKSxcbiAgICAgIG1heEVudHJpZXM6IHBvc2l0aXZlSW50ZWdlcihjb25maWcubWF4RW50cmllcywgREVGQVVMVF9NQVhfRU5UUklFUywgXCJtYXhFbnRyaWVzXCIpLFxuICAgICAgbWF4Qnl0ZXM6IHBvc2l0aXZlSW50ZWdlcihjb25maWcubWF4Qnl0ZXMsIERFRkFVTFRfTUFYX0JZVEVTLCBcIm1heEJ5dGVzXCIpLFxuICAgICAgbWF4U2NvcGVzOiBwb3NpdGl2ZUludGVnZXIoY29uZmlnLm1heFNjb3BlcywgREVGQVVMVF9NQVhfU0NPUEVTLCBcIm1heFNjb3Blc1wiKSxcbiAgICB9O1xuICAgIHRoaXMuc2NvcGVzID0gbmV3IExSVUNhY2hlKHtcbiAgICAgIG1heDogdGhpcy5jb25maWcubWF4U2NvcGVzLFxuICAgICAgZGlzcG9zZTogKHN0YXRlKSA9PiB7XG4gICAgICAgIHN0YXRlLmdyb3VwLnNjb3Blcy5kZWxldGUoc3RhdGUpO1xuICAgICAgfSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKiBSZXR1cm4gb25lIHVzZXItaXNvbGF0ZWQgY2FjaGUgd2l0aGluIGEgaG9zdC93b3Jrc3BhY2UgaW52YWxpZGF0aW9uIGdyb3VwLiAqL1xuICBhc3luYyBmb3JTY29wZShpbnB1dDogRmlsZXNDYWNoZVNjb3BlKTogUHJvbWlzZTxGaWxlU3lzdGVtQ2FjaGU+IHtcbiAgICByZXR1cm4gKGF3YWl0IHRoaXMucmVzb2x2ZVNjb3BlU3RhdGUoaW5wdXQpKS5jYWNoZTtcbiAgfVxuXG4gIC8qKiBSZXRhaW4gb25lIHN0YWJsZSBmcmFtZXdvcmsgZmlsZXN5c3RlbSBzb3VyY2UgZm9yIHRoZSBzY29wZSBhbmQgbW91bnRlZCBwYXRocy4gKi9cbiAgYXN5bmMgZm9yRmlsZVN5c3RlbTxUIGV4dGVuZHMgb2JqZWN0PihcbiAgICBpbnB1dDogRmlsZXNDYWNoZVNjb3BlLFxuICAgIGlkZW50aXR5OiBGaWxlc0NhY2hlU291cmNlSWRlbnRpdHksXG4gICAgbG9hZDogKCkgPT4gVCB8IFByb21pc2U8VD4sXG4gICk6IFByb21pc2U8VD4ge1xuICAgIGNvbnN0IHN0YXRlID0gYXdhaXQgdGhpcy5yZXNvbHZlU2NvcGVTdGF0ZShpbnB1dCk7XG4gICAgY29uc3QgcGF0aHMgPSBpZGVudGl0eS5wYXRocy5tYXAoKHBhdGgpID0+IHBvc2l4UGF0aC5ub3JtYWxpemVSb290KHBhdGgpKTtcbiAgICBpZiAocGF0aHMubGVuZ3RoID09PSAwKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiRmlsZXN5c3RlbSBzb3VyY2UgcGF0aHMgbXVzdCBub3QgYmUgZW1wdHlcIik7XG4gICAgY29uc3Qgc291cmNlS2V5ID0gb2JqZWN0LnRvU3RhYmxlS2V5KHsgcGF0aHMgfSk7XG4gICAgbGV0IHNvdXJjZSA9IHN0YXRlLnNvdXJjZXMuZ2V0KHNvdXJjZUtleSk7XG4gICAgaWYgKCFzb3VyY2UpIHtcbiAgICAgIHNvdXJjZSA9IFByb21pc2UucmVzb2x2ZShsb2FkKCkpO1xuICAgICAgc3RhdGUuc291cmNlcy5zZXQoc291cmNlS2V5LCBzb3VyY2UpO1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgcmV0dXJuIChhd2FpdCBzb3VyY2UpIGFzIFQ7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmIChzdGF0ZS5zb3VyY2VzLmdldChzb3VyY2VLZXkpID09PSBzb3VyY2UpIHN0YXRlLnNvdXJjZXMuZGVsZXRlKHNvdXJjZUtleSk7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHJlc29sdmVTY29wZVN0YXRlKGlucHV0OiBGaWxlc0NhY2hlU2NvcGUpOiBQcm9taXNlPFNjb3BlU3RhdGU+IHtcbiAgICBjb25zdCBzY29wZSA9IHJlc29sdmVTY29wZShpbnB1dCwgdGhpcy5jb25maWcudHRsTXMpO1xuICAgIGNvbnN0IHNjb3BlS2V5ID0gb2JqZWN0LnRvU3RhYmxlS2V5KHtcbiAgICAgIGhvc3Q6IHNjb3BlLmhvc3QsXG4gICAgICB1c2VyS2V5OiBzY29wZS51c2VyS2V5LFxuICAgICAgd29ya3NwYWNlSWQ6IHNjb3BlLndvcmtzcGFjZUlkLFxuICAgIH0pO1xuICAgIGxldCBzdGF0ZSA9IHRoaXMuc2NvcGVzLmdldChzY29wZUtleSk7XG4gICAgaWYgKCFzdGF0ZSkge1xuICAgICAgY29uc3QgZ3JvdXAgPSB0aGlzLmdyb3VwKHNjb3BlKTtcbiAgICAgIHN0YXRlID0gdGhpcy5jcmVhdGVTY29wZShzY29wZSwgZ3JvdXApO1xuICAgICAgZ3JvdXAuc2NvcGVzLmFkZChzdGF0ZSk7XG4gICAgICB0aGlzLnNjb3Blcy5zZXQoc2NvcGVLZXksIHN0YXRlKTtcbiAgICB9XG4gICAgcmV0dXJuIHN0YXRlO1xuICB9XG5cbiAgLyoqIEZsdXNoIGV2ZXJ5IHBlbmRpbmcgaW52YWxpZGF0aW9uIGJhdGNoLiAqL1xuICBhc3luYyBmbHVzaCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCBQcm9taXNlLmFsbChbLi4udGhpcy5ncm91cHMudmFsdWVzKCldLm1hcCgoZ3JvdXApID0+IHRoaXMuZmx1c2hJbnZhbGlkYXRpb25zKGdyb3VwKSkpO1xuICB9XG5cbiAgLyoqIEZsdXNoIHN0YXRlIGFuZCByZWxlYXNlIGFsbCBwcm9jZXNzLWxvY2FsIGVudHJpZXMgYW5kIHRpbWVycy4gKi9cbiAgYXN5bmMgY2xvc2UoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgZm9yIChjb25zdCBncm91cCBvZiB0aGlzLmdyb3Vwcy52YWx1ZXMoKSkge1xuICAgICAgaWYgKGdyb3VwLnRpbWVyKSBjbGVhclRpbWVvdXQoZ3JvdXAudGltZXIpO1xuICAgICAgZ3JvdXAudGltZXIgPSB1bmRlZmluZWQ7XG4gICAgfVxuICAgIGF3YWl0IHRoaXMuZmx1c2goKTtcbiAgICB0aGlzLnNjb3Blcy5jbGVhcigpO1xuICAgIHRoaXMuZ3JvdXBzLmNsZWFyKCk7XG4gIH1cblxuICBwcml2YXRlIGdyb3VwKHNjb3BlOiBSZXNvbHZlZEZpbGVzQ2FjaGVTY29wZSk6IEdyb3VwU3RhdGUge1xuICAgIGNvbnN0IGtleSA9IG9iamVjdC50b1N0YWJsZUtleSh7XG4gICAgICBob3N0OiBzY29wZS5ob3N0LFxuICAgICAgd29ya3NwYWNlSWQ6IHNjb3BlLndvcmtzcGFjZUlkLFxuICAgIH0pO1xuICAgIGNvbnN0IGV4aXN0aW5nID0gdGhpcy5ncm91cHMuZ2V0KGtleSk7XG4gICAgaWYgKGV4aXN0aW5nKSByZXR1cm4gZXhpc3Rpbmc7XG4gICAgY29uc3QgZ3JvdXA6IEdyb3VwU3RhdGUgPSB7XG4gICAgICBwZW5kaW5nOiBuZXcgU2V0KCksXG4gICAgICBzY29wZXM6IG5ldyBTZXQoKSxcbiAgICB9O1xuICAgIHRoaXMuZ3JvdXBzLnNldChrZXksIGdyb3VwKTtcbiAgICByZXR1cm4gZ3JvdXA7XG4gIH1cblxuICBwcml2YXRlIGNyZWF0ZVNjb3BlKHNjb3BlOiBSZXNvbHZlZEZpbGVzQ2FjaGVTY29wZSwgZ3JvdXA6IEdyb3VwU3RhdGUpOiBTY29wZVN0YXRlIHtcbiAgICBjb25zdCBzdGF0ZSA9IHt9IGFzIFNjb3BlU3RhdGU7XG4gICAgc3RhdGUuc2NvcGUgPSBzY29wZTtcbiAgICBzdGF0ZS5ncm91cCA9IGdyb3VwO1xuICAgIHN0YXRlLmVudHJpZXMgPSBuZXcgTFJVQ2FjaGUoe1xuICAgICAgbWF4OiB0aGlzLmNvbmZpZy5tYXhFbnRyaWVzLFxuICAgICAgbWF4U2l6ZTogdGhpcy5jb25maWcubWF4Qnl0ZXMsXG4gICAgICBzaXplQ2FsY3VsYXRpb246IChlbnRyeSwgY2FjaGVLZXkpID0+IHJldGFpbmVkU2l6ZShjYWNoZUtleSwgZW50cnkpLFxuICAgIH0pO1xuICAgIHN0YXRlLnNvdXJjZXMgPSBuZXcgTWFwKCk7XG4gICAgc3RhdGUuY2FjaGUgPSB7XG4gICAgICByZWFkOiA8VCBleHRlbmRzIENhY2hlVmFsdWU+KGNhY2hlS2V5OiBzdHJpbmcsIGxvYWQ6ICgpID0+IFQgfCBQcm9taXNlPFQ+KSA9PlxuICAgICAgICB0aGlzLnJlYWQoc3RhdGUsIGNhY2hlS2V5LCBsb2FkKSxcbiAgICAgIGludmFsaWRhdGU6IChjYWNoZUtleTogc3RyaW5nKSA9PiB0aGlzLnF1ZXVlSW52YWxpZGF0aW9uKHN0YXRlLCBjYWNoZUtleSksXG4gICAgICBrZXlzOiAoKSA9PiB0aGlzLmtleXMoc3RhdGUpLFxuICAgIH07XG4gICAgcmV0dXJuIHN0YXRlO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyByZWFkPFQgZXh0ZW5kcyBDYWNoZVZhbHVlPihcbiAgICBzdGF0ZTogU2NvcGVTdGF0ZSxcbiAgICBrZXk6IHN0cmluZyxcbiAgICBsb2FkOiAoKSA9PiBUIHwgUHJvbWlzZTxUPixcbiAgKTogUHJvbWlzZTxUPiB7XG4gICAgaWYgKCFzdGF0ZS5ncm91cC5wZW5kaW5nLmhhcyhrZXkpKSB7XG4gICAgICBjb25zdCByZXRhaW5lZCA9IHN0YXRlLmVudHJpZXMuZ2V0KGtleSk7XG4gICAgICBpZiAocmV0YWluZWQpIHJldHVybiByZXRhaW5lZC52YWx1ZSBhcyBUO1xuICAgIH1cbiAgICBjb25zdCB2YWx1ZSA9IGF3YWl0IGxvYWQoKTtcbiAgICBzdGF0ZS5lbnRyaWVzLnNldChrZXksIHsgdmFsdWUgfSwgeyB0dGw6IHN0YXRlLnNjb3BlLnR0bE1zIH0pO1xuICAgIHJldHVybiB2YWx1ZTtcbiAgfVxuXG4gIHByaXZhdGUgKmtleXMoc3RhdGU6IFNjb3BlU3RhdGUpOiBJdGVyYWJsZTxzdHJpbmc+IHtcbiAgICBmb3IgKGNvbnN0IGtleSBvZiBzdGF0ZS5lbnRyaWVzLmtleXMoKSkge1xuICAgICAgaWYgKCFzdGF0ZS5ncm91cC5wZW5kaW5nLmhhcyhrZXkpKSB5aWVsZCBrZXk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBxdWV1ZUludmFsaWRhdGlvbihzdGF0ZTogU2NvcGVTdGF0ZSwga2V5OiBzdHJpbmcpOiB2b2lkIHtcbiAgICBzdGF0ZS5ncm91cC5wZW5kaW5nLmFkZChrZXkpO1xuICAgIGlmIChzdGF0ZS5ncm91cC50aW1lcikgcmV0dXJuO1xuICAgIHN0YXRlLmdyb3VwLnRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICBzdGF0ZS5ncm91cC50aW1lciA9IHVuZGVmaW5lZDtcbiAgICAgIHZvaWQgdGhpcy5mbHVzaEludmFsaWRhdGlvbnMoc3RhdGUuZ3JvdXApLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICBsb2dnZXIud2FybihcImZpbGVzeXN0ZW0gY2FjaGUgaW52YWxpZGF0aW9uIGJhdGNoIGZhaWxlZFwiLCB7XG4gICAgICAgICAgZXJyb3I6IGVycm9yVXRpbHMuZXJyb3JNZXNzYWdlKGVycm9yKSxcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9LCB0aGlzLmNvbmZpZy5pbnZhbGlkYXRpb25CYXRjaE1zKTtcbiAgICBzdGF0ZS5ncm91cC50aW1lci51bnJlZj8uKCk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGZsdXNoSW52YWxpZGF0aW9ucyhncm91cDogR3JvdXBTdGF0ZSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmIChncm91cC50aW1lcikgY2xlYXJUaW1lb3V0KGdyb3VwLnRpbWVyKTtcbiAgICBncm91cC50aW1lciA9IHVuZGVmaW5lZDtcbiAgICBpZiAoZ3JvdXAucGVuZGluZy5zaXplID09PSAwKSByZXR1cm47XG4gICAgY29uc3Qga2V5cyA9IFsuLi5ncm91cC5wZW5kaW5nXTtcbiAgICBncm91cC5wZW5kaW5nLmNsZWFyKCk7XG4gICAgZm9yIChjb25zdCBzdGF0ZSBvZiBncm91cC5zY29wZXMpIHtcbiAgICAgIGZvciAoY29uc3Qga2V5IG9mIGtleXMpIHN0YXRlLmVudHJpZXMuZGVsZXRlKGtleSk7XG4gICAgfVxuICB9XG59XG5cbi8qKiBBcHBLaXQgcGx1Z2luIHRoYXQgb3ducyBwcm9jZXNzLWxvY2FsIGZpbGVzeXN0ZW0gTFJVIGNhY2hlcy4gKi9cbmV4cG9ydCBjbGFzcyBGaWxlc0NhY2hlUGx1Z2luIGV4dGVuZHMgUGx1Z2luPEZpbGVzQ2FjaGVQbHVnaW5Db25maWc+IHtcbiAgc3RhdGljIG1hbmlmZXN0ID0ge1xuICAgIG5hbWU6IFwiZmlsZXMtY2FjaGVcIixcbiAgICBkaXNwbGF5TmFtZTogXCJGaWxlcyBDYWNoZVwiLFxuICAgIGRlc2NyaXB0aW9uOiBcIlByb3ZpZGVzIGJvdW5kZWQgdXNlci1zY29wZWQgcHJvY2Vzcy1sb2NhbCBmaWxlc3lzdGVtIGNhY2hlcy5cIixcbiAgICBzdGFiaWxpdHk6IFwiYmV0YVwiLFxuICAgIHJlc291cmNlczogeyByZXF1aXJlZDogW10sIG9wdGlvbmFsOiBbXSB9LFxuICB9IHNhdGlzZmllcyBQbHVnaW5NYW5pZmVzdDxcImZpbGVzLWNhY2hlXCI+O1xuXG4gIHByaXZhdGUgbWFuYWdlcj86IEZpbGVzQ2FjaGVNYW5hZ2VyO1xuXG4gIG92ZXJyaWRlIGFzeW5jIHNldHVwKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMubWFuYWdlciA9IG5ldyBGaWxlc0NhY2hlTWFuYWdlcih0aGlzLmNvbmZpZyk7XG4gICAgdGhpcy5jb250ZXh0Py5vbkxpZmVjeWNsZShcInNodXRkb3duXCIsICgpID0+IHRoaXMubWFuYWdlcj8uY2xvc2UoKSk7XG4gIH1cblxuICBvdmVycmlkZSBleHBvcnRzKCk6IEZpbGVzQ2FjaGVFeHBvcnRzIHtcbiAgICByZXR1cm4ge1xuICAgICAgZm9yU2NvcGU6IChzY29wZSkgPT4gdGhpcy5yZXF1aXJlTWFuYWdlcigpLmZvclNjb3BlKHNjb3BlKSxcbiAgICAgIGZvckZpbGVTeXN0ZW06IChzY29wZSwgaWRlbnRpdHksIGxvYWQpID0+XG4gICAgICAgIHRoaXMucmVxdWlyZU1hbmFnZXIoKS5mb3JGaWxlU3lzdGVtKHNjb3BlLCBpZGVudGl0eSwgbG9hZCksXG4gICAgICBmbHVzaDogKCkgPT4gdGhpcy5yZXF1aXJlTWFuYWdlcigpLmZsdXNoKCksXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgcmVxdWlyZU1hbmFnZXIoKTogRmlsZXNDYWNoZU1hbmFnZXIge1xuICAgIGlmICghdGhpcy5tYW5hZ2VyKSB0aHJvdyBuZXcgRXJyb3IoXCJGaWxlcyBjYWNoZSBwbHVnaW4gaGFzIG5vdCBjb21wbGV0ZWQgc2V0dXBcIik7XG4gICAgcmV0dXJuIHRoaXMubWFuYWdlcjtcbiAgfVxufVxuXG4vKiogQXBwS2l0IHJlZ2lzdHJhdGlvbiBmYWN0b3J5IGZvciB7QGxpbmsgRmlsZXNDYWNoZVBsdWdpbn0uICovXG5leHBvcnQgY29uc3QgZmlsZXNDYWNoZSA9IHRvUGx1Z2luKEZpbGVzQ2FjaGVQbHVnaW4pO1xuXG5mdW5jdGlvbiByZXNvbHZlU2NvcGUoaW5wdXQ6IEZpbGVzQ2FjaGVTY29wZSwgZGVmYXVsdFR0bE1zOiBudW1iZXIpOiBSZXNvbHZlZEZpbGVzQ2FjaGVTY29wZSB7XG4gIGNvbnN0IGhvc3QgPSBpbnB1dC5ob3N0LnRyaW0oKS5yZXBsYWNlKC9cXC8rJC8sIFwiXCIpO1xuICBjb25zdCB1c2VyS2V5ID0gaW5wdXQudXNlcktleS50cmltKCk7XG4gIGNvbnN0IHdvcmtzcGFjZUlkID0gaW5wdXQud29ya3NwYWNlSWQ/LnRyaW0oKSB8fCB1bmRlZmluZWQ7XG4gIGlmICghaG9zdCkgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkZpbGVzIGNhY2hlIHNjb3BlIGhvc3QgbXVzdCBub3QgYmUgYmxhbmtcIik7XG4gIGlmICghdXNlcktleSkgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkZpbGVzIGNhY2hlIHNjb3BlIHVzZXJLZXkgbXVzdCBub3QgYmUgYmxhbmtcIik7XG4gIHJldHVybiB7XG4gICAgaG9zdCxcbiAgICB1c2VyS2V5LFxuICAgIC4uLih3b3Jrc3BhY2VJZCA/IHsgd29ya3NwYWNlSWQgfSA6IHt9KSxcbiAgICB0dGxNczogcG9zaXRpdmVEdXJhdGlvbihpbnB1dC50dGxNcywgZGVmYXVsdFR0bE1zLCBcInNjb3BlLnR0bE1zXCIpLFxuICB9O1xufVxuXG5mdW5jdGlvbiBwb3NpdGl2ZUR1cmF0aW9uKHZhbHVlOiBudW1iZXIgfCB1bmRlZmluZWQsIGZhbGxiYWNrOiBudW1iZXIsIG5hbWU6IHN0cmluZyk6IG51bWJlciB7XG4gIGNvbnN0IHJlc29sdmVkID0gdmFsdWUgPz8gZmFsbGJhY2s7XG4gIGlmICghTnVtYmVyLmlzRmluaXRlKHJlc29sdmVkKSB8fCByZXNvbHZlZCA8PSAwKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoYCR7bmFtZX0gbXVzdCBiZSBhIGZpbml0ZSBwb3NpdGl2ZSBudW1iZXJgKTtcbiAgfVxuICByZXR1cm4gcmVzb2x2ZWQ7XG59XG5cbmZ1bmN0aW9uIHBvc2l0aXZlSW50ZWdlcih2YWx1ZTogbnVtYmVyIHwgdW5kZWZpbmVkLCBmYWxsYmFjazogbnVtYmVyLCBuYW1lOiBzdHJpbmcpOiBudW1iZXIge1xuICByZXR1cm4gTWF0aC5mbG9vcihwb3NpdGl2ZUR1cmF0aW9uKHZhbHVlLCBmYWxsYmFjaywgbmFtZSkpO1xufVxuXG5mdW5jdGlvbiByZXRhaW5lZFNpemUoa2V5OiBzdHJpbmcsIGVudHJ5OiBSZXRhaW5lZEVudHJ5KTogbnVtYmVyIHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gQnVmZmVyLmJ5dGVMZW5ndGgoa2V5KSArIEJ1ZmZlci5ieXRlTGVuZ3RoKEpTT04uc3RyaW5naWZ5KGVudHJ5LnZhbHVlKSk7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUjtcbiAgfVxufVxuIl19
|
package/lib/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/_auto-configure.ts","../src/_cache-storage.ts","../src/appkit.ts","../src/brand-context.ts","../src/bundle.ts","../src/child-process.ts","../src/databricks.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-provider.ts","../src/toolkit-entries.ts","../index.ts"],"version":"5.9.3"}
|
|
1
|
+
{"root":["../src/_auto-configure.ts","../src/_cache-storage.ts","../src/appkit.ts","../src/brand-context.ts","../src/bundle.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-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.95",
|
|
24
24
|
"@types/node": "^24.6.0",
|
|
25
25
|
"typescript": "^5.9.3",
|
|
26
26
|
"vitest": "3.2.4"
|
|
@@ -30,11 +30,12 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@databricks/sdk-experimental": "^0.17.0",
|
|
33
|
-
"@dbx-tools/auth": "^0.9.
|
|
34
|
-
"@dbx-tools/core": "^0.9.
|
|
35
|
-
"@dbx-tools/lakebase": "^0.9.
|
|
36
|
-
"@dbx-tools/postgres": "^0.9.
|
|
37
|
-
"@dbx-tools/shared-core": "^0.9.
|
|
33
|
+
"@dbx-tools/auth": "^0.9.95",
|
|
34
|
+
"@dbx-tools/core": "^0.9.95",
|
|
35
|
+
"@dbx-tools/lakebase": "^0.9.95",
|
|
36
|
+
"@dbx-tools/postgres": "^0.9.95",
|
|
37
|
+
"@dbx-tools/shared-core": "^0.9.95",
|
|
38
|
+
"@dbx-tools/shared-fs": "^0.9.95",
|
|
38
39
|
"lru-cache": "11.5.3",
|
|
39
40
|
"zod": "4.3.6"
|
|
40
41
|
},
|
|
@@ -69,6 +70,10 @@
|
|
|
69
70
|
"types": "./lib/src/databricks.d.ts",
|
|
70
71
|
"default": "./lib/src/databricks.js"
|
|
71
72
|
},
|
|
73
|
+
"./files-cache": {
|
|
74
|
+
"types": "./lib/src/files-cache.d.ts",
|
|
75
|
+
"default": "./lib/src/files-cache.js"
|
|
76
|
+
},
|
|
72
77
|
"./identity": {
|
|
73
78
|
"types": "./lib/src/identity.d.ts",
|
|
74
79
|
"default": "./lib/src/identity.js"
|
|
@@ -116,7 +121,7 @@
|
|
|
116
121
|
"./package.json": "./package.json"
|
|
117
122
|
}
|
|
118
123
|
},
|
|
119
|
-
"version": "0.9.
|
|
124
|
+
"version": "0.9.95",
|
|
120
125
|
"types": "./lib/index.d.ts",
|
|
121
126
|
"dbxToolsConfig": {
|
|
122
127
|
"tags": [
|
|
@@ -149,6 +154,10 @@
|
|
|
149
154
|
"types": "./lib/src/databricks.d.ts",
|
|
150
155
|
"default": "./lib/src/databricks.js"
|
|
151
156
|
},
|
|
157
|
+
"./files-cache": {
|
|
158
|
+
"types": "./lib/src/files-cache.d.ts",
|
|
159
|
+
"default": "./lib/src/files-cache.js"
|
|
160
|
+
},
|
|
152
161
|
"./identity": {
|
|
153
162
|
"types": "./lib/src/identity.d.ts",
|
|
154
163
|
"default": "./lib/src/identity.js"
|
package/src/_cache-storage.ts
CHANGED
|
@@ -40,6 +40,7 @@ export interface L1CacheStorageOptions {
|
|
|
40
40
|
|
|
41
41
|
/** AppKit's internal persistent storage surface. */
|
|
42
42
|
export type PersistentStorageBase = CacheStorage & {
|
|
43
|
+
cleanupExpired?(): Promise<number>;
|
|
43
44
|
initialize(): Promise<void>;
|
|
44
45
|
initialized: boolean;
|
|
45
46
|
schemaName?: string;
|
|
@@ -113,6 +114,16 @@ export class L1CacheStorage implements CacheStorage {
|
|
|
113
114
|
await this.storage.close();
|
|
114
115
|
}
|
|
115
116
|
|
|
117
|
+
/** Forward AppKit's runtime-only persistent cleanup hook when available. */
|
|
118
|
+
async cleanupExpired(): Promise<number> {
|
|
119
|
+
const cleanup = (
|
|
120
|
+
this.storage as CacheStorage & {
|
|
121
|
+
cleanupExpired?: () => Promise<number>;
|
|
122
|
+
}
|
|
123
|
+
).cleanupExpired;
|
|
124
|
+
return cleanup ? cleanup.call(this.storage) : 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
116
127
|
private retain<T>(key: string, entry: CacheEntry<T>): void {
|
|
117
128
|
const ttl = entry.expiry - Date.now();
|
|
118
129
|
if (ttl > 0) this.entries.set(key, entry, { ttl });
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AppKit-global filesystem cache with user-isolated process-local LRU values.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Plugin, toPlugin, type BasePluginConfig, type PluginManifest } from "@databricks/appkit";
|
|
8
|
+
import { posixPath, type CacheValue, type FileSystemCache } from "@dbx-tools/shared-fs";
|
|
9
|
+
import { errorUtils, log, object } from "@dbx-tools/shared-core";
|
|
10
|
+
import { LRUCache } from "lru-cache";
|
|
11
|
+
|
|
12
|
+
const DEFAULT_TTL_MS = 60_000;
|
|
13
|
+
const DEFAULT_INVALIDATION_BATCH_MS = 25;
|
|
14
|
+
const DEFAULT_MAX_ENTRIES = 1_000;
|
|
15
|
+
const DEFAULT_MAX_BYTES = 64 * 1024 * 1024;
|
|
16
|
+
const DEFAULT_MAX_SCOPES = 256;
|
|
17
|
+
const logger = log.logger("files-cache");
|
|
18
|
+
|
|
19
|
+
interface RetainedEntry {
|
|
20
|
+
value: CacheValue;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface ScopeState {
|
|
24
|
+
cache: FileSystemCache;
|
|
25
|
+
entries: LRUCache<string, RetainedEntry>;
|
|
26
|
+
group: GroupState;
|
|
27
|
+
scope: ResolvedFilesCacheScope;
|
|
28
|
+
sources: Map<string, Promise<object>>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface GroupState {
|
|
32
|
+
pending: Set<string>;
|
|
33
|
+
scopes: Set<ScopeState>;
|
|
34
|
+
timer?: ReturnType<typeof setTimeout>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface ResolvedFilesCacheConfig {
|
|
38
|
+
invalidationBatchMs: number;
|
|
39
|
+
maxBytes: number;
|
|
40
|
+
maxEntries: number;
|
|
41
|
+
maxScopes: number;
|
|
42
|
+
ttlMs: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface ResolvedFilesCacheScope {
|
|
46
|
+
host: string;
|
|
47
|
+
ttlMs: number;
|
|
48
|
+
userKey: string;
|
|
49
|
+
workspaceId?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Configuration for the AppKit files-cache plugin. */
|
|
53
|
+
export interface FilesCachePluginConfig extends BasePluginConfig {
|
|
54
|
+
/** Default entry TTL in milliseconds. Defaults to 60 seconds. */
|
|
55
|
+
ttlMs?: number;
|
|
56
|
+
/** Invalidation debounce window in milliseconds. Defaults to 25ms. */
|
|
57
|
+
invalidationBatchMs?: number;
|
|
58
|
+
/** Maximum entries retained in each user L1. Defaults to 1,000. */
|
|
59
|
+
maxEntries?: number;
|
|
60
|
+
/** Maximum retained bytes in each user L1. Defaults to 64 MiB. */
|
|
61
|
+
maxBytes?: number;
|
|
62
|
+
/** Maximum active user scopes retained by the process. Defaults to 256. */
|
|
63
|
+
maxScopes?: number;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Identity for one authorization-safe filesystem cache scope. */
|
|
67
|
+
export interface FilesCacheScope {
|
|
68
|
+
/** Databricks workspace host. */
|
|
69
|
+
host: string;
|
|
70
|
+
/** Attributed user identifier used to isolate values. */
|
|
71
|
+
userKey: string;
|
|
72
|
+
/** Optional workspace identifier included in shared invalidation scope. */
|
|
73
|
+
workspaceId?: string;
|
|
74
|
+
/** Optional per-scope entry TTL override in milliseconds. */
|
|
75
|
+
ttlMs?: number;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Stable identity for a framework filesystem source retained within one user scope. */
|
|
79
|
+
export interface FilesCacheSourceIdentity {
|
|
80
|
+
/** Actual mounted filesystem paths represented by the source. */
|
|
81
|
+
paths: readonly string[];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Public exports from {@link FilesCachePlugin}. */
|
|
85
|
+
export interface FilesCacheExports {
|
|
86
|
+
/** Resolve one user-isolated filesystem cache. */
|
|
87
|
+
forScope(scope: FilesCacheScope): Promise<FileSystemCache>;
|
|
88
|
+
/** Resolve one app-lifetime filesystem source for a user and its actual mounted paths. */
|
|
89
|
+
forFileSystem<T extends object>(
|
|
90
|
+
scope: FilesCacheScope,
|
|
91
|
+
identity: FilesCacheSourceIdentity,
|
|
92
|
+
load: () => T | Promise<T>,
|
|
93
|
+
): Promise<T>;
|
|
94
|
+
/** Flush pending invalidation batches. */
|
|
95
|
+
flush(): Promise<void>;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Process-local filesystem cache manager. */
|
|
99
|
+
export class FilesCacheManager {
|
|
100
|
+
private readonly config: ResolvedFilesCacheConfig;
|
|
101
|
+
private readonly groups = new Map<string, GroupState>();
|
|
102
|
+
private readonly scopes: LRUCache<string, ScopeState>;
|
|
103
|
+
|
|
104
|
+
constructor(config: FilesCachePluginConfig = {}) {
|
|
105
|
+
this.config = {
|
|
106
|
+
ttlMs: positiveDuration(config.ttlMs, DEFAULT_TTL_MS, "ttlMs"),
|
|
107
|
+
invalidationBatchMs: positiveDuration(
|
|
108
|
+
config.invalidationBatchMs,
|
|
109
|
+
DEFAULT_INVALIDATION_BATCH_MS,
|
|
110
|
+
"invalidationBatchMs",
|
|
111
|
+
),
|
|
112
|
+
maxEntries: positiveInteger(config.maxEntries, DEFAULT_MAX_ENTRIES, "maxEntries"),
|
|
113
|
+
maxBytes: positiveInteger(config.maxBytes, DEFAULT_MAX_BYTES, "maxBytes"),
|
|
114
|
+
maxScopes: positiveInteger(config.maxScopes, DEFAULT_MAX_SCOPES, "maxScopes"),
|
|
115
|
+
};
|
|
116
|
+
this.scopes = new LRUCache({
|
|
117
|
+
max: this.config.maxScopes,
|
|
118
|
+
dispose: (state) => {
|
|
119
|
+
state.group.scopes.delete(state);
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Return one user-isolated cache within a host/workspace invalidation group. */
|
|
125
|
+
async forScope(input: FilesCacheScope): Promise<FileSystemCache> {
|
|
126
|
+
return (await this.resolveScopeState(input)).cache;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Retain one stable framework filesystem source for the scope and mounted paths. */
|
|
130
|
+
async forFileSystem<T extends object>(
|
|
131
|
+
input: FilesCacheScope,
|
|
132
|
+
identity: FilesCacheSourceIdentity,
|
|
133
|
+
load: () => T | Promise<T>,
|
|
134
|
+
): Promise<T> {
|
|
135
|
+
const state = await this.resolveScopeState(input);
|
|
136
|
+
const paths = identity.paths.map((path) => posixPath.normalizeRoot(path));
|
|
137
|
+
if (paths.length === 0) throw new TypeError("Filesystem source paths must not be empty");
|
|
138
|
+
const sourceKey = object.toStableKey({ paths });
|
|
139
|
+
let source = state.sources.get(sourceKey);
|
|
140
|
+
if (!source) {
|
|
141
|
+
source = Promise.resolve(load());
|
|
142
|
+
state.sources.set(sourceKey, source);
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
return (await source) as T;
|
|
146
|
+
} catch (error) {
|
|
147
|
+
if (state.sources.get(sourceKey) === source) state.sources.delete(sourceKey);
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private async resolveScopeState(input: FilesCacheScope): Promise<ScopeState> {
|
|
153
|
+
const scope = resolveScope(input, this.config.ttlMs);
|
|
154
|
+
const scopeKey = object.toStableKey({
|
|
155
|
+
host: scope.host,
|
|
156
|
+
userKey: scope.userKey,
|
|
157
|
+
workspaceId: scope.workspaceId,
|
|
158
|
+
});
|
|
159
|
+
let state = this.scopes.get(scopeKey);
|
|
160
|
+
if (!state) {
|
|
161
|
+
const group = this.group(scope);
|
|
162
|
+
state = this.createScope(scope, group);
|
|
163
|
+
group.scopes.add(state);
|
|
164
|
+
this.scopes.set(scopeKey, state);
|
|
165
|
+
}
|
|
166
|
+
return state;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Flush every pending invalidation batch. */
|
|
170
|
+
async flush(): Promise<void> {
|
|
171
|
+
await Promise.all([...this.groups.values()].map((group) => this.flushInvalidations(group)));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Flush state and release all process-local entries and timers. */
|
|
175
|
+
async close(): Promise<void> {
|
|
176
|
+
for (const group of this.groups.values()) {
|
|
177
|
+
if (group.timer) clearTimeout(group.timer);
|
|
178
|
+
group.timer = undefined;
|
|
179
|
+
}
|
|
180
|
+
await this.flush();
|
|
181
|
+
this.scopes.clear();
|
|
182
|
+
this.groups.clear();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
private group(scope: ResolvedFilesCacheScope): GroupState {
|
|
186
|
+
const key = object.toStableKey({
|
|
187
|
+
host: scope.host,
|
|
188
|
+
workspaceId: scope.workspaceId,
|
|
189
|
+
});
|
|
190
|
+
const existing = this.groups.get(key);
|
|
191
|
+
if (existing) return existing;
|
|
192
|
+
const group: GroupState = {
|
|
193
|
+
pending: new Set(),
|
|
194
|
+
scopes: new Set(),
|
|
195
|
+
};
|
|
196
|
+
this.groups.set(key, group);
|
|
197
|
+
return group;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
private createScope(scope: ResolvedFilesCacheScope, group: GroupState): ScopeState {
|
|
201
|
+
const state = {} as ScopeState;
|
|
202
|
+
state.scope = scope;
|
|
203
|
+
state.group = group;
|
|
204
|
+
state.entries = new LRUCache({
|
|
205
|
+
max: this.config.maxEntries,
|
|
206
|
+
maxSize: this.config.maxBytes,
|
|
207
|
+
sizeCalculation: (entry, cacheKey) => retainedSize(cacheKey, entry),
|
|
208
|
+
});
|
|
209
|
+
state.sources = new Map();
|
|
210
|
+
state.cache = {
|
|
211
|
+
read: <T extends CacheValue>(cacheKey: string, load: () => T | Promise<T>) =>
|
|
212
|
+
this.read(state, cacheKey, load),
|
|
213
|
+
invalidate: (cacheKey: string) => this.queueInvalidation(state, cacheKey),
|
|
214
|
+
keys: () => this.keys(state),
|
|
215
|
+
};
|
|
216
|
+
return state;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
private async read<T extends CacheValue>(
|
|
220
|
+
state: ScopeState,
|
|
221
|
+
key: string,
|
|
222
|
+
load: () => T | Promise<T>,
|
|
223
|
+
): Promise<T> {
|
|
224
|
+
if (!state.group.pending.has(key)) {
|
|
225
|
+
const retained = state.entries.get(key);
|
|
226
|
+
if (retained) return retained.value as T;
|
|
227
|
+
}
|
|
228
|
+
const value = await load();
|
|
229
|
+
state.entries.set(key, { value }, { ttl: state.scope.ttlMs });
|
|
230
|
+
return value;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
private *keys(state: ScopeState): Iterable<string> {
|
|
234
|
+
for (const key of state.entries.keys()) {
|
|
235
|
+
if (!state.group.pending.has(key)) yield key;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
private queueInvalidation(state: ScopeState, key: string): void {
|
|
240
|
+
state.group.pending.add(key);
|
|
241
|
+
if (state.group.timer) return;
|
|
242
|
+
state.group.timer = setTimeout(() => {
|
|
243
|
+
state.group.timer = undefined;
|
|
244
|
+
void this.flushInvalidations(state.group).catch((error) => {
|
|
245
|
+
logger.warn("filesystem cache invalidation batch failed", {
|
|
246
|
+
error: errorUtils.errorMessage(error),
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
}, this.config.invalidationBatchMs);
|
|
250
|
+
state.group.timer.unref?.();
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
private async flushInvalidations(group: GroupState): Promise<void> {
|
|
254
|
+
if (group.timer) clearTimeout(group.timer);
|
|
255
|
+
group.timer = undefined;
|
|
256
|
+
if (group.pending.size === 0) return;
|
|
257
|
+
const keys = [...group.pending];
|
|
258
|
+
group.pending.clear();
|
|
259
|
+
for (const state of group.scopes) {
|
|
260
|
+
for (const key of keys) state.entries.delete(key);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** AppKit plugin that owns process-local filesystem LRU caches. */
|
|
266
|
+
export class FilesCachePlugin extends Plugin<FilesCachePluginConfig> {
|
|
267
|
+
static manifest = {
|
|
268
|
+
name: "files-cache",
|
|
269
|
+
displayName: "Files Cache",
|
|
270
|
+
description: "Provides bounded user-scoped process-local filesystem caches.",
|
|
271
|
+
stability: "beta",
|
|
272
|
+
resources: { required: [], optional: [] },
|
|
273
|
+
} satisfies PluginManifest<"files-cache">;
|
|
274
|
+
|
|
275
|
+
private manager?: FilesCacheManager;
|
|
276
|
+
|
|
277
|
+
override async setup(): Promise<void> {
|
|
278
|
+
this.manager = new FilesCacheManager(this.config);
|
|
279
|
+
this.context?.onLifecycle("shutdown", () => this.manager?.close());
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
override exports(): FilesCacheExports {
|
|
283
|
+
return {
|
|
284
|
+
forScope: (scope) => this.requireManager().forScope(scope),
|
|
285
|
+
forFileSystem: (scope, identity, load) =>
|
|
286
|
+
this.requireManager().forFileSystem(scope, identity, load),
|
|
287
|
+
flush: () => this.requireManager().flush(),
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
private requireManager(): FilesCacheManager {
|
|
292
|
+
if (!this.manager) throw new Error("Files cache plugin has not completed setup");
|
|
293
|
+
return this.manager;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/** AppKit registration factory for {@link FilesCachePlugin}. */
|
|
298
|
+
export const filesCache = toPlugin(FilesCachePlugin);
|
|
299
|
+
|
|
300
|
+
function resolveScope(input: FilesCacheScope, defaultTtlMs: number): ResolvedFilesCacheScope {
|
|
301
|
+
const host = input.host.trim().replace(/\/+$/, "");
|
|
302
|
+
const userKey = input.userKey.trim();
|
|
303
|
+
const workspaceId = input.workspaceId?.trim() || undefined;
|
|
304
|
+
if (!host) throw new TypeError("Files cache scope host must not be blank");
|
|
305
|
+
if (!userKey) throw new TypeError("Files cache scope userKey must not be blank");
|
|
306
|
+
return {
|
|
307
|
+
host,
|
|
308
|
+
userKey,
|
|
309
|
+
...(workspaceId ? { workspaceId } : {}),
|
|
310
|
+
ttlMs: positiveDuration(input.ttlMs, defaultTtlMs, "scope.ttlMs"),
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function positiveDuration(value: number | undefined, fallback: number, name: string): number {
|
|
315
|
+
const resolved = value ?? fallback;
|
|
316
|
+
if (!Number.isFinite(resolved) || resolved <= 0) {
|
|
317
|
+
throw new RangeError(`${name} must be a finite positive number`);
|
|
318
|
+
}
|
|
319
|
+
return resolved;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function positiveInteger(value: number | undefined, fallback: number, name: string): number {
|
|
323
|
+
return Math.floor(positiveDuration(value, fallback, name));
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function retainedSize(key: string, entry: RetainedEntry): number {
|
|
327
|
+
try {
|
|
328
|
+
return Buffer.byteLength(key) + Buffer.byteLength(JSON.stringify(entry.value));
|
|
329
|
+
} catch {
|
|
330
|
+
return Number.MAX_SAFE_INTEGER;
|
|
331
|
+
}
|
|
332
|
+
}
|