You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CHANGELOG.md
+4Lines changed: 4 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
10
10
### Added
11
11
- **Phase-1 RBAC end-to-end enforcement (multi-tenant isolation)** — Every authenticated REST request now arrives at the SecurityPlugin middleware with a populated `ExecutionContext`, so RLS/FLS/CRUD checks actually fire. Three previously-silent context-drop sites were closed: (1) `@objectstack/objectql` `protocol.{find,get,create,update,delete}Data` now forward `request.context` into the engine call options; (2) `@objectstack/rest` `RestServer` gained `resolveExecCtx()` plus an `authServiceProvider` constructor hook (wired in `RestApiPlugin` from `ctx.getService('auth')`) that resolves the better-auth session for both single-kernel and multi-kernel deployments and threads `context` into all five CRUD handlers; (3) `@objectstack/plugin-hono-server` raw `/data/:object` fallback handlers now resolve the same context inline and map `PermissionDeniedError` → HTTP 403. `@objectstack/runtime` `resolveExecutionContext()` wraps plain header objects as Web `Headers` so better-auth's cookie lookup works. New seed link tables `sys_user_permission_set` / `sys_role_permission_set` (in `@objectstack/platform-objects`) plus default permission sets `admin_full_access` / `member_default` / `viewer_readonly`; `member_default` carries a wildcard `object: '*'` RLS policy (`tenant_id = current_user.tenant_id`) that SecurityPlugin rewrites onto the configured `tenantField` (default `organization_id`) and skips for tables that lack the field. Two further fixes landed alongside the wiring work: (a) `@objectstack/objectql` lost its legacy `registerTenantMiddleware` (a hardcoded `where.tenant_id = ctx.tenantId` injection that pre-dated SecurityPlugin, masked RLS bugs in older snapshots, and silently broke any table without a `tenant_id` column); SecurityPlugin is now the sole authority for tenant isolation. (b) The `tenantField` rewrite in SecurityPlugin (`tenant_id` → `organization_id` on the LHS column reference) was over-eager and was also rewriting the `current_user.tenant_id` placeholder, producing `current_user.organization_id` which `RLSUserContext` doesn't expose — silently dropping every wildcard tenant policy. The regex now anchors on a non-`.` boundary so only the column reference is rewritten. `member_default` and `viewer_readonly` also gained explicit per-object overrides for the two global tables that lack `organization_id`: `sys_organization_self` (`id = current_user.tenant_id`) and `sys_user_self` (`id = current_user.id`). Verified end-to-end on `pnpm dev:crm`: two users in different organizations each create records and only see their own org's rows on subsequent LISTs across `sys_organization`, `sys_member`, `sys_user`, and the new `sys_user_permission_set` / `sys_role_permission_set` link tables. **Known follow-up:** anonymous REST traffic still bypasses enforcement (SecurityPlugin short-circuits when `userId` is absent) — default-deny tightening, Sharing Rule evaluator, Studio RLS visual editor, per-user×org permission cache, and audit UI / denied-access logging remain queued.
12
+
- **`@objectstack/driver-mongodb` — first-class MongoDB driver (`packages/plugins/driver-mongodb`)** — A new built-in driver that implements the full `IDataDriver` contract on top of the official `mongodb@^6` Node.js driver. Highlights: per-collection `id` strategy (16-char nanoid stored as a top-level string field with a unique index; the internal `_id` is **never** exposed to consumers — every `find`/`findOne`/`findStream` uses `projection: { _id: 0 }`); pluggable filter translator (`mongodb-filter.ts`) that maps every ObjectStack operator (`$eq`/`$ne`/`$gt`/`$gte`/`$lt`/`$lte`/`$in`/`$nin`/`$exists`/`$contains`/`$startsWith`/`$endsWith`/`$null`/`$between`/`$not`/`$and`/`$or`/`$nor`) plus the legacy `[field, op, value]` tuple form into a native MongoDB query; aggregation pipeline builder (`mongodb-aggregation.ts`) supporting `count`/`sum`/`avg`/`min`/`max`/`count_distinct`/`string_agg` with `$group + $project` flattening; declarative schema sync that creates collections + unique/lookup/text/compound indexes (`mongodb-schema.ts`); cursor-based async streaming via `findStream`; `bulkCreate`/`bulkUpdate`/`bulkDelete` powered by `bulkWrite`; multi-document transactions (requires a replica set) via `MongoClient.startSession()` + `session.withTransaction()`. Ships with **75 unit tests** (filter, aggregation, full driver) running against `mongodb-memory-server` (`onlyBuiltDependencies` whitelist updated in the root `package.json` so the postinstall is allowed). Plugin entry exports a default `onEnable` hook so it can be registered as `kernel.use(mongodbPlugin, { url })` or instantiated directly via `new MongoDBDriver({ url })` and wrapped in `DriverPlugin`.
13
+
- **`OS_DATABASE_DRIVER` / `OS_DATABASE_URL` recognised by the CLI, with URL-scheme inference** — `packages/cli/src/commands/serve.ts` now selects the storage driver from `OS_DATABASE_URL` automatically: `mongodb://` / `mongodb+srv://` → `MongoDBDriver`, `postgres://` / `postgresql://` → `SqlDriver(client:'pg')`, `mysql://` / `mysql2://` → `SqlDriver(client:'mysql2')`, `libsql://` or `https://*.turso.…` → `TursoDriver`, `file:` / `sqlite:` / `:memory:` / `*.db` / `*.sqlite` → `SqlDriver(client:'better-sqlite3')`. `OS_DATABASE_DRIVER` remains an explicit override (`mongodb`/`mongo`/`postgres`/`pg`/`mysql`/`sqlite`/`turso`/`libsql`). The same selection logic is mirrored in `packages/services/service-cloud/src/{artifact-environment-registry,environment-registry,project-kernel-factory}.ts` so cloud-runtime nodes can also pin a project to MongoDB. `apps/objectos`, `packages/cli`, and `packages/services/service-cloud` now declare `@objectstack/driver-mongodb` (and the CLI now also declares `@objectstack/driver-turso`) as workspace dependencies so the dynamic `await import()` resolves.
14
+
-**MongoDB end-to-end test for the CRM example** — `examples/app-crm/playwright.config.ts` + `examples/app-crm/e2e/mongodb-driver.spec.ts` boot `pnpm dev:crm` with `OS_DATABASE_URL=mongodb://localhost:27017/objectstack_crm_test` against a local mongod (driver auto-inferred from the URL scheme — no `OS_DATABASE_DRIVER` needed) and verify (1) the Studio UI responds, (2) seed data is queryable through `GET /api/v1/data/account`, and (3) a full create → read → patch → re-read → delete round-trip lands records in MongoDB. New `pnpm --filter @example/app-crm test:e2e` script wires the suite into the workspace.
15
+
12
16
- **Hooks auto-register from `defineStack({ hooks })` (`@objectstack/objectql` + `@objectstack/runtime`)** — Hooks are metadata, and the runtime now treats them as such: `AppPlugin.start()`, `MultiProjectPlugin` seeders, and `ObjectQLPlugin.loadMetadataFromService` all funnel `Hook[]` through a single canonical entry point (`bindHooksToEngine` / `engine.bindHooks`), eliminating the previous boilerplate `engine.registerHook(...)` calls in user code. The binder honours every declarative field on `Hook` — `condition` (compiled as a formula), `async` (fire-and-forget on `after*` events), `retryPolicy` (max retries × linear backoff), `timeout` (Promise.race), `onError` (`'abort'` rethrows, `'log'` swallows), and `priority` — through a new `wrapDeclarativeHook` higher-order function so the engine's `triggerHooks` stays minimal. Adds `engine.registerFunction` / `resolveFunction` / `unregisterFunctionsByPackage` plus `engine.unregisterHooksByPackage(packageId)` for clean hot-reload, and a new `functions` field on `defineStack` so string-named handlers can be resolved by the binder. The built-in audit hooks in `ObjectQLPlugin.registerAuditHooks` were migrated to the same declarative form (dogfood). Example cleanup: `examples/app-crm/src/hooks/register-hooks.ts` deleted; the CRM example now just exports `allHooks` and lists them under `defineStack({ hooks })`.
13
17
-**Formula expression evaluator (`@objectstack/objectql`)** — `packages/objectql/src/formula.ts` ships a hand-written tokenizer + recursive-descent parser + tree-walking evaluator for the formula function library documented in `packages/spec/docs/formula-functions.md`. Supports text (`CONCAT`/`CONCATENATE`/`UPPER`/`LOWER`/`TEXT`/`LEN`), math (`SUM`/`AVERAGE`/`ROUND`/`CEILING`/`FLOOR`), date (`TODAY`/`NOW`/`YEAR`/`MONTH`/`DAY`/`ADDDAYS`), and logical (`IF`/`AND`/`OR`/`NOT`/`ISBLANK`) functions, plus comparison (`= == != <> < > <= >=`) and arithmetic operators with standard precedence. Public API: `compileFormula(expr)` (cached AST + dependency list) and `evaluateFormula(expr, record)`. Implementation is `eval`-free — untrusted formula strings are safe to evaluate. Used by `formula`-typed fields and decision-node conditions in flows.
14
18
-**Studio Flow Viewer + Flow Test Runner** — `apps/studio/src/components/FlowViewer.tsx` renders a flow's metadata (variables, nodes, edges, error handling) as inspector cards; `FlowTestRunner.tsx` provides an interactive form for the flow's `isInput` variables, executes the flow against the per-project kernel, and surfaces the result + run record. Wired into the Studio metadata browser via `flow-viewer-plugin.tsx` (registered in `apps/studio/src/plugins/built-in/index.ts`), so any `flow` metadata page exposes a "Run" tab. New `FlowRunsPanel.tsx` lists historical executions for the selected flow.
**Example:*`@objectstack/driver-sql` (Postgres / MySQL / SQLite via Knex), `@objectstack/driver-mongodb`, `@objectstack/driver-turso`.
94
94
95
95
### AST (Abstract Syntax Tree)
96
96
The intermediate representation of a query or schema. The Data Protocol parses a JSON request into an AST before the Driver translates it into SQL/NoSQL queries. This allows for security validation and optimization before execution.
**Example:*`@objectstack/driver-sql` (Postgres / MySQL / SQLite via Knex), `@objectstack/driver-mongodb`, `@objectstack/driver-turso`.
94
94
95
95
### AST (Abstract Syntax Tree)
96
96
The intermediate representation of a query or schema. The Data Protocol parses a JSON request into an AST before the Driver translates it into SQL/NoSQL queries. This allows for security validation and optimization before execution.
0 commit comments