@delma/fylo 1.1.0 → 1.1.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/.github/copilot-instructions.md +2 -112
- package/AGENTS.md +3 -0
- package/CLAUDE.md +3 -0
- package/package.json +4 -4
- package/src/core/directory.ts +1 -1
- package/src/core/format.ts +1 -1
- package/src/core/walker.ts +1 -1
- package/src/index.ts +2 -2
- package/src/types/fylo.d.ts +1 -1
- package/src/types/index.d.ts +1 -1
- package/src/types/vendor-modules.d.ts +31 -0
- package/tests/index.ts +2 -2
- package/tests/integration/edge-cases.test.ts +1 -1
- package/tsconfig.json +2 -2
|
@@ -1,113 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
Follow the shared workspace instructions in `../instructions.md` and shared context in `../memory.md`.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
FYLO (`@vyckr/fylo`) is an S3-backed NoSQL document store with SQL parsing, Redis pub/sub for real-time events, and a CLI. Documents are stored as S3 key paths — not as file contents — with dual key layouts for data access and indexed queries.
|
|
6
|
-
|
|
7
|
-
**Assume a serverless deployment model** (e.g., AWS Lambda, Cloudflare Workers). This means:
|
|
8
|
-
- No persistent in-memory state across invocations — every request starts cold
|
|
9
|
-
- Distributed coordination (e.g., TTID uniqueness) must use external stores like Redis, not in-process caches
|
|
10
|
-
- Avoid long-lived connections, background threads, or singleton patterns that assume process longevity
|
|
11
|
-
- Keep cold-start overhead minimal — lazy initialization over eager setup
|
|
12
|
-
|
|
13
|
-
## Architecture
|
|
14
|
-
|
|
15
|
-
### Key Storage Format
|
|
16
|
-
|
|
17
|
-
- **Data keys**: `{ttid}/{field}/{value}` — keyed by document ID for full-doc retrieval
|
|
18
|
-
- **Index keys**: `{field}/{value}/{ttid}` — keyed by field for query lookups
|
|
19
|
-
- Nested objects flatten to path segments: `address/city/Toronto`
|
|
20
|
-
- Forward slashes in values are escaped with an ASCII substitute
|
|
21
|
-
|
|
22
|
-
### Core Modules
|
|
23
|
-
|
|
24
|
-
| Module | Responsibility |
|
|
25
|
-
|--------|---------------|
|
|
26
|
-
| `src/index.ts` | Main `Fylo` class — CRUD, SQL execution, joins, bulk ops |
|
|
27
|
-
| `src/core/parser.ts` | SQL lexer/parser — tokenizes SQL into query objects |
|
|
28
|
-
| `src/core/query.ts` | Converts `$ops` into glob patterns for S3 key matching |
|
|
29
|
-
| `src/core/walker.ts` | S3 key traversal, document data retrieval, Redis event streaming |
|
|
30
|
-
| `src/core/directory.ts` | Key extraction, reconstruction, rollback tracking |
|
|
31
|
-
| `src/core/format.ts` | Console formatting for query output |
|
|
32
|
-
| `src/adapters/s3.ts` | S3 adapter (Bun S3Client) |
|
|
33
|
-
| `src/adapters/redis.ts` | Redis adapter (Bun RedisClient) |
|
|
34
|
-
| `src/cli/index.ts` | CLI entry point (`fylo.query`) |
|
|
35
|
-
|
|
36
|
-
### Folder Structure
|
|
37
|
-
|
|
38
|
-
```
|
|
39
|
-
src/
|
|
40
|
-
index.ts # Public API — main Fylo class
|
|
41
|
-
adapters/ # I/O boundary abstractions (S3, Redis)
|
|
42
|
-
core/ # Internal domain logic (parser, query, walker, directory)
|
|
43
|
-
cli/ # CLI entry point
|
|
44
|
-
types/ # Type declarations (.d.ts only — separate from implementation)
|
|
45
|
-
tests/
|
|
46
|
-
data.ts # Shared test data URLs
|
|
47
|
-
index.ts # Test barrel
|
|
48
|
-
mocks/ # Mock adapters (S3, Redis) for testing
|
|
49
|
-
schemas/ # CHEX-generated test schemas (.d.ts + .json)
|
|
50
|
-
integration/ # End-to-end tests (CRUD, operators, joins, edge cases)
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### Dependencies
|
|
54
|
-
|
|
55
|
-
- **`@vyckr/ttid`** — Time-based unique ID system. `TTID.generate()` creates new IDs; `TTID.generate(existingId)` creates a versioned ID sharing the same creation-time prefix.
|
|
56
|
-
- **`@vyckr/chex`** — Schema validation. Generates `interface` declarations in `.d.ts` files. Generic constraints must use `Record<string, any>` (not `Record<string, unknown>`) to accept these interfaces.
|
|
57
|
-
- **`Bun.Glob`** — Pattern matching for queries. Does NOT support negation extglob `!(pattern)`. Operators like `$ne`, `$gt`, `$lt` use broad globs with post-filtering instead.
|
|
58
|
-
|
|
59
|
-
## Engineering Standards
|
|
60
|
-
|
|
61
|
-
- **SOLID principles**: Single responsibility per class/method, depend on abstractions (e.g., S3/Redis adapters), open for extension without modifying core logic
|
|
62
|
-
- **Clean code**: Descriptive naming, small focused functions, no dead code or commented-out blocks, DRY without premature abstraction
|
|
63
|
-
- **Test discipline**: When changing `src/` code, update or add corresponding tests in `tests/` — never leave tests stale after a behaviour change
|
|
64
|
-
- **Error handling**: Fail fast with meaningful errors at system boundaries; use rollback mechanisms for partial writes
|
|
65
|
-
- **No magic values**: Use constants or environment variables; avoid hardcoded strings/numbers in logic
|
|
66
|
-
- **Type safety**: Leverage TypeScript's type system fully — avoid `any` in implementation code, prefer narrow types, and validate at I/O boundaries
|
|
67
|
-
|
|
68
|
-
## Code Style
|
|
69
|
-
|
|
70
|
-
- **Runtime**: Bun (ESNext target, ES modules)
|
|
71
|
-
- **Strict TypeScript**: `strict: true`, `noImplicitReturns`, `isolatedModules`
|
|
72
|
-
- **ESLint** enforces `@typescript-eslint/no-explicit-any` in `src/` and `tests/` — use it only in type declarations (`.d.ts`)
|
|
73
|
-
- **No default exports** except the main `Fylo` class
|
|
74
|
-
- Prefer `class` with `static` methods for modules (no standalone functions)
|
|
75
|
-
- Use `_ttid` branded type for document IDs — never plain `string`
|
|
76
|
-
- Prefix internal/test type names with underscore: `_post`, `_album`, `_storeQuery`
|
|
77
|
-
- Type declarations live in `src/types/*.d.ts` — keep separate from implementation
|
|
78
|
-
|
|
79
|
-
## Build & Test
|
|
80
|
-
|
|
81
|
-
```bash
|
|
82
|
-
bun test # Run all tests
|
|
83
|
-
bun run build # Compile TypeScript
|
|
84
|
-
bun run typecheck # Type-check without emitting
|
|
85
|
-
bun run lint # ESLint
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
- Tests use `bun:test` — `describe`, `test`, `expect`, `mock`, `beforeAll`, `afterAll`
|
|
89
|
-
- S3 and Redis are mocked via `mock.module()` in every test file using `tests/mocks/s3.ts` and `tests/mocks/redis.ts`
|
|
90
|
-
- Test schemas live in `tests/schemas/*.d.ts` as global `interface` declarations (generated by CHEX)
|
|
91
|
-
- Test data URLs are centralized in `tests/data.ts`
|
|
92
|
-
|
|
93
|
-
## Conventions
|
|
94
|
-
|
|
95
|
-
- Collection names may contain hyphens (e.g., `ec-test`, `jm-album`) — the parser supports this
|
|
96
|
-
- Nested field access in SQL uses dot notation (`address.city`) which the parser converts to slash-separated paths (`address/city`)
|
|
97
|
-
- `putData` creates documents; `patchDoc` updates them (deletes old keys, writes new ones)
|
|
98
|
-
- `getDocData` retrieves keys for a specific TTID — filters by exact ID, not just prefix
|
|
99
|
-
- Query `$ops` use OR semantics — a document matches if it satisfies at least one operator
|
|
100
|
-
- `$limit` on queries without `$ops` uses S3 `maxKeys`; with `$ops` it post-filters after glob matching
|
|
101
|
-
|
|
102
|
-
## Environment Variables
|
|
103
|
-
|
|
104
|
-
| Variable | Purpose |
|
|
105
|
-
|----------|---------|
|
|
106
|
-
| `BUCKET_PREFIX` | S3 bucket name prefix |
|
|
107
|
-
| `S3_ACCESS_KEY_ID` / `AWS_ACCESS_KEY_ID` | S3 credentials |
|
|
108
|
-
| `S3_SECRET_ACCESS_KEY` / `AWS_SECRET_ACCESS_KEY` | S3 credentials |
|
|
109
|
-
| `S3_REGION` / `AWS_REGION` | S3 region |
|
|
110
|
-
| `S3_ENDPOINT` / `AWS_ENDPOINT` | S3 endpoint (for compatible stores) |
|
|
111
|
-
| `REDIS_URL` | Redis connection URL |
|
|
112
|
-
| `LOGGING` | Enable debug logging |
|
|
113
|
-
| `STRICT` | Enable schema validation via CHEX |
|
|
3
|
+
If a repo-local instruction file adds stricter rules, follow the repo-local rule.
|
package/AGENTS.md
ADDED
package/CLAUDE.md
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@delma/fylo",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"types": "./dist/types/index.d.ts",
|
|
6
6
|
"bin": {
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"prettier": "^3.0.0"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@
|
|
29
|
-
"@
|
|
28
|
+
"@delma/ttid": "1.3.4",
|
|
29
|
+
"@delma/chex": "0.3.3"
|
|
30
30
|
},
|
|
31
31
|
"type": "module",
|
|
32
32
|
"peerDependencies": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"type": "git",
|
|
37
37
|
"url": "git+https://github.com/Chidelma/Fylo.git"
|
|
38
38
|
},
|
|
39
|
-
"homepage": "https://fylo.
|
|
39
|
+
"homepage": "https://fylo.del.ma",
|
|
40
40
|
"license": "MIT",
|
|
41
41
|
"keywords": [
|
|
42
42
|
"storage",
|
package/src/core/directory.ts
CHANGED
package/src/core/format.ts
CHANGED
package/src/core/walker.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { Query } from './core/query'
|
|
3
3
|
import { Parser } from './core/parser'
|
|
4
4
|
import { Dir } from "./core/directory";
|
|
5
|
-
import TTID from '@
|
|
6
|
-
import Gen from "@
|
|
5
|
+
import TTID from '@delma/ttid';
|
|
6
|
+
import Gen from "@delma/chex"
|
|
7
7
|
import { Walker } from './core/walker';
|
|
8
8
|
import { S3 } from "./adapters/s3"
|
|
9
9
|
import { Cipher } from "./adapters/cipher"
|
package/src/types/fylo.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ interface Console {
|
|
|
26
26
|
|
|
27
27
|
type _joinDocs<T, U> = _ttid[] | Record<string, _ttid[]> | Record<string, Record<_ttid, Partial<T | U>>> | Record<`${_ttid}, ${_ttid}`, T | U | (T & U) | (Partial<T> & Partial<U>)>
|
|
28
28
|
|
|
29
|
-
declare module "@
|
|
29
|
+
declare module "@delma/fylo" {
|
|
30
30
|
|
|
31
31
|
export default class {
|
|
32
32
|
|
package/src/types/index.d.ts
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
declare module "@delma/ttid" {
|
|
2
|
+
|
|
3
|
+
export type _ttid = string | `${string}-${string}` | `${string}-${string}-${string}`
|
|
4
|
+
|
|
5
|
+
export interface _timestamps {
|
|
6
|
+
createdAt: number
|
|
7
|
+
updatedAt?: number
|
|
8
|
+
deletedAt?: number
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default class TTID {
|
|
12
|
+
static isTTID(_id: string): Date | null
|
|
13
|
+
static isUUID(_id: string): RegExpMatchArray | null
|
|
14
|
+
static generate(_id?: string, del?: boolean): _ttid
|
|
15
|
+
static decodeTime(_id: string): _timestamps
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
declare module "@delma/chex" {
|
|
20
|
+
|
|
21
|
+
export default class Gen {
|
|
22
|
+
static generateDeclaration(json: unknown, interfaceName?: string): string
|
|
23
|
+
static sanitizePropertyName(key: string): string
|
|
24
|
+
static fromJsonString(jsonString: string, interfaceName?: string): string
|
|
25
|
+
static fromObject(obj: unknown, interfaceName?: string): string
|
|
26
|
+
static validateData<T extends Record<string, unknown>>(collection: string, data: T): Promise<T>
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type _ttid = import("@delma/ttid")._ttid
|
|
31
|
+
type _timestamps = import("@delma/ttid")._timestamps
|
package/tests/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Redis } from '../src/adapters/redis'
|
|
2
|
-
import ttid from '@
|
|
2
|
+
import ttid from '@delma/ttid'
|
|
3
3
|
|
|
4
4
|
const redisPub = new Redis()
|
|
5
5
|
const redisSub = new Redis()
|
|
@@ -16,4 +16,4 @@ await Bun.sleep(1000)
|
|
|
16
16
|
|
|
17
17
|
for await (const data of redisSub.subscribe("bun")) {
|
|
18
18
|
console.log("Received:", data)
|
|
19
|
-
}
|
|
19
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"noFallthroughCasesInSwitch": true,
|
|
13
13
|
"noImplicitReturns": true,
|
|
14
14
|
"forceConsistentCasingInFileNames": true,
|
|
15
|
-
"types": ["bun-types", "node"
|
|
15
|
+
"types": ["bun-types", "node"],
|
|
16
16
|
"isolatedModules": true,
|
|
17
17
|
"skipLibCheck": true
|
|
18
18
|
}
|
|
19
|
-
}
|
|
19
|
+
}
|