@objectstack/core 17.0.0-rc.4 → 17.0.0-rc.6
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 +521 -0
- package/dist/index.cjs +217 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +419 -45
- package/dist/index.d.ts +419 -45
- package/dist/index.js +211 -52
- package/dist/index.js.map +1 -1
- package/dist/logger.cjs +9 -1
- package/dist/logger.cjs.map +1 -1
- package/dist/logger.js +9 -1
- package/dist/logger.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,526 @@
|
|
|
1
1
|
# @objectstack/core
|
|
2
2
|
|
|
3
|
+
## 17.0.0-rc.6
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 82da264: feat: declare `ExecutionContext.authGate`, so the ADR-0069 gate sits inside the closed field set (#7280)
|
|
8
|
+
|
|
9
|
+
The ADR-0069 authentication-policy gate (expired password, enforced MFA) rode
|
|
10
|
+
the execution context **undeclared**: REST's `computeExecCtx` spread it onto the
|
|
11
|
+
assembled envelope with `...(authGate ? { authGate } : {})` behind an `as any`,
|
|
12
|
+
and its `enforceAuth` read it back ten lines later. Nothing was broken — but the
|
|
13
|
+
closed entry field set shipped in #6216 is derived from `keyof ExecutionContext`,
|
|
14
|
+
so a field that exists only inside an `as any` is **outside every closure gate by
|
|
15
|
+
construction**: `ENTRY_EXECUTION_CONTEXT_FIELDS` could not list it,
|
|
16
|
+
`ExecutionContextEntryFields` could not demand it, and the runtime pin that
|
|
17
|
+
reconciles the closed set against `ExecutionContextSchema.shape` could not see
|
|
18
|
+
it. It was the exact blind spot that gate exists to remove, sitting one `as any`
|
|
19
|
+
outside it.
|
|
20
|
+
|
|
21
|
+
**@objectstack/spec** declares the field:
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
authGate: z.object({ code: z.string(), message: z.string() }).optional();
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Both inner keys are required, matching the sole producer
|
|
28
|
+
(`AuthManager.computeAuthGate`, which sets both on every return branch) — `code`
|
|
29
|
+
is the stable machine code a client branches on, `message` is what the blocked
|
|
30
|
+
user reads, and the transport seam renders both as the `403` body.
|
|
31
|
+
|
|
32
|
+
**@objectstack/core** picks it up as an ENTRY-decided field — it is resolved from
|
|
33
|
+
the request's own session at the transport entry point, never written mid-request
|
|
34
|
+
— so `ExecutionContextAssemblyInput` gains a **required** `authGate` input on the
|
|
35
|
+
same footing as `accessToken`: every face states its decision instead of omitting
|
|
36
|
+
it. A guest principal never carries one (no authenticated session for a policy
|
|
37
|
+
gate to attach to). Also exported: `normalizeAuthGate`, which completes a session
|
|
38
|
+
user's loose `authGate` into the declared shape at the one producer rather than
|
|
39
|
+
tolerating a partial shape downstream — a gate naming a `code` but no `message`
|
|
40
|
+
no longer renders a `403` body with `message: undefined`. `AuthGate` is now
|
|
41
|
+
derived from the schema instead of being a second hand-written declaration.
|
|
42
|
+
|
|
43
|
+
**@objectstack/rest** passes the resolved gate as an assembler input and drops the
|
|
44
|
+
post-assembly spread; the remaining `as any` covers `__kernel` alone.
|
|
45
|
+
**@objectstack/runtime** (the runtime / MCP dispatcher) passes `authGate:
|
|
46
|
+
undefined` on the record: it enforces the same gate at its own seam
|
|
47
|
+
(`HttpDispatcher.enforceAuthGate` re-reads the session and calls
|
|
48
|
+
`evaluateAuthGate`) and never reads `context.authGate`, so carrying it there
|
|
49
|
+
would be a second copy no consumer reads.
|
|
50
|
+
|
|
51
|
+
**No runtime behaviour change on either surface.** The shared assembler omits
|
|
52
|
+
`undefined`-valued keys, so the key is present exactly when it was before. The one
|
|
53
|
+
new behaviour is the normalization above, on a shape the sole producer never
|
|
54
|
+
emits today.
|
|
55
|
+
|
|
56
|
+
- f586f1a: refactor: one shared `ExecutionContext` assembler, two named anonymous entries (#6216)
|
|
57
|
+
|
|
58
|
+
`resolveAuthzContext` already made AUTHORIZATION resolution single-sourced; the
|
|
59
|
+
step after it — turning the resolved envelope into the `ExecutionContext` that
|
|
60
|
+
reaches enforcement — was still one hand-written copy per transport, and the
|
|
61
|
+
copies drifted twice for real: **#6071** (the REST copy never set
|
|
62
|
+
`principalKind`, so every enforcement judgment reading it was silently
|
|
63
|
+
never-true on that face) and **#6206 / #6551** (a dropped `accessible_org_ids`
|
|
64
|
+
produced real 403s on the share-link faces).
|
|
65
|
+
|
|
66
|
+
**@objectstack/core** gains the single assembly, with the anonymous divergence
|
|
67
|
+
as named API rather than drift (maintainer ruling 2026-08-08 on #6216, Option
|
|
68
|
+
A):
|
|
69
|
+
|
|
70
|
+
- `assembleExecutionContext(input)` — the **fail-closed default** entry. No
|
|
71
|
+
resolved principal → `undefined`, and the surface answers 401.
|
|
72
|
+
- `assembleExecutionContextOrGuest(input)` — the **explicit guest** entry. No
|
|
73
|
+
resolved principal → a first-class guest envelope (`principalKind: 'guest'`,
|
|
74
|
+
`positions: ['guest']`), whose consumers are live (`explain-engine`'s
|
|
75
|
+
guest ⇒ `EXTERNAL` posture floor). Adopted only by a surface whose product
|
|
76
|
+
semantics serve anonymous principals.
|
|
77
|
+
- The field set is **closed by type**: `ExecutionContextEntryFields` requires a
|
|
78
|
+
decision for every `ExecutionContext` field that is not explicitly declared
|
|
79
|
+
non-entry-resolved, so a new field cannot reach one transport and miss
|
|
80
|
+
another. Also exported: `ENTRY_EXECUTION_CONTEXT_FIELDS`,
|
|
81
|
+
`EntryExecutionContextField`, `ExecutionContextAssemblyInput`,
|
|
82
|
+
`OAuthTokenProvenance`, `EntryLocalization`.
|
|
83
|
+
|
|
84
|
+
**@objectstack/runtime** (`resolveExecutionContext`, the runtime / MCP
|
|
85
|
+
dispatcher) and **@objectstack/rest** (`computeExecCtx`) now assemble through
|
|
86
|
+
that module — the dispatcher via the guest entry, REST via the fail-closed
|
|
87
|
+
default.
|
|
88
|
+
|
|
89
|
+
**No runtime behaviour change on either surface.** The remaining per-face
|
|
90
|
+
divergences are required inputs rather than silent omissions: REST passes
|
|
91
|
+
`accessToken: undefined` (it has never carried the session bearer on the
|
|
92
|
+
envelope, and `session.accessToken` is a published hook surface) and
|
|
93
|
+
`oauth: undefined` (OAuth bearers are honoured on the `/mcp` door alone). The
|
|
94
|
+
one measurable difference is that a key whose value was `undefined` is now
|
|
95
|
+
omitted rather than spelled — invisible to `ctx.x` reads, to `JSON.stringify`
|
|
96
|
+
and to spreading the envelope.
|
|
97
|
+
|
|
98
|
+
- 28d1eb7: fix(core): the QA `contains` assertion fails loudly instead of silently passing on a non-array/non-string actual (#7256)
|
|
99
|
+
|
|
100
|
+
`TestRunner.assert`'s `case 'contains':` handled the two shapes it can evaluate —
|
|
101
|
+
an array (membership) and a string (substring) — and had **no `else`**. Every
|
|
102
|
+
other shape fell straight out of the switch throwing nothing, so the assertion
|
|
103
|
+
reported **PASSED**. A scenario asserting
|
|
104
|
+
`{ field: "body.data.items", operator: "contains", expectedValue: "acme" }`
|
|
105
|
+
against a response that has no `body.data.items` at all reported ✅. The
|
|
106
|
+
overwhelmingly common way to reach that branch is the one that matters most: a
|
|
107
|
+
typo'd `field` path, or a response shape that moved under a suite nobody
|
|
108
|
+
re-read. The assertion that was supposed to _be_ the test is the thing that
|
|
109
|
+
silently disappears, and CI believes the green.
|
|
110
|
+
|
|
111
|
+
`contains` was the only path in this engine that could decide "no comparison
|
|
112
|
+
applies here" and report success. Every other unhandled shape already fails
|
|
113
|
+
loud — an operator with no branch throws `Unknown assertion operator`, an action
|
|
114
|
+
type with no adapter branch throws `Unsupported action type in HttpAdapter`,
|
|
115
|
+
and `equals`/`not_equals`/`is_null`/`not_null` all compare unconditionally. This
|
|
116
|
+
closes the asymmetry rather than adding a new posture: an assertion the engine
|
|
117
|
+
**cannot evaluate** is a **failed** assertion.
|
|
118
|
+
|
|
119
|
+
The message is written for the author who has to act on it, so it names the
|
|
120
|
+
field, the operator and the runtime type of what the path actually resolved to
|
|
121
|
+
(`null` and arrays get their own names, not `typeof`'s `object`), and then says
|
|
122
|
+
which of the two things is wrong:
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
Assertion failed: body.data.items cannot be evaluated by 'contains' — expected an
|
|
126
|
+
array or a string at that path, got undefined. The path resolved to nothing — the
|
|
127
|
+
field is absent from the result, or the path is misspelled. Use 'is_null' if
|
|
128
|
+
asserting absence is what you meant.
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`undefined`/`null` point at the **fixture** (the path did not resolve, so the
|
|
132
|
+
field path or the response shape it was written against is the suspect);
|
|
133
|
+
a number, boolean or object points at the **assertion** (the path resolved
|
|
134
|
+
fine and `contains` is the wrong operator for what it found).
|
|
135
|
+
|
|
136
|
+
**Behaviour change, and its measured blast radius.** Suites that today pass a
|
|
137
|
+
`contains` against a non-array/non-string will start failing — which is the
|
|
138
|
+
point; each such assertion was asserting nothing. The in-tree radius was
|
|
139
|
+
measured on the loud build and is **zero**: `os test` is the runner's only
|
|
140
|
+
consumer, and the repository contains no Quality Protocol suite documents at
|
|
141
|
+
all (no `qa/*.test.json` anywhere; the three example apps run `vitest`, and
|
|
142
|
+
`packages/qa/*` are vitest suites that never touch `TestRunner`). No CI workflow
|
|
143
|
+
invokes `os test`. So no in-repo case was passing vacuously and none needed
|
|
144
|
+
repair. Downstream suites are the ones that will see red, and every case they
|
|
145
|
+
see is a test that was never running.
|
|
146
|
+
|
|
147
|
+
The two evaluable shapes are untouched in both directions: a matching array or
|
|
148
|
+
string still passes, a non-matching one still fails with its existing message.
|
|
149
|
+
`not_contains`, `gt`, `gte`, `lt`, `lte` and `error` are declared in
|
|
150
|
+
`TestAssertionTypeSchema` and still have no branch in the runner — they were
|
|
151
|
+
already refused loudly at `default:` rather than silently passed, so they do not
|
|
152
|
+
carry this defect; that gap is recorded separately and is pinned here so a later
|
|
153
|
+
implementation is a deliberate change rather than an accident.
|
|
154
|
+
|
|
155
|
+
### Patch Changes
|
|
156
|
+
|
|
157
|
+
- b127c8b: fix(spec,core): a filter placeholder is recognised by INTENT — `{TODAY()}` refuses loudly instead of comparing as a literal (#5586)
|
|
158
|
+
|
|
159
|
+
`UnknownFilterTokenError` had a hole exactly where authors fall in. Recognition
|
|
160
|
+
used the token-NAME grammar `/^\$?\{([a-zA-Z0-9_]+)\}$/`, so any placeholder
|
|
161
|
+
carrying a **non-word character** classified as "not a placeholder at all" and
|
|
162
|
+
was handed to the driver verbatim, to be compared as a literal string — the
|
|
163
|
+
silent-wrong-result failure the diagnostic exists to abolish.
|
|
164
|
+
|
|
165
|
+
The failure was inverted against the author. Measured on 17.0.0-rc.2 against a
|
|
166
|
+
four-row fixture:
|
|
167
|
+
|
|
168
|
+
| filter value | before | |
|
|
169
|
+
| ------------------------ | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
|
|
170
|
+
| `due_date < '{today}'` | 2 rows | correct — the two overdue rows |
|
|
171
|
+
| `due_date < '{TODAY}'` | throws `UnknownFilterTokenError` | diagnostic working |
|
|
172
|
+
| `due_date < '{TODAY()}'` | **4 rows** | diagnostic bypassed — literal string compare, and `'2026-…' < '{'` in lexicographic order swallowed a row due a week later |
|
|
173
|
+
|
|
174
|
+
So misspelling `{today}` as `{TODAY}` was reported by name, while misspelling it
|
|
175
|
+
as `{TODAY()}` returned the wrong rows in silence — and the parenthesised,
|
|
176
|
+
kebab-case, natural-language and dotted spellings (`{TODAY()}`,
|
|
177
|
+
`{current-user-id}`, `{30 days ago}`, `{user.id}`) are precisely what an author
|
|
178
|
+
migrating from another system's macro syntax writes first.
|
|
179
|
+
|
|
180
|
+
**Both directions of the behaviour change:**
|
|
181
|
+
|
|
182
|
+
- **Previously silent, now refuses loudly** — a filter value that is entirely
|
|
183
|
+
brace-wrapped and outside the vocabulary now throws `UnknownFilterTokenError`
|
|
184
|
+
(`code: FILTER_TOKEN_UNKNOWN`, `status: 400`) on the ObjectQL read and write
|
|
185
|
+
paths and the analytics dataset executor, and is reported as
|
|
186
|
+
`filter-token-unknown` by `objectstack build` / `validate` / `lint`. Before,
|
|
187
|
+
it reached the data engine and compared as text.
|
|
188
|
+
- **Unchanged** — `{today}` / `{current_user_id}` still resolve; `{TODAY}` still
|
|
189
|
+
refuses with the same identity; a value that merely _contains_ braces
|
|
190
|
+
(`'acme {x} deal'`), or is not ONE pair around the whole value (`{a}{b}`,
|
|
191
|
+
`{{x}}`, `{}`), is still an ordinary literal and still reaches the driver
|
|
192
|
+
untouched.
|
|
193
|
+
|
|
194
|
+
Recognition and vocabulary are now two named grammars rather than one:
|
|
195
|
+
`FILTER_TOKEN_WRAPPED_RE` (`/^\$?\{([^{}]+)\}$/`) answers "did the author mean a
|
|
196
|
+
placeholder", and `isContextToken` / `isDateMacroToken` answer "is it in the
|
|
197
|
+
vocabulary". Wide in, strict out. No escape hatch for a literal `{…}` comparand
|
|
198
|
+
ships with this: a repo-wide measurement across structured metadata, examples,
|
|
199
|
+
seed data and fixtures found zero legitimate consumers comparing a
|
|
200
|
+
brace-wrapped literal, and an escape syntax is a public micro-contract that can
|
|
201
|
+
be added the day one shows up.
|
|
202
|
+
|
|
203
|
+
Flow templates are unaffected. `interpolateFilter` in
|
|
204
|
+
`@objectstack/service-automation` already recognised the same wide shape and
|
|
205
|
+
resolves `{record.id}` / `{TODAY() + 30}` from flow variables **before** the
|
|
206
|
+
filter reaches ObjectQL; its hand-off to the engine is keyed on the token
|
|
207
|
+
vocabulary (`isKnownFilterToken`), which this change does not touch.
|
|
208
|
+
|
|
209
|
+
- d6d1a50: refactor(core): one implementation per hook-dispatch flavour, plus a paired-pin gate (#5282)
|
|
210
|
+
|
|
211
|
+
`ObjectKernel` does not extend `ObjectKernelBase` — it is a standalone
|
|
212
|
+
production kernel with its own `hooks` map, and only `LiteKernel` extends the
|
|
213
|
+
base. Lifecycle-hook dispatch therefore existed **twice**, with no shared code
|
|
214
|
+
path: the base's `triggerHook` (isolating) / `triggerHookOrThrow` (propagating) /
|
|
215
|
+
`context.trigger` on one side, and `ObjectKernel`'s private
|
|
216
|
+
`triggerShutdownHookIsolating` / `context.trigger` on the other. The two
|
|
217
|
+
isolating loops printed the same `Hook handler failed: kernel:shutdown` line
|
|
218
|
+
because someone typed it twice.
|
|
219
|
+
|
|
220
|
+
That seam produced three consecutive bugs, each the same shape — one hook name
|
|
221
|
+
meaning opposite things on the two kernels: `kernel:ready` (#5170),
|
|
222
|
+
`kernel:bootstrapped` / `kernel:listening` (#5257, where a swallowed
|
|
223
|
+
`server.listen()` failure let a process print "✅ Bootstrap complete" with
|
|
224
|
+
nothing listening), and `kernel:shutdown` in the other direction (#5274, where
|
|
225
|
+
one bad handler skipped every `destroy()`).
|
|
226
|
+
|
|
227
|
+
**No behaviour change.** The two dispatch flavours move verbatim into an
|
|
228
|
+
internal module, `packages/core/src/hook-dispatch.ts`, which both kernels now
|
|
229
|
+
call:
|
|
230
|
+
|
|
231
|
+
- `dispatchHookIsolating` — a failing handler is logged as
|
|
232
|
+
`Hook handler failed: <name>` and the remaining handlers still run.
|
|
233
|
+
- `dispatchHookPropagating` — the first failure escapes unwrapped and the
|
|
234
|
+
handlers behind it are skipped.
|
|
235
|
+
|
|
236
|
+
Every call path keeps the flavour, the log wording and the trace line it had
|
|
237
|
+
before, including the one asymmetry inside the propagating flavour:
|
|
238
|
+
`PluginContext.trigger` has never emitted the `Triggering hook: <name>` trace on
|
|
239
|
+
either kernel, so it still does not. The kernels' two `hooks` maps are
|
|
240
|
+
deliberately **not** unified, and `ObjectKernel` deliberately does **not** gain a
|
|
241
|
+
base class — both were considered and ruled out of scope.
|
|
242
|
+
|
|
243
|
+
How "no behaviour change" was proved: the paired kernel pins from #5170 / #5257 /
|
|
244
|
+
#5274 pass untouched, and deleting the shared dispatcher's error log now turns
|
|
245
|
+
**both** kernels' test files red from a single edit — a property the hand-mirrored
|
|
246
|
+
copies could not have (editing `ObjectKernel`'s private loop could never turn
|
|
247
|
+
`lite-kernel.test.ts` red).
|
|
248
|
+
|
|
249
|
+
Shared dispatch cannot cover the residual two-maps seam, so the pairing of the
|
|
250
|
+
tests is now a gate rather than a convention: `pnpm check:kernel-hook-pairs`
|
|
251
|
+
(`scripts/check-kernel-hook-pairs.mjs`, wired into the ESLint job) requires every
|
|
252
|
+
`kernel:*` hook dispatched in `packages/core/src` to be named in a test title in
|
|
253
|
+
**both** `kernel.test.ts` and `lite-kernel.test.ts`, and fails naming the hook
|
|
254
|
+
and the side that lacks it. A fifth lifecycle hook can no longer arrive paired on
|
|
255
|
+
one kernel only.
|
|
256
|
+
|
|
257
|
+
Also pinned, deliberately unchanged: `kernel:shutdown` has two dispatch paths
|
|
258
|
+
with different flavours on both kernels — the kernel's own teardown isolates,
|
|
259
|
+
while a plugin calling `ctx.trigger('kernel:shutdown')` by hand propagates.
|
|
260
|
+
Nothing in the repo triggers it by hand today, so this is dormant; it is now a
|
|
261
|
+
documented fact with a named test on each side rather than a surprise found at
|
|
262
|
+
teardown.
|
|
263
|
+
|
|
264
|
+
- d0d5205: refactor(core,plugin-audit,service-storage,plugin-reports): give the `__` operation-private-key convention a single owner (#7284)
|
|
265
|
+
|
|
266
|
+
`withoutOperationPrivateKeys` — the rule that a consumer forwarding a caller's
|
|
267
|
+
execution envelope to a question about a DIFFERENT object must first drop the
|
|
268
|
+
`__`-prefixed keys plugin-security stamped for the operation in flight — had been
|
|
269
|
+
hand-copied into three packages: `plugin-audit`'s comment access hooks (#7141),
|
|
270
|
+
`service-storage`'s attachment access hooks (#7145) and `plugin-reports`' report
|
|
271
|
+
service (#7204). Each carried its own `OPERATION_PRIVATE_KEY_PREFIX` and its own
|
|
272
|
+
doc block, and the prose had already diverged while the code still agreed — the
|
|
273
|
+
shape that makes a later divergence in behaviour hard to notice.
|
|
274
|
+
|
|
275
|
+
The helper now lives once, in `@objectstack/core`
|
|
276
|
+
(`security/operation-private-keys.ts`), exported from the package root. Core is
|
|
277
|
+
the only candidate all three consumers already depend on: `plugin-security` is
|
|
278
|
+
the producer of the convention and the most honest owner, but none of the three
|
|
279
|
+
depends on it and a string-prefix filter does not justify three new dependency
|
|
280
|
+
edges onto a plugin; `@objectstack/spec` is fenced off by Prime Directive #2. The
|
|
281
|
+
new home sits beside `assemble-execution-context.ts`, which owns the other end of
|
|
282
|
+
the same lifecycle — that file is where an `ExecutionContext` is built at a
|
|
283
|
+
transport entry point, this one is where it is stripped back down before being
|
|
284
|
+
forwarded.
|
|
285
|
+
|
|
286
|
+
The full reasoning moved with the code rather than being thinned: which keys the
|
|
287
|
+
middleware stamps and why each is a widening input, why they are dropped by
|
|
288
|
+
PREFIX and never by a name list, and why the fresh copy is load-bearing in both
|
|
289
|
+
directions. Each consumer keeps only its own local half — which object _its_
|
|
290
|
+
gates actually ask about — and points at the shared home.
|
|
291
|
+
|
|
292
|
+
No behaviour change: the three copies were byte-equivalent, and all three
|
|
293
|
+
packages' suites pass unchanged. Two new pins at the home cover it — the rule's
|
|
294
|
+
own behaviour, which no package-level test had ever asserted directly, and a
|
|
295
|
+
repository-shape pin that turns red if a fourth file declares its own copy.
|
|
296
|
+
|
|
297
|
+
- Updated dependencies [3d5c090]
|
|
298
|
+
- Updated dependencies [e5bd768]
|
|
299
|
+
- Updated dependencies [e027b3e]
|
|
300
|
+
- Updated dependencies [c2429b0]
|
|
301
|
+
- Updated dependencies [445a0c2]
|
|
302
|
+
- Updated dependencies [f6609e6]
|
|
303
|
+
- Updated dependencies [a70358a]
|
|
304
|
+
- Updated dependencies [97e7e3c]
|
|
305
|
+
- Updated dependencies [8828b9e]
|
|
306
|
+
- Updated dependencies [53068c1]
|
|
307
|
+
- Updated dependencies [ee58392]
|
|
308
|
+
- Updated dependencies [f16e54e]
|
|
309
|
+
- Updated dependencies [06be54e]
|
|
310
|
+
- Updated dependencies [259459d]
|
|
311
|
+
- Updated dependencies [3f7f14e]
|
|
312
|
+
- Updated dependencies [6968885]
|
|
313
|
+
- Updated dependencies [eaed61f]
|
|
314
|
+
- Updated dependencies [debe2f6]
|
|
315
|
+
- Updated dependencies [97b0798]
|
|
316
|
+
- Updated dependencies [43a7a8d]
|
|
317
|
+
- Updated dependencies [73f69dc]
|
|
318
|
+
- Updated dependencies [04c56aa]
|
|
319
|
+
- Updated dependencies [b3efeb7]
|
|
320
|
+
- Updated dependencies [ddd075a]
|
|
321
|
+
- Updated dependencies [88154be]
|
|
322
|
+
- Updated dependencies [e8dc61e]
|
|
323
|
+
- Updated dependencies [2f3e793]
|
|
324
|
+
- Updated dependencies [d8e8d9c]
|
|
325
|
+
- Updated dependencies [94e749b]
|
|
326
|
+
- Updated dependencies [ea1d916]
|
|
327
|
+
- Updated dependencies [ae31a19]
|
|
328
|
+
- Updated dependencies [e0f300b]
|
|
329
|
+
- Updated dependencies [62b6a2f]
|
|
330
|
+
- Updated dependencies [5b4780b]
|
|
331
|
+
- Updated dependencies [a933452]
|
|
332
|
+
- Updated dependencies [8140915]
|
|
333
|
+
- Updated dependencies [7b48cf9]
|
|
334
|
+
- Updated dependencies [b5404f4]
|
|
335
|
+
- Updated dependencies [f764691]
|
|
336
|
+
- Updated dependencies [e120a5a]
|
|
337
|
+
- Updated dependencies [e650d67]
|
|
338
|
+
- Updated dependencies [04476e7]
|
|
339
|
+
- Updated dependencies [79228cd]
|
|
340
|
+
- Updated dependencies [b3363e9]
|
|
341
|
+
- Updated dependencies [2ef1807]
|
|
342
|
+
- Updated dependencies [d03fe25]
|
|
343
|
+
- Updated dependencies [2672f85]
|
|
344
|
+
- Updated dependencies [11066f6]
|
|
345
|
+
- Updated dependencies [916af17]
|
|
346
|
+
- Updated dependencies [84c86fb]
|
|
347
|
+
- Updated dependencies [2a2a9fb]
|
|
348
|
+
- Updated dependencies [a2e157c]
|
|
349
|
+
- Updated dependencies [95c4227]
|
|
350
|
+
- Updated dependencies [2a61116]
|
|
351
|
+
- Updated dependencies [d4df105]
|
|
352
|
+
- Updated dependencies [e2798fa]
|
|
353
|
+
- Updated dependencies [0fd8556]
|
|
354
|
+
- Updated dependencies [74155c7]
|
|
355
|
+
- Updated dependencies [6908830]
|
|
356
|
+
- Updated dependencies [8b06bba]
|
|
357
|
+
- Updated dependencies [4c54037]
|
|
358
|
+
- Updated dependencies [0f7157b]
|
|
359
|
+
- Updated dependencies [d9bef45]
|
|
360
|
+
- Updated dependencies [f549a0d]
|
|
361
|
+
- Updated dependencies [82da264]
|
|
362
|
+
- Updated dependencies [9b9b70f]
|
|
363
|
+
- Updated dependencies [f5a9bc2]
|
|
364
|
+
- Updated dependencies [881a3cc]
|
|
365
|
+
- Updated dependencies [ad6317b]
|
|
366
|
+
- Updated dependencies [8a88885]
|
|
367
|
+
- Updated dependencies [5f7669e]
|
|
368
|
+
- Updated dependencies [becbe53]
|
|
369
|
+
- Updated dependencies [b127c8b]
|
|
370
|
+
- Updated dependencies [a80302a]
|
|
371
|
+
- Updated dependencies [474f131]
|
|
372
|
+
- Updated dependencies [050cd82]
|
|
373
|
+
- Updated dependencies [4d552af]
|
|
374
|
+
- Updated dependencies [44d677c]
|
|
375
|
+
- Updated dependencies [c32944d]
|
|
376
|
+
- Updated dependencies [1dd780f]
|
|
377
|
+
- Updated dependencies [c8d6f6e]
|
|
378
|
+
- Updated dependencies [92a67f2]
|
|
379
|
+
- Updated dependencies [9136327]
|
|
380
|
+
- Updated dependencies [bf0ae99]
|
|
381
|
+
- Updated dependencies [cb3b6cd]
|
|
382
|
+
- Updated dependencies [73b7234]
|
|
383
|
+
- Updated dependencies [d2b97c3]
|
|
384
|
+
- Updated dependencies [59b794f]
|
|
385
|
+
- Updated dependencies [fc3a36a]
|
|
386
|
+
- Updated dependencies [69787f0]
|
|
387
|
+
- Updated dependencies [5d022a1]
|
|
388
|
+
- Updated dependencies [042b9ee]
|
|
389
|
+
- Updated dependencies [f549a0d]
|
|
390
|
+
- Updated dependencies [a36db28]
|
|
391
|
+
- Updated dependencies [3f8817a]
|
|
392
|
+
- Updated dependencies [a2443e3]
|
|
393
|
+
- Updated dependencies [e1554b1]
|
|
394
|
+
- Updated dependencies [4856789]
|
|
395
|
+
- Updated dependencies [c3f4916]
|
|
396
|
+
- Updated dependencies [33e0385]
|
|
397
|
+
- Updated dependencies [2205363]
|
|
398
|
+
- Updated dependencies [09fe58d]
|
|
399
|
+
- Updated dependencies [d0a5ceb]
|
|
400
|
+
- Updated dependencies [e18a162]
|
|
401
|
+
- Updated dependencies [d127ff0]
|
|
402
|
+
- Updated dependencies [9b86cf6]
|
|
403
|
+
- Updated dependencies [8825a06]
|
|
404
|
+
- Updated dependencies [5087ac6]
|
|
405
|
+
- Updated dependencies [2d1ddf0]
|
|
406
|
+
- Updated dependencies [354b00f]
|
|
407
|
+
- Updated dependencies [3de535b]
|
|
408
|
+
- Updated dependencies [fe2e15a]
|
|
409
|
+
- Updated dependencies [c6b6bb4]
|
|
410
|
+
- Updated dependencies [2f59da0]
|
|
411
|
+
- Updated dependencies [8ad609c]
|
|
412
|
+
- Updated dependencies [bbee302]
|
|
413
|
+
- Updated dependencies [08863dd]
|
|
414
|
+
- Updated dependencies [56664f5]
|
|
415
|
+
- Updated dependencies [31cbe90]
|
|
416
|
+
- Updated dependencies [90bbf25]
|
|
417
|
+
- Updated dependencies [eb91eba]
|
|
418
|
+
- Updated dependencies [42da73d]
|
|
419
|
+
- Updated dependencies [643b7c7]
|
|
420
|
+
- Updated dependencies [1a15893]
|
|
421
|
+
- Updated dependencies [b70e534]
|
|
422
|
+
- Updated dependencies [2233a85]
|
|
423
|
+
- Updated dependencies [62dd69a]
|
|
424
|
+
- Updated dependencies [e15e679]
|
|
425
|
+
- Updated dependencies [2ab1257]
|
|
426
|
+
- Updated dependencies [4cc4fb7]
|
|
427
|
+
- Updated dependencies [2c26040]
|
|
428
|
+
- Updated dependencies [f758cec]
|
|
429
|
+
- Updated dependencies [78f0be8]
|
|
430
|
+
- Updated dependencies [35f7fb4]
|
|
431
|
+
- Updated dependencies [a5302c7]
|
|
432
|
+
- Updated dependencies [7084313]
|
|
433
|
+
- Updated dependencies [0e043d8]
|
|
434
|
+
- Updated dependencies [dadd1ad]
|
|
435
|
+
- Updated dependencies [2f2e63c]
|
|
436
|
+
- Updated dependencies [486d526]
|
|
437
|
+
- Updated dependencies [89d7b35]
|
|
438
|
+
- Updated dependencies [85ec26d]
|
|
439
|
+
- Updated dependencies [f6476fc]
|
|
440
|
+
- Updated dependencies [4ac12ef]
|
|
441
|
+
- Updated dependencies [b88f5e8]
|
|
442
|
+
- Updated dependencies [42cc219]
|
|
443
|
+
- Updated dependencies [d7e0b42]
|
|
444
|
+
- Updated dependencies [3510e4a]
|
|
445
|
+
- Updated dependencies [aa4b90d]
|
|
446
|
+
- Updated dependencies [54299ca]
|
|
447
|
+
- Updated dependencies [dc61def]
|
|
448
|
+
- Updated dependencies [251e888]
|
|
449
|
+
- Updated dependencies [183b4c4]
|
|
450
|
+
- Updated dependencies [2fdb36e]
|
|
451
|
+
- Updated dependencies [20526f5]
|
|
452
|
+
- Updated dependencies [c5eef1d]
|
|
453
|
+
- Updated dependencies [e0f300b]
|
|
454
|
+
- Updated dependencies [761a0ba]
|
|
455
|
+
- Updated dependencies [be87153]
|
|
456
|
+
- Updated dependencies [60f0dd8]
|
|
457
|
+
- Updated dependencies [a87c5cd]
|
|
458
|
+
- Updated dependencies [a47f338]
|
|
459
|
+
- Updated dependencies [2598216]
|
|
460
|
+
- Updated dependencies [2c7e62d]
|
|
461
|
+
- Updated dependencies [eb7613c]
|
|
462
|
+
- Updated dependencies [ecc9110]
|
|
463
|
+
- Updated dependencies [f7bd4e2]
|
|
464
|
+
- Updated dependencies [361bd5b]
|
|
465
|
+
- Updated dependencies [1818998]
|
|
466
|
+
- Updated dependencies [09ee21c]
|
|
467
|
+
- Updated dependencies [f549a0d]
|
|
468
|
+
- Updated dependencies [3fc2e48]
|
|
469
|
+
- Updated dependencies [e8f435c]
|
|
470
|
+
- Updated dependencies [41610f6]
|
|
471
|
+
- @objectstack/spec@17.0.0-rc.6
|
|
472
|
+
|
|
473
|
+
## 17.0.0-rc.5
|
|
474
|
+
|
|
475
|
+
### Minor Changes
|
|
476
|
+
|
|
477
|
+
- 1363084: feat(spec,objectql): `engine.transaction` 契约收紧第一批 —— `opts.require` fail-closed 与 `owned` 信号 (#5696)
|
|
478
|
+
|
|
479
|
+
`IObjectQLEngine.transaction` 的声明面(`packages/spec/src/contracts/objectql-engine.ts`,
|
|
480
|
+
ADR-0119 D1)此前把「默认驱动之外的对象写在事务外」与「驱动没有 `beginTransaction`
|
|
481
|
+
时静默降级」写成**声明语义**的一部分。#4619 把这两条降级变得可观测(PR #5724),本次
|
|
482
|
+
把其中两条收紧为调用方可选的契约,并同步修订 TSDoc 的事实性偏差。
|
|
483
|
+
|
|
484
|
+
**新增(可选,默认行为完全不变):**
|
|
485
|
+
|
|
486
|
+
- `transaction(cb, base, { require: true })` —— 驱动没有 `beginTransaction` 时
|
|
487
|
+
**抛 `TransactionUnsupportedError`(`code: 'ERR_TRANSACTION_UNSUPPORTED'`)**,
|
|
488
|
+
而不是静默降级成「无事务、无回滚」。在回调运行**之前**拒绝,所以调用方收到错误时
|
|
489
|
+
一行都还没写。这是把 `batchData` 的 atomic 门(ADR-0119 D4)泛化成通用能力:
|
|
490
|
+
只为「开事务的唯一理由就是回滚」的调用方而设,不传 `require` 的行为一字未变
|
|
491
|
+
(仍然降级 + warn-once)。
|
|
492
|
+
- 回调的**第二个参数** `{ owned: boolean }` —— `true` 表示本次调用开启了事务并拥有
|
|
493
|
+
提交/回滚,`false` 表示它 **join** 了外层已开的 ambient 事务(ADR-0067 D2),
|
|
494
|
+
或者处在降级路径上(那里根本没有事务可拥有)。join 语义本身正确且保留;缺的是
|
|
495
|
+
调用方**无从分辨**,而「整体一起回滚」这类担保只在 owned 时成立。单参数回调不受影响。
|
|
496
|
+
|
|
497
|
+
两点在 `ctx.api.transaction`(`ScopedContext.transaction`,沙箱 hook/action 体)上
|
|
498
|
+
同样生效 —— 同一个原语的第二份实现不该变成第二种方言。
|
|
499
|
+
|
|
500
|
+
**契约文本修订:** transaction 的 TSDoc 原先写「路由到别处的对象在事务**外**写入」,
|
|
501
|
+
实测不符 —— 引擎无条件把 ambient 事务句柄穿给了目标驱动,语句在**错误的连接**上执行
|
|
502
|
+
(#5351 在真 SQL driver 上实测为 `no such table`)。TSDoc 已按实测改写,并声明了随后
|
|
503
|
+
落地的两条语义:业务写跨驱动**响亮拒绝**、系统账本(`lifecycle.class` 为
|
|
504
|
+
`audit`/`telemetry`/`event`)**移出事务执行**。
|
|
505
|
+
|
|
506
|
+
**类型面:** `@objectstack/core` 的 `EngineWithTransaction` 从「手抄签名」改为
|
|
507
|
+
`transaction: IObjectQLEngine['transaction']`,窄接口可以窄,但不能与真签名漂移。
|
|
508
|
+
新导出 `EngineTransactionOptions` / `EngineTransactionInfo`(spec `contracts` 命名空间,
|
|
509
|
+
经 `@objectstack/core` 转出)。
|
|
510
|
+
|
|
511
|
+
升级须知:无破坏性变更。既有调用点全部保持原行为;要 fail-closed 的调用方显式传
|
|
512
|
+
`{ require: true }`。
|
|
513
|
+
|
|
514
|
+
### Patch Changes
|
|
515
|
+
|
|
516
|
+
- Updated dependencies [e8f8f6c]
|
|
517
|
+
- Updated dependencies [7f713b6]
|
|
518
|
+
- Updated dependencies [c960170]
|
|
519
|
+
- Updated dependencies [def5919]
|
|
520
|
+
- Updated dependencies [ce0cfe9]
|
|
521
|
+
- Updated dependencies [1363084]
|
|
522
|
+
- @objectstack/spec@17.0.0-rc.5
|
|
523
|
+
|
|
3
524
|
## 17.0.0-rc.4
|
|
4
525
|
|
|
5
526
|
### Major Changes
|