@b9g/platform 0.1.0

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/package.json ADDED
@@ -0,0 +1,109 @@
1
+ {
2
+ "name": "@b9g/platform",
3
+ "version": "0.1.0",
4
+ "description": "Base Platform interface and types for Shovel deployment adapters",
5
+ "keywords": [
6
+ "shovel",
7
+ "platform",
8
+ "deployment",
9
+ "adapter",
10
+ "interface"
11
+ ],
12
+ "dependencies": {
13
+ "@types/wicg-file-system-access": "^2023.10.7"
14
+ },
15
+ "devDependencies": {
16
+ "@b9g/libuild": "^0.1.10",
17
+ "bun-types": "latest"
18
+ },
19
+ "type": "module",
20
+ "types": "src/index.d.ts",
21
+ "module": "src/index.js",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./src/index.d.ts",
25
+ "import": "./src/index.js"
26
+ },
27
+ "./types": {
28
+ "types": "./src/types.d.ts",
29
+ "import": "./src/types.js"
30
+ },
31
+ "./types.js": {
32
+ "types": "./src/types.d.ts",
33
+ "import": "./src/types.js"
34
+ },
35
+ "./package.json": "./package.json",
36
+ "./adapter-registry": {
37
+ "types": "./src/adapter-registry.d.ts",
38
+ "import": "./src/adapter-registry.js"
39
+ },
40
+ "./adapter-registry.js": {
41
+ "types": "./src/adapter-registry.d.ts",
42
+ "import": "./src/adapter-registry.js"
43
+ },
44
+ "./base-platform": {
45
+ "types": "./src/base-platform.d.ts",
46
+ "import": "./src/base-platform.js"
47
+ },
48
+ "./base-platform.js": {
49
+ "types": "./src/base-platform.d.ts",
50
+ "import": "./src/base-platform.js"
51
+ },
52
+ "./filesystem": {
53
+ "types": "./src/filesystem.d.ts",
54
+ "import": "./src/filesystem.js"
55
+ },
56
+ "./filesystem.js": {
57
+ "types": "./src/filesystem.d.ts",
58
+ "import": "./src/filesystem.js"
59
+ },
60
+ "./index": {
61
+ "types": "./src/index.d.ts",
62
+ "import": "./src/index.js"
63
+ },
64
+ "./index.js": {
65
+ "types": "./src/index.d.ts",
66
+ "import": "./src/index.js"
67
+ },
68
+ "./registry": {
69
+ "types": "./src/registry.d.ts",
70
+ "import": "./src/registry.js"
71
+ },
72
+ "./registry.js": {
73
+ "types": "./src/registry.d.ts",
74
+ "import": "./src/registry.js"
75
+ },
76
+ "./service-worker": {
77
+ "types": "./src/service-worker.d.ts",
78
+ "import": "./src/service-worker.js"
79
+ },
80
+ "./service-worker.js": {
81
+ "types": "./src/service-worker.d.ts",
82
+ "import": "./src/service-worker.js"
83
+ },
84
+ "./utils": {
85
+ "types": "./src/utils.d.ts",
86
+ "import": "./src/utils.js"
87
+ },
88
+ "./utils.js": {
89
+ "types": "./src/utils.d.ts",
90
+ "import": "./src/utils.js"
91
+ },
92
+ "./detection": {
93
+ "types": "./src/detection.d.ts",
94
+ "import": "./src/detection.js"
95
+ },
96
+ "./detection.js": {
97
+ "types": "./src/detection.d.ts",
98
+ "import": "./src/detection.js"
99
+ },
100
+ "./directory-storage": {
101
+ "types": "./src/directory-storage.d.ts",
102
+ "import": "./src/directory-storage.js"
103
+ },
104
+ "./directory-storage.js": {
105
+ "types": "./src/directory-storage.d.ts",
106
+ "import": "./src/directory-storage.js"
107
+ }
108
+ }
109
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Blessed alias registry for official Shovel adapters
3
+ * Maps short names to full package names for CLI convenience
4
+ */
5
+ export interface AdapterModule {
6
+ createCache?: (config: any) => any;
7
+ createFileSystem?: (config: any) => any;
8
+ }
9
+ /**
10
+ * Official blessed aliases for cache adapters
11
+ */
12
+ export declare const CACHE_ALIASES: {
13
+ readonly memory: "@b9g/cache";
14
+ readonly redis: "@b9g/cache-redis";
15
+ readonly kv: "@b9g/cache-kv";
16
+ readonly cloudflare: "@b9g/cache/cloudflare";
17
+ };
18
+ /**
19
+ * Official blessed aliases for filesystem adapters
20
+ */
21
+ export declare const FILESYSTEM_ALIASES: {
22
+ readonly memory: "@b9g/filesystem";
23
+ readonly fs: "@b9g/filesystem/node";
24
+ readonly "bun-s3": "@b9g/filesystem/bun-s3";
25
+ readonly s3: "@b9g/filesystem-s3";
26
+ readonly r2: "@b9g/filesystem-r2";
27
+ };
28
+ /**
29
+ * Resolve a cache adapter name to a package name
30
+ * @param name - Blessed alias (memory, redis) or full package name (@custom/cache)
31
+ * @returns Full package name
32
+ */
33
+ export declare function resolveCacheAdapter(name: string): string;
34
+ /**
35
+ * Resolve a filesystem adapter name to a package name
36
+ * @param name - Blessed alias (memory, s3) or full package name (@custom/filesystem)
37
+ * @returns Full package name
38
+ */
39
+ export declare function resolveFilesystemAdapter(name: string): string;
40
+ /**
41
+ * Dynamically load a cache adapter
42
+ * @param name - Adapter name (blessed alias or package name)
43
+ * @param config - Adapter configuration
44
+ * @returns Cache instance
45
+ */
46
+ export declare function loadCacheAdapter(name: string, config?: any): Promise<any>;
47
+ /**
48
+ * Dynamically load a filesystem adapter
49
+ * @param name - Adapter name (blessed alias or package name)
50
+ * @param config - Adapter configuration
51
+ * @returns Filesystem adapter instance
52
+ */
53
+ export declare function loadFilesystemAdapter(name: string, config?: any): Promise<any>;
@@ -0,0 +1,71 @@
1
+ /// <reference types="./adapter-registry.d.ts" />
2
+ // src/adapter-registry.ts
3
+ var CACHE_ALIASES = {
4
+ memory: "@b9g/cache",
5
+ redis: "@b9g/cache-redis",
6
+ kv: "@b9g/cache-kv",
7
+ cloudflare: "@b9g/cache/cloudflare"
8
+ };
9
+ var FILESYSTEM_ALIASES = {
10
+ memory: "@b9g/filesystem",
11
+ fs: "@b9g/filesystem/node",
12
+ "bun-s3": "@b9g/filesystem/bun-s3",
13
+ s3: "@b9g/filesystem-s3",
14
+ r2: "@b9g/filesystem-r2"
15
+ };
16
+ function resolveCacheAdapter(name) {
17
+ if (name.startsWith("@")) {
18
+ return name;
19
+ }
20
+ if (name in CACHE_ALIASES) {
21
+ return CACHE_ALIASES[name];
22
+ }
23
+ throw new Error(`Unknown cache adapter: ${name}. Available aliases: ${Object.keys(CACHE_ALIASES).join(", ")} or use full package name like @custom/cache`);
24
+ }
25
+ function resolveFilesystemAdapter(name) {
26
+ if (name.startsWith("@")) {
27
+ return name;
28
+ }
29
+ if (name in FILESYSTEM_ALIASES) {
30
+ return FILESYSTEM_ALIASES[name];
31
+ }
32
+ throw new Error(`Unknown filesystem adapter: ${name}. Available aliases: ${Object.keys(FILESYSTEM_ALIASES).join(", ")} or use full package name like @custom/filesystem`);
33
+ }
34
+ async function loadCacheAdapter(name, config = {}) {
35
+ const packageName = resolveCacheAdapter(name);
36
+ try {
37
+ const module = await import(packageName);
38
+ if (!module.createCache) {
39
+ throw new Error(`Package ${packageName} does not export a createCache function`);
40
+ }
41
+ return module.createCache(config);
42
+ } catch (error) {
43
+ if (error instanceof Error && error.message.includes("Cannot resolve module")) {
44
+ throw new Error(`Cache adapter '${name}' requires: npm install ${packageName}`);
45
+ }
46
+ throw error;
47
+ }
48
+ }
49
+ async function loadFilesystemAdapter(name, config = {}) {
50
+ const packageName = resolveFilesystemAdapter(name);
51
+ try {
52
+ const module = await import(packageName);
53
+ if (!module.createFileSystem) {
54
+ throw new Error(`Package ${packageName} does not export a createFileSystem function`);
55
+ }
56
+ return module.createFileSystem(config);
57
+ } catch (error) {
58
+ if (error instanceof Error && error.message.includes("Cannot resolve module")) {
59
+ throw new Error(`Filesystem adapter '${name}' requires: npm install ${packageName}`);
60
+ }
61
+ throw error;
62
+ }
63
+ }
64
+ export {
65
+ CACHE_ALIASES,
66
+ FILESYSTEM_ALIASES,
67
+ loadCacheAdapter,
68
+ loadFilesystemAdapter,
69
+ resolveCacheAdapter,
70
+ resolveFilesystemAdapter
71
+ };
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Base platform implementation with dynamic adapter loading
3
+ * Provides common functionality for all platform implementations
4
+ */
5
+ import type { Platform, PlatformConfig, CacheConfig, CacheBackendConfig, FilesystemConfig } from "./types.js";
6
+ import type { CacheStorage } from "@b9g/cache/cache-storage";
7
+ /**
8
+ * Base platform class with shared adapter loading logic
9
+ * Platform implementations extend this and provide platform-specific methods
10
+ */
11
+ export declare abstract class BasePlatform implements Platform {
12
+ protected config: PlatformConfig;
13
+ constructor(config?: PlatformConfig);
14
+ abstract readonly name: string;
15
+ abstract readonly distDir: FileSystemDirectoryHandle;
16
+ abstract loadServiceWorker(entrypoint: string, options?: any): Promise<any>;
17
+ abstract createServer(handler: any, options?: any): any;
18
+ abstract getFileSystemRoot(bucketName: string): Promise<FileSystemDirectoryHandle>;
19
+ /**
20
+ * Create cache storage with dynamic adapter loading
21
+ * Uses platform defaults when specific cache types aren't configured
22
+ */
23
+ createCaches(config?: CacheConfig): Promise<CacheStorage>;
24
+ /**
25
+ * Get platform-specific default cache configuration
26
+ * Subclasses override this to provide optimal defaults for their runtime
27
+ */
28
+ protected getDefaultCacheConfig(): CacheConfig;
29
+ /**
30
+ * Merge user config with platform defaults
31
+ */
32
+ protected mergeCacheConfig(userConfig?: CacheConfig): CacheConfig;
33
+ /**
34
+ * Build CacheStorage instance with dynamic adapter loading
35
+ */
36
+ protected buildCacheStorage(config: CacheConfig): Promise<CacheStorage>;
37
+ /**
38
+ * Load a single cache instance using dynamic import
39
+ */
40
+ protected loadCacheInstance(config: CacheBackendConfig): Promise<any>;
41
+ /**
42
+ * Load filesystem adapter using dynamic import
43
+ */
44
+ protected loadFilesystemAdapter(config?: FilesystemConfig): Promise<any>;
45
+ /**
46
+ * Get platform-specific default filesystem configuration
47
+ * Subclasses override this to provide optimal defaults for their runtime
48
+ */
49
+ protected getDefaultFilesystemConfig(): FilesystemConfig;
50
+ }
@@ -0,0 +1,114 @@
1
+ /// <reference types="./base-platform.d.ts" />
2
+ // src/base-platform.ts
3
+ import { loadCacheAdapter, loadFilesystemAdapter } from "./adapter-registry.js";
4
+ var BasePlatform = class {
5
+ config;
6
+ constructor(config = {}) {
7
+ this.config = config;
8
+ }
9
+ /**
10
+ * Create cache storage with dynamic adapter loading
11
+ * Uses platform defaults when specific cache types aren't configured
12
+ */
13
+ async createCaches(config) {
14
+ const mergedConfig = this.mergeCacheConfig(config);
15
+ return this.buildCacheStorage(mergedConfig);
16
+ }
17
+ /**
18
+ * Get platform-specific default cache configuration
19
+ * Subclasses override this to provide optimal defaults for their runtime
20
+ */
21
+ getDefaultCacheConfig() {
22
+ return {
23
+ pages: { type: "memory" },
24
+ api: { type: "memory" },
25
+ static: { type: "memory" }
26
+ };
27
+ }
28
+ /**
29
+ * Merge user config with platform defaults
30
+ */
31
+ mergeCacheConfig(userConfig) {
32
+ const defaults = this.getDefaultCacheConfig();
33
+ const platformConfig = this.config.caches || {};
34
+ return {
35
+ ...defaults,
36
+ ...platformConfig,
37
+ ...userConfig
38
+ };
39
+ }
40
+ /**
41
+ * Build CacheStorage instance with dynamic adapter loading
42
+ */
43
+ async buildCacheStorage(config) {
44
+ const caches = /* @__PURE__ */ new Map();
45
+ for (const [name, cacheConfig] of Object.entries(config)) {
46
+ if (cacheConfig && typeof cacheConfig === "object" && "type" in cacheConfig) {
47
+ const cache = await this.loadCacheInstance(cacheConfig);
48
+ caches.set(name, cache);
49
+ }
50
+ }
51
+ return {
52
+ async open(name) {
53
+ const cache = caches.get(name);
54
+ if (!cache) {
55
+ throw new Error(`Cache '${name}' not configured`);
56
+ }
57
+ return cache;
58
+ },
59
+ async delete(name) {
60
+ const deleted = caches.delete(name);
61
+ return deleted;
62
+ },
63
+ async has(name) {
64
+ return caches.has(name);
65
+ },
66
+ async keys() {
67
+ return Array.from(caches.keys());
68
+ }
69
+ };
70
+ }
71
+ /**
72
+ * Load a single cache instance using dynamic import
73
+ */
74
+ async loadCacheInstance(config) {
75
+ if (!config.type) {
76
+ throw new Error("Cache configuration must specify a type");
77
+ }
78
+ try {
79
+ return await loadCacheAdapter(config.type, config);
80
+ } catch (error) {
81
+ if (error instanceof Error) {
82
+ throw new Error(`Failed to load cache adapter: ${error.message}`);
83
+ }
84
+ throw error;
85
+ }
86
+ }
87
+ /**
88
+ * Load filesystem adapter using dynamic import
89
+ */
90
+ async loadFilesystemAdapter(config) {
91
+ const fsConfig = config || this.config.filesystem || this.getDefaultFilesystemConfig();
92
+ if (!fsConfig.type) {
93
+ throw new Error("Filesystem configuration must specify a type");
94
+ }
95
+ try {
96
+ return await loadFilesystemAdapter(fsConfig.type, fsConfig);
97
+ } catch (error) {
98
+ if (error instanceof Error) {
99
+ throw new Error(`Failed to load filesystem adapter: ${error.message}`);
100
+ }
101
+ throw error;
102
+ }
103
+ }
104
+ /**
105
+ * Get platform-specific default filesystem configuration
106
+ * Subclasses override this to provide optimal defaults for their runtime
107
+ */
108
+ getDefaultFilesystemConfig() {
109
+ return { type: "memory" };
110
+ }
111
+ };
112
+ export {
113
+ BasePlatform
114
+ };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Platform detection utilities
3
+ * Centralized logic for detecting JavaScript runtime and deployment platforms
4
+ */
5
+ import type { PlatformDetection } from "./types.js";
6
+ /**
7
+ * Detect the current JavaScript runtime
8
+ */
9
+ export declare function detectRuntime(): "bun" | "deno" | "node";
10
+ /**
11
+ * Detect platform for development (uses current runtime)
12
+ */
13
+ export declare function detectDevelopmentPlatform(): string;
14
+ /**
15
+ * Comprehensive platform detection with confidence scoring
16
+ */
17
+ export declare function detectPlatforms(): PlatformDetection[];
18
+ /**
19
+ * Get the best platform detection
20
+ */
21
+ export declare function getBestPlatformDetection(): PlatformDetection;
22
+ /**
23
+ * Resolve platform name from options or auto-detect
24
+ */
25
+ export declare function resolvePlatform(options: {
26
+ platform?: string;
27
+ target?: string;
28
+ }): string;
29
+ /**
30
+ * Create platform instance based on name
31
+ */
32
+ export declare function createPlatform(platformName: string, options?: any): Promise<any>;
33
+ /**
34
+ * Display platform information (for CLI info command)
35
+ */
36
+ export declare function displayPlatformInfo(platformName: string): void;
@@ -0,0 +1,126 @@
1
+ /// <reference types="./detection.d.ts" />
2
+ // src/detection.ts
3
+ function detectRuntime() {
4
+ if (typeof Bun !== "undefined" || process.versions?.bun) {
5
+ return "bun";
6
+ }
7
+ if (typeof Deno !== "undefined") {
8
+ return "deno";
9
+ }
10
+ return "node";
11
+ }
12
+ function detectDevelopmentPlatform() {
13
+ const runtime = detectRuntime();
14
+ switch (runtime) {
15
+ case "bun":
16
+ return "bun";
17
+ case "deno":
18
+ return "node";
19
+ case "node":
20
+ default:
21
+ return "node";
22
+ }
23
+ }
24
+ function detectPlatforms() {
25
+ const detections = [];
26
+ if (typeof Bun !== "undefined") {
27
+ detections.push({
28
+ platform: "bun",
29
+ confidence: 0.9,
30
+ reasons: ["Bun global detected"]
31
+ });
32
+ }
33
+ if (typeof EdgeRuntime !== "undefined") {
34
+ detections.push({
35
+ platform: "vercel",
36
+ confidence: 0.9,
37
+ reasons: ["Vercel EdgeRuntime detected"]
38
+ });
39
+ }
40
+ if (typeof Deno !== "undefined") {
41
+ detections.push({
42
+ platform: "deno",
43
+ confidence: 0.9,
44
+ reasons: ["Deno global detected"]
45
+ });
46
+ }
47
+ if (typeof caches !== "undefined" && typeof Response !== "undefined" && typeof crypto !== "undefined") {
48
+ if (typeof addEventListener !== "undefined" && typeof fetch !== "undefined") {
49
+ detections.push({
50
+ platform: "cloudflare-workers",
51
+ confidence: 0.8,
52
+ reasons: ["Worker-like environment detected", "Web APIs available"]
53
+ });
54
+ }
55
+ }
56
+ if (typeof process !== "undefined" && process.versions && process.versions.node) {
57
+ detections.push({
58
+ platform: "node",
59
+ confidence: 0.7,
60
+ reasons: ["Node.js process detected"]
61
+ });
62
+ }
63
+ if (detections.length === 0) {
64
+ detections.push({
65
+ platform: "unknown",
66
+ confidence: 0,
67
+ reasons: ["No platform detected"]
68
+ });
69
+ }
70
+ return detections.sort((a, b) => b.confidence - a.confidence);
71
+ }
72
+ function getBestPlatformDetection() {
73
+ const detections = detectPlatforms();
74
+ return detections[0];
75
+ }
76
+ function resolvePlatform(options) {
77
+ if (options.platform) {
78
+ return options.platform;
79
+ }
80
+ if (options.target) {
81
+ return options.target;
82
+ }
83
+ return detectDevelopmentPlatform();
84
+ }
85
+ async function createPlatform(platformName, options = {}) {
86
+ switch (platformName) {
87
+ case "node": {
88
+ const modulePath = import.meta.resolve("@b9g/platform-node");
89
+ const { createNodePlatform } = await import(modulePath);
90
+ return createNodePlatform(options);
91
+ }
92
+ case "bun": {
93
+ const modulePath = import.meta.resolve("@b9g/platform-bun");
94
+ const { createBunPlatform } = await import(modulePath);
95
+ return createBunPlatform(options);
96
+ }
97
+ case "cloudflare":
98
+ case "cloudflare-workers":
99
+ case "cf": {
100
+ const modulePath = import.meta.resolve("@b9g/platform-cloudflare");
101
+ const { createCloudflarePlatform } = await import(modulePath);
102
+ return createCloudflarePlatform(options);
103
+ }
104
+ default:
105
+ throw new Error(
106
+ `Unknown platform: ${platformName}. Available platforms: node, bun, cloudflare`
107
+ );
108
+ }
109
+ }
110
+ function displayPlatformInfo(platformName) {
111
+ const runtime = detectRuntime();
112
+ const detection = getBestPlatformDetection();
113
+ console.info(`\u{1F680} Platform: ${platformName}`);
114
+ console.info(`\u2699\uFE0F Runtime: ${runtime}`);
115
+ console.info(`\u{1F50D} Auto-detected: ${detection.platform} (confidence: ${detection.confidence})`);
116
+ console.info(`\u{1F4A1} Reasons: ${detection.reasons.join(", ")}`);
117
+ }
118
+ export {
119
+ createPlatform,
120
+ detectDevelopmentPlatform,
121
+ detectPlatforms,
122
+ detectRuntime,
123
+ displayPlatformInfo,
124
+ getBestPlatformDetection,
125
+ resolvePlatform
126
+ };
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Directory Storage implementation for ServiceWorker self.dirs API
3
+ *
4
+ * This implements the proposed web standard interface that parallels CacheStorage
5
+ * for structured filesystem access in ServiceWorkers.
6
+ */
7
+ import type { DirectoryStorage } from "./service-worker.js";
8
+ /**
9
+ * Platform-agnostic directory storage implementation
10
+ * Uses a single root directory with well-known subdirectories
11
+ */
12
+ export declare class PlatformDirectoryStorage implements DirectoryStorage {
13
+ private rootDir;
14
+ private cache;
15
+ constructor(rootDir: FileSystemDirectoryHandle);
16
+ /**
17
+ * Open a named directory - creates if it doesn't exist
18
+ * Well-known names: 'assets', 'static', 'server', 'client'
19
+ */
20
+ open(name: string): Promise<FileSystemDirectoryHandle>;
21
+ /**
22
+ * Check if a named directory exists
23
+ */
24
+ has(name: string): Promise<boolean>;
25
+ /**
26
+ * Delete a named directory and all its contents
27
+ */
28
+ delete(name: string): Promise<boolean>;
29
+ /**
30
+ * List all available directory names
31
+ */
32
+ keys(): Promise<string[]>;
33
+ /**
34
+ * Clear the cache (useful for hot reloading)
35
+ */
36
+ clearCache(): void;
37
+ }
38
+ /**
39
+ * Create a DirectoryStorage instance from a root directory
40
+ */
41
+ export declare function createDirectoryStorage(rootDir: FileSystemDirectoryHandle): DirectoryStorage;
@@ -0,0 +1,78 @@
1
+ /// <reference types="./directory-storage.d.ts" />
2
+ // src/directory-storage.ts
3
+ var PlatformDirectoryStorage = class {
4
+ rootDir;
5
+ cache = /* @__PURE__ */ new Map();
6
+ constructor(rootDir) {
7
+ this.rootDir = rootDir;
8
+ }
9
+ /**
10
+ * Open a named directory - creates if it doesn't exist
11
+ * Well-known names: 'assets', 'static', 'server', 'client'
12
+ */
13
+ async open(name) {
14
+ if (this.cache.has(name)) {
15
+ return this.cache.get(name);
16
+ }
17
+ try {
18
+ const dirHandle = await this.rootDir.getDirectoryHandle(name);
19
+ this.cache.set(name, dirHandle);
20
+ return dirHandle;
21
+ } catch (error) {
22
+ const dirHandle = await this.rootDir.getDirectoryHandle(name, { create: true });
23
+ this.cache.set(name, dirHandle);
24
+ return dirHandle;
25
+ }
26
+ }
27
+ /**
28
+ * Check if a named directory exists
29
+ */
30
+ async has(name) {
31
+ try {
32
+ await this.rootDir.getDirectoryHandle(name);
33
+ return true;
34
+ } catch {
35
+ return false;
36
+ }
37
+ }
38
+ /**
39
+ * Delete a named directory and all its contents
40
+ */
41
+ async delete(name) {
42
+ try {
43
+ await this.rootDir.removeEntry(name, { recursive: true });
44
+ this.cache.delete(name);
45
+ return true;
46
+ } catch {
47
+ return false;
48
+ }
49
+ }
50
+ /**
51
+ * List all available directory names
52
+ */
53
+ async keys() {
54
+ const keys = [];
55
+ try {
56
+ for await (const [name, handle] of this.rootDir.entries()) {
57
+ if (handle.kind === "directory") {
58
+ keys.push(name);
59
+ }
60
+ }
61
+ } catch {
62
+ }
63
+ return keys.sort();
64
+ }
65
+ /**
66
+ * Clear the cache (useful for hot reloading)
67
+ */
68
+ clearCache() {
69
+ this.cache.clear();
70
+ }
71
+ };
72
+ function createDirectoryStorage(rootDir) {
73
+ return new PlatformDirectoryStorage(rootDir);
74
+ }
75
+ export {
76
+ PlatformDirectoryStorage,
77
+ createDirectoryStorage
78
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * File System Access API implementation
3
+ */
4
+ /**
5
+ * Get the file system root handle for the specified name
6
+ * Auto-registers Node.js platform if no platform is detected
7
+ */
8
+ export declare function getFileSystemRoot(name?: string): Promise<FileSystemDirectoryHandle>;