hazo_files 2.0.0 → 2.0.1
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/CHANGE_LOG.md +24 -0
- package/README.md +161 -0
- package/dist/server/index.d.mts +44 -1
- package/dist/server/index.d.ts +44 -1
- package/dist/server/index.js +192 -0
- package/dist/server/index.mjs +190 -0
- package/dist/testing/index.d.mts +62 -0
- package/dist/testing/index.d.ts +62 -0
- package/dist/testing/index.js +71 -0
- package/dist/testing/index.mjs +44 -0
- package/docs/superpowers/plans/2026-05-23-test-app-v2-providers.md +1 -1
- package/package.json +8 -2
package/CHANGE_LOG.md
CHANGED
|
@@ -5,6 +5,30 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## 2.0.1 (2026-05-23)
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **`FileStorageProvider` interface** (`hazo_files/server`) — lightweight storage abstraction with `put`, `get`, `delete`, `exists`, `getSignedUrl`, and `probe` methods. Complements the existing `StorageModule`/`FileManager` stack for simpler use cases that don't need folder trees or metadata tracking.
|
|
13
|
+
- **`AppFileServerProvider`** (`hazo_files/server`) — local-filesystem provider with HMAC-SHA256-signed download URLs. Constructor options: `root` (filesystem root), `hmac_secret`, and `default_ttl_seconds` (default 300s). Includes `verifySignedUrl(token, path)` for use in the `/api/files/serve` API route. Path traversal is blocked at the `resolve()` layer.
|
|
14
|
+
- **`InMemoryProvider`** (`hazo_files/testing`) — in-memory `FileStorageProvider` backed by a `Map<string, Buffer>`. Intended for unit tests. `getSignedUrl` returns a `data:` URL so tests never need a real HTTP server. Includes `snapshot()` escape hatch for assertions.
|
|
15
|
+
- **`GoogleDriveProvider`** (`hazo_files/server`) — service-account Google Drive provider for Shared Drives. Accepts `service_account_json`, `shared_drive_id`, and a `DrivePathCache` for lazy folder-ID resolution. Unlike `GoogleDriveModule` (which uses OAuth), this provider is designed for server-side use with a GCP service account.
|
|
16
|
+
- **`hazo_files/testing` subpath export** — re-exports `InMemoryProvider` for use in test suites without pulling in server-only modules.
|
|
17
|
+
- **Error classes**: `StorageCollisionExhausted`, `StorageNotConfigured`, `StorageUnavailable` — exported from `hazo_files/server`.
|
|
18
|
+
- **Types**: `PutOpts`, `PutResult`, `SignedUrlOpts`, `ProbeResult`, `DrivePathCache` — exported from `hazo_files/server`.
|
|
19
|
+
|
|
20
|
+
### Breaking changes from 1.x
|
|
21
|
+
None. All additions are new exports; existing `FileManager`/`TrackedFileManager` API is unchanged.
|
|
22
|
+
|
|
23
|
+
## 2.0.0 (2026-05-22)
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- **`googleapis` and `mime-types` promoted to direct `dependencies`** (previously optional peer deps) — the package now bundles them so consumers no longer need to install them separately for Google Drive or MIME detection. This is a major bump because it changes the transitive dependency surface for all consumers.
|
|
28
|
+
|
|
29
|
+
### Not breaking
|
|
30
|
+
The public API is identical to 1.6.0. No migration required.
|
|
31
|
+
|
|
8
32
|
## 1.6.0 (2026-05-21)
|
|
9
33
|
|
|
10
34
|
### Added
|
package/README.md
CHANGED
|
@@ -7,6 +7,10 @@ A powerful, modular file management package for Node.js and React applications w
|
|
|
7
7
|
|
|
8
8
|
## Features
|
|
9
9
|
|
|
10
|
+
- **`FileStorageProvider` Interface**: Lightweight `put/get/delete/exists/getSignedUrl/probe` abstraction for simpler use cases
|
|
11
|
+
- **`AppFileServerProvider`**: Local filesystem + HMAC-signed download URLs — no cloud account required
|
|
12
|
+
- **`GoogleDriveProvider`**: Service-account Google Drive for Shared Drives with lazy path-cache
|
|
13
|
+
- **`InMemoryProvider`**: Zero-dependency in-memory store for unit tests (via `hazo_files/testing`)
|
|
10
14
|
- **Multiple Storage Providers**: Local filesystem, Google Drive, and Dropbox support out of the box
|
|
11
15
|
- **Modular Architecture**: Easily add custom storage providers
|
|
12
16
|
- **Unified API**: Single consistent interface across all storage providers
|
|
@@ -72,6 +76,17 @@ For the background-upload sonner toast bridge (optional):
|
|
|
72
76
|
npm install sonner # Toast notifications for background upload pipelines
|
|
73
77
|
```
|
|
74
78
|
|
|
79
|
+
### Subpath exports
|
|
80
|
+
|
|
81
|
+
| Import | Contents |
|
|
82
|
+
|--------|---------|
|
|
83
|
+
| `hazo_files` | Core types, utilities, naming helpers |
|
|
84
|
+
| `hazo_files/ui` | React components (FileBrowser, NamingRuleConfigurator, etc.) |
|
|
85
|
+
| `hazo_files/server` | Server-only: FileManager, TrackedFileManager, FileStorageProvider providers, schema exports |
|
|
86
|
+
| `hazo_files/background-upload` | Framework-agnostic UploadManager pipeline engine |
|
|
87
|
+
| `hazo_files/background-upload/react` | React bindings for background uploads |
|
|
88
|
+
| `hazo_files/testing` | `InMemoryProvider` — import in test suites, safe to use without `server-only` |
|
|
89
|
+
|
|
75
90
|
### Tailwind CSS v4 Setup (Required for UI Components)
|
|
76
91
|
|
|
77
92
|
If you're using Tailwind CSS v4 with the UI components, you must add a `@source` directive to your CSS file to ensure Tailwind scans the package's files for utility classes.
|
|
@@ -1866,6 +1881,152 @@ try {
|
|
|
1866
1881
|
}
|
|
1867
1882
|
```
|
|
1868
1883
|
|
|
1884
|
+
## FileStorageProvider (v2 Provider API)
|
|
1885
|
+
|
|
1886
|
+
v2 introduces a slimmer storage abstraction — `FileStorageProvider` — that sits alongside (not replacing) the existing `FileManager`/`StorageModule` stack. Use it when you don't need folder trees, metadata tracking, or naming conventions, and just want put/get/signed-URL semantics.
|
|
1887
|
+
|
|
1888
|
+
### Interface
|
|
1889
|
+
|
|
1890
|
+
```typescript
|
|
1891
|
+
import type { FileStorageProvider } from 'hazo_files/server';
|
|
1892
|
+
|
|
1893
|
+
interface FileStorageProvider {
|
|
1894
|
+
put(path: string, body: Buffer | Readable, opts?: PutOpts): Promise<PutResult>;
|
|
1895
|
+
get(path: string): Promise<Buffer | Readable>;
|
|
1896
|
+
delete(path: string): Promise<void>;
|
|
1897
|
+
exists(path: string): Promise<boolean>;
|
|
1898
|
+
getSignedUrl(path: string, opts?: SignedUrlOpts): Promise<string>;
|
|
1899
|
+
probe(): Promise<ProbeResult>;
|
|
1900
|
+
}
|
|
1901
|
+
```
|
|
1902
|
+
|
|
1903
|
+
### AppFileServerProvider
|
|
1904
|
+
|
|
1905
|
+
Local filesystem with HMAC-signed download URLs. Ideal for self-hosted apps where files are served through an API route.
|
|
1906
|
+
|
|
1907
|
+
```typescript
|
|
1908
|
+
import { AppFileServerProvider } from 'hazo_files/server';
|
|
1909
|
+
|
|
1910
|
+
const provider = new AppFileServerProvider({
|
|
1911
|
+
root: './storage', // filesystem root
|
|
1912
|
+
hmac_secret: process.env.FILE_HMAC_SECRET!,
|
|
1913
|
+
default_ttl_seconds: 300, // default 5 min
|
|
1914
|
+
});
|
|
1915
|
+
|
|
1916
|
+
// Store a file
|
|
1917
|
+
const result = await provider.put('uploads/report.pdf', buffer, {
|
|
1918
|
+
contentType: 'application/pdf',
|
|
1919
|
+
});
|
|
1920
|
+
// { provider: 'app_file_server', native_id: 'uploads/report.pdf', size: 12345 }
|
|
1921
|
+
|
|
1922
|
+
// Generate a signed URL (expires in 5 min)
|
|
1923
|
+
const url = await provider.getSignedUrl('uploads/report.pdf');
|
|
1924
|
+
// '/api/files/serve/1748080800.ABC123.../uploads/report.pdf'
|
|
1925
|
+
```
|
|
1926
|
+
|
|
1927
|
+
#### Serving signed URLs (Next.js API route)
|
|
1928
|
+
|
|
1929
|
+
```typescript
|
|
1930
|
+
// app/api/files/serve/[...token]/route.ts
|
|
1931
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
1932
|
+
import { AppFileServerProvider } from 'hazo_files/server';
|
|
1933
|
+
|
|
1934
|
+
const provider = new AppFileServerProvider({
|
|
1935
|
+
root: './storage',
|
|
1936
|
+
hmac_secret: process.env.FILE_HMAC_SECRET!,
|
|
1937
|
+
});
|
|
1938
|
+
|
|
1939
|
+
export async function GET(
|
|
1940
|
+
_req: NextRequest,
|
|
1941
|
+
{ params }: { params: { token: string[] } }
|
|
1942
|
+
) {
|
|
1943
|
+
// token = ['<exp>.<sig>', 'uploads', 'report.pdf']
|
|
1944
|
+
const [token, ...pathParts] = params.token;
|
|
1945
|
+
const filePath = pathParts.join('/');
|
|
1946
|
+
|
|
1947
|
+
if (!provider.verifySignedUrl(token, filePath)) {
|
|
1948
|
+
return new NextResponse('Forbidden', { status: 403 });
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1951
|
+
const buf = await provider.get(filePath) as Buffer;
|
|
1952
|
+
return new NextResponse(buf, {
|
|
1953
|
+
headers: { 'Content-Type': 'application/octet-stream' },
|
|
1954
|
+
});
|
|
1955
|
+
}
|
|
1956
|
+
```
|
|
1957
|
+
|
|
1958
|
+
### GoogleDriveProvider
|
|
1959
|
+
|
|
1960
|
+
Service-account Google Drive for Shared Drives. No OAuth flow — configure a GCP service account with Shared Drive access.
|
|
1961
|
+
|
|
1962
|
+
```typescript
|
|
1963
|
+
import { GoogleDriveProvider } from 'hazo_files/server';
|
|
1964
|
+
import type { DrivePathCache } from 'hazo_files/server';
|
|
1965
|
+
|
|
1966
|
+
// Implement the path cache (e.g., backed by your hazo_connect adapter)
|
|
1967
|
+
const pathCache: DrivePathCache = {
|
|
1968
|
+
lookup: async (key) => redis.get(`gdrive:${key}`),
|
|
1969
|
+
write: async (key, id) => redis.set(`gdrive:${key}`, id),
|
|
1970
|
+
invalidate: async (key) => redis.del(`gdrive:${key}`),
|
|
1971
|
+
};
|
|
1972
|
+
|
|
1973
|
+
const provider = new GoogleDriveProvider({
|
|
1974
|
+
service_account_json: process.env.GOOGLE_SERVICE_ACCOUNT_JSON!,
|
|
1975
|
+
shared_drive_id: 'your-shared-drive-id',
|
|
1976
|
+
path_cache: pathCache,
|
|
1977
|
+
});
|
|
1978
|
+
|
|
1979
|
+
// Upload a file (folders are created lazily)
|
|
1980
|
+
const result = await provider.put('2026/ACME/invoice.pdf', buffer, {
|
|
1981
|
+
contentType: 'application/pdf',
|
|
1982
|
+
});
|
|
1983
|
+
// { provider: 'gdrive', native_id: '<drive-file-id>', size: 12345 }
|
|
1984
|
+
|
|
1985
|
+
// Check connectivity
|
|
1986
|
+
const health = await provider.probe();
|
|
1987
|
+
// { ok: true } or { ok: false, error: 'drive_not_shared', message: '...' }
|
|
1988
|
+
```
|
|
1989
|
+
|
|
1990
|
+
**Note**: `getSignedUrl` for Google Drive returns a native `drive.google.com/uc?id=...` link, which requires the viewer to have Drive access. For public unauthenticated downloads, use `AppFileServerProvider` instead or implement your own proxy.
|
|
1991
|
+
|
|
1992
|
+
### InMemoryProvider (testing)
|
|
1993
|
+
|
|
1994
|
+
Import from the dedicated `hazo_files/testing` subpath — keeps server-only modules out of your test bundle.
|
|
1995
|
+
|
|
1996
|
+
```typescript
|
|
1997
|
+
import { InMemoryProvider } from 'hazo_files/testing';
|
|
1998
|
+
|
|
1999
|
+
const store = new InMemoryProvider();
|
|
2000
|
+
|
|
2001
|
+
await store.put('docs/readme.txt', Buffer.from('hello'));
|
|
2002
|
+
const buf = await store.get('docs/readme.txt');
|
|
2003
|
+
console.log(buf.toString()); // 'hello'
|
|
2004
|
+
|
|
2005
|
+
// Test helper: inspect internal state
|
|
2006
|
+
const snap = store.snapshot();
|
|
2007
|
+
console.log([...snap.keys()]); // ['docs/readme.txt']
|
|
2008
|
+
|
|
2009
|
+
// getSignedUrl returns a data: URL — no HTTP server needed
|
|
2010
|
+
const url = await store.getSignedUrl('docs/readme.txt');
|
|
2011
|
+
// 'data:application/octet-stream;base64,aGVsbG8='
|
|
2012
|
+
```
|
|
2013
|
+
|
|
2014
|
+
### Provider Errors
|
|
2015
|
+
|
|
2016
|
+
```typescript
|
|
2017
|
+
import {
|
|
2018
|
+
StorageCollisionExhausted,
|
|
2019
|
+
StorageNotConfigured,
|
|
2020
|
+
StorageUnavailable,
|
|
2021
|
+
} from 'hazo_files/server';
|
|
2022
|
+
|
|
2023
|
+
// StorageCollisionExhausted — thrown when put with ifNotExists keeps colliding
|
|
2024
|
+
// StorageNotConfigured — thrown when provider config is absent
|
|
2025
|
+
// StorageUnavailable — wraps a ProbeResult error for runtime checks
|
|
2026
|
+
```
|
|
2027
|
+
|
|
2028
|
+
---
|
|
2029
|
+
|
|
1869
2030
|
## Extending with Custom Storage Providers
|
|
1870
2031
|
|
|
1871
2032
|
See [docs/ADDING_MODULES.md](docs/ADDING_MODULES.md) for a complete guide on creating custom storage modules.
|
package/dist/server/index.d.mts
CHANGED
|
@@ -2665,6 +2665,49 @@ declare class AppFileServerProvider implements FileStorageProvider {
|
|
|
2665
2665
|
probe(): Promise<ProbeResult>;
|
|
2666
2666
|
}
|
|
2667
2667
|
|
|
2668
|
+
declare class InMemoryProvider implements FileStorageProvider {
|
|
2669
|
+
readonly provider_tag: "in_memory";
|
|
2670
|
+
private readonly store;
|
|
2671
|
+
put(path: string, body: Buffer | Readable, opts?: PutOpts): Promise<PutResult>;
|
|
2672
|
+
get(path: string): Promise<Buffer>;
|
|
2673
|
+
delete(path: string): Promise<void>;
|
|
2674
|
+
exists(path: string): Promise<boolean>;
|
|
2675
|
+
getSignedUrl(path: string, _opts?: SignedUrlOpts): Promise<string>;
|
|
2676
|
+
probe(): Promise<ProbeResult>;
|
|
2677
|
+
/** Test-only escape hatch — exposes the internal store for assertions. */
|
|
2678
|
+
snapshot(): Map<string, Buffer>;
|
|
2679
|
+
}
|
|
2680
|
+
|
|
2681
|
+
interface DrivePathCache {
|
|
2682
|
+
lookup(key: string): Promise<string | null>;
|
|
2683
|
+
write(key: string, folder_id: string): Promise<void>;
|
|
2684
|
+
invalidate(key: string): Promise<void>;
|
|
2685
|
+
}
|
|
2686
|
+
interface GoogleDriveOpts {
|
|
2687
|
+
/** Raw JSON keyfile contents (decoded from GOOGLE_SERVICE_ACCOUNT_JSON env var). */
|
|
2688
|
+
service_account_json: string;
|
|
2689
|
+
/** Target Shared Drive ID. */
|
|
2690
|
+
shared_drive_id: string;
|
|
2691
|
+
/** Lazy folder-ID cache, scoped per Hazodocs org. */
|
|
2692
|
+
path_cache: DrivePathCache;
|
|
2693
|
+
}
|
|
2694
|
+
declare class GoogleDriveProvider implements FileStorageProvider {
|
|
2695
|
+
readonly provider_tag: "gdrive";
|
|
2696
|
+
private readonly drive;
|
|
2697
|
+
private readonly driveId;
|
|
2698
|
+
private readonly cache;
|
|
2699
|
+
constructor(opts: GoogleDriveOpts);
|
|
2700
|
+
probe(): Promise<ProbeResult>;
|
|
2701
|
+
put(path: string, body: Buffer | Readable, opts?: PutOpts): Promise<PutResult>;
|
|
2702
|
+
get(path: string): Promise<Buffer>;
|
|
2703
|
+
delete(path: string): Promise<void>;
|
|
2704
|
+
exists(path: string): Promise<boolean>;
|
|
2705
|
+
getSignedUrl(path: string, _opts?: SignedUrlOpts): Promise<string>;
|
|
2706
|
+
private resolvePath;
|
|
2707
|
+
private findChild;
|
|
2708
|
+
private lookupFileId;
|
|
2709
|
+
}
|
|
2710
|
+
|
|
2668
2711
|
/**
|
|
2669
2712
|
* Migration: Add Reference Tracking (V2)
|
|
2670
2713
|
*
|
|
@@ -3728,4 +3771,4 @@ declare function toV2Record(record: FileMetadataRecord): FileMetadataRecordV2;
|
|
|
3728
3771
|
*/
|
|
3729
3772
|
declare function buildFileWithStatus(record: FileMetadataRecord): FileWithStatus;
|
|
3730
3773
|
|
|
3731
|
-
export { ALL_SYSTEM_VARIABLES, type AddExtractionOptions, type AddRefOptions, type AppFileServerOpts, AppFileServerProvider, type AuthCallbacks, AuthenticationError, type CleanupOrphanedOptions, ConfigurationError, type ContentTagConfig, type CreateFolderOptions, type CrudServiceLike, DEFAULT_DATE_FORMATS, type DatabaseSchemaDefinition, type DatabaseTrackingConfig, DirectoryExistsError, DirectoryNotEmptyError, DirectoryNotFoundError, type DownloadOptions, DropboxAuth, type DropboxAuthCallbacks, type DropboxAuthConfig, type DropboxConfig, DropboxModule, type DropboxTokenData, type ExtractionData, type ExtractionOptions, type ExtractionResult, type FileBrowserState, type FileDataStructure, FileExistsError, type FileInfo, type FileItem, FileManager, type FileManagerOptions, type FileMetadataInput, type FileMetadataRecord, type FileMetadataRecordV2, FileMetadataService, type FileMetadataServiceOptions, type FileMetadataUpdate, FileNotFoundError, type FileRef, type FileRefVisibility, type FileStatus, type FileStorageProvider, type FileSystemItem, FileTooLargeError, type FileWithStatus, type FindOrphanedOptions, type FolderItem, type GeneratedNameResult, type GoogleAuthConfig, GoogleDriveAuth, type GoogleDriveConfig, GoogleDriveModule, HAZO_FILES_DEFAULT_TABLE_NAME, HAZO_FILES_JOB_TYPES, HAZO_FILES_MIGRATION_V2, HAZO_FILES_MIGRATION_V3, HAZO_FILES_MIGRATION_V4, HAZO_FILES_NAMING_DEFAULT_TABLE_NAME, HAZO_FILES_NAMING_TABLE_SCHEMA, HAZO_FILES_TABLE_SCHEMA, HAZO_FILE_QUOTAS_DEFAULT_TABLE_NAME, HAZO_FILE_QUOTAS_TABLE_SCHEMA, type HazoFileQuotasColumnDefinitions, type HazoFilesColumnDefinitions, type HazoFilesConfig, HazoFilesError, type HazoFilesJobType, type HazoFilesMigrationV2, type HazoFilesMigrationV3, type HazoFilesMigrationV4, type HazoFilesNamingColumnDefinitions, type HazoFilesNamingTableSchema, type HazoFilesServerInstance, type HazoFilesServerOptions, type HazoFilesTableSchema, type HazoLLMInstance, type HazoLogger, ImportSizeCapError, InvalidExtensionError, InvalidPathError, LLMExtractionService, type LLMFactory, type LLMFactoryConfig, type LLMProvider, type ListNamingConventionsOptions, type ListOptions, type LocalStorageConfig, LocalStorageModule, type MetadataLogger, type MigrationExecutor, type MigrationSchemaDefinition, type MoveOptions, type NameGenerationOptions, type NamingConventionInput, type NamingConventionRecord, NamingConventionService, type NamingConventionServiceOptions, type NamingConventionType, type NamingConventionUpdate, type NamingRuleConfiguratorProps, type NamingRuleHistoryEntry, type NamingRuleSchema, type NamingVariable, OperationError, type OperationResult, type ParsedNamingConvention, type PatternSegment, PermissionDeniedError, type ProbeResult, type ProgressCallback, type PurgeJobHandlerOptions, type PurgeOnePayload, type PurgePlanPayload, type PurgePlanResult, type PutOpts, type PutResult, type QuotaCrudServiceLike, QuotaExceededError, QuotaService, type QuotaServiceOptions, type QuotaStatus, type QuotaThresholdEvent, type RemoveExtractionOptions, type RemoveRefsCriteria, type RenameOptions, SSRFError, SYSTEM_COUNTER_VARIABLES, SYSTEM_DATE_VARIABLES, SYSTEM_FILE_VARIABLES, type SignedUrlOpts, StorageCollisionExhausted, type StorageModule, StorageNotConfigured, type StoragePath, type StorageProvider, StorageUnavailable, type TokenData, TrackedFileManager, type TrackedFileManagerFullOptions, type TrackedFileManagerOptions, type TrackedUploadOptions, type TreeNode, type UploadExtractOptions, type UploadExtractResult, UploadExtractService, type UploadOptions, type UploadWithRefOptions, type UseNamingRuleActions, type UseNamingRuleReturn, type UseNamingRuleState, type VariableCategory, addExtractionToFileData, backfillV2Defaults, buildFileWithStatus, clearExtractions, clonePattern, computeFileHash, computeFileHashFromStream, computeFileHashSync, computeFileInfo, createAndInitializeModule, createBasicFileManager, createDropboxAuth, createDropboxModule, createEmptyFileDataStructure, createEmptyNamingRuleSchema, createFileItem, createFileManager, createFileMetadataService, createFileRef, createFolderItem, createGoogleDriveAuth, createGoogleDriveModule, createHazoFilesServer, createInitializedFileManager, createInitializedTrackedFileManager, createLLMExtractionService, createLiteralSegment, createLocalModule, createModule, createNamingConventionService, createPurgeJobHandlers, createQuotaService, createTrackedFileManager, createUploadExtractService, createVariableSegment, deepMerge, errorResult, filterItems, formatBytes, formatCounter, formatDateToken, generateExtractionId, generateId, generatePreviewName, generateRefId, generateSampleConfig, generateSegmentId, getBaseName, getBreadcrumbs, getDirName, getExtension, getExtensionFromMime, getExtractionById, getExtractionCount, getExtractions, getFileCategory, getFileMetadataValues, getMergedData, getMigrationForTable, getMigrationV3ForTable, getMigrationV4ForTable, getMimeType, getNameWithoutExtension, getNamingSchemaForTable, getParentPath, getPathSegments, getRegisteredProviders, getRelativePath, getSchemaForTable, getSystemVariablePreviewValues, hasExtension, hasExtractionStructure, hasFileContentChanged, hashesEqual, hazo_files_generate_file_name, hazo_files_generate_folder_name, isAudio, isChildPath, isCounterVariable, isDateVariable, isDocument, isFile, isFileMetadataVariable, isFolder, isImage, isPreviewable, isProviderRegistered, isText, isVideo, joinPath, loadConfig, loadConfigAsync, migrateToV2, migrateToV3, normalizePath, parseConfig, parseFileData, parseFileRefs, parsePatternString, patternToString, recalculateMergedData, registerModule, removeExtractionById, removeExtractionByIndex, removeRefFromArray, removeRefsByCriteriaFromArray, sanitizeFilename, saveConfig, sortItems, stringifyFileData, stringifyFileRefs, successResult, toV2Record, updateExtractionById, validateExtractionData, validateFileDataStructure, validateNamingRuleSchema, validatePath };
|
|
3774
|
+
export { ALL_SYSTEM_VARIABLES, type AddExtractionOptions, type AddRefOptions, type AppFileServerOpts, AppFileServerProvider, type AuthCallbacks, AuthenticationError, type CleanupOrphanedOptions, ConfigurationError, type ContentTagConfig, type CreateFolderOptions, type CrudServiceLike, DEFAULT_DATE_FORMATS, type DatabaseSchemaDefinition, type DatabaseTrackingConfig, DirectoryExistsError, DirectoryNotEmptyError, DirectoryNotFoundError, type DownloadOptions, type DrivePathCache, DropboxAuth, type DropboxAuthCallbacks, type DropboxAuthConfig, type DropboxConfig, DropboxModule, type DropboxTokenData, type ExtractionData, type ExtractionOptions, type ExtractionResult, type FileBrowserState, type FileDataStructure, FileExistsError, type FileInfo, type FileItem, FileManager, type FileManagerOptions, type FileMetadataInput, type FileMetadataRecord, type FileMetadataRecordV2, FileMetadataService, type FileMetadataServiceOptions, type FileMetadataUpdate, FileNotFoundError, type FileRef, type FileRefVisibility, type FileStatus, type FileStorageProvider, type FileSystemItem, FileTooLargeError, type FileWithStatus, type FindOrphanedOptions, type FolderItem, type GeneratedNameResult, type GoogleAuthConfig, GoogleDriveAuth, type GoogleDriveConfig, GoogleDriveModule, type GoogleDriveOpts, GoogleDriveProvider, HAZO_FILES_DEFAULT_TABLE_NAME, HAZO_FILES_JOB_TYPES, HAZO_FILES_MIGRATION_V2, HAZO_FILES_MIGRATION_V3, HAZO_FILES_MIGRATION_V4, HAZO_FILES_NAMING_DEFAULT_TABLE_NAME, HAZO_FILES_NAMING_TABLE_SCHEMA, HAZO_FILES_TABLE_SCHEMA, HAZO_FILE_QUOTAS_DEFAULT_TABLE_NAME, HAZO_FILE_QUOTAS_TABLE_SCHEMA, type HazoFileQuotasColumnDefinitions, type HazoFilesColumnDefinitions, type HazoFilesConfig, HazoFilesError, type HazoFilesJobType, type HazoFilesMigrationV2, type HazoFilesMigrationV3, type HazoFilesMigrationV4, type HazoFilesNamingColumnDefinitions, type HazoFilesNamingTableSchema, type HazoFilesServerInstance, type HazoFilesServerOptions, type HazoFilesTableSchema, type HazoLLMInstance, type HazoLogger, ImportSizeCapError, InMemoryProvider, InvalidExtensionError, InvalidPathError, LLMExtractionService, type LLMFactory, type LLMFactoryConfig, type LLMProvider, type ListNamingConventionsOptions, type ListOptions, type LocalStorageConfig, LocalStorageModule, type MetadataLogger, type MigrationExecutor, type MigrationSchemaDefinition, type MoveOptions, type NameGenerationOptions, type NamingConventionInput, type NamingConventionRecord, NamingConventionService, type NamingConventionServiceOptions, type NamingConventionType, type NamingConventionUpdate, type NamingRuleConfiguratorProps, type NamingRuleHistoryEntry, type NamingRuleSchema, type NamingVariable, OperationError, type OperationResult, type ParsedNamingConvention, type PatternSegment, PermissionDeniedError, type ProbeResult, type ProgressCallback, type PurgeJobHandlerOptions, type PurgeOnePayload, type PurgePlanPayload, type PurgePlanResult, type PutOpts, type PutResult, type QuotaCrudServiceLike, QuotaExceededError, QuotaService, type QuotaServiceOptions, type QuotaStatus, type QuotaThresholdEvent, type RemoveExtractionOptions, type RemoveRefsCriteria, type RenameOptions, SSRFError, SYSTEM_COUNTER_VARIABLES, SYSTEM_DATE_VARIABLES, SYSTEM_FILE_VARIABLES, type SignedUrlOpts, StorageCollisionExhausted, type StorageModule, StorageNotConfigured, type StoragePath, type StorageProvider, StorageUnavailable, type TokenData, TrackedFileManager, type TrackedFileManagerFullOptions, type TrackedFileManagerOptions, type TrackedUploadOptions, type TreeNode, type UploadExtractOptions, type UploadExtractResult, UploadExtractService, type UploadOptions, type UploadWithRefOptions, type UseNamingRuleActions, type UseNamingRuleReturn, type UseNamingRuleState, type VariableCategory, addExtractionToFileData, backfillV2Defaults, buildFileWithStatus, clearExtractions, clonePattern, computeFileHash, computeFileHashFromStream, computeFileHashSync, computeFileInfo, createAndInitializeModule, createBasicFileManager, createDropboxAuth, createDropboxModule, createEmptyFileDataStructure, createEmptyNamingRuleSchema, createFileItem, createFileManager, createFileMetadataService, createFileRef, createFolderItem, createGoogleDriveAuth, createGoogleDriveModule, createHazoFilesServer, createInitializedFileManager, createInitializedTrackedFileManager, createLLMExtractionService, createLiteralSegment, createLocalModule, createModule, createNamingConventionService, createPurgeJobHandlers, createQuotaService, createTrackedFileManager, createUploadExtractService, createVariableSegment, deepMerge, errorResult, filterItems, formatBytes, formatCounter, formatDateToken, generateExtractionId, generateId, generatePreviewName, generateRefId, generateSampleConfig, generateSegmentId, getBaseName, getBreadcrumbs, getDirName, getExtension, getExtensionFromMime, getExtractionById, getExtractionCount, getExtractions, getFileCategory, getFileMetadataValues, getMergedData, getMigrationForTable, getMigrationV3ForTable, getMigrationV4ForTable, getMimeType, getNameWithoutExtension, getNamingSchemaForTable, getParentPath, getPathSegments, getRegisteredProviders, getRelativePath, getSchemaForTable, getSystemVariablePreviewValues, hasExtension, hasExtractionStructure, hasFileContentChanged, hashesEqual, hazo_files_generate_file_name, hazo_files_generate_folder_name, isAudio, isChildPath, isCounterVariable, isDateVariable, isDocument, isFile, isFileMetadataVariable, isFolder, isImage, isPreviewable, isProviderRegistered, isText, isVideo, joinPath, loadConfig, loadConfigAsync, migrateToV2, migrateToV3, normalizePath, parseConfig, parseFileData, parseFileRefs, parsePatternString, patternToString, recalculateMergedData, registerModule, removeExtractionById, removeExtractionByIndex, removeRefFromArray, removeRefsByCriteriaFromArray, sanitizeFilename, saveConfig, sortItems, stringifyFileData, stringifyFileRefs, successResult, toV2Record, updateExtractionById, validateExtractionData, validateFileDataStructure, validateNamingRuleSchema, validatePath };
|
package/dist/server/index.d.ts
CHANGED
|
@@ -2665,6 +2665,49 @@ declare class AppFileServerProvider implements FileStorageProvider {
|
|
|
2665
2665
|
probe(): Promise<ProbeResult>;
|
|
2666
2666
|
}
|
|
2667
2667
|
|
|
2668
|
+
declare class InMemoryProvider implements FileStorageProvider {
|
|
2669
|
+
readonly provider_tag: "in_memory";
|
|
2670
|
+
private readonly store;
|
|
2671
|
+
put(path: string, body: Buffer | Readable, opts?: PutOpts): Promise<PutResult>;
|
|
2672
|
+
get(path: string): Promise<Buffer>;
|
|
2673
|
+
delete(path: string): Promise<void>;
|
|
2674
|
+
exists(path: string): Promise<boolean>;
|
|
2675
|
+
getSignedUrl(path: string, _opts?: SignedUrlOpts): Promise<string>;
|
|
2676
|
+
probe(): Promise<ProbeResult>;
|
|
2677
|
+
/** Test-only escape hatch — exposes the internal store for assertions. */
|
|
2678
|
+
snapshot(): Map<string, Buffer>;
|
|
2679
|
+
}
|
|
2680
|
+
|
|
2681
|
+
interface DrivePathCache {
|
|
2682
|
+
lookup(key: string): Promise<string | null>;
|
|
2683
|
+
write(key: string, folder_id: string): Promise<void>;
|
|
2684
|
+
invalidate(key: string): Promise<void>;
|
|
2685
|
+
}
|
|
2686
|
+
interface GoogleDriveOpts {
|
|
2687
|
+
/** Raw JSON keyfile contents (decoded from GOOGLE_SERVICE_ACCOUNT_JSON env var). */
|
|
2688
|
+
service_account_json: string;
|
|
2689
|
+
/** Target Shared Drive ID. */
|
|
2690
|
+
shared_drive_id: string;
|
|
2691
|
+
/** Lazy folder-ID cache, scoped per Hazodocs org. */
|
|
2692
|
+
path_cache: DrivePathCache;
|
|
2693
|
+
}
|
|
2694
|
+
declare class GoogleDriveProvider implements FileStorageProvider {
|
|
2695
|
+
readonly provider_tag: "gdrive";
|
|
2696
|
+
private readonly drive;
|
|
2697
|
+
private readonly driveId;
|
|
2698
|
+
private readonly cache;
|
|
2699
|
+
constructor(opts: GoogleDriveOpts);
|
|
2700
|
+
probe(): Promise<ProbeResult>;
|
|
2701
|
+
put(path: string, body: Buffer | Readable, opts?: PutOpts): Promise<PutResult>;
|
|
2702
|
+
get(path: string): Promise<Buffer>;
|
|
2703
|
+
delete(path: string): Promise<void>;
|
|
2704
|
+
exists(path: string): Promise<boolean>;
|
|
2705
|
+
getSignedUrl(path: string, _opts?: SignedUrlOpts): Promise<string>;
|
|
2706
|
+
private resolvePath;
|
|
2707
|
+
private findChild;
|
|
2708
|
+
private lookupFileId;
|
|
2709
|
+
}
|
|
2710
|
+
|
|
2668
2711
|
/**
|
|
2669
2712
|
* Migration: Add Reference Tracking (V2)
|
|
2670
2713
|
*
|
|
@@ -3728,4 +3771,4 @@ declare function toV2Record(record: FileMetadataRecord): FileMetadataRecordV2;
|
|
|
3728
3771
|
*/
|
|
3729
3772
|
declare function buildFileWithStatus(record: FileMetadataRecord): FileWithStatus;
|
|
3730
3773
|
|
|
3731
|
-
export { ALL_SYSTEM_VARIABLES, type AddExtractionOptions, type AddRefOptions, type AppFileServerOpts, AppFileServerProvider, type AuthCallbacks, AuthenticationError, type CleanupOrphanedOptions, ConfigurationError, type ContentTagConfig, type CreateFolderOptions, type CrudServiceLike, DEFAULT_DATE_FORMATS, type DatabaseSchemaDefinition, type DatabaseTrackingConfig, DirectoryExistsError, DirectoryNotEmptyError, DirectoryNotFoundError, type DownloadOptions, DropboxAuth, type DropboxAuthCallbacks, type DropboxAuthConfig, type DropboxConfig, DropboxModule, type DropboxTokenData, type ExtractionData, type ExtractionOptions, type ExtractionResult, type FileBrowserState, type FileDataStructure, FileExistsError, type FileInfo, type FileItem, FileManager, type FileManagerOptions, type FileMetadataInput, type FileMetadataRecord, type FileMetadataRecordV2, FileMetadataService, type FileMetadataServiceOptions, type FileMetadataUpdate, FileNotFoundError, type FileRef, type FileRefVisibility, type FileStatus, type FileStorageProvider, type FileSystemItem, FileTooLargeError, type FileWithStatus, type FindOrphanedOptions, type FolderItem, type GeneratedNameResult, type GoogleAuthConfig, GoogleDriveAuth, type GoogleDriveConfig, GoogleDriveModule, HAZO_FILES_DEFAULT_TABLE_NAME, HAZO_FILES_JOB_TYPES, HAZO_FILES_MIGRATION_V2, HAZO_FILES_MIGRATION_V3, HAZO_FILES_MIGRATION_V4, HAZO_FILES_NAMING_DEFAULT_TABLE_NAME, HAZO_FILES_NAMING_TABLE_SCHEMA, HAZO_FILES_TABLE_SCHEMA, HAZO_FILE_QUOTAS_DEFAULT_TABLE_NAME, HAZO_FILE_QUOTAS_TABLE_SCHEMA, type HazoFileQuotasColumnDefinitions, type HazoFilesColumnDefinitions, type HazoFilesConfig, HazoFilesError, type HazoFilesJobType, type HazoFilesMigrationV2, type HazoFilesMigrationV3, type HazoFilesMigrationV4, type HazoFilesNamingColumnDefinitions, type HazoFilesNamingTableSchema, type HazoFilesServerInstance, type HazoFilesServerOptions, type HazoFilesTableSchema, type HazoLLMInstance, type HazoLogger, ImportSizeCapError, InvalidExtensionError, InvalidPathError, LLMExtractionService, type LLMFactory, type LLMFactoryConfig, type LLMProvider, type ListNamingConventionsOptions, type ListOptions, type LocalStorageConfig, LocalStorageModule, type MetadataLogger, type MigrationExecutor, type MigrationSchemaDefinition, type MoveOptions, type NameGenerationOptions, type NamingConventionInput, type NamingConventionRecord, NamingConventionService, type NamingConventionServiceOptions, type NamingConventionType, type NamingConventionUpdate, type NamingRuleConfiguratorProps, type NamingRuleHistoryEntry, type NamingRuleSchema, type NamingVariable, OperationError, type OperationResult, type ParsedNamingConvention, type PatternSegment, PermissionDeniedError, type ProbeResult, type ProgressCallback, type PurgeJobHandlerOptions, type PurgeOnePayload, type PurgePlanPayload, type PurgePlanResult, type PutOpts, type PutResult, type QuotaCrudServiceLike, QuotaExceededError, QuotaService, type QuotaServiceOptions, type QuotaStatus, type QuotaThresholdEvent, type RemoveExtractionOptions, type RemoveRefsCriteria, type RenameOptions, SSRFError, SYSTEM_COUNTER_VARIABLES, SYSTEM_DATE_VARIABLES, SYSTEM_FILE_VARIABLES, type SignedUrlOpts, StorageCollisionExhausted, type StorageModule, StorageNotConfigured, type StoragePath, type StorageProvider, StorageUnavailable, type TokenData, TrackedFileManager, type TrackedFileManagerFullOptions, type TrackedFileManagerOptions, type TrackedUploadOptions, type TreeNode, type UploadExtractOptions, type UploadExtractResult, UploadExtractService, type UploadOptions, type UploadWithRefOptions, type UseNamingRuleActions, type UseNamingRuleReturn, type UseNamingRuleState, type VariableCategory, addExtractionToFileData, backfillV2Defaults, buildFileWithStatus, clearExtractions, clonePattern, computeFileHash, computeFileHashFromStream, computeFileHashSync, computeFileInfo, createAndInitializeModule, createBasicFileManager, createDropboxAuth, createDropboxModule, createEmptyFileDataStructure, createEmptyNamingRuleSchema, createFileItem, createFileManager, createFileMetadataService, createFileRef, createFolderItem, createGoogleDriveAuth, createGoogleDriveModule, createHazoFilesServer, createInitializedFileManager, createInitializedTrackedFileManager, createLLMExtractionService, createLiteralSegment, createLocalModule, createModule, createNamingConventionService, createPurgeJobHandlers, createQuotaService, createTrackedFileManager, createUploadExtractService, createVariableSegment, deepMerge, errorResult, filterItems, formatBytes, formatCounter, formatDateToken, generateExtractionId, generateId, generatePreviewName, generateRefId, generateSampleConfig, generateSegmentId, getBaseName, getBreadcrumbs, getDirName, getExtension, getExtensionFromMime, getExtractionById, getExtractionCount, getExtractions, getFileCategory, getFileMetadataValues, getMergedData, getMigrationForTable, getMigrationV3ForTable, getMigrationV4ForTable, getMimeType, getNameWithoutExtension, getNamingSchemaForTable, getParentPath, getPathSegments, getRegisteredProviders, getRelativePath, getSchemaForTable, getSystemVariablePreviewValues, hasExtension, hasExtractionStructure, hasFileContentChanged, hashesEqual, hazo_files_generate_file_name, hazo_files_generate_folder_name, isAudio, isChildPath, isCounterVariable, isDateVariable, isDocument, isFile, isFileMetadataVariable, isFolder, isImage, isPreviewable, isProviderRegistered, isText, isVideo, joinPath, loadConfig, loadConfigAsync, migrateToV2, migrateToV3, normalizePath, parseConfig, parseFileData, parseFileRefs, parsePatternString, patternToString, recalculateMergedData, registerModule, removeExtractionById, removeExtractionByIndex, removeRefFromArray, removeRefsByCriteriaFromArray, sanitizeFilename, saveConfig, sortItems, stringifyFileData, stringifyFileRefs, successResult, toV2Record, updateExtractionById, validateExtractionData, validateFileDataStructure, validateNamingRuleSchema, validatePath };
|
|
3774
|
+
export { ALL_SYSTEM_VARIABLES, type AddExtractionOptions, type AddRefOptions, type AppFileServerOpts, AppFileServerProvider, type AuthCallbacks, AuthenticationError, type CleanupOrphanedOptions, ConfigurationError, type ContentTagConfig, type CreateFolderOptions, type CrudServiceLike, DEFAULT_DATE_FORMATS, type DatabaseSchemaDefinition, type DatabaseTrackingConfig, DirectoryExistsError, DirectoryNotEmptyError, DirectoryNotFoundError, type DownloadOptions, type DrivePathCache, DropboxAuth, type DropboxAuthCallbacks, type DropboxAuthConfig, type DropboxConfig, DropboxModule, type DropboxTokenData, type ExtractionData, type ExtractionOptions, type ExtractionResult, type FileBrowserState, type FileDataStructure, FileExistsError, type FileInfo, type FileItem, FileManager, type FileManagerOptions, type FileMetadataInput, type FileMetadataRecord, type FileMetadataRecordV2, FileMetadataService, type FileMetadataServiceOptions, type FileMetadataUpdate, FileNotFoundError, type FileRef, type FileRefVisibility, type FileStatus, type FileStorageProvider, type FileSystemItem, FileTooLargeError, type FileWithStatus, type FindOrphanedOptions, type FolderItem, type GeneratedNameResult, type GoogleAuthConfig, GoogleDriveAuth, type GoogleDriveConfig, GoogleDriveModule, type GoogleDriveOpts, GoogleDriveProvider, HAZO_FILES_DEFAULT_TABLE_NAME, HAZO_FILES_JOB_TYPES, HAZO_FILES_MIGRATION_V2, HAZO_FILES_MIGRATION_V3, HAZO_FILES_MIGRATION_V4, HAZO_FILES_NAMING_DEFAULT_TABLE_NAME, HAZO_FILES_NAMING_TABLE_SCHEMA, HAZO_FILES_TABLE_SCHEMA, HAZO_FILE_QUOTAS_DEFAULT_TABLE_NAME, HAZO_FILE_QUOTAS_TABLE_SCHEMA, type HazoFileQuotasColumnDefinitions, type HazoFilesColumnDefinitions, type HazoFilesConfig, HazoFilesError, type HazoFilesJobType, type HazoFilesMigrationV2, type HazoFilesMigrationV3, type HazoFilesMigrationV4, type HazoFilesNamingColumnDefinitions, type HazoFilesNamingTableSchema, type HazoFilesServerInstance, type HazoFilesServerOptions, type HazoFilesTableSchema, type HazoLLMInstance, type HazoLogger, ImportSizeCapError, InMemoryProvider, InvalidExtensionError, InvalidPathError, LLMExtractionService, type LLMFactory, type LLMFactoryConfig, type LLMProvider, type ListNamingConventionsOptions, type ListOptions, type LocalStorageConfig, LocalStorageModule, type MetadataLogger, type MigrationExecutor, type MigrationSchemaDefinition, type MoveOptions, type NameGenerationOptions, type NamingConventionInput, type NamingConventionRecord, NamingConventionService, type NamingConventionServiceOptions, type NamingConventionType, type NamingConventionUpdate, type NamingRuleConfiguratorProps, type NamingRuleHistoryEntry, type NamingRuleSchema, type NamingVariable, OperationError, type OperationResult, type ParsedNamingConvention, type PatternSegment, PermissionDeniedError, type ProbeResult, type ProgressCallback, type PurgeJobHandlerOptions, type PurgeOnePayload, type PurgePlanPayload, type PurgePlanResult, type PutOpts, type PutResult, type QuotaCrudServiceLike, QuotaExceededError, QuotaService, type QuotaServiceOptions, type QuotaStatus, type QuotaThresholdEvent, type RemoveExtractionOptions, type RemoveRefsCriteria, type RenameOptions, SSRFError, SYSTEM_COUNTER_VARIABLES, SYSTEM_DATE_VARIABLES, SYSTEM_FILE_VARIABLES, type SignedUrlOpts, StorageCollisionExhausted, type StorageModule, StorageNotConfigured, type StoragePath, type StorageProvider, StorageUnavailable, type TokenData, TrackedFileManager, type TrackedFileManagerFullOptions, type TrackedFileManagerOptions, type TrackedUploadOptions, type TreeNode, type UploadExtractOptions, type UploadExtractResult, UploadExtractService, type UploadOptions, type UploadWithRefOptions, type UseNamingRuleActions, type UseNamingRuleReturn, type UseNamingRuleState, type VariableCategory, addExtractionToFileData, backfillV2Defaults, buildFileWithStatus, clearExtractions, clonePattern, computeFileHash, computeFileHashFromStream, computeFileHashSync, computeFileInfo, createAndInitializeModule, createBasicFileManager, createDropboxAuth, createDropboxModule, createEmptyFileDataStructure, createEmptyNamingRuleSchema, createFileItem, createFileManager, createFileMetadataService, createFileRef, createFolderItem, createGoogleDriveAuth, createGoogleDriveModule, createHazoFilesServer, createInitializedFileManager, createInitializedTrackedFileManager, createLLMExtractionService, createLiteralSegment, createLocalModule, createModule, createNamingConventionService, createPurgeJobHandlers, createQuotaService, createTrackedFileManager, createUploadExtractService, createVariableSegment, deepMerge, errorResult, filterItems, formatBytes, formatCounter, formatDateToken, generateExtractionId, generateId, generatePreviewName, generateRefId, generateSampleConfig, generateSegmentId, getBaseName, getBreadcrumbs, getDirName, getExtension, getExtensionFromMime, getExtractionById, getExtractionCount, getExtractions, getFileCategory, getFileMetadataValues, getMergedData, getMigrationForTable, getMigrationV3ForTable, getMigrationV4ForTable, getMimeType, getNameWithoutExtension, getNamingSchemaForTable, getParentPath, getPathSegments, getRegisteredProviders, getRelativePath, getSchemaForTable, getSystemVariablePreviewValues, hasExtension, hasExtractionStructure, hasFileContentChanged, hashesEqual, hazo_files_generate_file_name, hazo_files_generate_folder_name, isAudio, isChildPath, isCounterVariable, isDateVariable, isDocument, isFile, isFileMetadataVariable, isFolder, isImage, isPreviewable, isProviderRegistered, isText, isVideo, joinPath, loadConfig, loadConfigAsync, migrateToV2, migrateToV3, normalizePath, parseConfig, parseFileData, parseFileRefs, parsePatternString, patternToString, recalculateMergedData, registerModule, removeExtractionById, removeExtractionByIndex, removeRefFromArray, removeRefsByCriteriaFromArray, sanitizeFilename, saveConfig, sortItems, stringifyFileData, stringifyFileRefs, successResult, toV2Record, updateExtractionById, validateExtractionData, validateFileDataStructure, validateNamingRuleSchema, validatePath };
|
package/dist/server/index.js
CHANGED
|
@@ -47,6 +47,7 @@ __export(index_exports, {
|
|
|
47
47
|
FileTooLargeError: () => FileTooLargeError,
|
|
48
48
|
GoogleDriveAuth: () => GoogleDriveAuth,
|
|
49
49
|
GoogleDriveModule: () => GoogleDriveModule,
|
|
50
|
+
GoogleDriveProvider: () => GoogleDriveProvider,
|
|
50
51
|
HAZO_FILES_DEFAULT_TABLE_NAME: () => HAZO_FILES_DEFAULT_TABLE_NAME,
|
|
51
52
|
HAZO_FILES_JOB_TYPES: () => HAZO_FILES_JOB_TYPES,
|
|
52
53
|
HAZO_FILES_MIGRATION_V2: () => HAZO_FILES_MIGRATION_V2,
|
|
@@ -59,6 +60,7 @@ __export(index_exports, {
|
|
|
59
60
|
HAZO_FILE_QUOTAS_TABLE_SCHEMA: () => HAZO_FILE_QUOTAS_TABLE_SCHEMA,
|
|
60
61
|
HazoFilesError: () => HazoFilesError,
|
|
61
62
|
ImportSizeCapError: () => ImportSizeCapError,
|
|
63
|
+
InMemoryProvider: () => InMemoryProvider,
|
|
62
64
|
InvalidExtensionError: () => InvalidExtensionError,
|
|
63
65
|
InvalidPathError: () => InvalidPathError,
|
|
64
66
|
LLMExtractionService: () => LLMExtractionService,
|
|
@@ -6554,6 +6556,194 @@ async function streamToBuffer(s) {
|
|
|
6554
6556
|
return Buffer.concat(chunks);
|
|
6555
6557
|
}
|
|
6556
6558
|
|
|
6559
|
+
// src/providers/in-memory.ts
|
|
6560
|
+
var InMemoryProvider = class {
|
|
6561
|
+
constructor() {
|
|
6562
|
+
this.provider_tag = "in_memory";
|
|
6563
|
+
this.store = /* @__PURE__ */ new Map();
|
|
6564
|
+
}
|
|
6565
|
+
async put(path4, body, opts) {
|
|
6566
|
+
if (opts?.ifNotExists && this.store.has(path4)) throw new Error(`File exists: ${path4}`);
|
|
6567
|
+
const buf = Buffer.isBuffer(body) ? body : await streamToBuffer2(body);
|
|
6568
|
+
this.store.set(path4, buf);
|
|
6569
|
+
return { provider: this.provider_tag, native_id: path4, size: buf.length };
|
|
6570
|
+
}
|
|
6571
|
+
async get(path4) {
|
|
6572
|
+
const buf = this.store.get(path4);
|
|
6573
|
+
if (!buf) throw new Error(`Not found: ${path4}`);
|
|
6574
|
+
return buf;
|
|
6575
|
+
}
|
|
6576
|
+
async delete(path4) {
|
|
6577
|
+
this.store.delete(path4);
|
|
6578
|
+
}
|
|
6579
|
+
async exists(path4) {
|
|
6580
|
+
return this.store.has(path4);
|
|
6581
|
+
}
|
|
6582
|
+
async getSignedUrl(path4, _opts) {
|
|
6583
|
+
const buf = this.store.get(path4);
|
|
6584
|
+
if (!buf) throw new Error(`Not found: ${path4}`);
|
|
6585
|
+
return `data:application/octet-stream;base64,${buf.toString("base64")}`;
|
|
6586
|
+
}
|
|
6587
|
+
async probe() {
|
|
6588
|
+
return { ok: true };
|
|
6589
|
+
}
|
|
6590
|
+
/** Test-only escape hatch — exposes the internal store for assertions. */
|
|
6591
|
+
snapshot() {
|
|
6592
|
+
return new Map(this.store);
|
|
6593
|
+
}
|
|
6594
|
+
};
|
|
6595
|
+
async function streamToBuffer2(s) {
|
|
6596
|
+
const chunks = [];
|
|
6597
|
+
for await (const c of s) chunks.push(Buffer.isBuffer(c) ? c : Buffer.from(c));
|
|
6598
|
+
return Buffer.concat(chunks);
|
|
6599
|
+
}
|
|
6600
|
+
|
|
6601
|
+
// src/providers/google-drive.ts
|
|
6602
|
+
var import_googleapis3 = require("googleapis");
|
|
6603
|
+
var GoogleDriveProvider = class {
|
|
6604
|
+
constructor(opts) {
|
|
6605
|
+
this.provider_tag = "gdrive";
|
|
6606
|
+
let credentials = {};
|
|
6607
|
+
try {
|
|
6608
|
+
credentials = JSON.parse(opts.service_account_json);
|
|
6609
|
+
} catch {
|
|
6610
|
+
}
|
|
6611
|
+
const auth = new import_googleapis3.google.auth.GoogleAuth({
|
|
6612
|
+
credentials,
|
|
6613
|
+
scopes: ["https://www.googleapis.com/auth/drive"]
|
|
6614
|
+
});
|
|
6615
|
+
this.drive = import_googleapis3.google.drive({ version: "v3", auth });
|
|
6616
|
+
this.driveId = opts.shared_drive_id;
|
|
6617
|
+
this.cache = opts.path_cache;
|
|
6618
|
+
}
|
|
6619
|
+
async probe() {
|
|
6620
|
+
try {
|
|
6621
|
+
await this.drive.drives.get({
|
|
6622
|
+
driveId: this.driveId,
|
|
6623
|
+
supportsAllDrives: true
|
|
6624
|
+
});
|
|
6625
|
+
return { ok: true };
|
|
6626
|
+
} catch (err) {
|
|
6627
|
+
const e = err;
|
|
6628
|
+
if (e?.code === 404) return { ok: false, error: "drive_not_shared", message: "SA cannot see Shared Drive" };
|
|
6629
|
+
if (e?.code === 403) return { ok: false, error: "write_denied", message: "SA lacks permission" };
|
|
6630
|
+
return { ok: false, error: "transient", message: String(err) };
|
|
6631
|
+
}
|
|
6632
|
+
}
|
|
6633
|
+
async put(path4, body, opts) {
|
|
6634
|
+
const segments = path4.split("/").filter(Boolean);
|
|
6635
|
+
const filename = segments.pop();
|
|
6636
|
+
const parentId = await this.resolvePath(segments, { create: true });
|
|
6637
|
+
if (opts?.ifNotExists) {
|
|
6638
|
+
const existing = await this.findChild(filename, parentId);
|
|
6639
|
+
if (existing) throw new Error(`File exists: ${path4}`);
|
|
6640
|
+
}
|
|
6641
|
+
const buf = Buffer.isBuffer(body) ? body : await streamToBuffer3(body);
|
|
6642
|
+
const res = await this.drive.files.create({
|
|
6643
|
+
requestBody: {
|
|
6644
|
+
name: filename,
|
|
6645
|
+
parents: [parentId],
|
|
6646
|
+
mimeType: opts?.contentType ?? "application/octet-stream"
|
|
6647
|
+
},
|
|
6648
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6649
|
+
media: { body: buf },
|
|
6650
|
+
fields: "id, name"
|
|
6651
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6652
|
+
});
|
|
6653
|
+
return { provider: this.provider_tag, native_id: res.data.id, size: buf.length };
|
|
6654
|
+
}
|
|
6655
|
+
async get(path4) {
|
|
6656
|
+
const id = await this.lookupFileId(path4);
|
|
6657
|
+
const res = await this.drive.files.get(
|
|
6658
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6659
|
+
{ fileId: id, alt: "media", supportsAllDrives: true },
|
|
6660
|
+
{ responseType: "arraybuffer" }
|
|
6661
|
+
);
|
|
6662
|
+
return Buffer.from(res.data);
|
|
6663
|
+
}
|
|
6664
|
+
async delete(path4) {
|
|
6665
|
+
try {
|
|
6666
|
+
const id = await this.lookupFileId(path4);
|
|
6667
|
+
await this.drive.files.delete({ fileId: id, supportsAllDrives: true });
|
|
6668
|
+
} catch (err) {
|
|
6669
|
+
const e = err;
|
|
6670
|
+
if (e?.code !== 404) throw err;
|
|
6671
|
+
}
|
|
6672
|
+
}
|
|
6673
|
+
async exists(path4) {
|
|
6674
|
+
try {
|
|
6675
|
+
await this.lookupFileId(path4);
|
|
6676
|
+
return true;
|
|
6677
|
+
} catch {
|
|
6678
|
+
return false;
|
|
6679
|
+
}
|
|
6680
|
+
}
|
|
6681
|
+
async getSignedUrl(path4, _opts) {
|
|
6682
|
+
const id = await this.lookupFileId(path4);
|
|
6683
|
+
return `https://drive.google.com/uc?id=${id}&export=download`;
|
|
6684
|
+
}
|
|
6685
|
+
async resolvePath(segments, opts) {
|
|
6686
|
+
let parentId = this.driveId;
|
|
6687
|
+
const accumulated = [];
|
|
6688
|
+
for (const segment of segments) {
|
|
6689
|
+
accumulated.push(segment);
|
|
6690
|
+
const cacheKey = accumulated.join("/");
|
|
6691
|
+
const cached = await this.cache.lookup(cacheKey);
|
|
6692
|
+
if (cached) {
|
|
6693
|
+
parentId = cached;
|
|
6694
|
+
continue;
|
|
6695
|
+
}
|
|
6696
|
+
let found = await this.findChild(segment, parentId, "application/vnd.google-apps.folder");
|
|
6697
|
+
if (!found && opts.create) {
|
|
6698
|
+
const created = await this.drive.files.create({
|
|
6699
|
+
requestBody: {
|
|
6700
|
+
name: segment,
|
|
6701
|
+
parents: [parentId],
|
|
6702
|
+
mimeType: "application/vnd.google-apps.folder"
|
|
6703
|
+
},
|
|
6704
|
+
fields: "id"
|
|
6705
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6706
|
+
});
|
|
6707
|
+
found = created.data.id;
|
|
6708
|
+
}
|
|
6709
|
+
if (!found) throw new Error(`Folder not found and create=false: ${cacheKey}`);
|
|
6710
|
+
await this.cache.write(cacheKey, found);
|
|
6711
|
+
parentId = found;
|
|
6712
|
+
}
|
|
6713
|
+
return parentId;
|
|
6714
|
+
}
|
|
6715
|
+
async findChild(name, parentId, mimeType) {
|
|
6716
|
+
const q = [
|
|
6717
|
+
`name='${name.replace(/'/g, "\\'")}'`,
|
|
6718
|
+
`'${parentId}' in parents`,
|
|
6719
|
+
`trashed=false`
|
|
6720
|
+
];
|
|
6721
|
+
if (mimeType) q.push(`mimeType='${mimeType}'`);
|
|
6722
|
+
const res = await this.drive.files.list({
|
|
6723
|
+
q: q.join(" and "),
|
|
6724
|
+
driveId: this.driveId,
|
|
6725
|
+
corpora: "drive",
|
|
6726
|
+
includeItemsFromAllDrives: true,
|
|
6727
|
+
fields: "files(id, name)"
|
|
6728
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6729
|
+
});
|
|
6730
|
+
return res.data.files?.[0]?.id ?? null;
|
|
6731
|
+
}
|
|
6732
|
+
async lookupFileId(path4) {
|
|
6733
|
+
const segments = path4.split("/").filter(Boolean);
|
|
6734
|
+
const filename = segments.pop();
|
|
6735
|
+
const parentId = await this.resolvePath(segments, { create: false });
|
|
6736
|
+
const id = await this.findChild(filename, parentId);
|
|
6737
|
+
if (!id) throw Object.assign(new Error(`Not found: ${path4}`), { code: 404 });
|
|
6738
|
+
return id;
|
|
6739
|
+
}
|
|
6740
|
+
};
|
|
6741
|
+
async function streamToBuffer3(s) {
|
|
6742
|
+
const chunks = [];
|
|
6743
|
+
for await (const c of s) chunks.push(Buffer.isBuffer(c) ? c : Buffer.from(c));
|
|
6744
|
+
return Buffer.concat(chunks);
|
|
6745
|
+
}
|
|
6746
|
+
|
|
6557
6747
|
// src/providers/types.ts
|
|
6558
6748
|
var StorageCollisionExhausted = class extends Error {
|
|
6559
6749
|
constructor(attempts, lastPath) {
|
|
@@ -6636,6 +6826,7 @@ try {
|
|
|
6636
6826
|
FileTooLargeError,
|
|
6637
6827
|
GoogleDriveAuth,
|
|
6638
6828
|
GoogleDriveModule,
|
|
6829
|
+
GoogleDriveProvider,
|
|
6639
6830
|
HAZO_FILES_DEFAULT_TABLE_NAME,
|
|
6640
6831
|
HAZO_FILES_JOB_TYPES,
|
|
6641
6832
|
HAZO_FILES_MIGRATION_V2,
|
|
@@ -6648,6 +6839,7 @@ try {
|
|
|
6648
6839
|
HAZO_FILE_QUOTAS_TABLE_SCHEMA,
|
|
6649
6840
|
HazoFilesError,
|
|
6650
6841
|
ImportSizeCapError,
|
|
6842
|
+
InMemoryProvider,
|
|
6651
6843
|
InvalidExtensionError,
|
|
6652
6844
|
InvalidPathError,
|
|
6653
6845
|
LLMExtractionService,
|
package/dist/server/index.mjs
CHANGED
|
@@ -6368,6 +6368,194 @@ async function streamToBuffer(s) {
|
|
|
6368
6368
|
return Buffer.concat(chunks);
|
|
6369
6369
|
}
|
|
6370
6370
|
|
|
6371
|
+
// src/providers/in-memory.ts
|
|
6372
|
+
var InMemoryProvider = class {
|
|
6373
|
+
constructor() {
|
|
6374
|
+
this.provider_tag = "in_memory";
|
|
6375
|
+
this.store = /* @__PURE__ */ new Map();
|
|
6376
|
+
}
|
|
6377
|
+
async put(path4, body, opts) {
|
|
6378
|
+
if (opts?.ifNotExists && this.store.has(path4)) throw new Error(`File exists: ${path4}`);
|
|
6379
|
+
const buf = Buffer.isBuffer(body) ? body : await streamToBuffer2(body);
|
|
6380
|
+
this.store.set(path4, buf);
|
|
6381
|
+
return { provider: this.provider_tag, native_id: path4, size: buf.length };
|
|
6382
|
+
}
|
|
6383
|
+
async get(path4) {
|
|
6384
|
+
const buf = this.store.get(path4);
|
|
6385
|
+
if (!buf) throw new Error(`Not found: ${path4}`);
|
|
6386
|
+
return buf;
|
|
6387
|
+
}
|
|
6388
|
+
async delete(path4) {
|
|
6389
|
+
this.store.delete(path4);
|
|
6390
|
+
}
|
|
6391
|
+
async exists(path4) {
|
|
6392
|
+
return this.store.has(path4);
|
|
6393
|
+
}
|
|
6394
|
+
async getSignedUrl(path4, _opts) {
|
|
6395
|
+
const buf = this.store.get(path4);
|
|
6396
|
+
if (!buf) throw new Error(`Not found: ${path4}`);
|
|
6397
|
+
return `data:application/octet-stream;base64,${buf.toString("base64")}`;
|
|
6398
|
+
}
|
|
6399
|
+
async probe() {
|
|
6400
|
+
return { ok: true };
|
|
6401
|
+
}
|
|
6402
|
+
/** Test-only escape hatch — exposes the internal store for assertions. */
|
|
6403
|
+
snapshot() {
|
|
6404
|
+
return new Map(this.store);
|
|
6405
|
+
}
|
|
6406
|
+
};
|
|
6407
|
+
async function streamToBuffer2(s) {
|
|
6408
|
+
const chunks = [];
|
|
6409
|
+
for await (const c of s) chunks.push(Buffer.isBuffer(c) ? c : Buffer.from(c));
|
|
6410
|
+
return Buffer.concat(chunks);
|
|
6411
|
+
}
|
|
6412
|
+
|
|
6413
|
+
// src/providers/google-drive.ts
|
|
6414
|
+
import { google as google3 } from "googleapis";
|
|
6415
|
+
var GoogleDriveProvider = class {
|
|
6416
|
+
constructor(opts) {
|
|
6417
|
+
this.provider_tag = "gdrive";
|
|
6418
|
+
let credentials = {};
|
|
6419
|
+
try {
|
|
6420
|
+
credentials = JSON.parse(opts.service_account_json);
|
|
6421
|
+
} catch {
|
|
6422
|
+
}
|
|
6423
|
+
const auth = new google3.auth.GoogleAuth({
|
|
6424
|
+
credentials,
|
|
6425
|
+
scopes: ["https://www.googleapis.com/auth/drive"]
|
|
6426
|
+
});
|
|
6427
|
+
this.drive = google3.drive({ version: "v3", auth });
|
|
6428
|
+
this.driveId = opts.shared_drive_id;
|
|
6429
|
+
this.cache = opts.path_cache;
|
|
6430
|
+
}
|
|
6431
|
+
async probe() {
|
|
6432
|
+
try {
|
|
6433
|
+
await this.drive.drives.get({
|
|
6434
|
+
driveId: this.driveId,
|
|
6435
|
+
supportsAllDrives: true
|
|
6436
|
+
});
|
|
6437
|
+
return { ok: true };
|
|
6438
|
+
} catch (err) {
|
|
6439
|
+
const e = err;
|
|
6440
|
+
if (e?.code === 404) return { ok: false, error: "drive_not_shared", message: "SA cannot see Shared Drive" };
|
|
6441
|
+
if (e?.code === 403) return { ok: false, error: "write_denied", message: "SA lacks permission" };
|
|
6442
|
+
return { ok: false, error: "transient", message: String(err) };
|
|
6443
|
+
}
|
|
6444
|
+
}
|
|
6445
|
+
async put(path4, body, opts) {
|
|
6446
|
+
const segments = path4.split("/").filter(Boolean);
|
|
6447
|
+
const filename = segments.pop();
|
|
6448
|
+
const parentId = await this.resolvePath(segments, { create: true });
|
|
6449
|
+
if (opts?.ifNotExists) {
|
|
6450
|
+
const existing = await this.findChild(filename, parentId);
|
|
6451
|
+
if (existing) throw new Error(`File exists: ${path4}`);
|
|
6452
|
+
}
|
|
6453
|
+
const buf = Buffer.isBuffer(body) ? body : await streamToBuffer3(body);
|
|
6454
|
+
const res = await this.drive.files.create({
|
|
6455
|
+
requestBody: {
|
|
6456
|
+
name: filename,
|
|
6457
|
+
parents: [parentId],
|
|
6458
|
+
mimeType: opts?.contentType ?? "application/octet-stream"
|
|
6459
|
+
},
|
|
6460
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6461
|
+
media: { body: buf },
|
|
6462
|
+
fields: "id, name"
|
|
6463
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6464
|
+
});
|
|
6465
|
+
return { provider: this.provider_tag, native_id: res.data.id, size: buf.length };
|
|
6466
|
+
}
|
|
6467
|
+
async get(path4) {
|
|
6468
|
+
const id = await this.lookupFileId(path4);
|
|
6469
|
+
const res = await this.drive.files.get(
|
|
6470
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6471
|
+
{ fileId: id, alt: "media", supportsAllDrives: true },
|
|
6472
|
+
{ responseType: "arraybuffer" }
|
|
6473
|
+
);
|
|
6474
|
+
return Buffer.from(res.data);
|
|
6475
|
+
}
|
|
6476
|
+
async delete(path4) {
|
|
6477
|
+
try {
|
|
6478
|
+
const id = await this.lookupFileId(path4);
|
|
6479
|
+
await this.drive.files.delete({ fileId: id, supportsAllDrives: true });
|
|
6480
|
+
} catch (err) {
|
|
6481
|
+
const e = err;
|
|
6482
|
+
if (e?.code !== 404) throw err;
|
|
6483
|
+
}
|
|
6484
|
+
}
|
|
6485
|
+
async exists(path4) {
|
|
6486
|
+
try {
|
|
6487
|
+
await this.lookupFileId(path4);
|
|
6488
|
+
return true;
|
|
6489
|
+
} catch {
|
|
6490
|
+
return false;
|
|
6491
|
+
}
|
|
6492
|
+
}
|
|
6493
|
+
async getSignedUrl(path4, _opts) {
|
|
6494
|
+
const id = await this.lookupFileId(path4);
|
|
6495
|
+
return `https://drive.google.com/uc?id=${id}&export=download`;
|
|
6496
|
+
}
|
|
6497
|
+
async resolvePath(segments, opts) {
|
|
6498
|
+
let parentId = this.driveId;
|
|
6499
|
+
const accumulated = [];
|
|
6500
|
+
for (const segment of segments) {
|
|
6501
|
+
accumulated.push(segment);
|
|
6502
|
+
const cacheKey = accumulated.join("/");
|
|
6503
|
+
const cached = await this.cache.lookup(cacheKey);
|
|
6504
|
+
if (cached) {
|
|
6505
|
+
parentId = cached;
|
|
6506
|
+
continue;
|
|
6507
|
+
}
|
|
6508
|
+
let found = await this.findChild(segment, parentId, "application/vnd.google-apps.folder");
|
|
6509
|
+
if (!found && opts.create) {
|
|
6510
|
+
const created = await this.drive.files.create({
|
|
6511
|
+
requestBody: {
|
|
6512
|
+
name: segment,
|
|
6513
|
+
parents: [parentId],
|
|
6514
|
+
mimeType: "application/vnd.google-apps.folder"
|
|
6515
|
+
},
|
|
6516
|
+
fields: "id"
|
|
6517
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6518
|
+
});
|
|
6519
|
+
found = created.data.id;
|
|
6520
|
+
}
|
|
6521
|
+
if (!found) throw new Error(`Folder not found and create=false: ${cacheKey}`);
|
|
6522
|
+
await this.cache.write(cacheKey, found);
|
|
6523
|
+
parentId = found;
|
|
6524
|
+
}
|
|
6525
|
+
return parentId;
|
|
6526
|
+
}
|
|
6527
|
+
async findChild(name, parentId, mimeType) {
|
|
6528
|
+
const q = [
|
|
6529
|
+
`name='${name.replace(/'/g, "\\'")}'`,
|
|
6530
|
+
`'${parentId}' in parents`,
|
|
6531
|
+
`trashed=false`
|
|
6532
|
+
];
|
|
6533
|
+
if (mimeType) q.push(`mimeType='${mimeType}'`);
|
|
6534
|
+
const res = await this.drive.files.list({
|
|
6535
|
+
q: q.join(" and "),
|
|
6536
|
+
driveId: this.driveId,
|
|
6537
|
+
corpora: "drive",
|
|
6538
|
+
includeItemsFromAllDrives: true,
|
|
6539
|
+
fields: "files(id, name)"
|
|
6540
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6541
|
+
});
|
|
6542
|
+
return res.data.files?.[0]?.id ?? null;
|
|
6543
|
+
}
|
|
6544
|
+
async lookupFileId(path4) {
|
|
6545
|
+
const segments = path4.split("/").filter(Boolean);
|
|
6546
|
+
const filename = segments.pop();
|
|
6547
|
+
const parentId = await this.resolvePath(segments, { create: false });
|
|
6548
|
+
const id = await this.findChild(filename, parentId);
|
|
6549
|
+
if (!id) throw Object.assign(new Error(`Not found: ${path4}`), { code: 404 });
|
|
6550
|
+
return id;
|
|
6551
|
+
}
|
|
6552
|
+
};
|
|
6553
|
+
async function streamToBuffer3(s) {
|
|
6554
|
+
const chunks = [];
|
|
6555
|
+
for await (const c of s) chunks.push(Buffer.isBuffer(c) ? c : Buffer.from(c));
|
|
6556
|
+
return Buffer.concat(chunks);
|
|
6557
|
+
}
|
|
6558
|
+
|
|
6371
6559
|
// src/providers/types.ts
|
|
6372
6560
|
var StorageCollisionExhausted = class extends Error {
|
|
6373
6561
|
constructor(attempts, lastPath) {
|
|
@@ -6449,6 +6637,7 @@ export {
|
|
|
6449
6637
|
FileTooLargeError,
|
|
6450
6638
|
GoogleDriveAuth,
|
|
6451
6639
|
GoogleDriveModule,
|
|
6640
|
+
GoogleDriveProvider,
|
|
6452
6641
|
HAZO_FILES_DEFAULT_TABLE_NAME,
|
|
6453
6642
|
HAZO_FILES_JOB_TYPES,
|
|
6454
6643
|
HAZO_FILES_MIGRATION_V2,
|
|
@@ -6461,6 +6650,7 @@ export {
|
|
|
6461
6650
|
HAZO_FILE_QUOTAS_TABLE_SCHEMA,
|
|
6462
6651
|
HazoFilesError,
|
|
6463
6652
|
ImportSizeCapError,
|
|
6653
|
+
InMemoryProvider,
|
|
6464
6654
|
InvalidExtensionError,
|
|
6465
6655
|
InvalidPathError,
|
|
6466
6656
|
LLMExtractionService,
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Readable } from 'node:stream';
|
|
2
|
+
|
|
3
|
+
type StoragePath = string;
|
|
4
|
+
interface PutOpts {
|
|
5
|
+
/** Reject if the target path already exists (atomic). */
|
|
6
|
+
ifNotExists?: boolean;
|
|
7
|
+
/** Hint for content-type; provider may sniff if absent. */
|
|
8
|
+
contentType?: string;
|
|
9
|
+
/** Free-form key/value metadata persisted with the file when supported. */
|
|
10
|
+
metadata?: Record<string, string>;
|
|
11
|
+
}
|
|
12
|
+
interface PutResult {
|
|
13
|
+
/** Provider tag — `"app_file_server"`, `"gdrive"`, `"in_memory"`. */
|
|
14
|
+
provider: string;
|
|
15
|
+
/** Provider-native identifier (path for app-server; file ID for GDrive). */
|
|
16
|
+
native_id: string;
|
|
17
|
+
/** Size in bytes of the persisted body. */
|
|
18
|
+
size: number;
|
|
19
|
+
}
|
|
20
|
+
interface SignedUrlOpts {
|
|
21
|
+
/** Seconds the URL is valid for. */
|
|
22
|
+
ttl_seconds?: number;
|
|
23
|
+
/** Suggested download filename (Content-Disposition). */
|
|
24
|
+
filename_hint?: string;
|
|
25
|
+
}
|
|
26
|
+
interface ProbeResult {
|
|
27
|
+
ok: boolean;
|
|
28
|
+
/** Machine-readable error tag when ok=false. */
|
|
29
|
+
error?: "drive_not_shared" | "write_denied" | "invalid_id" | "transient" | "config_missing";
|
|
30
|
+
/** Free-form detail for logging. */
|
|
31
|
+
message?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Storage provider abstraction. Every method MUST be idempotent at the
|
|
35
|
+
* data-content level — re-invoking put with identical body is allowed.
|
|
36
|
+
*
|
|
37
|
+
* Paths are logical; providers translate to native identifiers internally.
|
|
38
|
+
*/
|
|
39
|
+
interface FileStorageProvider {
|
|
40
|
+
put(path: StoragePath, body: Buffer | Readable, opts?: PutOpts): Promise<PutResult>;
|
|
41
|
+
get(path: StoragePath): Promise<Buffer | Readable>;
|
|
42
|
+
delete(path: StoragePath): Promise<void>;
|
|
43
|
+
exists(path: StoragePath): Promise<boolean>;
|
|
44
|
+
getSignedUrl(path: StoragePath, opts?: SignedUrlOpts): Promise<string>;
|
|
45
|
+
/** Used by validation cron + onboarding step 2. */
|
|
46
|
+
probe(): Promise<ProbeResult>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
declare class InMemoryProvider implements FileStorageProvider {
|
|
50
|
+
readonly provider_tag: "in_memory";
|
|
51
|
+
private readonly store;
|
|
52
|
+
put(path: string, body: Buffer | Readable, opts?: PutOpts): Promise<PutResult>;
|
|
53
|
+
get(path: string): Promise<Buffer>;
|
|
54
|
+
delete(path: string): Promise<void>;
|
|
55
|
+
exists(path: string): Promise<boolean>;
|
|
56
|
+
getSignedUrl(path: string, _opts?: SignedUrlOpts): Promise<string>;
|
|
57
|
+
probe(): Promise<ProbeResult>;
|
|
58
|
+
/** Test-only escape hatch — exposes the internal store for assertions. */
|
|
59
|
+
snapshot(): Map<string, Buffer>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export { InMemoryProvider };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Readable } from 'node:stream';
|
|
2
|
+
|
|
3
|
+
type StoragePath = string;
|
|
4
|
+
interface PutOpts {
|
|
5
|
+
/** Reject if the target path already exists (atomic). */
|
|
6
|
+
ifNotExists?: boolean;
|
|
7
|
+
/** Hint for content-type; provider may sniff if absent. */
|
|
8
|
+
contentType?: string;
|
|
9
|
+
/** Free-form key/value metadata persisted with the file when supported. */
|
|
10
|
+
metadata?: Record<string, string>;
|
|
11
|
+
}
|
|
12
|
+
interface PutResult {
|
|
13
|
+
/** Provider tag — `"app_file_server"`, `"gdrive"`, `"in_memory"`. */
|
|
14
|
+
provider: string;
|
|
15
|
+
/** Provider-native identifier (path for app-server; file ID for GDrive). */
|
|
16
|
+
native_id: string;
|
|
17
|
+
/** Size in bytes of the persisted body. */
|
|
18
|
+
size: number;
|
|
19
|
+
}
|
|
20
|
+
interface SignedUrlOpts {
|
|
21
|
+
/** Seconds the URL is valid for. */
|
|
22
|
+
ttl_seconds?: number;
|
|
23
|
+
/** Suggested download filename (Content-Disposition). */
|
|
24
|
+
filename_hint?: string;
|
|
25
|
+
}
|
|
26
|
+
interface ProbeResult {
|
|
27
|
+
ok: boolean;
|
|
28
|
+
/** Machine-readable error tag when ok=false. */
|
|
29
|
+
error?: "drive_not_shared" | "write_denied" | "invalid_id" | "transient" | "config_missing";
|
|
30
|
+
/** Free-form detail for logging. */
|
|
31
|
+
message?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Storage provider abstraction. Every method MUST be idempotent at the
|
|
35
|
+
* data-content level — re-invoking put with identical body is allowed.
|
|
36
|
+
*
|
|
37
|
+
* Paths are logical; providers translate to native identifiers internally.
|
|
38
|
+
*/
|
|
39
|
+
interface FileStorageProvider {
|
|
40
|
+
put(path: StoragePath, body: Buffer | Readable, opts?: PutOpts): Promise<PutResult>;
|
|
41
|
+
get(path: StoragePath): Promise<Buffer | Readable>;
|
|
42
|
+
delete(path: StoragePath): Promise<void>;
|
|
43
|
+
exists(path: StoragePath): Promise<boolean>;
|
|
44
|
+
getSignedUrl(path: StoragePath, opts?: SignedUrlOpts): Promise<string>;
|
|
45
|
+
/** Used by validation cron + onboarding step 2. */
|
|
46
|
+
probe(): Promise<ProbeResult>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
declare class InMemoryProvider implements FileStorageProvider {
|
|
50
|
+
readonly provider_tag: "in_memory";
|
|
51
|
+
private readonly store;
|
|
52
|
+
put(path: string, body: Buffer | Readable, opts?: PutOpts): Promise<PutResult>;
|
|
53
|
+
get(path: string): Promise<Buffer>;
|
|
54
|
+
delete(path: string): Promise<void>;
|
|
55
|
+
exists(path: string): Promise<boolean>;
|
|
56
|
+
getSignedUrl(path: string, _opts?: SignedUrlOpts): Promise<string>;
|
|
57
|
+
probe(): Promise<ProbeResult>;
|
|
58
|
+
/** Test-only escape hatch — exposes the internal store for assertions. */
|
|
59
|
+
snapshot(): Map<string, Buffer>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export { InMemoryProvider };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/testing/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
InMemoryProvider: () => InMemoryProvider
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
|
|
27
|
+
// src/providers/in-memory.ts
|
|
28
|
+
var InMemoryProvider = class {
|
|
29
|
+
constructor() {
|
|
30
|
+
this.provider_tag = "in_memory";
|
|
31
|
+
this.store = /* @__PURE__ */ new Map();
|
|
32
|
+
}
|
|
33
|
+
async put(path, body, opts) {
|
|
34
|
+
if (opts?.ifNotExists && this.store.has(path)) throw new Error(`File exists: ${path}`);
|
|
35
|
+
const buf = Buffer.isBuffer(body) ? body : await streamToBuffer(body);
|
|
36
|
+
this.store.set(path, buf);
|
|
37
|
+
return { provider: this.provider_tag, native_id: path, size: buf.length };
|
|
38
|
+
}
|
|
39
|
+
async get(path) {
|
|
40
|
+
const buf = this.store.get(path);
|
|
41
|
+
if (!buf) throw new Error(`Not found: ${path}`);
|
|
42
|
+
return buf;
|
|
43
|
+
}
|
|
44
|
+
async delete(path) {
|
|
45
|
+
this.store.delete(path);
|
|
46
|
+
}
|
|
47
|
+
async exists(path) {
|
|
48
|
+
return this.store.has(path);
|
|
49
|
+
}
|
|
50
|
+
async getSignedUrl(path, _opts) {
|
|
51
|
+
const buf = this.store.get(path);
|
|
52
|
+
if (!buf) throw new Error(`Not found: ${path}`);
|
|
53
|
+
return `data:application/octet-stream;base64,${buf.toString("base64")}`;
|
|
54
|
+
}
|
|
55
|
+
async probe() {
|
|
56
|
+
return { ok: true };
|
|
57
|
+
}
|
|
58
|
+
/** Test-only escape hatch — exposes the internal store for assertions. */
|
|
59
|
+
snapshot() {
|
|
60
|
+
return new Map(this.store);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
async function streamToBuffer(s) {
|
|
64
|
+
const chunks = [];
|
|
65
|
+
for await (const c of s) chunks.push(Buffer.isBuffer(c) ? c : Buffer.from(c));
|
|
66
|
+
return Buffer.concat(chunks);
|
|
67
|
+
}
|
|
68
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
69
|
+
0 && (module.exports = {
|
|
70
|
+
InMemoryProvider
|
|
71
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// src/providers/in-memory.ts
|
|
2
|
+
var InMemoryProvider = class {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.provider_tag = "in_memory";
|
|
5
|
+
this.store = /* @__PURE__ */ new Map();
|
|
6
|
+
}
|
|
7
|
+
async put(path, body, opts) {
|
|
8
|
+
if (opts?.ifNotExists && this.store.has(path)) throw new Error(`File exists: ${path}`);
|
|
9
|
+
const buf = Buffer.isBuffer(body) ? body : await streamToBuffer(body);
|
|
10
|
+
this.store.set(path, buf);
|
|
11
|
+
return { provider: this.provider_tag, native_id: path, size: buf.length };
|
|
12
|
+
}
|
|
13
|
+
async get(path) {
|
|
14
|
+
const buf = this.store.get(path);
|
|
15
|
+
if (!buf) throw new Error(`Not found: ${path}`);
|
|
16
|
+
return buf;
|
|
17
|
+
}
|
|
18
|
+
async delete(path) {
|
|
19
|
+
this.store.delete(path);
|
|
20
|
+
}
|
|
21
|
+
async exists(path) {
|
|
22
|
+
return this.store.has(path);
|
|
23
|
+
}
|
|
24
|
+
async getSignedUrl(path, _opts) {
|
|
25
|
+
const buf = this.store.get(path);
|
|
26
|
+
if (!buf) throw new Error(`Not found: ${path}`);
|
|
27
|
+
return `data:application/octet-stream;base64,${buf.toString("base64")}`;
|
|
28
|
+
}
|
|
29
|
+
async probe() {
|
|
30
|
+
return { ok: true };
|
|
31
|
+
}
|
|
32
|
+
/** Test-only escape hatch — exposes the internal store for assertions. */
|
|
33
|
+
snapshot() {
|
|
34
|
+
return new Map(this.store);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
async function streamToBuffer(s) {
|
|
38
|
+
const chunks = [];
|
|
39
|
+
for await (const c of s) chunks.push(Buffer.isBuffer(c) ? c : Buffer.from(c));
|
|
40
|
+
return Buffer.concat(chunks);
|
|
41
|
+
}
|
|
42
|
+
export {
|
|
43
|
+
InMemoryProvider
|
|
44
|
+
};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
- [x] Task 4: Signed-URL serve route — 0983dfa (2026-05-23)
|
|
9
9
|
- [x] Task 5: AppFileServerProvider scenario page — fdff8ec (2026-05-23)
|
|
10
10
|
- [x] Task 6: Stub pages (InMemory + GDrive) — d815df6 (2026-05-23)
|
|
11
|
-
- [
|
|
11
|
+
- [x] Task 7: Smoke test — passed, published to npm (2026-05-23)
|
|
12
12
|
|
|
13
13
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
14
14
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hazo_files",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "File management including integration to cloud files",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -30,6 +30,11 @@
|
|
|
30
30
|
"types": "./dist/background-upload/react/index.d.ts",
|
|
31
31
|
"import": "./dist/background-upload/react/index.mjs",
|
|
32
32
|
"require": "./dist/background-upload/react/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./testing": {
|
|
35
|
+
"types": "./dist/testing/index.d.ts",
|
|
36
|
+
"import": "./dist/testing/index.mjs",
|
|
37
|
+
"require": "./dist/testing/index.js"
|
|
33
38
|
}
|
|
34
39
|
},
|
|
35
40
|
"files": [
|
|
@@ -47,7 +52,8 @@
|
|
|
47
52
|
},
|
|
48
53
|
"sideEffects": false,
|
|
49
54
|
"scripts": {
|
|
50
|
-
"build": "npm run build:main && npm run build:ui && npm run build:server && npm run build:bg-upload && npm run build:bg-upload-react",
|
|
55
|
+
"build": "npm run build:main && npm run build:ui && npm run build:server && npm run build:bg-upload && npm run build:bg-upload-react && npm run build:testing",
|
|
56
|
+
"build:testing": "tsup src/testing/index.ts --outDir dist/testing --dts --format cjs,esm --no-clean",
|
|
51
57
|
"build:main": "tsup src/index.ts --dts --format cjs,esm --clean",
|
|
52
58
|
"build:ui": "tsup src/ui/index.ts --outDir dist/ui --dts --format cjs,esm --no-clean --external react --external react-dom --external @dnd-kit/core --external @dnd-kit/sortable --external @dnd-kit/utilities",
|
|
53
59
|
"build:server": "tsup src/server/index.ts --outDir dist/server --dts --format cjs,esm --no-clean",
|