@modularizer/plat 0.8.0 → 0.9.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.
Files changed (78) hide show
  1. package/README.md +75 -0
  2. package/dist/client-server-entry.d.ts +4 -0
  3. package/dist/client-server-entry.d.ts.map +1 -1
  4. package/dist/client-server-entry.js +4 -0
  5. package/dist/client-server-entry.js.map +1 -1
  6. package/dist/client-side-python/runtime.d.ts +1 -0
  7. package/dist/client-side-python/runtime.d.ts.map +1 -1
  8. package/dist/client-side-python/runtime.js +10 -1
  9. package/dist/client-side-python/runtime.js.map +1 -1
  10. package/dist/client-side-server/channel.d.ts +1 -1
  11. package/dist/client-side-server/channel.d.ts.map +1 -1
  12. package/dist/client-side-server/channel.js +113 -4
  13. package/dist/client-side-server/channel.js.map +1 -1
  14. package/dist/client-side-server/mqtt-webrtc.d.ts.map +1 -1
  15. package/dist/client-side-server/mqtt-webrtc.js +4 -0
  16. package/dist/client-side-server/mqtt-webrtc.js.map +1 -1
  17. package/dist/client-side-server/plat-bridge.d.ts +40 -0
  18. package/dist/client-side-server/plat-bridge.d.ts.map +1 -0
  19. package/dist/client-side-server/plat-bridge.js +876 -0
  20. package/dist/client-side-server/plat-bridge.js.map +1 -0
  21. package/dist/client-side-server/plat-fetch.d.ts +33 -0
  22. package/dist/client-side-server/plat-fetch.d.ts.map +1 -0
  23. package/dist/client-side-server/plat-fetch.js +199 -0
  24. package/dist/client-side-server/plat-fetch.js.map +1 -0
  25. package/dist/client-side-server/plat-service-worker-client.d.ts +30 -0
  26. package/dist/client-side-server/plat-service-worker-client.d.ts.map +1 -0
  27. package/dist/client-side-server/plat-service-worker-client.js +141 -0
  28. package/dist/client-side-server/plat-service-worker-client.js.map +1 -0
  29. package/dist/client-side-server/plat-service-worker.d.ts +35 -0
  30. package/dist/client-side-server/plat-service-worker.d.ts.map +1 -0
  31. package/dist/client-side-server/plat-service-worker.js +292 -0
  32. package/dist/client-side-server/plat-service-worker.js.map +1 -0
  33. package/dist/client-side-server/protocol.d.ts +22 -0
  34. package/dist/client-side-server/protocol.d.ts.map +1 -1
  35. package/dist/client-side-server/protocol.js.map +1 -1
  36. package/dist/client-side-server/runtime.d.ts +9 -0
  37. package/dist/client-side-server/runtime.d.ts.map +1 -1
  38. package/dist/client-side-server/runtime.js +37 -13
  39. package/dist/client-side-server/runtime.js.map +1 -1
  40. package/dist/client-side-server/server.d.ts +17 -0
  41. package/dist/client-side-server/server.d.ts.map +1 -1
  42. package/dist/client-side-server/server.js +111 -7
  43. package/dist/client-side-server/server.js.map +1 -1
  44. package/dist/generated/python-browser-sources.js +4 -4
  45. package/dist/generated/python-browser-sources.js.map +1 -1
  46. package/dist/server/core.d.ts +8 -0
  47. package/dist/server/core.d.ts.map +1 -1
  48. package/dist/server/core.js +21 -0
  49. package/dist/server/core.js.map +1 -1
  50. package/dist/server/server.d.ts +4 -0
  51. package/dist/server/server.d.ts.map +1 -1
  52. package/dist/server/server.js +81 -2
  53. package/dist/server/server.js.map +1 -1
  54. package/dist/static/file-response.d.ts +42 -0
  55. package/dist/static/file-response.d.ts.map +1 -0
  56. package/dist/static/file-response.js +57 -0
  57. package/dist/static/file-response.js.map +1 -0
  58. package/dist/static/glob-match.d.ts +16 -0
  59. package/dist/static/glob-match.d.ts.map +1 -0
  60. package/dist/static/glob-match.js +48 -0
  61. package/dist/static/glob-match.js.map +1 -0
  62. package/dist/static/index.d.ts +9 -0
  63. package/dist/static/index.d.ts.map +1 -0
  64. package/dist/static/index.js +6 -0
  65. package/dist/static/index.js.map +1 -0
  66. package/dist/static/mime-types.d.ts +6 -0
  67. package/dist/static/mime-types.d.ts.map +1 -0
  68. package/dist/static/mime-types.js +74 -0
  69. package/dist/static/mime-types.js.map +1 -0
  70. package/dist/static/static-folder.d.ts +69 -0
  71. package/dist/static/static-folder.d.ts.map +1 -0
  72. package/dist/static/static-folder.js +206 -0
  73. package/dist/static/static-folder.js.map +1 -0
  74. package/dist/static/virtual-file-system.d.ts +45 -0
  75. package/dist/static/virtual-file-system.d.ts.map +1 -0
  76. package/dist/static/virtual-file-system.js +100 -0
  77. package/dist/static/virtual-file-system.js.map +1 -0
  78. package/package.json +5 -1
@@ -0,0 +1,74 @@
1
+ const MIME_TYPES = {
2
+ // Text
3
+ '.html': 'text/html',
4
+ '.htm': 'text/html',
5
+ '.css': 'text/css',
6
+ '.csv': 'text/csv',
7
+ '.txt': 'text/plain',
8
+ '.xml': 'text/xml',
9
+ '.md': 'text/markdown',
10
+ '.yaml': 'text/yaml',
11
+ '.yml': 'text/yaml',
12
+ // JavaScript / JSON
13
+ '.js': 'application/javascript',
14
+ '.mjs': 'application/javascript',
15
+ '.cjs': 'application/javascript',
16
+ '.json': 'application/json',
17
+ '.jsonld': 'application/ld+json',
18
+ '.map': 'application/json',
19
+ '.ts': 'text/typescript',
20
+ // Images
21
+ '.png': 'image/png',
22
+ '.jpg': 'image/jpeg',
23
+ '.jpeg': 'image/jpeg',
24
+ '.gif': 'image/gif',
25
+ '.svg': 'image/svg+xml',
26
+ '.ico': 'image/x-icon',
27
+ '.webp': 'image/webp',
28
+ '.avif': 'image/avif',
29
+ '.bmp': 'image/bmp',
30
+ '.tiff': 'image/tiff',
31
+ '.tif': 'image/tiff',
32
+ // Fonts
33
+ '.woff': 'font/woff',
34
+ '.woff2': 'font/woff2',
35
+ '.ttf': 'font/ttf',
36
+ '.otf': 'font/otf',
37
+ '.eot': 'application/vnd.ms-fontobject',
38
+ // Audio
39
+ '.mp3': 'audio/mpeg',
40
+ '.wav': 'audio/wav',
41
+ '.ogg': 'audio/ogg',
42
+ '.flac': 'audio/flac',
43
+ '.aac': 'audio/aac',
44
+ '.m4a': 'audio/mp4',
45
+ // Video
46
+ '.mp4': 'video/mp4',
47
+ '.webm': 'video/webm',
48
+ '.avi': 'video/x-msvideo',
49
+ '.mov': 'video/quicktime',
50
+ '.mkv': 'video/x-matroska',
51
+ // Documents
52
+ '.pdf': 'application/pdf',
53
+ '.zip': 'application/zip',
54
+ '.gz': 'application/gzip',
55
+ '.tar': 'application/x-tar',
56
+ '.7z': 'application/x-7z-compressed',
57
+ '.rar': 'application/vnd.rar',
58
+ // Web
59
+ '.wasm': 'application/wasm',
60
+ '.manifest': 'text/cache-manifest',
61
+ '.webmanifest': 'application/manifest+json',
62
+ };
63
+ /**
64
+ * Get MIME content-type from a filename or extension.
65
+ * Returns 'application/octet-stream' for unrecognized extensions.
66
+ */
67
+ export function getMimeType(filename) {
68
+ const dot = filename.lastIndexOf('.');
69
+ if (dot === -1)
70
+ return 'application/octet-stream';
71
+ const ext = filename.slice(dot).toLowerCase();
72
+ return MIME_TYPES[ext] ?? 'application/octet-stream';
73
+ }
74
+ //# sourceMappingURL=mime-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mime-types.js","sourceRoot":"","sources":["../../src/static/mime-types.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,GAA2B;IACzC,OAAO;IACP,OAAO,EAAE,WAAW;IACpB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,UAAU;IAClB,MAAM,EAAE,UAAU;IAClB,MAAM,EAAE,YAAY;IACpB,MAAM,EAAE,UAAU;IAClB,KAAK,EAAE,eAAe;IACtB,OAAO,EAAE,WAAW;IACpB,MAAM,EAAE,WAAW;IAEnB,oBAAoB;IACpB,KAAK,EAAE,wBAAwB;IAC/B,MAAM,EAAE,wBAAwB;IAChC,MAAM,EAAE,wBAAwB;IAChC,OAAO,EAAE,kBAAkB;IAC3B,SAAS,EAAE,qBAAqB;IAChC,MAAM,EAAE,kBAAkB;IAC1B,KAAK,EAAE,iBAAiB;IAExB,SAAS;IACT,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,eAAe;IACvB,MAAM,EAAE,cAAc;IACtB,OAAO,EAAE,YAAY;IACrB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,YAAY;IAEpB,QAAQ;IACR,OAAO,EAAE,WAAW;IACpB,QAAQ,EAAE,YAAY;IACtB,MAAM,EAAE,UAAU;IAClB,MAAM,EAAE,UAAU;IAClB,MAAM,EAAE,+BAA+B;IAEvC,QAAQ;IACR,MAAM,EAAE,YAAY;IACpB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,WAAW;IAEnB,QAAQ;IACR,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,iBAAiB;IACzB,MAAM,EAAE,iBAAiB;IACzB,MAAM,EAAE,kBAAkB;IAE1B,YAAY;IACZ,MAAM,EAAE,iBAAiB;IACzB,MAAM,EAAE,iBAAiB;IACzB,KAAK,EAAE,kBAAkB;IACzB,MAAM,EAAE,mBAAmB;IAC3B,KAAK,EAAE,6BAA6B;IACpC,MAAM,EAAE,qBAAqB;IAE7B,MAAM;IACN,OAAO,EAAE,kBAAkB;IAC3B,WAAW,EAAE,qBAAqB;IAClC,cAAc,EAAE,2BAA2B;CAC5C,CAAA;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,MAAM,GAAG,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;IACrC,IAAI,GAAG,KAAK,CAAC,CAAC;QAAE,OAAO,0BAA0B,CAAA;IACjD,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAA;IAC7C,OAAO,UAAU,CAAC,GAAG,CAAC,IAAI,0BAA0B,CAAA;AACtD,CAAC"}
@@ -0,0 +1,69 @@
1
+ import { FileResponse } from './file-response';
2
+ import { type MemoryFileEntry, type VirtualFileSystem } from './virtual-file-system';
3
+ export declare const STATIC_FOLDER_BRAND: unique symbol;
4
+ export interface StaticFolderOpts {
5
+ /** Gitignore-style exclude patterns */
6
+ exclude?: string[];
7
+ /** Cache-Control max-age in seconds */
8
+ maxAge?: number;
9
+ /** Extra response headers */
10
+ headers?: Record<string, string>;
11
+ /** How to handle dotfiles: 'ignore' (404), 'allow', or 'deny' (403). Default: 'ignore' */
12
+ dotfiles?: 'ignore' | 'allow' | 'deny';
13
+ /**
14
+ * What to return when someone requests a directory.
15
+ * - 'none' : 404 (default when index is not set)
16
+ * - 'index' : serve the index file if it exists (default when index is set)
17
+ * - 'list' : return a JSON array of filenames
18
+ * - 'directory' : return an HTML directory listing page
19
+ * - function : custom handler — receives file list, returns a FileResponse
20
+ */
21
+ onDirectory?: 'none' | 'index' | 'list' | 'directory' | ((files: string[]) => FileResponse | Promise<FileResponse>);
22
+ /** Index file to serve for directory requests when onDirectory is 'index' (e.g. 'index.html') */
23
+ index?: string;
24
+ }
25
+ /**
26
+ * A static folder that serves files from a VirtualFileSystem.
27
+ * Used as a class variable on controllers:
28
+ *
29
+ * @Controller()
30
+ * class MyApp {
31
+ * assets = new StaticFolder('./public', { exclude: ['**\/*.map'] })
32
+ * }
33
+ */
34
+ export declare class StaticFolder {
35
+ readonly [STATIC_FOLDER_BRAND] = true;
36
+ readonly vfs: VirtualFileSystem;
37
+ readonly opts: StaticFolderOpts;
38
+ constructor(directory: string, opts?: StaticFolderOpts);
39
+ constructor(files: Record<string, MemoryFileEntry>, opts?: StaticFolderOpts);
40
+ constructor(vfs: VirtualFileSystem, opts?: StaticFolderOpts);
41
+ /**
42
+ * Recursively enumerate all file paths available in this folder.
43
+ * Returns paths relative to the folder root (no leading slash).
44
+ * Respects exclude patterns and dotfile policy.
45
+ * Useful for building manifests so clients know what paths are serveable.
46
+ */
47
+ listAllFiles(maxDepth?: number): Promise<string[]>;
48
+ private walkDir;
49
+ /**
50
+ * Resolve a sub-path to a FileResponse, or null if not found.
51
+ * Handles: exclude globs, dotfile policy, stem matching, onDirectory behavior.
52
+ */
53
+ resolve(subPath: string): Promise<FileResponse | null>;
54
+ private isDotfile;
55
+ private hasExtension;
56
+ /**
57
+ * Stem matching: if request path has no extension and exactly one file matches the stem, serve it.
58
+ * e.g. /assets/readme → serves readme.md if it's the only readme.* in that directory
59
+ */
60
+ private stemMatch;
61
+ private handleDirectory;
62
+ private renderDirectoryPage;
63
+ private createFileResponse;
64
+ }
65
+ /**
66
+ * Check if a value is a StaticFolder instance (works across module boundaries).
67
+ */
68
+ export declare function isStaticFolder(value: unknown): value is StaticFolder;
69
+ //# sourceMappingURL=static-folder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-folder.d.ts","sourceRoot":"","sources":["../../src/static/static-folder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAG9C,OAAO,EAIL,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACvB,MAAM,uBAAuB,CAAA;AAE9B,eAAO,MAAM,mBAAmB,eAAkC,CAAA;AAElE,MAAM,WAAW,gBAAgB;IAC/B,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,6BAA6B;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAA;IACtC;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,WAAW,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAA;IACnH,iGAAiG;IACjG,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;;;;;;GAQG;AACH,qBAAa,YAAY;IACvB,QAAQ,CAAC,CAAC,mBAAmB,CAAC,QAAO;IAErC,QAAQ,CAAC,GAAG,EAAE,iBAAiB,CAAA;IAC/B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAA;gBAEnB,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,gBAAgB;gBAC1C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EAAE,IAAI,CAAC,EAAE,gBAAgB;gBAC/D,GAAG,EAAE,iBAAiB,EAAE,IAAI,CAAC,EAAE,gBAAgB;IAgB3D;;;;;OAKG;IACG,YAAY,CAAC,QAAQ,SAAK,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YAMtC,OAAO;IAwBrB;;;OAGG;IACG,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAwC5D,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,YAAY;IAKpB;;;OAGG;YACW,SAAS;YA+BT,eAAe;IAgC7B,OAAO,CAAC,mBAAmB;IAoB3B,OAAO,CAAC,kBAAkB;CAW3B;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,YAAY,CAEpE"}
@@ -0,0 +1,206 @@
1
+ import { FileResponse } from './file-response.js';
2
+ import { isExcluded } from './glob-match.js';
3
+ import { getMimeType } from './mime-types.js';
4
+ import { isVirtualFileSystem, MemoryFileSystem, NodeFileSystem, } from './virtual-file-system.js';
5
+ export const STATIC_FOLDER_BRAND = Symbol.for('plat:StaticFolder');
6
+ /**
7
+ * A static folder that serves files from a VirtualFileSystem.
8
+ * Used as a class variable on controllers:
9
+ *
10
+ * @Controller()
11
+ * class MyApp {
12
+ * assets = new StaticFolder('./public', { exclude: ['**\/*.map'] })
13
+ * }
14
+ */
15
+ export class StaticFolder {
16
+ [STATIC_FOLDER_BRAND] = true;
17
+ vfs;
18
+ opts;
19
+ constructor(source, opts) {
20
+ this.opts = opts ?? {};
21
+ if (typeof source === 'string') {
22
+ this.vfs = new NodeFileSystem(source);
23
+ }
24
+ else if (isVirtualFileSystem(source)) {
25
+ this.vfs = source;
26
+ }
27
+ else {
28
+ this.vfs = new MemoryFileSystem(source);
29
+ }
30
+ }
31
+ /**
32
+ * Recursively enumerate all file paths available in this folder.
33
+ * Returns paths relative to the folder root (no leading slash).
34
+ * Respects exclude patterns and dotfile policy.
35
+ * Useful for building manifests so clients know what paths are serveable.
36
+ */
37
+ async listAllFiles(maxDepth = 20) {
38
+ const results = [];
39
+ await this.walkDir('', results, 0, maxDepth);
40
+ return results;
41
+ }
42
+ async walkDir(dirPath, results, depth, maxDepth) {
43
+ if (depth > maxDepth)
44
+ return;
45
+ const entries = await this.vfs.list(dirPath);
46
+ for (const entry of entries) {
47
+ if (entry.endsWith('/')) {
48
+ const dirName = entry.slice(0, -1);
49
+ const fullDirPath = dirPath ? `${dirPath}/${dirName}` : dirName;
50
+ if (this.isDotfile(fullDirPath)) {
51
+ const policy = this.opts.dotfiles ?? 'ignore';
52
+ if (policy === 'ignore' || policy === 'deny')
53
+ continue;
54
+ }
55
+ await this.walkDir(fullDirPath, results, depth + 1, maxDepth);
56
+ }
57
+ else {
58
+ const filePath = dirPath ? `${dirPath}/${entry}` : entry;
59
+ if (this.isDotfile(filePath)) {
60
+ const policy = this.opts.dotfiles ?? 'ignore';
61
+ if (policy === 'ignore' || policy === 'deny')
62
+ continue;
63
+ }
64
+ if (this.opts.exclude && isExcluded(filePath, this.opts.exclude))
65
+ continue;
66
+ results.push(filePath);
67
+ }
68
+ }
69
+ }
70
+ /**
71
+ * Resolve a sub-path to a FileResponse, or null if not found.
72
+ * Handles: exclude globs, dotfile policy, stem matching, onDirectory behavior.
73
+ */
74
+ async resolve(subPath) {
75
+ // Normalize: strip leading/trailing slashes
76
+ const normalized = subPath.replace(/^\/+|\/+$/g, '');
77
+ // Check dotfile policy
78
+ if (this.isDotfile(normalized)) {
79
+ const policy = this.opts.dotfiles ?? 'ignore';
80
+ if (policy === 'ignore' || policy === 'deny')
81
+ return null;
82
+ }
83
+ // Check exclude patterns
84
+ if (this.opts.exclude && normalized && isExcluded(normalized, this.opts.exclude)) {
85
+ return null;
86
+ }
87
+ // Empty path = directory root request
88
+ if (!normalized) {
89
+ return this.handleDirectory('');
90
+ }
91
+ // Try exact file match
92
+ const content = await this.vfs.read(normalized);
93
+ if (content !== null) {
94
+ return this.createFileResponse(content, normalized);
95
+ }
96
+ // Check if it's a directory (by listing it)
97
+ const dirEntries = await this.vfs.list(normalized);
98
+ if (dirEntries.length > 0) {
99
+ return this.handleDirectory(normalized);
100
+ }
101
+ // Stem matching: if no extension, look for unique match
102
+ if (!this.hasExtension(normalized)) {
103
+ return this.stemMatch(normalized);
104
+ }
105
+ return null;
106
+ }
107
+ isDotfile(path) {
108
+ const parts = path.split('/');
109
+ return parts.some(p => p.startsWith('.') && p.length > 1);
110
+ }
111
+ hasExtension(path) {
112
+ const basename = path.split('/').pop() ?? '';
113
+ return basename.includes('.') && !basename.startsWith('.');
114
+ }
115
+ /**
116
+ * Stem matching: if request path has no extension and exactly one file matches the stem, serve it.
117
+ * e.g. /assets/readme → serves readme.md if it's the only readme.* in that directory
118
+ */
119
+ async stemMatch(normalizedPath) {
120
+ const parts = normalizedPath.split('/');
121
+ const stem = parts.pop();
122
+ const dir = parts.join('/');
123
+ const entries = await this.vfs.list(dir);
124
+ const matches = entries.filter(entry => {
125
+ if (entry.endsWith('/'))
126
+ return false;
127
+ const dot = entry.lastIndexOf('.');
128
+ const entryStem = dot > 0 ? entry.slice(0, dot) : entry;
129
+ return entryStem === stem;
130
+ });
131
+ if (matches.length === 1) {
132
+ const matched = matches[0];
133
+ const fullPath = dir ? `${dir}/${matched}` : matched;
134
+ // Check exclude on the resolved path
135
+ if (this.opts.exclude && isExcluded(fullPath, this.opts.exclude)) {
136
+ return null;
137
+ }
138
+ const content = await this.vfs.read(fullPath);
139
+ if (content !== null) {
140
+ return this.createFileResponse(content, fullPath);
141
+ }
142
+ }
143
+ return null;
144
+ }
145
+ async handleDirectory(dirPath) {
146
+ const onDir = this.opts.onDirectory ?? (this.opts.index ? 'index' : 'none');
147
+ if (onDir === 'none')
148
+ return null;
149
+ if (onDir === 'index') {
150
+ if (!this.opts.index)
151
+ return null;
152
+ const indexPath = dirPath ? `${dirPath}/${this.opts.index}` : this.opts.index;
153
+ const content = await this.vfs.read(indexPath);
154
+ if (content === null)
155
+ return null;
156
+ return this.createFileResponse(content, indexPath);
157
+ }
158
+ const entries = await this.vfs.list(dirPath);
159
+ if (onDir === 'list') {
160
+ const json = JSON.stringify(entries);
161
+ return FileResponse.from(json, 'listing.json');
162
+ }
163
+ if (onDir === 'directory') {
164
+ const html = this.renderDirectoryPage(dirPath, entries);
165
+ return FileResponse.from(html, 'index.html');
166
+ }
167
+ if (typeof onDir === 'function') {
168
+ return onDir(entries);
169
+ }
170
+ return null;
171
+ }
172
+ renderDirectoryPage(dirPath, entries) {
173
+ const title = dirPath || '/';
174
+ const links = entries
175
+ .map(entry => {
176
+ const href = entry;
177
+ return ` <li><a href="${href}">${entry}</a></li>`;
178
+ })
179
+ .join('\n');
180
+ return `<!DOCTYPE html>
181
+ <html>
182
+ <head><meta charset="utf-8"><title>Index of ${title}</title></head>
183
+ <body>
184
+ <h1>Index of /${title}</h1>
185
+ <ul>
186
+ ${links}
187
+ </ul>
188
+ </body>
189
+ </html>`;
190
+ }
191
+ createFileResponse(content, filePath) {
192
+ const filename = filePath.split('/').pop() ?? filePath;
193
+ return FileResponse.from(content, filename, {
194
+ contentType: getMimeType(filename),
195
+ maxAge: this.opts.maxAge,
196
+ headers: this.opts.headers,
197
+ });
198
+ }
199
+ }
200
+ /**
201
+ * Check if a value is a StaticFolder instance (works across module boundaries).
202
+ */
203
+ export function isStaticFolder(value) {
204
+ return value != null && typeof value === 'object' && STATIC_FOLDER_BRAND in value;
205
+ }
206
+ //# sourceMappingURL=static-folder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-folder.js","sourceRoot":"","sources":["../../src/static/static-folder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Abstraction over file storage. StaticFolder resolves files through this interface.
3
+ * Implementations: NodeFileSystem (real fs), MemoryFileSystem (in-memory map), or any custom backend.
4
+ */
5
+ export interface VirtualFileSystem {
6
+ /**
7
+ * List entries at a path. Return filenames only (not full paths).
8
+ * Directories should be suffixed with '/'.
9
+ * path is '' for root, 'subdir' for a subdirectory.
10
+ */
11
+ list(path: string): string[] | Promise<string[]>;
12
+ /**
13
+ * Read a file's content. Return null if not found.
14
+ */
15
+ read(path: string): string | Uint8Array | null | Promise<string | Uint8Array | null>;
16
+ }
17
+ /**
18
+ * Check if a value implements the VirtualFileSystem interface.
19
+ */
20
+ export declare function isVirtualFileSystem(value: unknown): value is VirtualFileSystem;
21
+ /**
22
+ * VFS backed by Node.js filesystem. Used when StaticFolder is given a directory path string.
23
+ */
24
+ export declare class NodeFileSystem implements VirtualFileSystem {
25
+ private root;
26
+ constructor(directory: string);
27
+ private resolveSafe;
28
+ list(subPath: string): Promise<string[]>;
29
+ read(subPath: string): Promise<Uint8Array | null>;
30
+ }
31
+ export type MemoryFileEntry = string | Uint8Array | {
32
+ read(): string | Uint8Array | Promise<string | Uint8Array>;
33
+ };
34
+ /**
35
+ * VFS backed by an in-memory file map.
36
+ * Keys are paths like 'index.html' or 'css/style.css'.
37
+ * Values can be raw content or objects with a read() method for lazy evaluation.
38
+ */
39
+ export declare class MemoryFileSystem implements VirtualFileSystem {
40
+ private files;
41
+ constructor(files: Record<string, MemoryFileEntry>);
42
+ list(subPath: string): string[];
43
+ read(subPath: string): Promise<string | Uint8Array | null>;
44
+ }
45
+ //# sourceMappingURL=virtual-file-system.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"virtual-file-system.d.ts","sourceRoot":"","sources":["../../src/static/virtual-file-system.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IAEhD;;OAEG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC,CAAA;CACrF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,iBAAiB,CAO9E;AAED;;GAEG;AACH,qBAAa,cAAe,YAAW,iBAAiB;IACtD,OAAO,CAAC,IAAI,CAAQ;gBAER,SAAS,EAAE,MAAM;IAM7B,OAAO,CAAC,WAAW;IAeb,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAexC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;CAUxD;AAED,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,UAAU,GAAG;IAAE,IAAI,IAAI,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,MAAM,GAAG,UAAU,CAAC,CAAA;CAAE,CAAA;AAElH;;;;GAIG;AACH,qBAAa,gBAAiB,YAAW,iBAAiB;IAC5C,OAAO,CAAC,KAAK;gBAAL,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC;IAE1D,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAkBzB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC;CAOjE"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Check if a value implements the VirtualFileSystem interface.
3
+ */
4
+ export function isVirtualFileSystem(value) {
5
+ return (value != null &&
6
+ typeof value === 'object' &&
7
+ 'list' in value && typeof value.list === 'function' &&
8
+ 'read' in value && typeof value.read === 'function');
9
+ }
10
+ /**
11
+ * VFS backed by Node.js filesystem. Used when StaticFolder is given a directory path string.
12
+ */
13
+ export class NodeFileSystem {
14
+ root;
15
+ constructor(directory) {
16
+ // Resolve to absolute path at construction time
17
+ const path = require('node:path');
18
+ this.root = path.resolve(directory);
19
+ }
20
+ resolveSafe(subPath) {
21
+ const path = require('node:path');
22
+ // Reject paths with .. segments to prevent directory traversal
23
+ const normalized = path.normalize(subPath);
24
+ if (normalized.startsWith('..') || path.isAbsolute(normalized)) {
25
+ return null;
26
+ }
27
+ const resolved = path.resolve(this.root, normalized);
28
+ // Verify the resolved path is still within root
29
+ if (!resolved.startsWith(this.root + path.sep) && resolved !== this.root) {
30
+ return null;
31
+ }
32
+ return resolved;
33
+ }
34
+ async list(subPath) {
35
+ const fs = require('node:fs/promises');
36
+ const path = require('node:path');
37
+ const dir = subPath ? this.resolveSafe(subPath) : this.root;
38
+ if (!dir)
39
+ return [];
40
+ try {
41
+ const entries = await fs.readdir(dir, { withFileTypes: true });
42
+ return entries.map((e) => e.isDirectory() ? e.name + '/' : e.name);
43
+ }
44
+ catch {
45
+ return [];
46
+ }
47
+ }
48
+ async read(subPath) {
49
+ const fs = require('node:fs/promises');
50
+ const resolved = this.resolveSafe(subPath);
51
+ if (!resolved)
52
+ return null;
53
+ try {
54
+ return await fs.readFile(resolved);
55
+ }
56
+ catch {
57
+ return null;
58
+ }
59
+ }
60
+ }
61
+ /**
62
+ * VFS backed by an in-memory file map.
63
+ * Keys are paths like 'index.html' or 'css/style.css'.
64
+ * Values can be raw content or objects with a read() method for lazy evaluation.
65
+ */
66
+ export class MemoryFileSystem {
67
+ files;
68
+ constructor(files) {
69
+ this.files = files;
70
+ }
71
+ list(subPath) {
72
+ const prefix = subPath ? (subPath.endsWith('/') ? subPath : subPath + '/') : '';
73
+ const seen = new Set();
74
+ for (const key of Object.keys(this.files)) {
75
+ if (!key.startsWith(prefix))
76
+ continue;
77
+ const rest = key.slice(prefix.length);
78
+ const slashIndex = rest.indexOf('/');
79
+ if (slashIndex === -1) {
80
+ // Direct file in this directory
81
+ seen.add(rest);
82
+ }
83
+ else {
84
+ // Subdirectory
85
+ seen.add(rest.slice(0, slashIndex) + '/');
86
+ }
87
+ }
88
+ return Array.from(seen);
89
+ }
90
+ async read(subPath) {
91
+ const entry = this.files[subPath];
92
+ if (entry === undefined)
93
+ return null;
94
+ if (typeof entry === 'string' || entry instanceof Uint8Array)
95
+ return entry;
96
+ // Lazy read() object
97
+ return entry.read();
98
+ }
99
+ }
100
+ //# sourceMappingURL=virtual-file-system.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"virtual-file-system.js","sourceRoot":"","sources":["../../src/static/virtual-file-system.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@modularizer/plat",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Protocol and Language Agnostic Tooling Yielding Universal Semantics",
5
5
  "type": "module",
6
6
  "author": {
@@ -38,6 +38,10 @@
38
38
  "./python-browser": {
39
39
  "import": "./dist/python-browser-entry.js",
40
40
  "types": "./dist/python-browser-entry.d.ts"
41
+ },
42
+ "./static": {
43
+ "import": "./dist/static/index.js",
44
+ "types": "./dist/static/index.d.ts"
41
45
  }
42
46
  },
43
47
  "files": [