@utilarium/overcontext 0.0.6 → 0.0.7-dev.20260220025748.d61df74

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.
@@ -2,8 +2,12 @@ import * as fs from 'node:fs/promises';
2
2
  import { existsSync, statSync } from 'node:fs';
3
3
  import * as path from 'node:path';
4
4
  import * as yaml from 'js-yaml';
5
- import { ReadonlyStorageError, SchemaNotRegisteredError, StorageAccessError, ValidationError } from './errors.js';
5
+ import { StorageAccessError, ReadonlyStorageError, SchemaNotRegisteredError, ValidationError } from './errors.js';
6
6
 
7
+ /**
8
+ * Maximum number of entities allowed in a single batch operation.
9
+ * Prevents resource exhaustion from unbounded batch sizes.
10
+ */ const MAX_BATCH_SIZE = 1000;
7
11
  const createFileSystemProvider = async (options)=>{
8
12
  const { basePath, registry, createIfMissing = true, extension = '.yaml', readonly = false, defaultNamespace, filenameStrategy } = options;
9
13
  // --- Helper Functions ---
@@ -114,10 +118,8 @@ const createFileSystemProvider = async (options)=>{
114
118
  const prefix = id.substring(0, Math.min(8, id.length));
115
119
  const files = await fs.readdir(dir);
116
120
  const candidates = files.filter((f)=>(f.endsWith('.yaml') || f.endsWith('.yml')) && f.startsWith(prefix));
117
- if (candidates.length === 1) {
118
- return path.join(dir, candidates[0]);
119
- }
120
- // Multiple prefix matches — read and verify the id field
121
+ // Always verify the entity ID inside the file to prevent
122
+ // returning the wrong entity when IDs share a common prefix.
121
123
  for (const file of candidates){
122
124
  const filePath = path.join(dir, file);
123
125
  const entity = await readEntity(filePath, type);
@@ -134,8 +136,35 @@ const createFileSystemProvider = async (options)=>{
134
136
  });
135
137
  }
136
138
  };
139
+ // Cache the real basePath to handle symlinked temp directories (e.g., macOS /var/folders -> /private/var/folders).
140
+ // Computed lazily on first readEntity call once the directory exists.
141
+ let realBasePath;
137
142
  const readEntity = async (filePath, type)=>{
138
143
  try {
144
+ // Resolve symlinks and verify the real path is within basePath
145
+ // to prevent symlink-based path traversal.
146
+ let realFilePath;
147
+ try {
148
+ realFilePath = await fs.realpath(filePath);
149
+ } catch {
150
+ // If realpath fails (e.g., file doesn't exist), fall through to readFile
151
+ // which will throw ENOENT and be handled below.
152
+ realFilePath = filePath;
153
+ }
154
+ // Resolve basePath's real path to handle symlinked parent directories.
155
+ // Fall back to path.resolve if basePath doesn't exist yet.
156
+ if (!realBasePath) {
157
+ try {
158
+ realBasePath = await fs.realpath(basePath);
159
+ } catch {
160
+ realBasePath = path.resolve(basePath);
161
+ }
162
+ }
163
+ if (!realFilePath.startsWith(realBasePath + path.sep) && realFilePath !== realBasePath) {
164
+ // eslint-disable-next-line no-console
165
+ console.warn(`Symlink traversal attempt detected: ${filePath} resolves to ${realFilePath}`);
166
+ return undefined;
167
+ }
139
168
  const content = await fs.readFile(filePath, 'utf-8');
140
169
  let parsed;
141
170
  try {
@@ -148,14 +177,29 @@ const createFileSystemProvider = async (options)=>{
148
177
  if (!parsed || typeof parsed !== 'object') {
149
178
  return undefined;
150
179
  }
151
- // Protect against prototype pollution from malicious YAML
152
- // Only __proto__ is dangerous - constructor/prototype as string keys are safe
153
- const parsedObj = parsed;
154
- if (Object.prototype.hasOwnProperty.call(parsedObj, '__proto__')) {
180
+ // Protect against prototype pollution from malicious YAML.
181
+ // Recursively check for __proto__ keys at all nesting levels,
182
+ // since nested __proto__ can still cause pollution when objects
183
+ // are spread or assigned downstream.
184
+ const hasProtoKey = (obj)=>{
185
+ if (!obj || typeof obj !== 'object') return false;
186
+ if (Object.prototype.hasOwnProperty.call(obj, '__proto__')) return true;
187
+ for (const value of Object.values(obj)){
188
+ if (hasProtoKey(value)) return true;
189
+ }
190
+ if (Array.isArray(obj)) {
191
+ for (const item of obj){
192
+ if (hasProtoKey(item)) return true;
193
+ }
194
+ }
195
+ return false;
196
+ };
197
+ if (hasProtoKey(parsed)) {
155
198
  // eslint-disable-next-line no-console
156
199
  console.warn(`Potential prototype pollution attempt in ${filePath}: __proto__ key detected`);
157
200
  return undefined;
158
201
  }
202
+ const parsedObj = parsed;
159
203
  // Validate against registered schema
160
204
  const result = registry.validateAs(type, {
161
205
  ...parsedObj,
@@ -371,6 +415,9 @@ const createFileSystemProvider = async (options)=>{
371
415
  }
372
416
  },
373
417
  async saveBatch (entities, namespace) {
418
+ if (entities.length > MAX_BATCH_SIZE) {
419
+ throw new StorageAccessError(`Batch size ${entities.length} exceeds maximum of ${MAX_BATCH_SIZE}. Split into smaller batches.`);
420
+ }
374
421
  const saved = [];
375
422
  for (const entity of entities){
376
423
  saved.push(await this.save(entity, namespace));
@@ -378,6 +425,9 @@ const createFileSystemProvider = async (options)=>{
378
425
  return saved;
379
426
  },
380
427
  async deleteBatch (refs, namespace) {
428
+ if (refs.length > MAX_BATCH_SIZE) {
429
+ throw new StorageAccessError(`Batch size ${refs.length} exceeds maximum of ${MAX_BATCH_SIZE}. Split into smaller batches.`);
430
+ }
381
431
  let count = 0;
382
432
  for (const ref of refs){
383
433
  if (await this.delete(ref.type, ref.id, namespace)) {
@@ -1 +1 @@
1
- {"version":3,"file":"filesystem.js","sources":["../../src/storage/filesystem.ts"],"sourcesContent":["import * as fs from 'node:fs/promises';\nimport { existsSync, statSync } from 'node:fs';\nimport * as path from 'node:path';\nimport * as yaml from 'js-yaml';\nimport {\n StorageProvider,\n StorageProviderOptions,\n EntityFilter,\n} from './interface';\nimport { BaseEntity } from '../schema/base';\nimport {\n StorageAccessError,\n ValidationError,\n SchemaNotRegisteredError,\n ReadonlyStorageError,\n} from './errors';\n\nexport interface FileSystemProviderOptions extends StorageProviderOptions {\n /** Base path for context storage */\n basePath: string;\n\n /** Create directories if they don't exist */\n createIfMissing?: boolean;\n\n /** File extension to use (default: .yaml) */\n extension?: '.yaml' | '.yml';\n\n /**\n * Custom filename strategy. Given an entity, returns the filename stem (without extension).\n * When not provided, entity.id is used as the filename.\n * \n * Example: `(entity) => \\`\\${entity.id.substring(0, 8)}-\\${entity.slug}\\``\n * would produce filenames like `d00acdc4-gerald-corson.yaml`\n */\n filenameStrategy?: (entity: BaseEntity) => string;\n}\n\nexport const createFileSystemProvider = async (\n options: FileSystemProviderOptions\n): Promise<StorageProvider> => {\n const {\n basePath,\n registry,\n createIfMissing = true,\n extension = '.yaml',\n readonly = false,\n defaultNamespace,\n filenameStrategy,\n } = options;\n\n // --- Helper Functions ---\n\n /**\n * Sanitize a path component to prevent directory traversal attacks.\n * Rejects path separators, parent directory references, and other unsafe characters.\n */\n const sanitizePathComponent = (input: string, componentName: string): string => {\n // Reject path separators and parent directory references\n if (input.includes('/') || input.includes('\\\\') || input.includes('..')) {\n throw new ValidationError(\n `Invalid characters in ${componentName}: cannot contain path separators or \"..\"`,\n [{ path: componentName, message: 'Path component cannot contain path separators or \"..\"' }]\n );\n }\n // Reject null bytes and control characters\n if (input.includes('\\0')) {\n throw new ValidationError(\n `Invalid characters in ${componentName}: cannot contain null bytes`,\n [{ path: componentName, message: 'Path component cannot contain null bytes' }]\n );\n }\n // Check for control characters (0x00-0x1F and 0x7F)\n for (let i = 0; i < input.length; i++) {\n const code = input.charCodeAt(i);\n if ((code >= 0 && code <= 0x1F) || code === 0x7F) {\n throw new ValidationError(\n `Invalid characters in ${componentName}: cannot contain control characters`,\n [{ path: componentName, message: 'Path component cannot contain control characters' }]\n );\n }\n }\n return input;\n };\n\n /**\n * Verify that a resolved path stays within the basePath to prevent path traversal.\n */\n const verifyPathWithinBase = (resolvedPath: string): void => {\n const resolvedBase = path.resolve(basePath);\n const resolvedTarget = path.resolve(resolvedPath);\n \n if (!resolvedTarget.startsWith(resolvedBase + path.sep) && resolvedTarget !== resolvedBase) {\n throw new StorageAccessError('Path traversal attempt detected');\n }\n };\n\n const getEntityDir = (type: string, namespace?: string): string => {\n const dirName = registry.getDirectoryName(type);\n if (!dirName) {\n throw new SchemaNotRegisteredError(type);\n }\n\n // Sanitize namespace if provided\n const safeNamespace = namespace ? sanitizePathComponent(namespace, 'namespace') : undefined;\n \n // Sanitize directory name (should already be safe from registry, but double-check)\n const safeDirName = sanitizePathComponent(dirName, 'directoryName');\n\n let dir: string;\n if (safeNamespace) {\n dir = path.join(basePath, safeNamespace, safeDirName);\n } else {\n dir = path.join(basePath, safeDirName);\n }\n\n // Verify the path stays within basePath\n verifyPathWithinBase(dir);\n return dir;\n };\n\n const getEntityPath = (type: string, id: string, namespace?: string): string => {\n // Sanitize ID to prevent path traversal\n const safeId = sanitizePathComponent(id, 'id');\n \n const dir = getEntityDir(type, namespace);\n const fullPath = path.join(dir, `${safeId}${extension}`);\n \n // Verify the final path stays within basePath\n verifyPathWithinBase(fullPath);\n return fullPath;\n };\n\n const getEntityPathForWrite = (entity: BaseEntity, namespace?: string): string => {\n if (!filenameStrategy) {\n return getEntityPath(entity.type, entity.id, namespace);\n }\n\n const filename = filenameStrategy(entity);\n const safeFilename = sanitizePathComponent(filename, 'filename');\n const dir = getEntityDir(entity.type, namespace);\n const fullPath = path.join(dir, `${safeFilename}${extension}`);\n verifyPathWithinBase(fullPath);\n return fullPath;\n };\n\n /**\n * Find the actual file path for an entity by id, handling custom filename strategies.\n * Tries direct {id}{ext} first, then scans the directory using id prefix matching.\n */\n const findEntityFileById = async (type: string, id: string, namespace?: string): Promise<string | undefined> => {\n const directPath = getEntityPath(type, id, namespace);\n if (existsSync(directPath)) {\n return directPath;\n }\n\n if (!filenameStrategy) {\n return undefined;\n }\n\n let dir: string;\n try {\n dir = getEntityDir(type, namespace);\n } catch {\n return undefined;\n }\n\n if (!existsSync(dir)) {\n return undefined;\n }\n\n const prefix = id.substring(0, Math.min(8, id.length));\n const files = await fs.readdir(dir);\n const candidates = files.filter(f =>\n (f.endsWith('.yaml') || f.endsWith('.yml')) && f.startsWith(prefix)\n );\n\n if (candidates.length === 1) {\n return path.join(dir, candidates[0]);\n }\n\n // Multiple prefix matches — read and verify the id field\n for (const file of candidates) {\n const filePath = path.join(dir, file);\n const entity = await readEntity(filePath, type);\n if (entity && entity.id === id) {\n return filePath;\n }\n }\n\n return undefined;\n };\n\n const ensureDir = async (dir: string): Promise<void> => {\n if (!existsSync(dir) && createIfMissing && !readonly) {\n await fs.mkdir(dir, { recursive: true });\n }\n };\n\n const readEntity = async <T extends BaseEntity>(\n filePath: string,\n type: string\n ): Promise<T | undefined> => {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n \n let parsed: unknown;\n try {\n parsed = yaml.load(content);\n } catch (yamlError) {\n // eslint-disable-next-line no-console\n console.warn(`Invalid YAML at ${filePath}:`, yamlError);\n return undefined;\n }\n\n if (!parsed || typeof parsed !== 'object') {\n return undefined;\n }\n\n // Protect against prototype pollution from malicious YAML\n // Only __proto__ is dangerous - constructor/prototype as string keys are safe\n const parsedObj = parsed as Record<string, unknown>;\n if (Object.prototype.hasOwnProperty.call(parsedObj, '__proto__')) {\n // eslint-disable-next-line no-console\n console.warn(`Potential prototype pollution attempt in ${filePath}: __proto__ key detected`);\n return undefined;\n }\n\n // Validate against registered schema\n const result = registry.validateAs<T>(type, {\n ...parsedObj,\n source: filePath,\n });\n\n if (!result.success) {\n // eslint-disable-next-line no-console\n console.warn(`Invalid entity at ${filePath}:`, result.errors);\n return undefined;\n }\n\n return result.data;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return undefined;\n }\n throw new StorageAccessError(`Failed to read ${filePath}`, error as Error);\n }\n };\n\n const writeEntity = async <T extends BaseEntity>(\n entity: T,\n namespace?: string\n ): Promise<T> => {\n if (readonly) {\n throw new ReadonlyStorageError();\n }\n\n // Validate against schema\n const validationResult = registry.validate(entity);\n if (!validationResult.success) {\n throw new ValidationError(\n 'Entity validation failed',\n validationResult.errors || []\n );\n }\n\n const dir = getEntityDir(entity.type, namespace);\n await ensureDir(dir);\n\n const filePath = getEntityPathForWrite(entity, namespace);\n\n // If filenameStrategy is set, clean up any old file with a different name for the same id\n if (filenameStrategy) {\n const oldPath = await findEntityFileById(entity.type, entity.id, namespace);\n if (oldPath && path.resolve(oldPath) !== path.resolve(filePath)) {\n try { await fs.unlink(oldPath); } catch { /* best-effort cleanup */ }\n }\n }\n\n // Remove framework-managed fields from saved YAML\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { type: _type, source: _source, ...entityToSave } = entity;\n\n // Update metadata\n const now = new Date();\n const toSave = {\n ...entityToSave,\n updatedAt: now,\n createdAt: entityToSave.createdAt || now,\n };\n\n const content = yaml.dump(toSave, {\n lineWidth: -1,\n sortKeys: false,\n });\n await fs.writeFile(filePath, content, 'utf-8');\n\n return {\n ...entity,\n ...toSave,\n type: entity.type,\n source: filePath,\n } as T;\n };\n\n const listDirectoryTypes = async (basePath: string): Promise<string[]> => {\n const types: string[] = [];\n\n try {\n const entries = await fs.readdir(basePath, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n const type = registry.getTypeFromDirectory(entry.name);\n if (type) {\n types.push(type);\n }\n }\n }\n } catch {\n // Directory doesn't exist\n }\n\n return types;\n };\n\n // --- StorageProvider Implementation ---\n\n const provider: StorageProvider = {\n name: 'filesystem',\n location: basePath,\n registry,\n\n async initialize(): Promise<void> {\n if (createIfMissing && !readonly) {\n await ensureDir(basePath);\n }\n\n if (!existsSync(basePath)) {\n throw new StorageAccessError(`Context path does not exist: ${basePath}`);\n }\n },\n\n async dispose(): Promise<void> {\n // No cleanup needed for filesystem\n },\n\n async isAvailable(): Promise<boolean> {\n try {\n const stat = statSync(basePath);\n return stat.isDirectory();\n } catch {\n return false;\n }\n },\n\n async get<T extends BaseEntity>(\n type: string,\n id: string,\n namespace?: string\n ): Promise<T | undefined> {\n const ns = namespace ?? defaultNamespace;\n if (filenameStrategy) {\n const filePath = await findEntityFileById(type, id, ns);\n if (!filePath) return undefined;\n return readEntity<T>(filePath, type);\n }\n const filePath = getEntityPath(type, id, ns);\n return readEntity<T>(filePath, type);\n },\n\n async getAll<T extends BaseEntity>(\n type: string,\n namespace?: string\n ): Promise<T[]> {\n const ns = namespace ?? defaultNamespace;\n\n let dir: string;\n try {\n dir = getEntityDir(type, ns);\n } catch (error) {\n if (error instanceof SchemaNotRegisteredError) {\n return [];\n }\n throw error;\n }\n\n if (!existsSync(dir)) {\n return [];\n }\n\n const files = await fs.readdir(dir);\n const entities: T[] = [];\n\n for (const file of files) {\n if (!file.endsWith('.yaml') && !file.endsWith('.yml')) {\n continue;\n }\n\n const entity = await readEntity<T>(path.join(dir, file), type);\n if (entity) {\n entities.push(entity);\n }\n }\n\n return entities;\n },\n\n async find<T extends BaseEntity>(filter: EntityFilter): Promise<T[]> {\n let results: T[] = [];\n\n const types = filter.type\n ? (Array.isArray(filter.type) ? filter.type : [filter.type])\n : registry.types();\n\n const namespace = filter.namespace ?? defaultNamespace;\n\n for (const type of types) {\n const entities = await this.getAll<T>(type, namespace);\n results = results.concat(entities);\n }\n\n // Apply ID filter\n if (filter.ids?.length) {\n results = results.filter(e => filter.ids!.includes(e.id));\n }\n\n // Apply search filter\n if (filter.search) {\n const searchLower = filter.search.toLowerCase();\n results = results.filter(e =>\n e.name.toLowerCase().includes(searchLower)\n );\n }\n\n // Apply pagination\n if (filter.offset) {\n results = results.slice(filter.offset);\n }\n if (filter.limit) {\n results = results.slice(0, filter.limit);\n }\n\n return results;\n },\n\n async exists(type: string, id: string, namespace?: string): Promise<boolean> {\n const ns = namespace ?? defaultNamespace;\n try {\n if (filenameStrategy) {\n const filePath = await findEntityFileById(type, id, ns);\n return filePath !== undefined;\n }\n const filePath = getEntityPath(type, id, ns);\n return existsSync(filePath);\n } catch {\n return false;\n }\n },\n\n async count(filter: EntityFilter): Promise<number> {\n const results = await this.find(filter);\n return results.length;\n },\n\n async save<T extends BaseEntity>(entity: T, namespace?: string): Promise<T> {\n const ns = namespace ?? defaultNamespace;\n return writeEntity(entity, ns);\n },\n\n async delete(type: string, id: string, namespace?: string): Promise<boolean> {\n if (readonly) {\n throw new ReadonlyStorageError();\n }\n\n const ns = namespace ?? defaultNamespace;\n\n try {\n if (filenameStrategy) {\n const filePath = await findEntityFileById(type, id, ns);\n if (!filePath) return false;\n await fs.unlink(filePath);\n return true;\n }\n const filePath = getEntityPath(type, id, ns);\n await fs.unlink(filePath);\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return false;\n }\n throw error;\n }\n },\n\n async saveBatch<T extends BaseEntity>(\n entities: T[],\n namespace?: string\n ): Promise<T[]> {\n const saved: T[] = [];\n for (const entity of entities) {\n saved.push(await this.save(entity, namespace));\n }\n return saved;\n },\n\n async deleteBatch(\n refs: Array<{ type: string; id: string }>,\n namespace?: string\n ): Promise<number> {\n let count = 0;\n for (const ref of refs) {\n if (await this.delete(ref.type, ref.id, namespace)) {\n count++;\n }\n }\n return count;\n },\n\n async listNamespaces(): Promise<string[]> {\n const namespaces: string[] = [];\n\n if (!existsSync(basePath)) {\n return namespaces;\n }\n\n const entries = await fs.readdir(basePath, { withFileTypes: true });\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n // Check if it's a namespace (contains entity type directories)\n // vs being an entity type directory itself\n const subPath = path.join(basePath, entry.name);\n const subTypes = await listDirectoryTypes(subPath);\n\n if (subTypes.length > 0) {\n namespaces.push(entry.name);\n }\n }\n\n return namespaces;\n },\n\n async namespaceExists(namespace: string): Promise<boolean> {\n // Sanitize namespace to prevent path traversal\n const safeNamespace = sanitizePathComponent(namespace, 'namespace');\n const namespacePath = path.join(basePath, safeNamespace);\n \n // Verify path stays within basePath\n verifyPathWithinBase(namespacePath);\n return existsSync(namespacePath);\n },\n\n async listTypes(namespace?: string): Promise<string[]> {\n const ns = namespace ?? defaultNamespace;\n let searchPath: string;\n if (ns) {\n // Sanitize namespace to prevent path traversal\n const safeNamespace = sanitizePathComponent(ns, 'namespace');\n searchPath = path.join(basePath, safeNamespace);\n verifyPathWithinBase(searchPath);\n } else {\n searchPath = basePath;\n }\n return listDirectoryTypes(searchPath);\n },\n };\n\n return provider;\n};\n"],"names":["createFileSystemProvider","options","basePath","registry","createIfMissing","extension","readonly","defaultNamespace","filenameStrategy","sanitizePathComponent","input","componentName","includes","ValidationError","path","message","i","length","code","charCodeAt","verifyPathWithinBase","resolvedPath","resolvedBase","resolve","resolvedTarget","startsWith","sep","StorageAccessError","getEntityDir","type","namespace","dirName","getDirectoryName","SchemaNotRegisteredError","safeNamespace","undefined","safeDirName","dir","join","getEntityPath","id","safeId","fullPath","getEntityPathForWrite","entity","filename","safeFilename","findEntityFileById","directPath","existsSync","prefix","substring","Math","min","files","fs","readdir","candidates","filter","f","endsWith","file","filePath","readEntity","ensureDir","mkdir","recursive","content","readFile","parsed","yaml","load","yamlError","console","warn","parsedObj","Object","prototype","hasOwnProperty","call","result","validateAs","source","success","errors","data","error","writeEntity","ReadonlyStorageError","validationResult","validate","oldPath","unlink","_type","_source","entityToSave","now","Date","toSave","updatedAt","createdAt","dump","lineWidth","sortKeys","writeFile","listDirectoryTypes","types","entries","withFileTypes","entry","isDirectory","getTypeFromDirectory","name","push","provider","location","initialize","dispose","isAvailable","stat","statSync","get","ns","getAll","entities","find","results","Array","isArray","concat","ids","e","search","searchLower","toLowerCase","offset","slice","limit","exists","count","save","delete","saveBatch","saved","deleteBatch","refs","ref","listNamespaces","namespaces","subPath","subTypes","namespaceExists","namespacePath","listTypes","searchPath"],"mappings":"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"}
1
+ {"version":3,"file":"filesystem.js","sources":["../../src/storage/filesystem.ts"],"sourcesContent":["import * as fs from 'node:fs/promises';\nimport { existsSync, statSync } from 'node:fs';\nimport * as path from 'node:path';\nimport * as yaml from 'js-yaml';\nimport {\n StorageProvider,\n StorageProviderOptions,\n EntityFilter,\n} from './interface';\nimport { BaseEntity } from '../schema/base';\nimport {\n StorageAccessError,\n ValidationError,\n SchemaNotRegisteredError,\n ReadonlyStorageError,\n} from './errors';\n\nexport interface FileSystemProviderOptions extends StorageProviderOptions {\n /** Base path for context storage */\n basePath: string;\n\n /** Create directories if they don't exist */\n createIfMissing?: boolean;\n\n /** File extension to use (default: .yaml) */\n extension?: '.yaml' | '.yml';\n\n /**\n * Custom filename strategy. Given an entity, returns the filename stem (without extension).\n * When not provided, entity.id is used as the filename.\n * \n * Example: `(entity) => \\`\\${entity.id.substring(0, 8)}-\\${entity.slug}\\``\n * would produce filenames like `d00acdc4-gerald-corson.yaml`\n */\n filenameStrategy?: (entity: BaseEntity) => string;\n}\n\n/**\n * Maximum number of entities allowed in a single batch operation.\n * Prevents resource exhaustion from unbounded batch sizes.\n */\nconst MAX_BATCH_SIZE = 1000;\n\nexport const createFileSystemProvider = async (\n options: FileSystemProviderOptions\n): Promise<StorageProvider> => {\n const {\n basePath,\n registry,\n createIfMissing = true,\n extension = '.yaml',\n readonly = false,\n defaultNamespace,\n filenameStrategy,\n } = options;\n\n // --- Helper Functions ---\n\n /**\n * Sanitize a path component to prevent directory traversal attacks.\n * Rejects path separators, parent directory references, and other unsafe characters.\n */\n const sanitizePathComponent = (input: string, componentName: string): string => {\n // Reject path separators and parent directory references\n if (input.includes('/') || input.includes('\\\\') || input.includes('..')) {\n throw new ValidationError(\n `Invalid characters in ${componentName}: cannot contain path separators or \"..\"`,\n [{ path: componentName, message: 'Path component cannot contain path separators or \"..\"' }]\n );\n }\n // Reject null bytes and control characters\n if (input.includes('\\0')) {\n throw new ValidationError(\n `Invalid characters in ${componentName}: cannot contain null bytes`,\n [{ path: componentName, message: 'Path component cannot contain null bytes' }]\n );\n }\n // Check for control characters (0x00-0x1F and 0x7F)\n for (let i = 0; i < input.length; i++) {\n const code = input.charCodeAt(i);\n if ((code >= 0 && code <= 0x1F) || code === 0x7F) {\n throw new ValidationError(\n `Invalid characters in ${componentName}: cannot contain control characters`,\n [{ path: componentName, message: 'Path component cannot contain control characters' }]\n );\n }\n }\n return input;\n };\n\n /**\n * Verify that a resolved path stays within the basePath to prevent path traversal.\n */\n const verifyPathWithinBase = (resolvedPath: string): void => {\n const resolvedBase = path.resolve(basePath);\n const resolvedTarget = path.resolve(resolvedPath);\n \n if (!resolvedTarget.startsWith(resolvedBase + path.sep) && resolvedTarget !== resolvedBase) {\n throw new StorageAccessError('Path traversal attempt detected');\n }\n };\n\n const getEntityDir = (type: string, namespace?: string): string => {\n const dirName = registry.getDirectoryName(type);\n if (!dirName) {\n throw new SchemaNotRegisteredError(type);\n }\n\n // Sanitize namespace if provided\n const safeNamespace = namespace ? sanitizePathComponent(namespace, 'namespace') : undefined;\n \n // Sanitize directory name (should already be safe from registry, but double-check)\n const safeDirName = sanitizePathComponent(dirName, 'directoryName');\n\n let dir: string;\n if (safeNamespace) {\n dir = path.join(basePath, safeNamespace, safeDirName);\n } else {\n dir = path.join(basePath, safeDirName);\n }\n\n // Verify the path stays within basePath\n verifyPathWithinBase(dir);\n return dir;\n };\n\n const getEntityPath = (type: string, id: string, namespace?: string): string => {\n // Sanitize ID to prevent path traversal\n const safeId = sanitizePathComponent(id, 'id');\n \n const dir = getEntityDir(type, namespace);\n const fullPath = path.join(dir, `${safeId}${extension}`);\n \n // Verify the final path stays within basePath\n verifyPathWithinBase(fullPath);\n return fullPath;\n };\n\n const getEntityPathForWrite = (entity: BaseEntity, namespace?: string): string => {\n if (!filenameStrategy) {\n return getEntityPath(entity.type, entity.id, namespace);\n }\n\n const filename = filenameStrategy(entity);\n const safeFilename = sanitizePathComponent(filename, 'filename');\n const dir = getEntityDir(entity.type, namespace);\n const fullPath = path.join(dir, `${safeFilename}${extension}`);\n verifyPathWithinBase(fullPath);\n return fullPath;\n };\n\n /**\n * Find the actual file path for an entity by id, handling custom filename strategies.\n * Tries direct {id}{ext} first, then scans the directory using id prefix matching.\n */\n const findEntityFileById = async (type: string, id: string, namespace?: string): Promise<string | undefined> => {\n const directPath = getEntityPath(type, id, namespace);\n if (existsSync(directPath)) {\n return directPath;\n }\n\n if (!filenameStrategy) {\n return undefined;\n }\n\n let dir: string;\n try {\n dir = getEntityDir(type, namespace);\n } catch {\n return undefined;\n }\n\n if (!existsSync(dir)) {\n return undefined;\n }\n\n const prefix = id.substring(0, Math.min(8, id.length));\n const files = await fs.readdir(dir);\n const candidates = files.filter(f =>\n (f.endsWith('.yaml') || f.endsWith('.yml')) && f.startsWith(prefix)\n );\n\n // Always verify the entity ID inside the file to prevent\n // returning the wrong entity when IDs share a common prefix.\n for (const file of candidates) {\n const filePath = path.join(dir, file);\n const entity = await readEntity(filePath, type);\n if (entity && entity.id === id) {\n return filePath;\n }\n }\n\n return undefined;\n };\n\n const ensureDir = async (dir: string): Promise<void> => {\n if (!existsSync(dir) && createIfMissing && !readonly) {\n await fs.mkdir(dir, { recursive: true });\n }\n };\n\n // Cache the real basePath to handle symlinked temp directories (e.g., macOS /var/folders -> /private/var/folders).\n // Computed lazily on first readEntity call once the directory exists.\n let realBasePath: string | undefined;\n\n const readEntity = async <T extends BaseEntity>(\n filePath: string,\n type: string\n ): Promise<T | undefined> => {\n try {\n // Resolve symlinks and verify the real path is within basePath\n // to prevent symlink-based path traversal.\n let realFilePath: string;\n try {\n realFilePath = await fs.realpath(filePath);\n } catch {\n // If realpath fails (e.g., file doesn't exist), fall through to readFile\n // which will throw ENOENT and be handled below.\n realFilePath = filePath;\n }\n // Resolve basePath's real path to handle symlinked parent directories.\n // Fall back to path.resolve if basePath doesn't exist yet.\n if (!realBasePath) {\n try {\n realBasePath = await fs.realpath(basePath);\n } catch {\n realBasePath = path.resolve(basePath);\n }\n }\n if (!realFilePath.startsWith(realBasePath + path.sep) && realFilePath !== realBasePath) {\n // eslint-disable-next-line no-console\n console.warn(`Symlink traversal attempt detected: ${filePath} resolves to ${realFilePath}`);\n return undefined;\n }\n\n const content = await fs.readFile(filePath, 'utf-8');\n \n let parsed: unknown;\n try {\n parsed = yaml.load(content);\n } catch (yamlError) {\n // eslint-disable-next-line no-console\n console.warn(`Invalid YAML at ${filePath}:`, yamlError);\n return undefined;\n }\n\n if (!parsed || typeof parsed !== 'object') {\n return undefined;\n }\n\n // Protect against prototype pollution from malicious YAML.\n // Recursively check for __proto__ keys at all nesting levels,\n // since nested __proto__ can still cause pollution when objects\n // are spread or assigned downstream.\n const hasProtoKey = (obj: unknown): boolean => {\n if (!obj || typeof obj !== 'object') return false;\n if (Object.prototype.hasOwnProperty.call(obj, '__proto__')) return true;\n for (const value of Object.values(obj as Record<string, unknown>)) {\n if (hasProtoKey(value)) return true;\n }\n if (Array.isArray(obj)) {\n for (const item of obj) {\n if (hasProtoKey(item)) return true;\n }\n }\n return false;\n };\n\n if (hasProtoKey(parsed)) {\n // eslint-disable-next-line no-console\n console.warn(`Potential prototype pollution attempt in ${filePath}: __proto__ key detected`);\n return undefined;\n }\n\n const parsedObj = parsed as Record<string, unknown>;\n\n // Validate against registered schema\n const result = registry.validateAs<T>(type, {\n ...parsedObj,\n source: filePath,\n });\n\n if (!result.success) {\n // eslint-disable-next-line no-console\n console.warn(`Invalid entity at ${filePath}:`, result.errors);\n return undefined;\n }\n\n return result.data;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return undefined;\n }\n throw new StorageAccessError(`Failed to read ${filePath}`, error as Error);\n }\n };\n\n const writeEntity = async <T extends BaseEntity>(\n entity: T,\n namespace?: string\n ): Promise<T> => {\n if (readonly) {\n throw new ReadonlyStorageError();\n }\n\n // Validate against schema\n const validationResult = registry.validate(entity);\n if (!validationResult.success) {\n throw new ValidationError(\n 'Entity validation failed',\n validationResult.errors || []\n );\n }\n\n const dir = getEntityDir(entity.type, namespace);\n await ensureDir(dir);\n\n const filePath = getEntityPathForWrite(entity, namespace);\n\n // If filenameStrategy is set, clean up any old file with a different name for the same id\n if (filenameStrategy) {\n const oldPath = await findEntityFileById(entity.type, entity.id, namespace);\n if (oldPath && path.resolve(oldPath) !== path.resolve(filePath)) {\n try { await fs.unlink(oldPath); } catch { /* best-effort cleanup */ }\n }\n }\n\n // Remove framework-managed fields from saved YAML\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { type: _type, source: _source, ...entityToSave } = entity;\n\n // Update metadata\n const now = new Date();\n const toSave = {\n ...entityToSave,\n updatedAt: now,\n createdAt: entityToSave.createdAt || now,\n };\n\n const content = yaml.dump(toSave, {\n lineWidth: -1,\n sortKeys: false,\n });\n await fs.writeFile(filePath, content, 'utf-8');\n\n return {\n ...entity,\n ...toSave,\n type: entity.type,\n source: filePath,\n } as T;\n };\n\n const listDirectoryTypes = async (basePath: string): Promise<string[]> => {\n const types: string[] = [];\n\n try {\n const entries = await fs.readdir(basePath, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n const type = registry.getTypeFromDirectory(entry.name);\n if (type) {\n types.push(type);\n }\n }\n }\n } catch {\n // Directory doesn't exist\n }\n\n return types;\n };\n\n // --- StorageProvider Implementation ---\n\n const provider: StorageProvider = {\n name: 'filesystem',\n location: basePath,\n registry,\n\n async initialize(): Promise<void> {\n if (createIfMissing && !readonly) {\n await ensureDir(basePath);\n }\n\n if (!existsSync(basePath)) {\n throw new StorageAccessError(`Context path does not exist: ${basePath}`);\n }\n },\n\n async dispose(): Promise<void> {\n // No cleanup needed for filesystem\n },\n\n async isAvailable(): Promise<boolean> {\n try {\n const stat = statSync(basePath);\n return stat.isDirectory();\n } catch {\n return false;\n }\n },\n\n async get<T extends BaseEntity>(\n type: string,\n id: string,\n namespace?: string\n ): Promise<T | undefined> {\n const ns = namespace ?? defaultNamespace;\n if (filenameStrategy) {\n const filePath = await findEntityFileById(type, id, ns);\n if (!filePath) return undefined;\n return readEntity<T>(filePath, type);\n }\n const filePath = getEntityPath(type, id, ns);\n return readEntity<T>(filePath, type);\n },\n\n async getAll<T extends BaseEntity>(\n type: string,\n namespace?: string\n ): Promise<T[]> {\n const ns = namespace ?? defaultNamespace;\n\n let dir: string;\n try {\n dir = getEntityDir(type, ns);\n } catch (error) {\n if (error instanceof SchemaNotRegisteredError) {\n return [];\n }\n throw error;\n }\n\n if (!existsSync(dir)) {\n return [];\n }\n\n const files = await fs.readdir(dir);\n const entities: T[] = [];\n\n for (const file of files) {\n if (!file.endsWith('.yaml') && !file.endsWith('.yml')) {\n continue;\n }\n\n const entity = await readEntity<T>(path.join(dir, file), type);\n if (entity) {\n entities.push(entity);\n }\n }\n\n return entities;\n },\n\n async find<T extends BaseEntity>(filter: EntityFilter): Promise<T[]> {\n let results: T[] = [];\n\n const types = filter.type\n ? (Array.isArray(filter.type) ? filter.type : [filter.type])\n : registry.types();\n\n const namespace = filter.namespace ?? defaultNamespace;\n\n for (const type of types) {\n const entities = await this.getAll<T>(type, namespace);\n results = results.concat(entities);\n }\n\n // Apply ID filter\n if (filter.ids?.length) {\n results = results.filter(e => filter.ids!.includes(e.id));\n }\n\n // Apply search filter\n if (filter.search) {\n const searchLower = filter.search.toLowerCase();\n results = results.filter(e =>\n e.name.toLowerCase().includes(searchLower)\n );\n }\n\n // Apply pagination\n if (filter.offset) {\n results = results.slice(filter.offset);\n }\n if (filter.limit) {\n results = results.slice(0, filter.limit);\n }\n\n return results;\n },\n\n async exists(type: string, id: string, namespace?: string): Promise<boolean> {\n const ns = namespace ?? defaultNamespace;\n try {\n if (filenameStrategy) {\n const filePath = await findEntityFileById(type, id, ns);\n return filePath !== undefined;\n }\n const filePath = getEntityPath(type, id, ns);\n return existsSync(filePath);\n } catch {\n return false;\n }\n },\n\n async count(filter: EntityFilter): Promise<number> {\n const results = await this.find(filter);\n return results.length;\n },\n\n async save<T extends BaseEntity>(entity: T, namespace?: string): Promise<T> {\n const ns = namespace ?? defaultNamespace;\n return writeEntity(entity, ns);\n },\n\n async delete(type: string, id: string, namespace?: string): Promise<boolean> {\n if (readonly) {\n throw new ReadonlyStorageError();\n }\n\n const ns = namespace ?? defaultNamespace;\n\n try {\n if (filenameStrategy) {\n const filePath = await findEntityFileById(type, id, ns);\n if (!filePath) return false;\n await fs.unlink(filePath);\n return true;\n }\n const filePath = getEntityPath(type, id, ns);\n await fs.unlink(filePath);\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return false;\n }\n throw error;\n }\n },\n\n async saveBatch<T extends BaseEntity>(\n entities: T[],\n namespace?: string\n ): Promise<T[]> {\n if (entities.length > MAX_BATCH_SIZE) {\n throw new StorageAccessError(\n `Batch size ${entities.length} exceeds maximum of ${MAX_BATCH_SIZE}. Split into smaller batches.`\n );\n }\n const saved: T[] = [];\n for (const entity of entities) {\n saved.push(await this.save(entity, namespace));\n }\n return saved;\n },\n\n async deleteBatch(\n refs: Array<{ type: string; id: string }>,\n namespace?: string\n ): Promise<number> {\n if (refs.length > MAX_BATCH_SIZE) {\n throw new StorageAccessError(\n `Batch size ${refs.length} exceeds maximum of ${MAX_BATCH_SIZE}. Split into smaller batches.`\n );\n }\n let count = 0;\n for (const ref of refs) {\n if (await this.delete(ref.type, ref.id, namespace)) {\n count++;\n }\n }\n return count;\n },\n\n async listNamespaces(): Promise<string[]> {\n const namespaces: string[] = [];\n\n if (!existsSync(basePath)) {\n return namespaces;\n }\n\n const entries = await fs.readdir(basePath, { withFileTypes: true });\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n // Check if it's a namespace (contains entity type directories)\n // vs being an entity type directory itself\n const subPath = path.join(basePath, entry.name);\n const subTypes = await listDirectoryTypes(subPath);\n\n if (subTypes.length > 0) {\n namespaces.push(entry.name);\n }\n }\n\n return namespaces;\n },\n\n async namespaceExists(namespace: string): Promise<boolean> {\n // Sanitize namespace to prevent path traversal\n const safeNamespace = sanitizePathComponent(namespace, 'namespace');\n const namespacePath = path.join(basePath, safeNamespace);\n \n // Verify path stays within basePath\n verifyPathWithinBase(namespacePath);\n return existsSync(namespacePath);\n },\n\n async listTypes(namespace?: string): Promise<string[]> {\n const ns = namespace ?? defaultNamespace;\n let searchPath: string;\n if (ns) {\n // Sanitize namespace to prevent path traversal\n const safeNamespace = sanitizePathComponent(ns, 'namespace');\n searchPath = path.join(basePath, safeNamespace);\n verifyPathWithinBase(searchPath);\n } else {\n searchPath = basePath;\n }\n return listDirectoryTypes(searchPath);\n },\n };\n\n return provider;\n};\n"],"names":["MAX_BATCH_SIZE","createFileSystemProvider","options","basePath","registry","createIfMissing","extension","readonly","defaultNamespace","filenameStrategy","sanitizePathComponent","input","componentName","includes","ValidationError","path","message","i","length","code","charCodeAt","verifyPathWithinBase","resolvedPath","resolvedBase","resolve","resolvedTarget","startsWith","sep","StorageAccessError","getEntityDir","type","namespace","dirName","getDirectoryName","SchemaNotRegisteredError","safeNamespace","undefined","safeDirName","dir","join","getEntityPath","id","safeId","fullPath","getEntityPathForWrite","entity","filename","safeFilename","findEntityFileById","directPath","existsSync","prefix","substring","Math","min","files","fs","readdir","candidates","filter","f","endsWith","file","filePath","readEntity","ensureDir","mkdir","recursive","realBasePath","realFilePath","realpath","console","warn","content","readFile","parsed","yaml","load","yamlError","hasProtoKey","obj","Object","prototype","hasOwnProperty","call","value","values","Array","isArray","item","parsedObj","result","validateAs","source","success","errors","data","error","writeEntity","ReadonlyStorageError","validationResult","validate","oldPath","unlink","_type","_source","entityToSave","now","Date","toSave","updatedAt","createdAt","dump","lineWidth","sortKeys","writeFile","listDirectoryTypes","types","entries","withFileTypes","entry","isDirectory","getTypeFromDirectory","name","push","provider","location","initialize","dispose","isAvailable","stat","statSync","get","ns","getAll","entities","find","results","concat","ids","e","search","searchLower","toLowerCase","offset","slice","limit","exists","count","save","delete","saveBatch","saved","deleteBatch","refs","ref","listNamespaces","namespaces","subPath","subTypes","namespaceExists","namespacePath","listTypes","searchPath"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@utilarium/overcontext",
3
- "version": "0.0.6",
3
+ "version": "0.0.7-dev.20260220025748.d61df74",
4
4
  "description": "Schema-driven framework for context management - provides infrastructure for defining and managing custom entity schemas.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -29,8 +29,8 @@
29
29
  "watch": "vite build --watch",
30
30
  "test": "vitest run --coverage",
31
31
  "precommit": "npm run lint && npm run test",
32
- "lint": "eslint . --ext .ts",
33
- "lint:fix": "eslint . --ext .ts --fix",
32
+ "lint": "eslint .",
33
+ "lint:fix": "eslint . --fix",
34
34
  "clean": "rm -rf dist",
35
35
  "prepublishOnly": "npm run clean && npm run build",
36
36
  "docs:dev": "cd docs && cp ../README.md public/ && npm install && npm run dev",
@@ -60,24 +60,24 @@
60
60
  "zod": "^4.3.6"
61
61
  },
62
62
  "devDependencies": {
63
- "@eslint/eslintrc": "^3.3.1",
64
- "@eslint/js": "^9.30.1",
65
- "@rollup/plugin-replace": "^6.0.2",
66
- "@swc/core": "^1.12.11",
63
+ "@eslint/compat": "^1.4.1",
64
+ "@eslint/js": "^9.39.2",
65
+ "@rollup/plugin-replace": "^6.0.3",
66
+ "@swc/core": "^1.15.11",
67
67
  "@types/js-yaml": "^4.0.9",
68
- "@types/node": "^25.0.3",
69
- "@typescript-eslint/eslint-plugin": "^8.36.0",
70
- "@typescript-eslint/parser": "^8.36.0",
71
- "@vitest/coverage-v8": "^4.0.16",
72
- "ajv": "^8.17.1",
73
- "eslint": "^9.30.1",
68
+ "@types/node": "^25.3.0",
69
+ "@typescript-eslint/eslint-plugin": "^8.56.0",
70
+ "@typescript-eslint/parser": "^8.56.0",
71
+ "@vitest/coverage-v8": "^4.0.18",
72
+ "ajv": "^8.18.0",
73
+ "eslint": "^9.39.2",
74
74
  "eslint-plugin-import": "^2.32.0",
75
- "globals": "^17.0.0",
76
- "typescript": "^5.8.3",
77
- "vite": "^7.0.4",
75
+ "globals": "^17.3.0",
76
+ "typescript": "^5.9.3",
77
+ "vite": "^7.3.1",
78
78
  "vite-plugin-dts": "^4.5.4",
79
79
  "vite-plugin-node": "^7.0.0",
80
- "vitest": "^4.0.16"
80
+ "vitest": "^4.0.18"
81
81
  },
82
82
  "overrides": {
83
83
  "wrap-ansi": "7.0.0"