@simtlix/simfinity-core 3.18.0 → 3.19.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/README.md +78 -63
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,90 +1,105 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Driver-free GraphQL runtime, model metadata, and shared GraphQL helpers for Simfinity. It requires GraphQL 16 and Node.js 18.18 or later, and does not import Mongoose, MongoDB, PostgreSQL, or MCP packages.
|
|
4
|
-
|
|
5
|
-
All Simfinity packages are released together. Install from npm and keep their versions aligned. Source: [simtlix/simfinity.js](https://github.com/simtlix/simfinity.js).
|
|
6
|
-
|
|
7
|
-
For relational storage, `@simtlix/simfinity-sql` builds on core and delegates physical database behavior to a plugin. PostgreSQL is the first supported plugin; its `createPostgres` facade remains available. See the [SQL plugin guide](https://simtlix.github.io/simfinity.js/guide/sql-plugins.html).
|
|
8
|
-
|
|
9
|
-
## Runtime
|
|
1
|
+
[](https://simtlix.github.io/simfinity.js/)
|
|
10
2
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
- `connect`, `addNoEndpointType`, and `createSchema` for registration and schema creation;
|
|
14
|
-
- `getModel`, `getType`, `getInputType`, and `getRegistrations` for runtime inspection;
|
|
15
|
-
- `use`, `registerMutation`, and `saveObject` for middleware and write orchestration, and `updateObject`, `deleteObject` and `transitionObject`, which run the lifecycle of the generated update, delete and state action mutations from code;
|
|
16
|
-
- `registerCustomQuery` for reads whose results are not stored records, such as previews, other sources or permission evaluations;
|
|
17
|
-
- `registerView` for a named list read of one registered type, with params and a fixed predicate, run through the type's scope;
|
|
18
|
-
- `preventCreatingCollection` to pass validation-only storage setup to an adapter;
|
|
19
|
-
- `configureQueryLimits` and `configureMutationLimits` for the process-wide page-size, compiled-frame, frame-nesting, nested-operation and transaction-operation limits (`maxTransactionOperations`).
|
|
20
|
-
|
|
21
|
-
The adapter supplies model creation, identifiers, transactions, record reads and writes, queries, counts, aggregations, and inverse collection reads. `DatabaseAdapter`, `Runtime`, controller, middleware, registration, and state-machine interfaces are exported in the TypeScript declarations. A runtime binds one adapter; create another runtime to use another database or configuration. The GraphQL types that `prepare()` and `createModel()` receive still contain virtual fields, which must never be stored: an adapter that builds storage from a type's fields skips each field for which `isVirtualField(field)`, exported by this package with `virtualFieldOptions(field)`, returns true, on entities and embedded types alike, or builds it from `describeModels()`, which leaves them out. Generated writes, filters, sorts and aggregations never name a virtual field, but a controller hook can still assign one. An adapter can also define `getByIds(model, ids, { context })`, which returns the records it finds in `getById` shape and any order; the runtime then batches generated single-reference reads per request and type, matching records by `castId`, splitting batches at `maxPageSize`, and reading an ID with `getById` when a batch read fails or when `castId` would normalize or reject it. `castId` should throw a `NOT_VALID_ID` (400) `SimfinityError` for a malformed value and must not create a new identifier. An adapter can define `readByIdIsInert(model)`, returning `true` when a `getById` of that model has no side effects and `update()` and `delete()` reject the same malformed IDs with `NOT_VALID_ID` (400) and return null for a missing record; the runtime then skips the reads before deletes without an `onDelete` hook and before updates that merge no embedded value and have neither `onUpdating` nor nested collection items. The SQL adapter always reports it, and the MongoDB adapter does for models without `find`, `findOne`, `findOneAndUpdate` or `findOneAndDelete` middleware and without application `_id` setters or overrides of the statics those reads and writes call. When `getById` rejects a stored reference value that way, including one that `castId` rejected first, the generated reference field fails with an `InternalServerError` (500), since the client did not send the value. `update()` resolves to the updated record as stored, or null; nested collection children of that record are linked to and checked against its `_id`, else `id`, else the requested ID. An adapter that hydrates records can define `readEmbeddedValue(value)`: every nullable, singular embedded object field without a resolver then passes its value through it, so an explicitly stored `null` reads as `null`. The field is read as graphql's default resolver reads it, so a method on the parent is called and a promise it returns is awaited before the hook receives the value. Simfinity then reads as `null` an object that holds no data when a required member would read as `null`, not counting `id`, `readOnly` and virtual members, interface and union members, members with an application resolver and referenced collections; runtimes that share the type read the same. It reads the stored members, never calling a getter, and counts a stored `_id` as `id`; it reads nothing from objects whose type has no member that counts, and an error while reading returns the object unchanged. An adapter whose hydrated records render members through getters can also define `rawEmbeddedValue(value)`, which returns a record's stored data as a plain object, or the record unchanged when that data does not show what it renders; a value that is not a plain object counts as data. The MongoDB adapter defines both.
|
|
22
|
-
|
|
23
|
-
An adapter can also define `findChildrenBatch(model, type, connectionField, parentIds, args, { context })`, the batch form of `findChildren` for generated collection fields, and a synchronous `batchesChildren(model, type, connectionField)` predicate. The runtime calls both as adapter methods and checks them on every read. When the method is missing or the predicate returns `false`, each field calls `findChildren` at once with the arguments object it built, as before. Otherwise, within one request (a context object), the runtime groups the collection reads of one related type and connection storage field whose effective arguments (after middleware, the scope and joined scopes) hold the same plain data and are requested in the same tick, that is before the promise jobs queued so far have run. It calls the method with 2 to 100 distinct parent IDs, each a raw ID that `castId` accepts without changing its string form, and with a copy of the arguments that the method may change; a group with one distinct parent calls `findChildren`. Return one array per parent ID, in order, each holding exactly the records, order and page that `findChildren` returns for that parent; records should show their parent under the connection field, or not show one. Fields of one parent share its records, each with its own array. After a rejection, or a result of another shape or with records of another parent, each field reads alone with `findChildren`; failures other than a `SimfinityError`, and results of another shape, are logged once per type. Pairing rule: the batch must reproduce `this.findChildren`, so `batchesChildren` must return `false` when `this.findChildren` is not the adapter's own function, as with a spread copy or an `Object.assign` override that changes how children are read. The bundled adapters follow this rule: both define the two members only with `batchedCollections: true`: the SQL adapter when the schema is prepared and its plugin's `compileChildrenQuery` is paired with its `compileQuery`, and the MongoDB adapter at creation. To opt out on one adapter instance, set `adapter.findChildrenBatch = undefined` (deleting it does nothing for a class whose method is on the prototype), or make `batchesChildren` return `false`. A copy that overrides `getById` still inherits the base `getByIds`, as before.
|
|
24
|
-
|
|
25
|
-
An adapter declares the filter operators it compiles as `queryFeatures: { operators }`, a list of `QLOperator` values that includes `EQ`, which a condition without an operator means; names this version does not know are ignored, until a version that knows them, so a declaration that listed `CONTAINS_ALL` or `IIN` before they existed starts receiving them on upgrade: list only the operators the adapter compiles. `createRuntime()` reads it once and throws `INVALID_QUERY_FEATURES` (500) unless it is `undefined`, `null` or an object whose `operators` is an array of strings and whose optional `referenceEmptiness` is a boolean, `undefined` or `null`. Without a declaration the adapter supports the operators of 3.7.0, `EQ`, `NE`, `LT`, `LTE`, `GT`, `GTE`, `BTW`, `IN`, `NIN` and `LIKE`, so it never receives a text operator such as `ILIKE`, an emptiness operator, `IS_EMPTY` or `IS_NOT_EMPTY`, or a list operator, `CONTAINS_ALL` or `IIN`, that it would drop or misread. A list, count, aggregate or collection read, or a by-ID read through a `get_by_id` scope, that uses another `QLOperator` value fails with `UNSUPPORTED_QUERY` (400): the runtime checks the client's arguments before middleware runs and the final arguments, with what middleware, scopes and joined scopes added, before it calls the adapter. Unknown operators on actual filter predicates fail with `INVALID_FILTER_OPERATOR` (400) before the adapter is called. An adapter that receives the text operators must apply their rules: literal values, a `String` field or list, and `INVALID_FILTER_VALUE` (400) for a value that is not a string or contains U+0000. `createQueryPlan(models, entity, args, { operators })` validates them and rejects operators outside `operators` with `UNSUPPORTED_QUERY`. An adapter that declares `IIN` receives an array of strings without U+0000, possibly empty, on a `String` field or list, and must match where `IEQ` would match one of them, under the same case-folding rules, and nothing for `[]`. An adapter that declares `CONTAINS_ALL` receives a non-empty array of non-null scalars, validated but not cast, on a path that ends at a scalar list or at a scalar read through embedded lists and crosses no collection and no reference after an embedded list; it must cast each element as for `IN` and match the records whose values at the path, those of every item of embedded lists included, hold every element, and stay two-valued under negation, where a missing or `null` list holds none. See [filters on lists](https://simtlix.github.io/simfinity.js/guide/queries.html#filters-on-lists). An adapter that declares `IS_EMPTY` and `IS_NOT_EMPTY` must compile their semantics on the queried record's own fields, where `IS_NOT_EMPTY` is the exact complement of `IS_EMPTY`: a `String` is empty when missing, `null` or `""`, any other scalar or enum when missing or `null`, a list when missing, `null` or `[]`, and an embedded object when missing, `null` or every stored member is empty. The runtime rejects a value other than `null` and a path inside a list before it calls the adapter, and also emptiness through references and collections unless the adapter declares `referenceEmptiness: true`, so the adapter receives conditions whose `value` may be absent and whose term or group `path` may be omitted, `null` or `""` to name the field itself; `createQueryPlan` plans them as `{ kind: 'predicate', path, operator, value: null }`, whose `path` may end at a scalar list, an embedded list or an embedded object. See [empty values](https://simtlix.github.io/simfinity.js/guide/queries.html#empty-values). An adapter that declares `referenceEmptiness: true` also receives emptiness conditions whose path crosses single references and ends at a reference or a collection, and embedded objects with reference and collection members. A client's such term or group condition carries the key `__scope: { id, scopes }`, where `scopes` holds, for each reference it crosses and each reference, collection or member it ends at or reads, keyed by the dotted path relative to the containing frame, the arguments that the target type's `find` scope produced, or `null` when it added nothing. The adapter must join a crossed reference only where that scope admits the target, and count at an end or member only the records that the scope admits, so that a record the caller may not see reads as a missing one, also on a later hop with a `null` scope; a condition without `__scope` reads stored data, as server conditions and unmarked clients on unscoped chains do. `createQueryPlan(models, entity, args, { operators, referenceEmptiness: true })` lifts each filled `__scope` into the predicate's `scopes`, planning each scope on its target type, and throws `DETACHED_CLIENT_FILTER` (500) for a `__scope` that lacks a path; its `referenceEmptiness` option defaults to `true` when `operators` is omitted and to `false` otherwise. See [references and collections](https://simtlix.github.io/simfinity.js/guide/queries.html#references-and-collections).
|
|
3
|
+
# @simtlix/simfinity-core
|
|
26
4
|
|
|
27
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/@simtlix/simfinity-core)
|
|
6
|
+
[](https://nodejs.org/)
|
|
7
|
+
[](https://github.com/simtlix/simfinity.js/blob/master/LICENSE)
|
|
8
|
+
[](https://simtlix.github.io/simfinity.js/)
|
|
28
9
|
|
|
29
|
-
|
|
10
|
+
**The driver-free GraphQL runtime of [Simfinity.js](https://simtlix.github.io/simfinity.js/).** It holds model metadata, schema generation, the query and mutation engine, and the shared `auth`, `validators`, `scalars` and `plugins` helpers. It imports no Mongoose, MongoDB, PostgreSQL or MCP package.
|
|
30
11
|
|
|
31
|
-
|
|
12
|
+
Applications rarely install it by hand: the database packages depend on it. Start with [`@simtlix/simfinity-js`](https://www.npmjs.com/package/@simtlix/simfinity-js) for MongoDB or [`@simtlix/simfinity-postgres`](https://www.npmjs.com/package/@simtlix/simfinity-postgres) for PostgreSQL. Install core directly when you import one of its subpaths or write a database adapter.
|
|
32
13
|
|
|
33
|
-
|
|
14
|
+
**[Documentation](https://simtlix.github.io/simfinity.js/)** ·
|
|
15
|
+
**[API reference](https://simtlix.github.io/simfinity.js/reference/api.html)** ·
|
|
16
|
+
**[Field extensions](https://simtlix.github.io/simfinity.js/reference/extensions.html)** ·
|
|
17
|
+
**[Errors](https://simtlix.github.io/simfinity.js/reference/errors.html)** ·
|
|
18
|
+
**[Releases](https://github.com/simtlix/simfinity.js/releases)**
|
|
34
19
|
|
|
35
|
-
|
|
20
|
+
## Install
|
|
36
21
|
|
|
37
|
-
|
|
22
|
+
```sh
|
|
23
|
+
npm install @simtlix/simfinity-core graphql@^16.11.0
|
|
24
|
+
```
|
|
38
25
|
|
|
39
|
-
|
|
26
|
+
| Requirement | Version |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| Node.js | 18.18 or later, ES modules |
|
|
29
|
+
| `graphql` (peer) | `^16.11.0` |
|
|
40
30
|
|
|
41
|
-
|
|
31
|
+
As a direct dependency, pin core to the exact version of the database package you use, also under pnpm or Yarn PnP.
|
|
42
32
|
|
|
43
|
-
|
|
33
|
+
## Create a runtime
|
|
44
34
|
|
|
45
|
-
`
|
|
35
|
+
`createRuntime(adapter)` binds one database adapter. Each runtime owns its registrations, generated input types, middleware, scopes, hooks, custom operations, views and state machines.
|
|
46
36
|
|
|
47
|
-
|
|
37
|
+
```javascript
|
|
38
|
+
import { createRuntime } from '@simtlix/simfinity-core';
|
|
48
39
|
|
|
49
|
-
|
|
40
|
+
const simfinity = createRuntime(adapter); // for example, createMongoAdapter()
|
|
41
|
+
simfinity.connect(null, BookType, 'book', 'books');
|
|
42
|
+
const schema = simfinity.createSchema();
|
|
43
|
+
```
|
|
50
44
|
|
|
51
|
-
|
|
45
|
+
| Area | Functions | Reference |
|
|
46
|
+
| --- | --- | --- |
|
|
47
|
+
| Registration and schema | `connect`, `addNoEndpointType`, `createSchema` | [connect](https://simtlix.github.io/simfinity.js/reference/api.html#connect), [createSchema](https://simtlix.github.io/simfinity.js/reference/api.html#createschema) |
|
|
48
|
+
| Inspection | `getModel`, `getType`, `getInputType`, `getRegistrations` | [Core API](https://simtlix.github.io/simfinity.js/reference/api.html) |
|
|
49
|
+
| Middleware and custom writes | `use`, `registerMutation` | [Middleware](https://simtlix.github.io/simfinity.js/guide/middleware.html), [registerMutation](https://simtlix.github.io/simfinity.js/reference/api.html#registermutation) |
|
|
50
|
+
| Custom reads | `registerCustomQuery`, `registerView` | [registerCustomQuery](https://simtlix.github.io/simfinity.js/reference/api.html#registercustomquery), [registerView](https://simtlix.github.io/simfinity.js/reference/api.html#registerview) |
|
|
51
|
+
| Writes from your own code | `saveObject`, `updateObject`, `deleteObject`, `transitionObject` | [Server-side operations](https://simtlix.github.io/simfinity.js/guide/server-side-operations.html) |
|
|
52
|
+
| Limits and setup | `configureQueryLimits`, `configureMutationLimits`, `preventCreatingCollection` | [configureQueryLimits](https://simtlix.github.io/simfinity.js/reference/api.html#configurequerylimits) |
|
|
52
53
|
|
|
53
|
-
|
|
54
|
+
## Shared helpers
|
|
54
55
|
|
|
55
|
-
|
|
56
|
+
The package root also exports what every database package re-exports:
|
|
56
57
|
|
|
57
|
-
|
|
58
|
+
| Export | Purpose | Reference |
|
|
59
|
+
| --- | --- | --- |
|
|
60
|
+
| `auth` | Authorization rules and policy expressions | [Authorization](https://simtlix.github.io/simfinity.js/guide/authorization.html) |
|
|
61
|
+
| `validators`, `createValidatedScalar` | Field validators and validated scalars | [Validation](https://simtlix.github.io/simfinity.js/guide/validation.html), [scalars](https://simtlix.github.io/simfinity.js/reference/scalars.html) |
|
|
62
|
+
| `scalars` | Built-in scalar types | [Scalars](https://simtlix.github.io/simfinity.js/reference/scalars.html) |
|
|
63
|
+
| `plugins` | Server plugins: `createAuthPlugin`, `envelopCountPlugin` and `apolloCountPlugin` | [Plugins](https://simtlix.github.io/simfinity.js/reference/plugins.html) |
|
|
64
|
+
| `SimfinityError` and subclasses, `buildErrorFormatter` | Error identities and formatting | [Errors](https://simtlix.github.io/simfinity.js/reference/errors.html) |
|
|
65
|
+
| `RecordVersion`, `MAX_RECORD_VERSION` | The managed version of optimistic concurrency | [Optimistic concurrency](https://simtlix.github.io/simfinity.js/guide/concurrency.html) |
|
|
66
|
+
| `describeModels`, `createQueryPlan` | Model metadata and query plans for adapter authors | [SQL core & plugins](https://simtlix.github.io/simfinity.js/guide/sql-plugins.html) |
|
|
58
67
|
|
|
59
|
-
|
|
68
|
+
Public subpaths: `/auth`, `/auth/errors`, `/auth/expressions`, `/auth/rules`, `/plugins`, `/scalars`, `/validators` and `/introspection`. Paths under `/internal/` are for the Simfinity packages and can change in any release.
|
|
60
69
|
|
|
61
|
-
##
|
|
70
|
+
## Documentation
|
|
62
71
|
|
|
63
|
-
|
|
72
|
+
| I want to… | Read |
|
|
73
|
+
| --- | --- |
|
|
74
|
+
| Learn the model and schema rules | [Schema & models](https://simtlix.github.io/simfinity.js/guide/schema.html), [relationships](https://simtlix.github.io/simfinity.js/guide/relationships.html) |
|
|
75
|
+
| Understand filters, quantifiers and pagination | [Queries & filtering](https://simtlix.github.io/simfinity.js/guide/queries.html) |
|
|
76
|
+
| Understand generated and transaction mutations | [Mutations](https://simtlix.github.io/simfinity.js/guide/mutations.html) |
|
|
77
|
+
| Add business logic | [Controllers & hooks](https://simtlix.github.io/simfinity.js/guide/controllers.html), [state machines](https://simtlix.github.io/simfinity.js/guide/state-machines.html) |
|
|
78
|
+
| Restrict what a request can read | [Query scope](https://simtlix.github.io/simfinity.js/guide/query-scope.html) |
|
|
79
|
+
| Serve client metadata or disable the legacy introspection field | [Client descriptor](https://simtlix.github.io/simfinity.js/reference/client-descriptor.html) |
|
|
80
|
+
| Write a database adapter | [Custom database adapters](https://simtlix.github.io/simfinity.js/reference/api.html#custom-database-adapters) |
|
|
81
|
+
| Write a relational database plugin | [SQL core & plugins](https://simtlix.github.io/simfinity.js/guide/sql-plugins.html) |
|
|
82
|
+
| Upgrade between versions | [Compatibility & releases](https://simtlix.github.io/simfinity.js/resources/compatibility.html) |
|
|
64
83
|
|
|
65
|
-
|
|
84
|
+
## Packages
|
|
66
85
|
|
|
67
|
-
|
|
86
|
+
All Simfinity packages are released together under the same version. Keep the ones you install aligned. The ESLint plugin has its own version.
|
|
68
87
|
|
|
69
|
-
|
|
88
|
+
| Package | Use it for |
|
|
89
|
+
| --- | --- |
|
|
90
|
+
| [`@simtlix/simfinity-js`](https://www.npmjs.com/package/@simtlix/simfinity-js) | MongoDB/Mongoose applications |
|
|
91
|
+
| [`@simtlix/simfinity-postgres`](https://www.npmjs.com/package/@simtlix/simfinity-postgres) | PostgreSQL 15+ applications, with real tables and foreign keys |
|
|
92
|
+
| [`@simtlix/simfinity-mcp`](https://www.npmjs.com/package/@simtlix/simfinity-mcp) | MCP tools and transports for any Simfinity schema |
|
|
93
|
+
| [`@simtlix/simfinity-js-client`](https://www.npmjs.com/package/@simtlix/simfinity-js-client) | JavaScript client for Simfinity APIs |
|
|
94
|
+
| [`@simtlix/simfinity-descriptor`](https://www.npmjs.com/package/@simtlix/simfinity-descriptor) | Client metadata endpoint for a schema |
|
|
95
|
+
| **`@simtlix/simfinity-core`** | Shared GraphQL runtime, installed automatically (this package) |
|
|
96
|
+
| [`@simtlix/simfinity-sql`](https://www.npmjs.com/package/@simtlix/simfinity-sql) | Relational runtime and database plugin contract |
|
|
97
|
+
| [`@simtlix/eslint-plugin-simfinity`](https://www.npmjs.com/package/@simtlix/eslint-plugin-simfinity) | Optional lint rules for Simfinity applications |
|
|
70
98
|
|
|
71
|
-
|
|
72
|
-
aligned with your Simfinity version. It exports `buildClientDescriptor(schema)`
|
|
73
|
-
and `createClientDescriptorHandler(schema, { authorize: 'public' })`. The builder
|
|
74
|
-
describes the exact `createSchema()` result; the explicitly mounted handler can
|
|
75
|
-
instead use an application access function. These functions are not facade/core
|
|
76
|
-
exports. The descriptor does not evaluate dynamic permissions or serialize
|
|
77
|
-
arbitrary validators.
|
|
99
|
+
## Contributing
|
|
78
100
|
|
|
79
|
-
|
|
80
|
-
`configureIntrospection` from `@simtlix/simfinity-core/introspection` in a separate
|
|
81
|
-
bootstrap module and call it with `{ fieldExtensions: false }` **before importing
|
|
82
|
-
the runtime or facades**. That direct import requires core as a direct dependency
|
|
83
|
-
pinned to the facade's exact version, including under pnpm or Yarn PnP. A late
|
|
84
|
-
call fails without deleting installed metadata. Migrate clients selecting
|
|
85
|
-
`__Field.extensions` before opting out. See the [descriptor reference](https://simtlix.github.io/simfinity.js/reference/client-descriptor.html)
|
|
86
|
-
for the format, protected HTTP access and composition limits.
|
|
101
|
+
Source, issues and the contribution guide live in the [simtlix/simfinity.js](https://github.com/simtlix/simfinity.js) monorepo, under `packages/core`. See [Contributing](https://simtlix.github.io/simfinity.js/resources/contributing.html).
|
|
87
102
|
|
|
88
|
-
|
|
103
|
+
## License
|
|
89
104
|
|
|
90
|
-
|
|
105
|
+
[Apache-2.0](https://github.com/simtlix/simfinity.js/blob/master/LICENSE)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simtlix/simfinity-core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.19.1",
|
|
4
4
|
"description": "Driver-free GraphQL runtime and model metadata for Simfinity",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -88,6 +88,7 @@
|
|
|
88
88
|
"node": ">=18.18.0"
|
|
89
89
|
},
|
|
90
90
|
"license": "Apache-2.0",
|
|
91
|
+
"homepage": "https://simtlix.github.io/simfinity.js/reference/api.html",
|
|
91
92
|
"repository": {
|
|
92
93
|
"type": "git",
|
|
93
94
|
"url": "https://github.com/simtlix/simfinity.js",
|