@open-predicate/open-predicate 0.6.0 → 0.6.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/CHANGELOG.md +107 -9
- package/README.md +43 -14
- package/package.json +4 -1
- package/tools/generate-filter-schema.mjs +20 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,46 @@ minor release may break compatibility, in which case the break is spelled out be
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.6.1] — 2026-09-14
|
|
11
|
+
|
|
12
|
+
**A packaging release.** No change to the grammar, the schema or the semantics of evaluation:
|
|
13
|
+
`open-predicate-schema.json` is byte-identical to 0.6.0, and the `$id` still names `v0.4.0`. What
|
|
14
|
+
changed is that the package now works the way 0.6.0 said it did.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- **The CLI did nothing when invoked as a CLI.** `tools/generate-filter-schema.mjs` guarded its entry
|
|
19
|
+
point with `fileURLToPath(import.meta.url) === process.argv[1]`, and npm installs a `bin` as a
|
|
20
|
+
**symlink** — so `argv[1]` was `node_modules/.bin/open-predicate-generate` while `import.meta.url`
|
|
21
|
+
was the file it pointed at. The comparison was false, `main()` never ran, and the process exited
|
|
22
|
+
**0 having printed nothing**. Every `npx @open-predicate/open-predicate` and every global install
|
|
23
|
+
was affected in `0.6.0`, the first release to ship a `bin` at all.
|
|
24
|
+
|
|
25
|
+
It went unnoticed because the two ways it is exercised here both avoid the symlink:
|
|
26
|
+
`npm run generate:example` and the tests call the file by path. The same comparison also failed for
|
|
27
|
+
a plain path invocation anywhere under a symlinked directory — including `/tmp` on macOS, which is
|
|
28
|
+
a symlink to `/private/tmp`.
|
|
29
|
+
|
|
30
|
+
The guard now compares through `realpathSync` on both sides, and `tests/generator.test.mjs` runs
|
|
31
|
+
the real generator through a real symlink and requires output, so the regression cannot return. It
|
|
32
|
+
still must not run on import, and that is asserted in the same test.
|
|
33
|
+
|
|
34
|
+
- **`engines` was missing, so an unsupported Node failed obscurely.** The package now declares
|
|
35
|
+
`"node": ">=20.10.0"`. That is the real floor, not a guess: the generator uses `parseArgs` from
|
|
36
|
+
`node:util`, and the consumption path the README documents —
|
|
37
|
+
`import schema from '@open-predicate/open-predicate' with { type: 'json' }` — needs import
|
|
38
|
+
attributes, which is 20.10. Without the field, npm had nothing to warn against and a user on an
|
|
39
|
+
older line got a stack trace instead of a version complaint.
|
|
40
|
+
|
|
41
|
+
- **The release pipeline never exercised the artifact it publishes.** `npm test` and
|
|
42
|
+
`npm run generate:example` both invoke the generator by path, which is the one way that never
|
|
43
|
+
crosses the symlink npm installs a `bin` as — so the no-op above passed every check and shipped.
|
|
44
|
+
[`.github/workflows/release.yml`](./.github/workflows/release.yml) now packs the tarball, installs
|
|
45
|
+
it into a scratch project the way a consumer would, and drives every entry point the README
|
|
46
|
+
documents: the bin through its symlink, `require()`, the ESM import attribute, and
|
|
47
|
+
`./generate`. It also asserts the generator stays silent when merely imported. A release cannot
|
|
48
|
+
now ship an artifact whose documented entry points do not work.
|
|
49
|
+
|
|
10
50
|
### Changed
|
|
11
51
|
|
|
12
52
|
- **The npm package is scoped: `@open-predicate/open-predicate`.** 0.6.0 named it `open-predicate`,
|
|
@@ -27,13 +67,63 @@ minor release may break compatibility, in which case the break is spelled out be
|
|
|
27
67
|
|
|
28
68
|
### Added
|
|
29
69
|
|
|
70
|
+
- **The project has a written governance and contribution process.**
|
|
71
|
+
[`GOVERNANCE.md`](./GOVERNANCE.md) states how a decision is made and what it costs — editorial,
|
|
72
|
+
substantive-compatible, or normative, where normative requires a record under
|
|
73
|
+
[`decisions/`](./decisions), a migration note and a `$id` bump. It sets out how a disputed design
|
|
74
|
+
call is resolved (answered in writing, then a decision record quoting the objection in the
|
|
75
|
+
objector's words, then 14-day lazy consensus, then the editor decides **and the dissent is recorded
|
|
76
|
+
in the record**), what earns commit rights, and an explicit royalty-free patent posture — MIT
|
|
77
|
+
settles copyright and says nothing about patents, which is the first thing an adopter's lawyer
|
|
78
|
+
looks for. It also states that there is currently one maintainer and calls that a defect rather
|
|
79
|
+
than a design.
|
|
80
|
+
|
|
81
|
+
[`CONTRIBUTING.md`](./CONTRIBUTING.md) leads with the thing the README already says is most useful
|
|
82
|
+
— *disagreement* — and makes the three entry points concrete: file a design objection, build an
|
|
83
|
+
implementation, or claim conformance for a library that already exists. It is candid that
|
|
84
|
+
`tests/fixtures/` checks schema well-formedness only, has no records or expected results, uses an
|
|
85
|
+
ajv-flavoured `expectKeyword`, and is excluded from the published package; and it names promoting
|
|
86
|
+
`experiments/filter-to-sql/cases.mjs` (73 cases over 10 records, already shaped
|
|
87
|
+
`{group, id, title, filter, expect}`) into a portable conformance suite as the highest-value
|
|
88
|
+
contribution currently available.
|
|
89
|
+
|
|
90
|
+
Also added: [`CODE_OF_CONDUCT.md`](./CODE_OF_CONDUCT.md), which makes explicit that blunt technical
|
|
91
|
+
disagreement is welcome and is not incivility, and discloses that a report about the sole
|
|
92
|
+
maintainer has nowhere independent to go inside the project;
|
|
93
|
+
[`SECURITY.md`](./SECURITY.md), which defines what a vulnerability even means for a specification
|
|
94
|
+
— a rule that makes conforming implementations unsafe, a filter that stays inside the §7 limits and
|
|
95
|
+
is still superlinear, or any path where a predicate ends up dropped, widened or truncated, since
|
|
96
|
+
that is an authorization bypass wherever filters carry tenancy; [`SUPPORT.md`](./SUPPORT.md); three
|
|
97
|
+
issue forms; and a pull-request template whose checklist is tied to the invariants the tests
|
|
98
|
+
already enforce. Discussions and private vulnerability reporting are enabled on the repository.
|
|
99
|
+
|
|
100
|
+
- **The schema is served from its `$id`.**
|
|
101
|
+
`https://openpredicate.tech/schema/v0.4.0/open-predicate-schema.json` now returns the file it
|
|
102
|
+
identifies, as `application/schema+json`, with `Access-Control-Allow-Origin: *` so browser-based
|
|
103
|
+
tooling can fetch it and `Cache-Control: public,max-age=31536000,immutable` because a versioned
|
|
104
|
+
`$id` never changes (§9). The served bytes are identical to
|
|
105
|
+
[`open-predicate-schema.json`](./open-predicate-schema.json) in this repository.
|
|
106
|
+
|
|
107
|
+
This closes what the README called the one piece of remaining work. The `$ref`-by-URL workflow
|
|
108
|
+
that [Using it from OpenAPI](./README.md#using-it-from-openapi) and the capability document
|
|
109
|
+
examples are written around now describes today rather than an intended end state, and the five
|
|
110
|
+
RFC 9457 problem types under `https://openpredicate.tech/problems/` dereference as well. There is
|
|
111
|
+
deliberately **no** unversioned or `latest` schema URL; both 404.
|
|
112
|
+
|
|
113
|
+
Serving it is a second repository's job, so a release is not finished when the tag is pushed —
|
|
114
|
+
[`OpenPredicate/openpredicate.tech`](https://github.com/OpenPredicate/openpredicate.tech) vendors
|
|
115
|
+
the artefacts and has to be synced at the tag. That step is now written down in
|
|
116
|
+
[`RELEASING.md`](./RELEASING.md#serving-the-schema-from-its-id).
|
|
117
|
+
|
|
30
118
|
- **Publishing is back on, and npmjs.com authenticates by OIDC.**
|
|
31
119
|
[`.github/workflows/release.yml`](./.github/workflows/release.yml) publishes to both registries
|
|
32
120
|
when a GitHub Release is published. The npmjs job uses npm's [trusted
|
|
33
121
|
publishing](https://docs.npmjs.com/trusted-publishers): it requests `id-token: write` and npm
|
|
34
122
|
exchanges that for a short-lived credential, so there is **no `NPM_TOKEN` secret** in this
|
|
35
123
|
repository and nothing to rotate. Provenance is attached automatically, linking each tarball to
|
|
36
|
-
the workflow run and commit that built it
|
|
124
|
+
the workflow run and commit that built it — though only for tarballs the workflow publishes, so
|
|
125
|
+
0.6.0 has none: its bootstrap publish came from a laptop, which is the one publish OIDC cannot
|
|
126
|
+
do. 0.6.1 is the first over OIDC. GitHub Packages stays token-authenticated — it has no
|
|
37
127
|
OIDC equivalent — but `GITHUB_TOKEN` is minted per run and expires with it.
|
|
38
128
|
|
|
39
129
|
`.github/scripts/version-published.sh` is restored alongside, so each job skips a version it has
|
|
@@ -43,10 +133,16 @@ minor release may break compatibility, in which case the break is spelled out be
|
|
|
43
133
|
breaks publishing until the trusted publisher is updated to match.
|
|
44
134
|
|
|
45
135
|
**npm cannot mint a package's first version over OIDC**, because a trusted publisher can only be
|
|
46
|
-
attached to a package that already exists. Claiming `@open-predicate/open-predicate`
|
|
47
|
-
a one-time manual publish, documented in
|
|
48
|
-
[`RELEASING.md`](./RELEASING.md#trusted-publishing-and-the-one-time-bootstrap)
|
|
49
|
-
|
|
136
|
+
attached to a package that already exists. Claiming `@open-predicate/open-predicate` was therefore
|
|
137
|
+
a one-time manual publish, documented along with everything it cost to get right in
|
|
138
|
+
[`RELEASING.md`](./RELEASING.md#trusted-publishing-and-the-one-time-bootstrap) — including that
|
|
139
|
+
*configuring* the trusted publisher needs npm >= 12, which fails with an unexplained `E400` on
|
|
140
|
+
npm 11 because the older client omits the `permissions` field the registry now requires.
|
|
141
|
+
|
|
142
|
+
- **`@open-predicate/open-predicate` is on npmjs.com**, public and installable, from `0.6.0` on. The
|
|
143
|
+
package is the schema: `require()` it, or `import` it with `{ type: 'json' }`. The trusted
|
|
144
|
+
publisher is configured, so every release from here is published by the workflow rather than by
|
|
145
|
+
hand. GitHub Packages gets its first copy with the next release.
|
|
50
146
|
|
|
51
147
|
## [0.6.0] — 2026-09-13
|
|
52
148
|
|
|
@@ -147,10 +243,11 @@ document's top-level members. No filter valid under 0.4.0 becomes invalid.
|
|
|
147
243
|
`--max-filter-depth` is given and `maxDepth` is not, the enforced bound is published.
|
|
148
244
|
- **The generator is part of the package.** `tools/` was not in `package.json` `files` and there
|
|
149
245
|
was no `bin` entry, so the tool the README points readers at could not travel with the package
|
|
150
|
-
at all. It is now a `bin` named `open-predicate-generate`, with
|
|
151
|
-
`generateFilterSchema` for programmatic use.
|
|
152
|
-
|
|
153
|
-
|
|
246
|
+
at all. It is now a `bin` named `open-predicate-generate`, with
|
|
247
|
+
`@open-predicate/open-predicate/generate` exporting `generateFilterSchema` for programmatic use.
|
|
248
|
+
At the time of this release the repository still published no artifacts, so the command was
|
|
249
|
+
reachable from a clone or a git install and not from npmjs; what changed here is that it was
|
|
250
|
+
ready to be, and `npm pack` contained it. Publishing arrived in 0.6.0.
|
|
154
251
|
- **[SPEC.md §2.2](./SPEC.md#22-capability-discovery) documents the capability document's
|
|
155
252
|
top-level members** — `queryLanguage`, `profiles`, `fields`, `limits` and `filterSchema` — in a
|
|
156
253
|
table beside the existing per-field one. `limits` appeared in the example and in no table, and
|
|
@@ -523,6 +620,7 @@ Initial research draft: `$and`, `$or`, `$not` over eight leaf condition types
|
|
|
523
620
|
(`$eq`, `$ne`, `$in`, `$nin`, `$like`, `$nlike`, `$gt`/`$gte`/`$lt`/`$lte`/`$between`, `$isnull`),
|
|
524
621
|
laid out as an OpenAPI `components.schemas` fragment.
|
|
525
622
|
|
|
623
|
+
[0.6.1]: https://github.com/OpenPredicate/open-predicate/compare/v0.6.0...v0.6.1
|
|
526
624
|
[0.6.0]: https://github.com/OpenPredicate/open-predicate/compare/v0.5.0...v0.6.0
|
|
527
625
|
[0.5.0]: https://github.com/OpenPredicate/open-predicate/compare/v0.4.0...v0.5.0
|
|
528
626
|
[0.4.0]: https://github.com/OpenPredicate/open-predicate/compare/v0.3.1...v0.4.0
|
package/README.md
CHANGED
|
@@ -21,6 +21,7 @@ Write the filter grammar once. Use it for every `POST /…/search` and `QUERY /
|
|
|
21
21
|
|
|
22
22
|
One schema, two integration points, because JSON Schema is what both already speak: it is the interchange format of OpenAPI 3.1, and it is what an MCP `inputSchema` is.
|
|
23
23
|
|
|
24
|
+
- **Install** — `npm i @open-predicate/open-predicate` (Node >= 20.10) ([npmjs.com](https://www.npmjs.com/package/@open-predicate/open-predicate)). The package *is* the schema: `require()` it, or `import schema from '@open-predicate/open-predicate' with { type: 'json' }` — ESM needs that import attribute, and a bare `import` throws without it.
|
|
24
25
|
- **Schema** — [`open-predicate-schema.json`](./open-predicate-schema.json) (JSON Schema draft 2020-12)
|
|
25
26
|
- **Semantics** — [`SPEC.md`](./SPEC.md) — nulls, paths, coercion, errors, limits
|
|
26
27
|
- **MCP server** — [`examples/mcp-server/`](./examples/mcp-server) — a search tool with the language as its `inputSchema`, runnable
|
|
@@ -28,9 +29,9 @@ One schema, two integration points, because JSON Schema is what both already spe
|
|
|
28
29
|
- **Generator** — [`tools/generate-filter-schema.mjs`](./tools/generate-filter-schema.mjs) — turns a resource's JSON Schema, plus the slice of the language you can serve, into a per-field filter schema
|
|
29
30
|
- **Compared with GraphQL** — [`COMPARISON.md`](./COMPARISON.md) — what this overlaps with, what it does not, and what a JSON-Schema-native alternative would still need
|
|
30
31
|
- **Stewardship** — the [OpenPredicate](https://openpredicate.tech) organisation — see [About OpenPredicate](#about-openpredicate)
|
|
31
|
-
- **Version** — `0.
|
|
32
|
+
- **Version** — `0.6.1`. The schema's `$id` still names `v0.4.0`: the `$id` tracks the grammar, and neither 0.5.0 nor 0.6.0 touched it. See [`CHANGELOG.md`](./CHANGELOG.md) for this release, and [`decisions/0001`](./decisions/0001-array-quantifiers-and-unknown-handling.md) for the v0.4.0 migration.
|
|
32
33
|
|
|
33
|
-
> **
|
|
34
|
+
> **Pre-1.0, and installable.** The name is settled — *OpenPredicate*, stewarded by the [OpenPredicate](https://openpredicate.tech) organisation, with the repository, both package names, the schema `$id` and the problem-type URIs all derived from it — the package is on npm as [`@open-predicate/open-predicate`](https://www.npmjs.com/package/@open-predicate/open-predicate), and the schema is **served at its `$id`** — so `$ref` it by URL, or from a packaged copy, whichever suits. One thing is still provisional: the grammar may still break before 1.0, with each break recorded in [`CHANGELOG.md`](./CHANGELOG.md). See [Status](#status) for what is reachable today.
|
|
34
35
|
|
|
35
36
|
---
|
|
36
37
|
|
|
@@ -234,6 +235,7 @@ Both work, and they trade off differently:
|
|
|
234
235
|
| | Absolute `$id` URL | Bundled copy |
|
|
235
236
|
| --- | --- | --- |
|
|
236
237
|
| `$ref` | `https://…/v0.4.0/open-predicate-schema.json` | `./schemas/open-predicate-schema.json` |
|
|
238
|
+
| Where the copy comes from | resolved at use | `npm i @open-predicate/open-predicate`, or `curl` from raw GitHub |
|
|
237
239
|
| Upgrades | change one URL | re-vendor the file |
|
|
238
240
|
| Tooling | needs a resolver that fetches remote refs | works everywhere |
|
|
239
241
|
| MCP `inputSchema` | no — nothing on that path resolves remote refs | yes, and it is the only option |
|
|
@@ -371,7 +373,7 @@ Opt a single property out, or override its operators, from the resource schema i
|
|
|
371
373
|
|
|
372
374
|
`--include`, `--exclude`, `--max-depth` and `--pointer` do the rest. Run `--help` for the full list.
|
|
373
375
|
|
|
374
|
-
The tool ships inside the package as a `bin` named `open-predicate-generate`, so from a registry it is `npx @open-predicate/open-predicate` rather than a path — the package name, not the bin name, because the package is scoped and `npx` resolves packages.
|
|
376
|
+
The tool ships inside the package as a `bin` named `open-predicate-generate`, so from a registry it is `npx @open-predicate/open-predicate` rather than a path — the package name, not the bin name, because the package is scoped and `npx` resolves packages. From a clone it stays `node tools/generate-filter-schema.mjs`.
|
|
375
377
|
|
|
376
378
|
## Exposing search to an agent
|
|
377
379
|
|
|
@@ -428,8 +430,11 @@ A filter is user input that becomes a query plan. [SPEC.md §7](./SPEC.md#7-safe
|
|
|
428
430
|
```
|
|
429
431
|
open-predicate-schema.json the schema — the only file you need to consume
|
|
430
432
|
SPEC.md normative semantics
|
|
431
|
-
|
|
433
|
+
CONTRIBUTING.md how to object, implement, or claim conformance
|
|
434
|
+
GOVERNANCE.md how decisions get made, who makes them, and the IPR posture
|
|
435
|
+
RELEASING.md how a release is cut, and how trusted publishing is set up
|
|
432
436
|
COMPARISON.md how this relates to GraphQL, OData and JSON:API
|
|
437
|
+
decisions/ one numbered record per significant design decision
|
|
433
438
|
tools/generate-filter-schema.mjs resource schema + capability selection -> filter schema + capabilities
|
|
434
439
|
examples/mcp-server/ a runnable MCP server; the language as a tool's inputSchema
|
|
435
440
|
examples/ working OpenAPI 3.1 and 3.2 documents
|
|
@@ -439,34 +444,54 @@ tests/generator.test.mjs the generator: narrowing, soundness, recursion
|
|
|
439
444
|
tests/fixtures/valid/ one per operator; also the docs' example set
|
|
440
445
|
tests/fixtures/invalid/ every defect this version fixes, pinned
|
|
441
446
|
experiments/filter-to-sql/ an exercise: compile a filter to SQL, then judge the design by it
|
|
447
|
+
.github/ISSUE_TEMPLATE/ design objection, spec ambiguity, implementation report
|
|
442
448
|
.github/workflows/ci.yml tests on Node 20/22/24 + OpenAPI lint
|
|
443
|
-
.github/workflows/release.yml
|
|
449
|
+
.github/workflows/release.yml publishes to npmjs over OIDC when a GitHub Release is published
|
|
444
450
|
```
|
|
445
451
|
|
|
446
452
|
`npm test` meta-validates the schema under ajv's strict mode, checks that `x-profiles` covers exactly the operators the grammar defines, validates every inline example against its own subschema, and runs all fixtures — invalid ones asserting *which* keyword rejected them, so a fixture cannot pass for the wrong reason. It also compiles the generated pet filter schema, asserts that everything it accepts the published grammar accepts too, and checks the committed `examples/pet.filter.json` against a fresh run so it cannot drift. `npm run generate:example` refreshes it.
|
|
447
453
|
|
|
448
454
|
## Status
|
|
449
455
|
|
|
450
|
-
**Work in progress.** Pre-1.0.
|
|
456
|
+
**Work in progress.** Pre-1.0. The design is published so it can be read and argued with, and the package is installable — but the grammar may still break before 1.0, so pin an exact version if you depend on it.
|
|
451
457
|
|
|
452
458
|
**The name is settled.** *OpenPredicate* is the name; [`OpenPredicate/open-predicate`](https://github.com/OpenPredicate/open-predicate) is the home; `openpredicate.tech` is the namespace every identifier derives from — the repository, both package names, the schema `$id`, the problem-type URIs, the CLI name and the vendor keyword alike. [`CHANGELOG.md`](./CHANGELOG.md) lists them in one table.
|
|
453
459
|
|
|
454
|
-
**
|
|
460
|
+
**Naming and availability are both settled.** The identifiers below are final and reachable. One exception remains — GitHub Packages — and it is called out so nobody has to discover it the hard way:
|
|
455
461
|
|
|
456
462
|
| What the README says | Reality today |
|
|
457
463
|
| --- | --- |
|
|
458
|
-
| `$id` / `$ref` — `https://openpredicate.tech/schema/v0.4.0/open-predicate-schema.json` |
|
|
459
|
-
|
|
|
464
|
+
| `$id` / `$ref` — `https://openpredicate.tech/schema/v0.4.0/open-predicate-schema.json` | **Served**, as `application/schema+json`, with `Access-Control-Allow-Origin: *` and immutable caching, byte-identical to the copy in this repository. `$ref` it directly, as [Using it from OpenAPI](#using-it-from-openapi) and the capability document examples do. |
|
|
465
|
+
| [`@open-predicate/open-predicate`](https://www.npmjs.com/package/@open-predicate/open-predicate) on npmjs.com | **Published**, from `v0.6.0` on. Public, no credential needed to install. |
|
|
466
|
+
| `@openpredicate/open-predicate` on GitHub Packages | Not published yet — the first copy goes up with the next GitHub Release. Installing from it needs an `.npmrc` and a token even though it is public, so npmjs.com is the easier path. |
|
|
460
467
|
| The version line at the top, and the version inside the `$id` | May lag the latest tag. `CHANGELOG.md` is authoritative. |
|
|
461
|
-
| `npx @open-predicate/open-predicate` |
|
|
468
|
+
| `npx @open-predicate/open-predicate` | Works from `0.6.1`. **Broken in `0.6.0`**, where the `bin` exited 0 having printed nothing — the entry guard compared `process.argv[1]` against `import.meta.url`, and npm installs a `bin` as a *symlink*. Use the package name, not the bin name `open-predicate-generate`, which is not a package. |
|
|
462
469
|
|
|
463
|
-
|
|
470
|
+
**The `$id` resolves.** The schema is served from the URL that identifies it, so the workflow the OpenAPI sections describe is a description of today rather than an intended end state:
|
|
464
471
|
|
|
465
472
|
```bash
|
|
466
|
-
curl -
|
|
473
|
+
curl -sI https://openpredicate.tech/schema/v0.4.0/open-predicate-schema.json
|
|
474
|
+
# content-type: application/schema+json; charset=utf-8
|
|
475
|
+
# access-control-allow-origin: *
|
|
476
|
+
# cache-control: public,max-age=31536000,immutable
|
|
467
477
|
```
|
|
468
478
|
|
|
469
|
-
|
|
479
|
+
Those three headers are the ones that matter: the media type so validators recognise it, the CORS header so browser-based tooling can fetch it, and immutable caching because a versioned `$id` never changes (§9). `$ref` it by URL and you are done.
|
|
480
|
+
|
|
481
|
+
A local copy is still the right choice for air-gapped builds, for pinning independently of DNS, or for the bundle-and-narrow workflow in [Restricting the queryable field set](#restricting-the-queryable-field-set). Either get it from the package:
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
npm i @open-predicate/open-predicate
|
|
485
|
+
# -> node_modules/@open-predicate/open-predicate/open-predicate-schema.json
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
or with no package manager in the way — pinning a tag rather than `main`:
|
|
489
|
+
|
|
490
|
+
```bash
|
|
491
|
+
curl -O https://raw.githubusercontent.com/OpenPredicate/open-predicate/v0.6.1/open-predicate-schema.json
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
The served copy and the packaged copy are the same bytes: the site vendors the schema out of this repository at a tag, so a release moves both together. See [`RELEASING.md`](./RELEASING.md).
|
|
470
495
|
|
|
471
496
|
**What is stable enough to review.** The grammar, the operator set and profile grouping, the null and three-valued semantics, and the error model. Those are what the schema, [`SPEC.md`](./SPEC.md) and the test suite pin down, and they are what feedback is most useful on. The grammar may still change before 1.0; each break is recorded in [`CHANGELOG.md`](./CHANGELOG.md) with a migration note.
|
|
472
497
|
|
|
@@ -476,7 +501,11 @@ OpenPredicate is stewarded by the [**OpenPredicate**](https://openpredicate.tech
|
|
|
476
501
|
|
|
477
502
|
That goal sets the terms of the work. The grammar is specified normatively in [`SPEC.md`](./SPEC.md) rather than left to a reference implementation, so that independent implementations can agree; every breaking change is recorded with a migration note; and each significant design decision is argued in writing under [`decisions/`](./decisions) rather than settled by commit. Adoption arguments belong in the open too — [`COMPARISON.md`](./COMPARISON.md) is where the case against the nearest alternative is made and its gaps admitted.
|
|
478
503
|
|
|
479
|
-
|
|
504
|
+
[`GOVERNANCE.md`](./GOVERNANCE.md) is where that process is written down: what each class of change costs, how a disputed design call is resolved — including that dissent is recorded in the decision record rather than discarded — what earns commit rights, and the project's royalty-free patent posture. It also states plainly that there is currently one maintainer, and treats that as the defect it is.
|
|
505
|
+
|
|
506
|
+
The specification and this repository are [MIT](./LICENSE)-licensed, so the grammar can be implemented, vendored, extended and re-specified without permission, commercially or otherwise.
|
|
507
|
+
|
|
508
|
+
**Disagreement is the most useful contribution at this stage**, and [`CONTRIBUTING.md`](./CONTRIBUTING.md) says how to make it: file a design objection, build an implementation (or help turn the fixtures into a real conformance suite), or claim conformance for a library you already maintain. Open-ended design talk belongs in [Discussions](https://github.com/OpenPredicate/open-predicate/discussions); a defect or an objection belongs in an [issue](https://github.com/OpenPredicate/open-predicate/issues/new/choose).
|
|
480
509
|
|
|
481
510
|
## License
|
|
482
511
|
|
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-predicate/open-predicate",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "OpenPredicate — an open standard for JSON-encoded, SQL-flavoured predicates, described by a single JSON Schema: $ref it from OpenAPI, or inline it into an MCP tool's inputSchema.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=20.10.0"
|
|
9
|
+
},
|
|
7
10
|
"author": "Christos Gkoros",
|
|
8
11
|
"contributors": [
|
|
9
12
|
"OpenPredicate (https://openpredicate.tech)"
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
* "x-open-predicate": { "operators": ["$eq"] } — exactly these operators
|
|
68
68
|
*/
|
|
69
69
|
|
|
70
|
-
import { readFileSync, writeFileSync } from "node:fs";
|
|
70
|
+
import { readFileSync, realpathSync, writeFileSync } from "node:fs";
|
|
71
71
|
import { fileURLToPath } from "node:url";
|
|
72
72
|
import { dirname, join, resolve } from "node:path";
|
|
73
73
|
import { parseArgs } from "node:util";
|
|
@@ -1148,6 +1148,24 @@ function main(argv) {
|
|
|
1148
1148
|
}
|
|
1149
1149
|
}
|
|
1150
1150
|
|
|
1151
|
-
|
|
1151
|
+
// Run only when invoked as a program, not when imported. `process.argv[1]` is
|
|
1152
|
+
// compared through realpathSync because npm installs a `bin` as a *symlink* —
|
|
1153
|
+
// argv[1] is then `node_modules/.bin/open-predicate-generate` while
|
|
1154
|
+
// import.meta.url is the file it points at, so a direct comparison is always
|
|
1155
|
+
// false and the CLI exits 0 having done nothing. That is how `npx` invocation
|
|
1156
|
+
// silently no-opped while `node tools/generate-filter-schema.mjs` worked.
|
|
1157
|
+
function invokedAsProgram() {
|
|
1158
|
+
const entry = process.argv[1];
|
|
1159
|
+
if (!entry) return false;
|
|
1160
|
+
const self = fileURLToPath(import.meta.url);
|
|
1161
|
+
if (entry === self) return true;
|
|
1162
|
+
try {
|
|
1163
|
+
return realpathSync(entry) === realpathSync(self);
|
|
1164
|
+
} catch {
|
|
1165
|
+
return false;
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
if (invokedAsProgram()) {
|
|
1152
1170
|
main(process.argv.slice(2));
|
|
1153
1171
|
}
|