@objectstack/core 17.0.0-rc.5 → 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 CHANGED
@@ -1,5 +1,475 @@
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
+
3
473
  ## 17.0.0-rc.5
4
474
 
5
475
  ### Minor Changes