@objectstack/core 17.0.0-rc.0 → 17.0.0-rc.2
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 +3295 -0
- package/dist/index.cjs +659 -101
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +454 -19
- package/dist/index.d.ts +454 -19
- package/dist/index.js +642 -97
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,3295 @@
|
|
|
1
|
+
# @objectstack/core
|
|
2
|
+
|
|
3
|
+
## 17.0.0-rc.2
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 98877c9: feat(core,platform-objects,spec): the ADR-0119 D2 migration-journal runner — a migration killed mid-run is resumable to completion or compensable to clean, with journal rows proving which (#4617)
|
|
8
|
+
|
|
9
|
+
**The gap D1 left open.** ADR-0119 D1 made `engine.transaction()` reachable
|
|
10
|
+
through the contract, which is the right answer for multi-write atomicity that
|
|
11
|
+
fits in one transaction. Migration-class work does not fit: a million-row
|
|
12
|
+
backfill cannot hold one write-lock for its duration, `driver-memory`'s
|
|
13
|
+
`beginTransaction` deep-clones the entire database (O(db) per begin),
|
|
14
|
+
`ObjectQL.transaction()` binds the **default driver only** so a multi-datasource
|
|
15
|
+
migration silently commits part of its work outside it, and a process **killed**
|
|
16
|
+
— as distinct from a thrown error — defeats in-process rollback entirely. So the
|
|
17
|
+
unit of atomicity is the _chunk_, and durability across chunks is a journal.
|
|
18
|
+
|
|
19
|
+
Four consumers had each converged on the same four moves — dry-run preflight,
|
|
20
|
+
undo journal, LIFO compensation, re-entrant forward recovery (ADR-0105 D13
|
|
21
|
+
promotion, ADR-0117 D8's ownership backfill, the org lifecycle transitions, and
|
|
22
|
+
D10 master-data distribution #4585). One copy is engineering; four is platform
|
|
23
|
+
debt, and the fourth author would have had to rediscover the invariant below
|
|
24
|
+
from scratch.
|
|
25
|
+
|
|
26
|
+
**New: `runMigrationJournal` (`@objectstack/core`).** Preflight runs every
|
|
27
|
+
step's read-only validator before any step writes, so a plan that would fail at
|
|
28
|
+
step 3 has not written step 1. Rows are chunked per the `bulk-write.ts`
|
|
29
|
+
discipline; each chunk's writes run inside `engine.transaction()`. On failure,
|
|
30
|
+
committed chunks are compensated newest-first, each in its own transaction. On
|
|
31
|
+
restart, a rediscovered run resumes forward from the first chunk lacking
|
|
32
|
+
`chunk_done`, or unwinds, per the plan's `onCrash` policy. Forward and
|
|
33
|
+
compensate callbacks receive an `attempt` counter; `attempt > 1` means the prior
|
|
34
|
+
outcome is UNKNOWN and the callback must recheck by natural key before
|
|
35
|
+
re-writing — the same at-least-once contract `bulk-write.ts` already documents,
|
|
36
|
+
reused rather than re-derived.
|
|
37
|
+
|
|
38
|
+
**The invariant that carries the design:** `chunk_done(i)` is written **inside**
|
|
39
|
+
the chunk's own transaction, so `done ⇔ committed` holds by construction;
|
|
40
|
+
`chunk_started(i)` is written autonomously **before** it. That asymmetry is what
|
|
41
|
+
gives `started ∧ ¬done` exactly one meaning — _the outcome is unknown_ — which
|
|
42
|
+
is the only state a crash can leave and the only state recovery reasons about.
|
|
43
|
+
Making both writes symmetric would look tidier and would destroy recovery.
|
|
44
|
+
|
|
45
|
+
**New: `sys_migration_journal` (`@objectstack/platform-objects`).** Rows keyed
|
|
46
|
+
`(run_id, seq)` under a unique index, so a resumed run that miscomputes its next
|
|
47
|
+
sequence fails loudly rather than double-recording an event. Registered
|
|
48
|
+
unconditionally alongside `sys_migration` because recovery must be discoverable
|
|
49
|
+
with **zero host wiring** — a journal some kernels compose and others do not is
|
|
50
|
+
a journal a boot scanner cannot rely on (ADR-0078). Distinct in grain from
|
|
51
|
+
`sys_migration`, which holds one durable verdict per named migration; this holds
|
|
52
|
+
many rows per _run_. Read-only over the API; writes go through the runner in
|
|
53
|
+
system context.
|
|
54
|
+
|
|
55
|
+
**The runner refuses rather than degrades**, in four places: the runtime cannot
|
|
56
|
+
roll back; any preflight fails; the plan declares `onCrash: 'compensate'` but a
|
|
57
|
+
step cannot compensate; or a resume's plan hash disagrees with the journal
|
|
58
|
+
(resuming a changed plan would apply chunk boundaries the journal never
|
|
59
|
+
described). A compensation failure halts and is journalled — never swallowed —
|
|
60
|
+
and the run ends `failed`, not `compensated`, because a database in a state no
|
|
61
|
+
clean story covers must not be reported as a tidy rollback.
|
|
62
|
+
|
|
63
|
+
**`engineCanRollBack` is now shared.** The two-level probe (engine method AND
|
|
64
|
+
default-driver `beginTransaction`) was the same condition written twice — here
|
|
65
|
+
and in `batchData`'s atomic gate. It now lives in `@objectstack/core` and
|
|
66
|
+
`@objectstack/metadata-protocol` imports it, as a type predicate so callers do
|
|
67
|
+
not each re-narrow the optional member by hand. Two copies of "can this runtime
|
|
68
|
+
actually roll back?" drift by one clause and leave one caller believing it has
|
|
69
|
+
atomicity it does not have.
|
|
70
|
+
|
|
71
|
+
Boot reconciliation and `os migrate resume` land separately; `findInterruptedRuns`
|
|
72
|
+
is the discovery primitive they will consume, and is exported here.
|
|
73
|
+
|
|
74
|
+
**Docs:** ADR-0118 (plugin-reachable transactions) is renumbered **ADR-0119**.
|
|
75
|
+
It merged one day after an unrelated ADR-0118 (非用户 actor 的平台契约) and the
|
|
76
|
+
earlier merge holds the number; citations of "ADR-0118 D1/D2/D3/D4" written
|
|
77
|
+
before 2026-08-03 mean the renumbered record.
|
|
78
|
+
|
|
79
|
+
- 071d0dc: feat(runtime,cli,core): boot reconciliation and `os migrate resume` for the migration journal — an interrupted run can no longer go unnoticed (ADR-0119 D2, #4617)
|
|
80
|
+
|
|
81
|
+
Completes ADR-0119 D2. The runner and `sys_migration_journal` landed in #4668; this is the discovery channel that makes an interrupted run findable by someone who does not already know it happened.
|
|
82
|
+
|
|
83
|
+
**`MigrationRecoveryPlugin` (`@objectstack/runtime`)** — at `kernel:ready`, scans the journal for runs that started and never concluded, and warns per run: how many chunks committed, which have an **unknown** outcome (`chunk_started` with no `chunk_done`), whether a compensation was left half-finished, and the exact command that will act. It also owns the `migration-plans` registry service.
|
|
84
|
+
|
|
85
|
+
**`os migrate resume` (`@objectstack/cli`)** — lists interrupted runs (read-only, the default), or acts on one with `--run <id>`, under confirmation. Exits non-zero when a run ends `failed`, so a scripted recovery cannot move on from a migration that needs a human.
|
|
86
|
+
|
|
87
|
+
**`MigrationPlanRegistry` (`@objectstack/core`)** — where a resume finds the plan it has to re-run.
|
|
88
|
+
|
|
89
|
+
## Boot discovers, the CLI acts
|
|
90
|
+
|
|
91
|
+
This is the design decision, and it is deliberate rather than incidental.
|
|
92
|
+
|
|
93
|
+
Resuming is a large, irreversible, potentially hour-long write against production data. Doing that as an unrequested side effect of a process starting is the kind of behaviour an operator finds out about from a graph. It is also not always possible at boot: a resume needs the plan's live callbacks, and the package that owns them may not be loaded in whichever process happened to restart first.
|
|
94
|
+
|
|
95
|
+
So boot surfaces the run and names the command; the command acts, under explicit operator intent. ADR-0119 D2's per-plan `onCrash` policy still decides **what** acting means — resume forward from the first chunk lacking `chunk_done`, or unwind what committed — it just does not decide **when**, and "when" is the part a human should own.
|
|
96
|
+
|
|
97
|
+
Deferring is safe precisely because of the runner's re-entrancy: `started ∧ ¬done` is durable, so an interrupted run stays exactly as recoverable an hour later as it was at boot. Nothing decays while the operator decides.
|
|
98
|
+
|
|
99
|
+
## Why a plan registry exists at all
|
|
100
|
+
|
|
101
|
+
A journal cannot hold a plan. `forward` and `compensate` are functions and `load()` reads the live database, so none of it crosses a process boundary — which is why the journal records the plan **hash**, not the plan. Recovery therefore needs the plan handed back by the code that owns it, and `migration-plans` is that seam: between "the journal knows a run stopped at chunk 7" and "something in this process knows what chunk 7 was supposed to do".
|
|
102
|
+
|
|
103
|
+
A run whose plan no loaded package registers is **reported**, never silently skipped — the operator is told which plan id is missing. "Nothing to resume" and "the code that owns this run is not here" are different facts, and only one of them is safe to ignore.
|
|
104
|
+
|
|
105
|
+
## Degradation
|
|
106
|
+
|
|
107
|
+
No engine, or no `sys_migration_journal` registered (a lean kernel that never composed platform-objects) → the scan is skipped in **silence**: such a kernel has no interrupted runs to find, and a warning there would train operators to ignore this plugin's output, which is the one thing it cannot afford. A scan that **fails**, by contrast, is reported — "I could not check" and "there is nothing to find" are different answers.
|
|
108
|
+
|
|
109
|
+
11 new tests pin the split (boot writes nothing to the journal), the three states an operator must tell apart (clean / interrupted / half-unwound), and both degradation paths.
|
|
110
|
+
|
|
111
|
+
### Patch Changes
|
|
112
|
+
|
|
113
|
+
- 833b512: fix(core): 插件 init/start 的超时守卫定时器在 race 结束时被清除,进程不再空转 `startupTimeout` (#4813)
|
|
114
|
+
|
|
115
|
+
`ObjectKernel.initPluginWithTimeout()` / `startPluginWithTimeout()` 各自 `setTimeout` armed
|
|
116
|
+
一根超时守卫,然后**把它扔了**:插件赢下 race 之后,那根定时器既没 `clearTimeout` 也没
|
|
117
|
+
`unref()`,带着 ref 一直挂到 `startupTimeout` 走完。于是每个进程在活干完之后还要空转整整
|
|
118
|
+
一个 `startupTimeout` —— `ObjectQLPlugin` 是 120 秒。
|
|
119
|
+
|
|
120
|
+
实测(`examples/app-crm`,同一条 `migrate recorded-by --json`,同一个构建链,唯一差别是本
|
|
121
|
+
改动):
|
|
122
|
+
|
|
123
|
+
| | 墙钟 |
|
|
124
|
+
| :----- | :----- |
|
|
125
|
+
| 修复前 | 122.4s |
|
|
126
|
+
| 修复后 | 3.1s |
|
|
127
|
+
|
|
128
|
+
JSON 与 `✅ Graceful shutdown complete` 两次都在 ~3 秒出现 —— 后面那 119 秒纯粹是 8 根
|
|
129
|
+
孤儿定时器(4 个 init + 4 个 start)钉着事件循环。`os serve` 里同样漏,只是那里进程本来
|
|
130
|
+
就长命,看不出来。
|
|
131
|
+
|
|
132
|
+
**为什么是 `clearTimeout` 而不是 `unref()`。** 隔壁 `shutdown()` 的守卫用的是 `unref()`,
|
|
133
|
+
但那个写法在这里是错的,而且不是风格问题:`unref()` 让定时器不再钉住事件循环,**同时也
|
|
134
|
+
让它不再是一个守卫** —— 若 hook 永不 settle 且没有别的东西撑着事件循环,Node 会在定时器
|
|
135
|
+
触发之前直接退出,超时被**静默吞掉**,谁也不会收到那个 error。守卫必须在 race 未决期间
|
|
136
|
+
保持 ref'd,在 race 落定的那一刻被回收,这正是 `finally { clearTimeout(guard) }` 表达的
|
|
137
|
+
语义。两个守卫合并为一个私有 helper `raceStartupTimeout()`,措辞与理由写在它的 doc
|
|
138
|
+
comment 里。
|
|
139
|
+
|
|
140
|
+
`startupTimeout` 的取值一个都没动 —— 慢启动的插件需要那个上限,问题从来不在时长,而在
|
|
141
|
+
没人回收。
|
|
142
|
+
|
|
143
|
+
- Updated dependencies [430dcc2]
|
|
144
|
+
- Updated dependencies [e6ac4bd]
|
|
145
|
+
- Updated dependencies [80334c7]
|
|
146
|
+
- Updated dependencies [ce5242c]
|
|
147
|
+
- Updated dependencies [a7163ea]
|
|
148
|
+
- Updated dependencies [e6e9379]
|
|
149
|
+
- Updated dependencies [98877c9]
|
|
150
|
+
- Updated dependencies [98877c9]
|
|
151
|
+
- Updated dependencies [e6b1b69]
|
|
152
|
+
- Updated dependencies [ad047d2]
|
|
153
|
+
- Updated dependencies [2826d1e]
|
|
154
|
+
- Updated dependencies [5a84d41]
|
|
155
|
+
- Updated dependencies [20b1a9e]
|
|
156
|
+
- Updated dependencies [203a449]
|
|
157
|
+
- Updated dependencies [ac37fc6]
|
|
158
|
+
- Updated dependencies [4820f55]
|
|
159
|
+
- Updated dependencies [462d9c4]
|
|
160
|
+
- Updated dependencies [7d21581]
|
|
161
|
+
- Updated dependencies [f2445c9]
|
|
162
|
+
- Updated dependencies [23338c3]
|
|
163
|
+
- Updated dependencies [5b843fb]
|
|
164
|
+
- Updated dependencies [b4487aa]
|
|
165
|
+
- Updated dependencies [65ca83a]
|
|
166
|
+
- Updated dependencies [67bf2e2]
|
|
167
|
+
- Updated dependencies [c6d1cb4]
|
|
168
|
+
- Updated dependencies [36030ff]
|
|
169
|
+
- Updated dependencies [6117f7b]
|
|
170
|
+
- Updated dependencies [e533b0b]
|
|
171
|
+
- Updated dependencies [cdf4d9a]
|
|
172
|
+
- Updated dependencies [aee1806]
|
|
173
|
+
- Updated dependencies [c13350b]
|
|
174
|
+
- Updated dependencies [c13350b]
|
|
175
|
+
- Updated dependencies [9ca2d85]
|
|
176
|
+
- Updated dependencies [c13350b]
|
|
177
|
+
- Updated dependencies [891d345]
|
|
178
|
+
- Updated dependencies [a52e2ef]
|
|
179
|
+
- Updated dependencies [5293114]
|
|
180
|
+
- Updated dependencies [20bc357]
|
|
181
|
+
- Updated dependencies [5966c2a]
|
|
182
|
+
- Updated dependencies [2382580]
|
|
183
|
+
- Updated dependencies [d9fa683]
|
|
184
|
+
- Updated dependencies [3c7bcc0]
|
|
185
|
+
- Updated dependencies [4b6cac7]
|
|
186
|
+
- Updated dependencies [7631964]
|
|
187
|
+
- Updated dependencies [ac471a0]
|
|
188
|
+
- Updated dependencies [60ae58e]
|
|
189
|
+
- Updated dependencies [ce92674]
|
|
190
|
+
- Updated dependencies [9f601e8]
|
|
191
|
+
- Updated dependencies [51c5227]
|
|
192
|
+
- Updated dependencies [a4a85c8]
|
|
193
|
+
- Updated dependencies [07a4e26]
|
|
194
|
+
- Updated dependencies [ec975f1]
|
|
195
|
+
- Updated dependencies [eb4204b]
|
|
196
|
+
- Updated dependencies [4f13be2]
|
|
197
|
+
- Updated dependencies [61cc079]
|
|
198
|
+
- Updated dependencies [0e96e46]
|
|
199
|
+
- Updated dependencies [d52d4fe]
|
|
200
|
+
- Updated dependencies [742cebb]
|
|
201
|
+
- Updated dependencies [ce92674]
|
|
202
|
+
- Updated dependencies [cf2c9b7]
|
|
203
|
+
- Updated dependencies [0f9faa2]
|
|
204
|
+
- Updated dependencies [7cf42fe]
|
|
205
|
+
- Updated dependencies [5966c2a]
|
|
206
|
+
- Updated dependencies [f78dd83]
|
|
207
|
+
- Updated dependencies [a2cd18a]
|
|
208
|
+
- Updated dependencies [4638aaa]
|
|
209
|
+
- Updated dependencies [0222d3c]
|
|
210
|
+
- Updated dependencies [0a936ea]
|
|
211
|
+
- Updated dependencies [023c00b]
|
|
212
|
+
- Updated dependencies [155507e]
|
|
213
|
+
- Updated dependencies [7bba90b]
|
|
214
|
+
- Updated dependencies [7e05d8e]
|
|
215
|
+
- Updated dependencies [061406d]
|
|
216
|
+
- Updated dependencies [c1f344b]
|
|
217
|
+
- Updated dependencies [9c93465]
|
|
218
|
+
- Updated dependencies [ebb209c]
|
|
219
|
+
- Updated dependencies [63b33e6]
|
|
220
|
+
- Updated dependencies [2a44c1d]
|
|
221
|
+
- Updated dependencies [695cfbd]
|
|
222
|
+
- Updated dependencies [7445149]
|
|
223
|
+
- Updated dependencies [071d0dc]
|
|
224
|
+
- Updated dependencies [0848bea]
|
|
225
|
+
- Updated dependencies [d51bed2]
|
|
226
|
+
- Updated dependencies [b8b3c64]
|
|
227
|
+
- Updated dependencies [0c0fbd9]
|
|
228
|
+
- Updated dependencies [f3141d8]
|
|
229
|
+
- Updated dependencies [5a84d41]
|
|
230
|
+
- Updated dependencies [fd3013a]
|
|
231
|
+
- Updated dependencies [21676eb]
|
|
232
|
+
- Updated dependencies [e336549]
|
|
233
|
+
- Updated dependencies [d40f43a]
|
|
234
|
+
- Updated dependencies [e5e7ee0]
|
|
235
|
+
- Updated dependencies [a2ebea2]
|
|
236
|
+
- Updated dependencies [800bdb0]
|
|
237
|
+
- Updated dependencies [04f1182]
|
|
238
|
+
- Updated dependencies [5647006]
|
|
239
|
+
- Updated dependencies [38f7e4f]
|
|
240
|
+
- Updated dependencies [c57f3cf]
|
|
241
|
+
- Updated dependencies [97faca3]
|
|
242
|
+
- Updated dependencies [ad5fe25]
|
|
243
|
+
- Updated dependencies [ea90179]
|
|
244
|
+
- Updated dependencies [ce92674]
|
|
245
|
+
- Updated dependencies [5ef0b5b]
|
|
246
|
+
- Updated dependencies [48fbacb]
|
|
247
|
+
- Updated dependencies [355e951]
|
|
248
|
+
- Updated dependencies [dadb43f]
|
|
249
|
+
- @objectstack/spec@17.0.0-rc.2
|
|
250
|
+
|
|
251
|
+
## 17.0.0-rc.1
|
|
252
|
+
|
|
253
|
+
### Minor Changes
|
|
254
|
+
|
|
255
|
+
- 32ccb23: feat(spec,core,runtime)!: ADR-0112 batch 1 — one error-code vocabulary, SCREAMING_SNAKE, schema-enforced (#3841)
|
|
256
|
+
|
|
257
|
+
Settles #3841 per ADR-0112: the top-level `error.code` vocabulary is
|
|
258
|
+
SCREAMING_SNAKE, in two tiers.
|
|
259
|
+
|
|
260
|
+
- **`StandardErrorCode` members renamed in place** (`validation_error` →
|
|
261
|
+
`VALIDATION_ERROR`, all 53). Breaking for importers that branch on the old
|
|
262
|
+
lowercase members; the type name and member _meanings_ are unchanged.
|
|
263
|
+
- **New `ERROR_CODE_LEDGER`** (`@objectstack/spec/api`): service-specific codes
|
|
264
|
+
(`AUTH_REQUIRED`, `VALIDATION_FAILED`, `ATTACHMENT_DOWNLOAD_DENIED`, …) are
|
|
265
|
+
registered per owning package. `ErrorCode` = standard ∪ registered.
|
|
266
|
+
- **`ApiErrorSchema.code` is now `ErrorCode`**, not `z.string()` — an
|
|
267
|
+
unregistered code fails parse, so the envelope conformance suites assert
|
|
268
|
+
values, not just shape.
|
|
269
|
+
- **`FieldErrorSchema.code` widened to `z.string()`** (ADR-0112 D6): field-level
|
|
270
|
+
codes are a separate vocabulary the enum never described; #3977 owns its real
|
|
271
|
+
catalog.
|
|
272
|
+
- **Derived codes changed case on the wire**: `standardErrorCodeForHttpStatus`
|
|
273
|
+
now yields SCREAMING members (`permission_denied` → `PERMISSION_DENIED`,
|
|
274
|
+
`method_not_allowed` → `METHOD_NOT_ALLOWED`, …) — this map was #3842's
|
|
275
|
+
designated one-file sweep point for exactly this decision.
|
|
276
|
+
- **`ANONYMOUS_DENY_CODE` is `'UNAUTHENTICATED'`** (was `'unauthenticated'`) —
|
|
277
|
+
the promoted code on anonymous-denied requests and the REST `enforceAuth`
|
|
278
|
+
body change spelling with it.
|
|
279
|
+
|
|
280
|
+
`error-catalog.mdx` and the error-handling guides are rewritten to the single
|
|
281
|
+
vocabulary; a spec test now locks the catalog page's headings to the enum so
|
|
282
|
+
they cannot drift apart again. Remaining lowercase emitters (cloud-connection,
|
|
283
|
+
plugin-auth envelope codes, metadata-protocol, …) are the batch-2 sweep.
|
|
284
|
+
|
|
285
|
+
- 0af50a3: fix(driver-sql,service-analytics): a bare-day upper bound covers the whole day on `Field.datetime` (#3777)
|
|
286
|
+
|
|
287
|
+
A bare `YYYY-MM-DD` comparand anchors to midnight UTC. That is right for a
|
|
288
|
+
lower bound and was silently wrong for an upper one: the dashboard date-range
|
|
289
|
+
filter compiles `{ $gte: from, $lte: to }` with bare-day bounds, so on a
|
|
290
|
+
`datetime` column every row created after 00:00 of the `to` day vanished from
|
|
291
|
+
the result — no error, the chart renders, the numbers are just smaller. The
|
|
292
|
+
default configuration hit it: the filter's default field is `created_at`
|
|
293
|
+
(a system-injected `Field.datetime`) and 7 of the 13 presets end "today".
|
|
294
|
+
|
|
295
|
+
The translation is operator-sensitive and half-open, applied at every
|
|
296
|
+
comparison emitter:
|
|
297
|
+
|
|
298
|
+
- `SqlDriver` (and `SqliteWasmDriver` by inheritance): `$lte`/`<=` with a
|
|
299
|
+
bare-day comparand on a `datetime` column compiles to `< next-day-midnight`
|
|
300
|
+
in the column's storage form; `$between [min, max]` with a bare-day max
|
|
301
|
+
decomposes to `>= min AND < next-day(max)`. Both the plain and the
|
|
302
|
+
legacy-repair (mixed-storage) column paths, both `where` spellings.
|
|
303
|
+
- `NativeSQLStrategy`: `dateRange` windows and `lte` filters bind `< next-day`
|
|
304
|
+
instead of an inclusive `BETWEEN`/`<=` when the bound is a bare day.
|
|
305
|
+
- The `/analytics/sql` rendering and the dataset preview evaluator apply the
|
|
306
|
+
same rule, so the echoed SQL and drafted numbers reproduce execution.
|
|
307
|
+
|
|
308
|
+
`@objectstack/core` gains the shared primitive `nextUtcCalendarDay(value)`:
|
|
309
|
+
the next calendar day of a valid bare `YYYY-MM-DD` (else `null` — instants,
|
|
310
|
+
`Date`s and impossible days are never widened).
|
|
311
|
+
|
|
312
|
+
Unchanged on purpose, per the semantics table on #3777: `date`/`time` columns
|
|
313
|
+
(`<= day` is already whole-day-correct there), full-ISO/`Date` comparands
|
|
314
|
+
(instant semantics), and `$gte`/`$gt`/`$lt` (midnight anchoring is correct for
|
|
315
|
+
those). No authored metadata changes: a dashboard's existing
|
|
316
|
+
`{ $gte, $lte }` window now simply includes its final day.
|
|
317
|
+
|
|
318
|
+
- 3c628ce: feat(auth)!: retire the `api.requireAuth` opt-out — anonymous access to object data is always denied (#3963)
|
|
319
|
+
|
|
320
|
+
`api.requireAuth: false` let a deployment open its ENTIRE data plane with one
|
|
321
|
+
config key. It is removed. Auth is a kernel concern, not a deployment posture:
|
|
322
|
+
anonymous callers are denied on every HTTP surface that reaches object data,
|
|
323
|
+
unconditionally.
|
|
324
|
+
|
|
325
|
+
Every surface that legitimately serves a session-less caller already derives its
|
|
326
|
+
own narrow authorization from a DECLARATION, so none of them needed the global
|
|
327
|
+
switch:
|
|
328
|
+
|
|
329
|
+
- control plane (`/auth/*`, `/health`, `/ready`, `/discovery`, ADR-0069
|
|
330
|
+
remediation) — the auth-gate allowlist;
|
|
331
|
+
- public form submission — `publicFormGrant` (ADR-0056 Option A);
|
|
332
|
+
- share links — the capability token, validated then read as SYSTEM;
|
|
333
|
+
- a `book.audience: 'public'` read — the ADR-0046 §6.7 audience gate (#3995);
|
|
334
|
+
- MCP — an OAuth token or API key.
|
|
335
|
+
|
|
336
|
+
**Breaking changes.**
|
|
337
|
+
|
|
338
|
+
- `api.requireAuth` is a retired key. It is tombstoned (`retiredKey`) in both
|
|
339
|
+
`RestApiConfigSchema` and the stack `api` block, so authoring it now fails with
|
|
340
|
+
a fix-it message rather than being silently stripped (the ADR-0104 / #3733
|
|
341
|
+
quiet-failure this whole line of work has been closing). `os migrate meta`
|
|
342
|
+
drops it via the protocol-17 conversion `stack-api-require-auth-removed`.
|
|
343
|
+
- `shouldDenyAnonymous` (@objectstack/core) no longer takes a `requireAuth`
|
|
344
|
+
input; it denies any anonymous, non-system caller outside the control-plane
|
|
345
|
+
allowlist.
|
|
346
|
+
- A stack that mounts **no auth at all** now FAILS AT BOOT when it would serve a
|
|
347
|
+
data API (`objectstack serve`, plugin-dev), instead of getting an explicit
|
|
348
|
+
fail-open. Enable auth (the `auth` tier or AuthPlugin), or run without the data
|
|
349
|
+
API. There is no anonymous-data carve-out any more — publishing a public
|
|
350
|
+
surface is done by declaration (see above).
|
|
351
|
+
|
|
352
|
+
**Migration.** Delete `api.requireAuth` from the stack config (or run
|
|
353
|
+
`os migrate meta`). If you were serving data publicly with `requireAuth: false`,
|
|
354
|
+
replace it with the declaration that fits: a public form view, a share link, or
|
|
355
|
+
`book.audience: 'public'`. If you have an auth-less stack that intentionally
|
|
356
|
+
served data, it must now mount auth or stop serving the data API.
|
|
357
|
+
|
|
358
|
+
- d13004a: feat(core,runtime): plugin ordering is a declared, kernel-enforced contract (ADR-0116, #4131)
|
|
359
|
+
|
|
360
|
+
`kernel.use()` registration order was never a contract — the kernel resolves
|
|
361
|
+
init/start order from the plugin dependency graph — but a plugin that needed a
|
|
362
|
+
service at init _when its provider is composed_ while also booting _without_
|
|
363
|
+
the provider had no way to declare that. `AppPlugin` was the standing example:
|
|
364
|
+
it grabs `manifest`/`objectql` synchronously in `init()`, declared nothing
|
|
365
|
+
(a hard dependency would break empty-env / metadata-only / mock-engine
|
|
366
|
+
kernels), and so its correctness rode on which array slot each caller put it
|
|
367
|
+
in. That convention failed the same way twice (`DefaultDatasourcePlugin`'s
|
|
368
|
+
first cut; then #4085, disguised for months as "crashes when the artifact is
|
|
369
|
+
missing").
|
|
370
|
+
|
|
371
|
+
The kernel `Plugin` contract gains three additive fields, enforced by both
|
|
372
|
+
`ObjectKernel` and `LiteKernel` through one shared implementation
|
|
373
|
+
(`plugin-order.ts` — the previously duplicated topological sort is unified
|
|
374
|
+
there):
|
|
375
|
+
|
|
376
|
+
- **`optionalDependencies: string[]`** — order-if-present: hoisted ahead
|
|
377
|
+
exactly like `dependencies` when composed (real topology edges, including
|
|
378
|
+
cycle detection), silently skipped when absent.
|
|
379
|
+
- **`requiresServices: string[]`** — services resolved synchronously during
|
|
380
|
+
`init()` with no fallback. Validated **before Phase 1**: a required service
|
|
381
|
+
whose only declared provider initializes later fails the boot with an error
|
|
382
|
+
naming both plugins, both slots, and the fix — before any init side
|
|
383
|
+
effects. Re-checked immediately before the plugin's own init, where a still-
|
|
384
|
+
missing service becomes a named composition error exactly where the old
|
|
385
|
+
bare `Service not found` crash fired.
|
|
386
|
+
- **`providesServices: string[]`** — services a plugin's `init()`
|
|
387
|
+
unconditionally registers; powers the validation and the diagnostics.
|
|
388
|
+
|
|
389
|
+
Plugins that declare nothing get the diagnosis too: a `getService` miss
|
|
390
|
+
during Phase 1 now appends which plugin was initializing and — when a
|
|
391
|
+
composed plugin declares the service — who provides it and how to declare the
|
|
392
|
+
ordering. The `Service '<name>' not found` prefix and the factory-backed
|
|
393
|
+
`is async - use await` message are unchanged.
|
|
394
|
+
|
|
395
|
+
First adopters: `AppPlugin` declares
|
|
396
|
+
`optionalDependencies: ['com.objectstack.engine.objectql']` +
|
|
397
|
+
`requiresServices: ['manifest']` (cleared on the empty-env no-op path), so
|
|
398
|
+
the #4085 composition — AppPlugin registered before the engine — now boots
|
|
399
|
+
correctly in every slot; `ObjectQLPlugin` declares
|
|
400
|
+
`providesServices: ['objectql', 'data', 'manifest', 'lifecycle']` and
|
|
401
|
+
`MetadataPlugin` declares `providesServices: ['metadata']`.
|
|
402
|
+
|
|
403
|
+
Everything is additive — plugins that declare nothing keep their exact
|
|
404
|
+
ordering semantics; no existing declaration changes meaning.
|
|
405
|
+
|
|
406
|
+
- e4c2dc8: Order temporal operands correctly when one side is a JS `Date` on the two
|
|
407
|
+
type-blind filter backends (ADR-0053 D-A3 / #4191).
|
|
408
|
+
|
|
409
|
+
`utcInstantMs` joins `nextUtcCalendarDay` in `@objectstack/spec/data`
|
|
410
|
+
(re-exported from `@objectstack/core`): it reads the UTC instant a temporal
|
|
411
|
+
operand denotes, accepting only unambiguous spellings — a `Date`, epoch ms, a
|
|
412
|
+
bare `YYYY-MM-DD`, and an ISO timestamp with or without an explicit zone (a
|
|
413
|
+
zone-naive one being UTC, per D-B2) — and returning `null` for everything
|
|
414
|
+
else, notably a bare wall clock, which denotes no instant.
|
|
415
|
+
|
|
416
|
+
Both type-blind evaluators now use it to compare a `Date` against wire text,
|
|
417
|
+
which JS relational operators cannot do: `<` and friends coerce with hint
|
|
418
|
+
`number`, so the `Date` becomes its epoch and the string becomes `NaN`.
|
|
419
|
+
|
|
420
|
+
- `formula`'s `matchesFilterCondition` (the RLS write-side `check`) dropped
|
|
421
|
+
every `Date`-valued row in 10 of the 16 shared conformance cases. The
|
|
422
|
+
post-image is the caller's raw write payload, so an SDK write of
|
|
423
|
+
`new Date()` hit this directly, and fail-closed turned it into a **denied
|
|
424
|
+
write**.
|
|
425
|
+
- `service-analytics`' preview evaluator diverged on the same 10 cases in
|
|
426
|
+
BOTH directions, because `String(new Date())` sorts after every `'2026-…'`
|
|
427
|
+
comparand — a drafted chart both lost rows and gained ones, then changed
|
|
428
|
+
its numbers at publish. Rows from a mongo-backed dataset arrive as BSON
|
|
429
|
+
`Date`s, so this was reachable in normal use.
|
|
430
|
+
|
|
431
|
+
Comparisons that did not involve a `Date` are unchanged.
|
|
432
|
+
|
|
433
|
+
### Patch Changes
|
|
434
|
+
|
|
435
|
+
- 2af1988: fix(formula,spec,core): the RLS write-side `check` evaluator honours calendar-day upper bounds (ADR-0053 D-D)
|
|
436
|
+
|
|
437
|
+
`@objectstack/formula`'s `matchesFilterCondition` — the evaluator behind RLS
|
|
438
|
+
write-side `check` policies (ADR-0058 D4) — compared a bare `YYYY-MM-DD` `$lte`
|
|
439
|
+
bound literally. On a `datetime` post-image that meant a policy of the shape
|
|
440
|
+
`{ signed_on: { $lte: '{today}' } }` **denied every write made after 00:00**:
|
|
441
|
+
the write-side twin of the read-side data loss #3777 fixed, and the last of the
|
|
442
|
+
platform's filter backends that disagreed about what a bare day means as a
|
|
443
|
+
bound.
|
|
444
|
+
|
|
445
|
+
`$lte` and a `$between` max now evaluate half-open against the next calendar
|
|
446
|
+
day, matching the SQL compiler, the memory and mongo drivers, and the analytics
|
|
447
|
+
preview evaluator. Unchanged, per the same semantics table: full-ISO bounds keep
|
|
448
|
+
exact-instant semantics, `$gte`/`$gt`/`$lt` keep their midnight anchoring, and a
|
|
449
|
+
plain `YYYY-MM-DD` value compares identically (string ordering makes the two
|
|
450
|
+
forms equivalent). The evaluator stays fail-closed on a null bound.
|
|
451
|
+
|
|
452
|
+
**Where the rule now lives.** `nextUtcCalendarDay` moved from
|
|
453
|
+
`@objectstack/core` to `@objectstack/spec/data` — beside `date-macros.zod.ts`,
|
|
454
|
+
whose vocabulary it interprets. `formula` cannot depend on `core`, and a second
|
|
455
|
+
copy of the rule is exactly the divergence #3777 catalogued; `spec` is the one
|
|
456
|
+
package all six consumers already depend on, so this adds no dependency edge.
|
|
457
|
+
|
|
458
|
+
No import changes are required: `@objectstack/core` re-exports the symbol, so
|
|
459
|
+
existing `import { nextUtcCalendarDay } from '@objectstack/core'` keeps working.
|
|
460
|
+
New code should prefer `@objectstack/spec/data`.
|
|
461
|
+
|
|
462
|
+
- 2e836de: chore(packaging): CHANGELOG.md ships in every npm tarball (#4261)
|
|
463
|
+
|
|
464
|
+
The AGENTS.md post-task checklist requires breaking changesets to carry their
|
|
465
|
+
FROM → TO migration because "this text ships to consumers as `CHANGELOG.md`
|
|
466
|
+
inside the npm package and is what an upgrading agent greps after the tombstone
|
|
467
|
+
error." That delivery path was severed for 68 of the 69 publishable packages:
|
|
468
|
+
npm packs `package.json` / `README*` / `LICENSE*` unconditionally but — unlike
|
|
469
|
+
older npm versions — not `CHANGELOG.md`, and the canonical
|
|
470
|
+
`"files": ["dist", "README.md"]` whitelist never named it. Measured on npm
|
|
471
|
+
10.9.7: `npm pack --dry-run` on `@objectstack/types` shipped 3 files while its
|
|
472
|
+
70KB `CHANGELOG.md` stayed behind. Only `@objectstack/spec` listed it
|
|
473
|
+
explicitly.
|
|
474
|
+
|
|
475
|
+
The tombstone-error scenario is precisely the one where the repo is out of
|
|
476
|
+
reach — the upgrading agent has `node_modules` and nothing else — so the
|
|
477
|
+
migration text has to ride in the tarball. Every publishable package now
|
|
478
|
+
declares `CHANGELOG.md` in `files`, and the canonical whitelist is
|
|
479
|
+
`["dist", "README.md", "CHANGELOG.md"]`.
|
|
480
|
+
|
|
481
|
+
The other half is the gate: `check:published-files` gains a fifth invariant,
|
|
482
|
+
COMPLETE — a whitelist that fails to cover `CHANGELOG.md` fails the
|
|
483
|
+
always-required lint job, so the next package cannot silently sever the path
|
|
484
|
+
again. `@objectstack/spec`'s per-package EXTRA_ENTRIES exemption dissolves
|
|
485
|
+
into the canonical set.
|
|
486
|
+
|
|
487
|
+
Consumer-visible change: one more file per install (the package's changelog,
|
|
488
|
+
e.g. 70.8KB for `@objectstack/types`), and `grep -r "removed key"
|
|
489
|
+
node_modules/@objectstack/*/CHANGELOG.md` now finds the migration it was
|
|
490
|
+
promised.
|
|
491
|
+
|
|
492
|
+
- 45dc446: Every in-memory fallback and dev stub now self-describes with the standard `__serviceInfo` descriptor, classified by what it actually is (#4058 step 1).
|
|
493
|
+
|
|
494
|
+
ADR-0076 D12 gave services one way to say "I am not the real thing", but the producers never converged on it:
|
|
495
|
+
|
|
496
|
+
- The kernel's own fallbacks (`createMemoryCache` / `Queue` / `Job` / `I18n` / `Metadata`) carried `_fallback: true` — a marker **no** consumer recognized, `readServiceSelfInfo` included — so both discovery builders reported them as fully `available`.
|
|
497
|
+
- `plugin-dev` marked all of its implementations with the same `_dev: true`, normalized to `status: 'stub', handlerReady: false`. That declared a working in-memory search index exactly as fake as an AI stub returning invented text.
|
|
498
|
+
|
|
499
|
+
Both now carry `__serviceInfo`, split by a rule that holds across the whole set:
|
|
500
|
+
|
|
501
|
+
- **`degraded`** — really does the work, with reduced capability: `cache`, `queue`, `job`, `file-storage`, `search`, `i18n`, `metadata`, `workflow`, `realtime`. Its answers are true answers; the `message` names what is missing (no persistence, no scheduling timer, no state-machine validation, …).
|
|
502
|
+
- **`stub`** — the answer is fabricated: `ai`, `automation`, `notification`, `data`, `auth`, `security.permissions`, `security.rls`, `security.fieldMasker`. Never to be mistaken for a capability.
|
|
503
|
+
|
|
504
|
+
`handlerReady: false` is set independently wherever no HTTP handler serves the slot (`cache` / `queue` / `job` / `realtime`, and every `stub`).
|
|
505
|
+
|
|
506
|
+
Discovery output changes accordingly — a kernel fallback that used to report `status: 'available'` now reports `degraded` with an explanatory message. No routing, gating, or dispatch behavior changes: every dispatcher domain still resolves services exactly as before. Consumers reading `discovery.services.*` get the truth instead of a uniform claim.
|
|
507
|
+
|
|
508
|
+
For anything that duck-typed the old markers: `svc._fallback` / `svc._dev` → `readServiceSelfInfo(svc)` from `@objectstack/spec/api` (the legacy `_dev` key is still understood by that reader, so third-party stubs carrying it keep working).
|
|
509
|
+
|
|
510
|
+
- f985b3f: fix(spec,core,cloud-connection,metadata): one HTTP contract, one canonical slot name — and the dead shadow copy that helped cause the false exemption is deleted (#4251)
|
|
511
|
+
|
|
512
|
+
**`packages/core/src/contracts/` was a dead near-copy of the real contracts,
|
|
513
|
+
and it is gone.** The directory (http-server.ts, data-engine.ts, logger.ts) had
|
|
514
|
+
ZERO importers — no relative import, no subpath export, not a tsup entry;
|
|
515
|
+
core's barrel has re-exported the `@objectstack/spec/contracts` versions all
|
|
516
|
+
along ("Re-export contracts from @objectstack/spec for backward
|
|
517
|
+
compatibility"). But the shadow had already **diverged** from the live
|
|
518
|
+
contract (spec's `IHttpResponse` grew `write?`/`end?` and `IHttpRequest` grew
|
|
519
|
+
`rawBody?`; the copy never did), so anyone who grepped their way into it read a
|
|
520
|
+
stale contract that nothing enforces — the exact both-humans-and-AI failure
|
|
521
|
+
mode behind the false `http.server` exemption (#4382). Deleting it is
|
|
522
|
+
zero-risk by construction: nothing could reach it.
|
|
523
|
+
|
|
524
|
+
**`http.server` is the canonical slot name, and the ledger now says so.**
|
|
525
|
+
`ServiceSlotContracts` gains `'http.server': IHttpServer` plus the deprecated
|
|
526
|
+
`'http-server'` alias entry (same instance — hono-plugin and qa's node-plugin
|
|
527
|
+
register both two lines apart; cloud's two server entrypoints do the same).
|
|
528
|
+
Canonical is the only name present on EVERY provider path: runtime's
|
|
529
|
+
`config.server` path registers no alias, so the three cloud-connection plugins
|
|
530
|
+
that read the alias alone (marketplace-proxy, runtime-config,
|
|
531
|
+
marketplace-install-local) found an empty slot there — a live miss, now fixed:
|
|
532
|
+
all readers go canonical-first with the alias as a fallback that dies with the
|
|
533
|
+
alias registrations. The registrations themselves are untouched this release;
|
|
534
|
+
both sites now carry the deprecation note.
|
|
535
|
+
|
|
536
|
+
**`getRawApp?(): any` joins `IHttpServer`** — the deliberate framework-handle
|
|
537
|
+
escape, declared once. Four consumers were each declaring it locally
|
|
538
|
+
(cloud-connection ×2, metadata's HMR routes, cloud's serverless node-server);
|
|
539
|
+
those local `RawAppHost`/`HttpServerWithRawApp` types are deleted. The `any`
|
|
540
|
+
return is deliberate and documented at the single declaration: the handle's
|
|
541
|
+
real type belongs to the framework, and naming it would give the contract a
|
|
542
|
+
framework dependency. Adapters are not required to expose it; consumers
|
|
543
|
+
feature-detect.
|
|
544
|
+
|
|
545
|
+
**`IMetadataService.bulkRegister`/`bulkUnregister` declare the write options
|
|
546
|
+
their implementation has always accepted.** `bulkRegister`'s contract options
|
|
547
|
+
dropped the `MetadataWriteOptions` half its implementation intersects in
|
|
548
|
+
(`notify` is destructured on the method's first line); `bulkUnregister`
|
|
549
|
+
declared no options at all while the manager takes them. Same shape as the
|
|
550
|
+
`IDataEngine` read-methods gap from B2: a caller typed to the contract could
|
|
551
|
+
not reach the channel without erasing the lookup. Both additive; no implementor
|
|
552
|
+
or caller breaks.
|
|
553
|
+
|
|
554
|
+
Slot-lookup baseline ratchets 168 → 167 (marketplace-install-local's lookup
|
|
555
|
+
typed while touched).
|
|
556
|
+
|
|
557
|
+
- 7777e8f: fix(spec)!: retire the never-built typed-event system; the lifecycle registry now lists the events that actually fire (#4212 follow-up)
|
|
558
|
+
|
|
559
|
+
The lifecycle-event surface promised a typed-event system that was never
|
|
560
|
+
built, in three layers. `kernel/plugin-lifecycle-events.zod.ts` shipped ten
|
|
561
|
+
payload schemas (`PluginRegisteredEvent`, `PluginErrorEvent`,
|
|
562
|
+
`HookTriggeredEvent`, `KernelReadyEvent`, …) and a 21-name
|
|
563
|
+
`PluginLifecycleEventType` enum — zero consumers for every export, and the
|
|
564
|
+
enum was wrong in both directions: 17 names nothing fires, 10 real events
|
|
565
|
+
missing. `contracts/plugin-lifecycle-events.ts` declared the same 17 dead
|
|
566
|
+
names in `IPluginLifecycleEvents` next to 5 real ones, plus an
|
|
567
|
+
`ITypedEventEmitter` interface nothing implements. All of it read as a
|
|
568
|
+
promise; anyone who coded against it (hooking `plugin:started`, awaiting
|
|
569
|
+
`plugin:error`) registered a handler that could never fire, with no error
|
|
570
|
+
saying so — the same silent-drop shape as the #4212 lifecycle-hook family.
|
|
571
|
+
|
|
572
|
+
Removed, with zero consumers verified repo-wide:
|
|
573
|
+
|
|
574
|
+
- `kernel/plugin-lifecycle-events.zod.ts` and every export: `EventPhase`,
|
|
575
|
+
`PluginEventBase`, `PluginRegisteredEvent`, `PluginLifecyclePhaseEvent`,
|
|
576
|
+
`PluginErrorEvent`, `ServiceRegisteredEvent`, `ServiceUnregisteredEvent`,
|
|
577
|
+
`HookRegisteredEvent`, `HookTriggeredEvent`, `KernelEventBase`,
|
|
578
|
+
`KernelReadyEvent`, `KernelShutdownEvent`, `PluginLifecycleEventType`
|
|
579
|
+
(schemas and inferred types).
|
|
580
|
+
- `ITypedEventEmitter` from `contracts/plugin-lifecycle-events.ts`.
|
|
581
|
+
- The 17 never-fired names from `IPluginLifecycleEvents`.
|
|
582
|
+
|
|
583
|
+
`IPluginLifecycleEvents` is now the registry of the **14 events with a real
|
|
584
|
+
emitter** — `kernel:{ready,bootstrapped,listening,shutdown}`, `app:seeded`,
|
|
585
|
+
`metadata:reloaded` (payload `metadata` now optional, matching the documented
|
|
586
|
+
contract), `external.schema.drift`, `ai:routes`, `auth:configure`, and the
|
|
587
|
+
`{service}:ready` convention family (`mcp`, `automation`, `analytics`,
|
|
588
|
+
`external-datasource`, `datasource-admin`) — each payload as observed at its
|
|
589
|
+
fire site. A new `LifecycleEventName` union types
|
|
590
|
+
`PluginContext.hook`/`trigger` in `@objectstack/core` as
|
|
591
|
+
`LifecycleEventName | (string & {})`: known names autocomplete, custom
|
|
592
|
+
cross-plugin names stay legal, existing callers compile unchanged. A pinning
|
|
593
|
+
test asserts two-way equality between the interface keys and the fire-site
|
|
594
|
+
inventory.
|
|
595
|
+
|
|
596
|
+
FROM → TO:
|
|
597
|
+
|
|
598
|
+
- `PluginLifecycleEventType` → `LifecycleEventName` (the union of names that
|
|
599
|
+
fire). There is no runtime enum; the bus is open by design.
|
|
600
|
+
- Event payload schemas (`KernelReadyEvent`, `PluginErrorEvent`, …) → the
|
|
601
|
+
payload tuples on `IPluginLifecycleEvents`. No wire format existed or
|
|
602
|
+
exists; payloads are in-process arguments.
|
|
603
|
+
- `ITypedEventEmitter` → `PluginContext.hook`/`trigger` (the emitter that
|
|
604
|
+
actually exists).
|
|
605
|
+
- Handlers for the 17 dead names → delete them; they never ran. For plugin
|
|
606
|
+
phase observation use the boot report (ADR-0084); for per-plugin errors the
|
|
607
|
+
kernel throws/logs at the failing phase.
|
|
608
|
+
|
|
609
|
+
Plain deletion rather than `retiredKey()` tombstones, per the #4233
|
|
610
|
+
precedent: these keys were never authorable — they described runtime event
|
|
611
|
+
payload records no config author can write, so the silent-strip class the
|
|
612
|
+
authorable-surface ratchet guards against is vacuous. Its baseline entries
|
|
613
|
+
and the `json-schema.manifest.json` keys are dropped deliberately in this PR.
|
|
614
|
+
No ADR-0087 conversion: no stack metadata names these types; there is nothing
|
|
615
|
+
for `os migrate meta` to rewrite.
|
|
616
|
+
|
|
617
|
+
- 7ce02eb: feat(spec,objectql): `IObjectQLEngine` — the `objectql` slot's contract exists, the class `implements` it, and the seven consumer-local stand-ins are deleted (#4251 B3)
|
|
618
|
+
|
|
619
|
+
ObjectQL registers one instance under two names, and the ledger can finally say
|
|
620
|
+
what each name means: `data` stays `IDataEngine` (the data plane), `objectql`
|
|
621
|
+
now resolves to **`IObjectQLEngine`** — the full engine: schema access
|
|
622
|
+
(`getSchema` / `getObject` / `registry`), actions (`registerAction` /
|
|
623
|
+
`removeActionsByPackage` / `executeAction`), the hook/middleware seams
|
|
624
|
+
(`registerHook` / `unregisterHooksByPackage` / `registerFunction` /
|
|
625
|
+
`registerMiddleware` / `bindHooks`), the first-wins default runners and hook
|
|
626
|
+
metrics, boot wiring (`registerDriver` / `setDatasourceMapping` /
|
|
627
|
+
`registerApp`), and the ops probes (`checkDriversHealth` /
|
|
628
|
+
`wasDatastoreCreatedFromEmpty` / `invalidateDataMigrationFlags`). The ledger
|
|
629
|
+
test pins the new relation: `objectql` strictly widens `data`, deliberately no
|
|
630
|
+
longer equal.
|
|
631
|
+
|
|
632
|
+
**Why now, and why `implements` is the point.** The honest state for two
|
|
633
|
+
batches was recorded on `DomainHandlerContext.getObjectQL`: ObjectQL is wider
|
|
634
|
+
than `IDataEngine`, the wider part had no contract, and typing it `IDataEngine`
|
|
635
|
+
would be "the more comfortable-looking lie". The interim discipline — each
|
|
636
|
+
consumer declares the narrow slice it uses — produced seven local surfaces
|
|
637
|
+
(`AppEngineSurface`, `EngineRegistrySurface`, `EngineExtensionSurface`,
|
|
638
|
+
`SecurityEngineSurface`, `FreshDatastoreEngine`, the dispatcher's inline
|
|
639
|
+
`checkDriversHealth` slice, the `getObjectQL: any` itself). Each was honest and
|
|
640
|
+
each was an UNCHECKED claim: `getService<Surface>('objectql')` is an assertion,
|
|
641
|
+
so an engine rename would have broken every consumer at runtime with zero
|
|
642
|
+
compile errors. `ObjectQL implements IObjectQLEngine` converts all of them into
|
|
643
|
+
one compiler-verified claim. All seven stand-ins are deleted; consumers import
|
|
644
|
+
the one declaration. `getObjectQL` is typed `Promise<IObjectQLEngine | null>`
|
|
645
|
+
end to end, closing the oldest documented `any` in the dispatcher.
|
|
646
|
+
|
|
647
|
+
**Evidence bar unchanged.** Every declared member has a cross-package consumer
|
|
648
|
+
reaching it through the slot; engine members without one (e.g. `triggerHooks`,
|
|
649
|
+
cross-package only in tests) stay off until a caller appears. The registry view
|
|
650
|
+
(`EngineSchemaRegistryView`) declares exactly the eight members consumers use.
|
|
651
|
+
|
|
652
|
+
**`_registry` never leaves the engine package now.** plugin-security's
|
|
653
|
+
declared-metadata readers (`readDeclared`, permission-set projection, suggested
|
|
654
|
+
audience bindings) reached ObjectQL's private `_registry` field through `any` —
|
|
655
|
+
the same private reach `/me/apps` had in B2, five more times. All migrated to
|
|
656
|
+
the public `registry` getter the contract declares, test doubles included.
|
|
657
|
+
|
|
658
|
+
**`IMetadataService` gains `subscribe?` / `loadMany?`** — implemented by
|
|
659
|
+
`MetadataManager` beside `watch` all along, reached through the slot only via
|
|
660
|
+
`any` by ObjectQLPlugin's metadata bridge (the re-sync keeping runtime-authored
|
|
661
|
+
hooks/actions live). With them declared, the bridge's six `metadata` lookups
|
|
662
|
+
and metadata-protocol's `objectql` lookup carry contract types, and both files
|
|
663
|
+
leave the grandfather list entirely: baseline **167 → 159 sites, 36 → 34
|
|
664
|
+
files**.
|
|
665
|
+
|
|
666
|
+
- be7360c: chore(plugins,services): declare `providesServices` on the 20 remaining init-time service providers (ADR-0116 follow-up, #4131)
|
|
667
|
+
|
|
668
|
+
ADR-0116 gave the kernel a declared ordering contract, but only
|
|
669
|
+
`ObjectQLPlugin` and `MetadataPlugin` had declared what their `init()`
|
|
670
|
+
registers. The pre-Phase-1 ordering check can only _name a provider_ for
|
|
671
|
+
services someone declared, so its coverage was two plugins wide.
|
|
672
|
+
|
|
673
|
+
An audit of every plugin's `init()` body (brace-matched, comments stripped,
|
|
674
|
+
each call classified by whether it sits inside a `try`/`if`) found 20 plugins
|
|
675
|
+
that register a service on every path without declaring it. All 20 now
|
|
676
|
+
declare `providesServices`. Purely additive: no ordering changes, no new
|
|
677
|
+
failure modes — a `providesServices` entry only lets the kernel say _who_
|
|
678
|
+
provides a service when it reports a misordering, and enriches the Phase-1
|
|
679
|
+
`getService` miss diagnostic.
|
|
680
|
+
|
|
681
|
+
Three needed a closer read before declaring, because they register the same
|
|
682
|
+
service from several branches (`cache`, `queue`, `job`): each early-return
|
|
683
|
+
branch plus the fallback registers it, so every path does — the declaration
|
|
684
|
+
is honest. ADR-0116's rule that a _conditionally_ registered service must
|
|
685
|
+
never be declared is unchanged and was applied throughout.
|
|
686
|
+
|
|
687
|
+
The same audit found 12 plugins that hard-resolve a service during `init()`
|
|
688
|
+
(11 of them `manifest`) without declaring `requiresServices`. None is a live
|
|
689
|
+
exposure — every one already declares a hard `dependencies` entry on the
|
|
690
|
+
provider, so the kernel orders them correctly today. Those are tracked
|
|
691
|
+
separately: with a hard dependency in place, `requiresServices` mostly
|
|
692
|
+
restates what the kernel already enforces, and its real value is on
|
|
693
|
+
_soft_-dependency consumers, of which `AppPlugin` is currently the only one.
|
|
694
|
+
|
|
695
|
+
- 857a6cf: fix(cli,core,metadata,runtime): `os serve` boots with no compiled artifact — the platform does not need an application to start (#4085)
|
|
696
|
+
|
|
697
|
+
The artifact (`dist/objectstack.json`) defines an **application**. ObjectStack is
|
|
698
|
+
a development platform, so it has to start without one — but `os serve
|
|
699
|
+
objectstack.config.ts` died during boot whenever the artifact was absent:
|
|
700
|
+
|
|
701
|
+
```
|
|
702
|
+
Loading objectstack.config.ts...
|
|
703
|
+
[StandaloneStack] artifact read FAILED: path='…/dist/objectstack.json' error=ENOENT…
|
|
704
|
+
|
|
705
|
+
✗ Service 'manifest' is async - use await
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
Exit 1 — on a **known-good app** (`examples/app-todo` fails the same way with
|
|
709
|
+
only its `dist/objectstack.json` moved aside), and on every freshly authored
|
|
710
|
+
project between `os init` and its first `os compile`. The message named neither
|
|
711
|
+
the missing artifact nor a fix, so it read as an internal kernel fault.
|
|
712
|
+
|
|
713
|
+
Three separate faults, each of which alone was enough to refuse the boot:
|
|
714
|
+
|
|
715
|
+
- **`serve` registered the config-derived `AppPlugin` before the stack's own
|
|
716
|
+
`plugins[]`.** Registration order _is_ the kernel's init/start order, and that
|
|
717
|
+
slot sits ahead of `ObjectQLPlugin` (which registers `manifest`/`objectql`) and
|
|
718
|
+
`DefaultDatasourcePlugin` (which connects the database the app seeds through).
|
|
719
|
+
The wrap is now **appended** to `plugins[]`, the same slot
|
|
720
|
+
`createStandaloneStack` gives its artifact-derived `AppPlugin` — so config-boot
|
|
721
|
+
and artifact-boot share one plugin order. The artifact path never hit this,
|
|
722
|
+
which is exactly what made a plugin-**order** bug look artifact-related.
|
|
723
|
+
|
|
724
|
+
- **`ctx.getService()` reported a never-registered service as "is async".**
|
|
725
|
+
`PluginLoader.getService` is an `async` method, so its return value is _always_
|
|
726
|
+
a Promise and its internal "not found" rejection can never surface
|
|
727
|
+
synchronously — the kernel read the answer off that Promise and told every
|
|
728
|
+
caller to `await` a service that did not exist, while the `not found` branch
|
|
729
|
+
below it was unreachable. It now decides from the registry: absent ⇒
|
|
730
|
+
`[Kernel] Service 'x' not found`, registered-but-uninstantiated ⇒ the unchanged
|
|
731
|
+
`Service 'x' is async - use await`. The same crash now reads
|
|
732
|
+
`[Kernel] Service 'manifest' not found`, which points at the layer that is
|
|
733
|
+
actually wrong.
|
|
734
|
+
|
|
735
|
+
- **`MetadataPlugin` treated an absent `local-file` artifact as fatal.**
|
|
736
|
+
`createStandaloneStack` always points it at `dist/objectstack.json`, so a stack
|
|
737
|
+
with no app at all could not boot. A **missing** local artifact is now "nothing
|
|
738
|
+
compiled yet": it logs, starts empty, and leaves the artifact watcher armed, so
|
|
739
|
+
a later `os compile` hydrates the running server. The tolerance is
|
|
740
|
+
ENOENT-only — a malformed or unreadable artifact stays fatal — and
|
|
741
|
+
`bootstrap: 'artifact-only'` (sealed runtime, where the artifact _is_ the
|
|
742
|
+
deployment) keeps failing loudly rather than silently serving an empty runtime.
|
|
743
|
+
|
|
744
|
+
`[StandaloneStack] artifact read FAILED … ENOENT` is likewise no longer shouted
|
|
745
|
+
at callers for whom "no artifact" is a healthy state; a present-but-unusable
|
|
746
|
+
artifact keeps the loud warning.
|
|
747
|
+
|
|
748
|
+
Pinned by an e2e pair that drives the real `os serve` with **no `os compile`
|
|
749
|
+
anywhere**: an app defined only by `objectstack.config.ts` (asserting its object
|
|
750
|
+
is in the started plugin set, not merely that boot survived) and a bare
|
|
751
|
+
`export default {}` platform. The #4012 fixture drops the `os compile` this bug
|
|
752
|
+
had forced on it.
|
|
753
|
+
|
|
754
|
+
- d92c72d: fix(lint,runtime,core): the slot-lookup guard sees the split-declaration form — the shape that made the ratchet look cleaner the more it was used (#4251)
|
|
755
|
+
|
|
756
|
+
The three selectors from #4321 all key off the erasure and the lookup being in
|
|
757
|
+
ONE expression. Split them and every selector misses:
|
|
758
|
+
|
|
759
|
+
```ts
|
|
760
|
+
let ql: any;
|
|
761
|
+
try {
|
|
762
|
+
ql = ctx.getService("objectql");
|
|
763
|
+
} catch {
|
|
764
|
+
/* optional */
|
|
765
|
+
}
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
Selector 1 needs the call inside the declarator (this declarator has no init),
|
|
769
|
+
selector 2 needs `as`, selector 3 needs a type argument. The contract is erased
|
|
770
|
+
exactly as in `const ql: any = ctx.getService(…)`.
|
|
771
|
+
|
|
772
|
+
**Why this could not wait for the batches.** The baseline's monotonicity check
|
|
773
|
+
means a file that leaves the grandfather list can never be re-added. So every
|
|
774
|
+
batch converted more of this shape from "grandfathered" into "lint covers this
|
|
775
|
+
file and says nothing" — B2 alone moved `plugin-security/security-plugin.ts`
|
|
776
|
+
into that state. A ratchet that reports a cleaner number the more you sweep is
|
|
777
|
+
the #4342 failure wearing different clothes, and the fix only gets more
|
|
778
|
+
expensive per batch shipped.
|
|
779
|
+
|
|
780
|
+
**It is a rule, not a fourth selector, and that is the whole finding.** esquery
|
|
781
|
+
can match `AssignmentExpression:has(CallExpression[…])`, but it cannot tell
|
|
782
|
+
which declaration the assigned identifier resolves to — so it would equally
|
|
783
|
+
flag the correctly-typed form this work line exists to produce (`let
|
|
784
|
+
i18nService: II18nService | undefined; i18nService = …`, 8 such sites today in
|
|
785
|
+
runtime/app-plugin.ts, service-automation and metadata-protocol). Resolving the
|
|
786
|
+
identifier needs SCOPE analysis. That is cheap and needs no type information, so
|
|
787
|
+
this stays out of the typed-lint pass the KNOWN RESIDUAL still waits on — but it
|
|
788
|
+
is a rule, and the earlier "just one more selector" estimate was wrong.
|
|
789
|
+
|
|
790
|
+
Verified against exactly that: the rule flags all 16 real sites and none of the
|
|
791
|
+
8 correctly-typed lookalikes.
|
|
792
|
+
|
|
793
|
+
**Scale.** The baseline goes 140 → **169 sites** with the file count unchanged
|
|
794
|
+
at 37: 29 sites were already inside grandfathered files and simply invisible.
|
|
795
|
+
16 more could NOT be grandfathered (12 in files earlier batches had cleared, 3
|
|
796
|
+
in files never listed, 1 the regex sweep had missed) and are typed here —
|
|
797
|
+
`runtime/app-plugin.ts` ×5, `core/fallbacks/authored-translation-sync.ts` ×2,
|
|
798
|
+
`plugin-security/security-plugin.ts` ×2, `cloud-connection/{runtime-config,
|
|
799
|
+
marketplace-proxy}-plugin.ts` ×3, `platform-objects/src/plugin.ts` ×2,
|
|
800
|
+
`runtime/http-dispatcher.ts`, `runtime/domains/ai.ts`. No baseline key was
|
|
801
|
+
added; the key set still only shrinks.
|
|
802
|
+
|
|
803
|
+
Contracts where they exist (`IAIService`, `IJobService`, `IMetadataService`,
|
|
804
|
+
`II18nService`, `IDataEngine`, `IHttpServer`), named local surfaces where they
|
|
805
|
+
do not — `AppEngineSurface`, `SecurityEngineSurface`, `RawAppHost`,
|
|
806
|
+
`EnvRegistrySurface`, `FreshDatastoreEngine`, `AuthoredTranslationSink`. Two of
|
|
807
|
+
those record something worth naming: `IHttpServer` has no `getRawApp()` (the
|
|
808
|
+
contract is framework-agnostic and the raw app is Hono's own handle), and
|
|
809
|
+
ObjectQL's `_defaultBodyRunner` / `_defaultActionRunner` have no public reader
|
|
810
|
+
at all — the engine attaches them via `(this as any)` and publishes nothing,
|
|
811
|
+
while `getHookMetricsRecorder()` exists for exactly that question about the
|
|
812
|
+
metrics recorder. Declared rather than laundered through `any`, and filed.
|
|
813
|
+
|
|
814
|
+
- Updated dependencies [6a67d7a]
|
|
815
|
+
- Updated dependencies [0ecc656]
|
|
816
|
+
- Updated dependencies [06772eb]
|
|
817
|
+
- Updated dependencies [270650f]
|
|
818
|
+
- Updated dependencies [3aef718]
|
|
819
|
+
- Updated dependencies [1ea6bce]
|
|
820
|
+
- Updated dependencies [c1dcacd]
|
|
821
|
+
- Updated dependencies [ad303ed]
|
|
822
|
+
- Updated dependencies [32ccb23]
|
|
823
|
+
- Updated dependencies [f5a4ef0]
|
|
824
|
+
- Updated dependencies [2d3e255]
|
|
825
|
+
- Updated dependencies [7d7521f]
|
|
826
|
+
- Updated dependencies [5dc4d02]
|
|
827
|
+
- Updated dependencies [05154a1]
|
|
828
|
+
- Updated dependencies [9b6fe7c]
|
|
829
|
+
- Updated dependencies [8c711fb]
|
|
830
|
+
- Updated dependencies [09e4547]
|
|
831
|
+
- Updated dependencies [91f4c78]
|
|
832
|
+
- Updated dependencies [820eff9]
|
|
833
|
+
- Updated dependencies [8d895ff]
|
|
834
|
+
- Updated dependencies [f6472d7]
|
|
835
|
+
- Updated dependencies [78caf51]
|
|
836
|
+
- Updated dependencies [62a789b]
|
|
837
|
+
- Updated dependencies [789ad63]
|
|
838
|
+
- Updated dependencies [2af1988]
|
|
839
|
+
- Updated dependencies [12a19a8]
|
|
840
|
+
- Updated dependencies [41dcda3]
|
|
841
|
+
- Updated dependencies [c8124e5]
|
|
842
|
+
- Updated dependencies [a1a4140]
|
|
843
|
+
- Updated dependencies [217e2e6]
|
|
844
|
+
- Updated dependencies [86a71d1]
|
|
845
|
+
- Updated dependencies [d5c75e2]
|
|
846
|
+
- Updated dependencies [03d26f7]
|
|
847
|
+
- Updated dependencies [4384921]
|
|
848
|
+
- Updated dependencies [3c628ce]
|
|
849
|
+
- Updated dependencies [7cb922e]
|
|
850
|
+
- Updated dependencies [1d22114]
|
|
851
|
+
- Updated dependencies [b5f9397]
|
|
852
|
+
- Updated dependencies [ed77493]
|
|
853
|
+
- Updated dependencies [58a03d2]
|
|
854
|
+
- Updated dependencies [dc530b4]
|
|
855
|
+
- Updated dependencies [e59786e]
|
|
856
|
+
- Updated dependencies [bcf1112]
|
|
857
|
+
- Updated dependencies [9774b78]
|
|
858
|
+
- Updated dependencies [b07d829]
|
|
859
|
+
- Updated dependencies [a648e96]
|
|
860
|
+
- Updated dependencies [a47ac06]
|
|
861
|
+
- Updated dependencies [e4c61a7]
|
|
862
|
+
- Updated dependencies [cc60165]
|
|
863
|
+
- Updated dependencies [081aa6f]
|
|
864
|
+
- Updated dependencies [91f4c78]
|
|
865
|
+
- Updated dependencies [e8d0c21]
|
|
866
|
+
- Updated dependencies [c1d44f7]
|
|
867
|
+
- Updated dependencies [ab9fb5c]
|
|
868
|
+
- Updated dependencies [f985b3f]
|
|
869
|
+
- Updated dependencies [9a4932a]
|
|
870
|
+
- Updated dependencies [f9fc874]
|
|
871
|
+
- Updated dependencies [011b386]
|
|
872
|
+
- Updated dependencies [7777e8f]
|
|
873
|
+
- Updated dependencies [507b92a]
|
|
874
|
+
- Updated dependencies [7309c81]
|
|
875
|
+
- Updated dependencies [20bc1ec]
|
|
876
|
+
- Updated dependencies [90c2b15]
|
|
877
|
+
- Updated dependencies [42eeb7d]
|
|
878
|
+
- Updated dependencies [01e124d]
|
|
879
|
+
- Updated dependencies [7ce02eb]
|
|
880
|
+
- Updated dependencies [a13827e]
|
|
881
|
+
- Updated dependencies [7733604]
|
|
882
|
+
- Updated dependencies [40e420f]
|
|
883
|
+
- Updated dependencies [d13004a]
|
|
884
|
+
- Updated dependencies [5b47ab5]
|
|
885
|
+
- Updated dependencies [b09d8d9]
|
|
886
|
+
- Updated dependencies [b09d8d9]
|
|
887
|
+
- Updated dependencies [8675db6]
|
|
888
|
+
- Updated dependencies [b09d8d9]
|
|
889
|
+
- Updated dependencies [3eb1b2b]
|
|
890
|
+
- Updated dependencies [59b85c0]
|
|
891
|
+
- Updated dependencies [6e357ed]
|
|
892
|
+
- Updated dependencies [d6938bf]
|
|
893
|
+
- Updated dependencies [31e0be9]
|
|
894
|
+
- Updated dependencies [4bfd455]
|
|
895
|
+
- Updated dependencies [ffd2ce2]
|
|
896
|
+
- Updated dependencies [62f8017]
|
|
897
|
+
- Updated dependencies [a831df1]
|
|
898
|
+
- Updated dependencies [f752ee3]
|
|
899
|
+
- Updated dependencies [a1b61e0]
|
|
900
|
+
- Updated dependencies [cd6b9f2]
|
|
901
|
+
- Updated dependencies [2cb6d3c]
|
|
902
|
+
- Updated dependencies [af2a095]
|
|
903
|
+
- Updated dependencies [ec796d5]
|
|
904
|
+
- Updated dependencies [e87fea1]
|
|
905
|
+
- Updated dependencies [c65e529]
|
|
906
|
+
- Updated dependencies [3ca34c1]
|
|
907
|
+
- Updated dependencies [239c3a3]
|
|
908
|
+
- Updated dependencies [94a0bbc]
|
|
909
|
+
- Updated dependencies [d6bfb3d]
|
|
910
|
+
- Updated dependencies [a2266a6]
|
|
911
|
+
- Updated dependencies [d25a0ec]
|
|
912
|
+
- Updated dependencies [667b83e]
|
|
913
|
+
- Updated dependencies [627b188]
|
|
914
|
+
- Updated dependencies [8d4eae7]
|
|
915
|
+
- Updated dependencies [65a3a84]
|
|
916
|
+
- Updated dependencies [ccd9397]
|
|
917
|
+
- Updated dependencies [bca935b]
|
|
918
|
+
- Updated dependencies [c54c822]
|
|
919
|
+
- Updated dependencies [8dcc0f5]
|
|
920
|
+
- Updated dependencies [75b9e51]
|
|
921
|
+
- Updated dependencies [0a2f233]
|
|
922
|
+
- Updated dependencies [8621cdd]
|
|
923
|
+
- Updated dependencies [6f23667]
|
|
924
|
+
- Updated dependencies [5d21a48]
|
|
925
|
+
- Updated dependencies [19365b7]
|
|
926
|
+
- Updated dependencies [b7ed26d]
|
|
927
|
+
- Updated dependencies [b3a3d83]
|
|
928
|
+
- Updated dependencies [7a55913]
|
|
929
|
+
- Updated dependencies [35accbf]
|
|
930
|
+
- Updated dependencies [6038de7]
|
|
931
|
+
- Updated dependencies [eb95d97]
|
|
932
|
+
- Updated dependencies [e4c2dc8]
|
|
933
|
+
- Updated dependencies [1bd2795]
|
|
934
|
+
- Updated dependencies [8186a70]
|
|
935
|
+
- Updated dependencies [a329cca]
|
|
936
|
+
- Updated dependencies [6eec18c]
|
|
937
|
+
- Updated dependencies [4d7bebf]
|
|
938
|
+
- Updated dependencies [821ac7a]
|
|
939
|
+
- Updated dependencies [8f81731]
|
|
940
|
+
- Updated dependencies [8b50cb3]
|
|
941
|
+
- Updated dependencies [8c2db68]
|
|
942
|
+
- Updated dependencies [22b5e54]
|
|
943
|
+
- Updated dependencies [0166bd5]
|
|
944
|
+
- Updated dependencies [9b702dc]
|
|
945
|
+
- Updated dependencies [ab16331]
|
|
946
|
+
- @objectstack/spec@17.0.0-rc.1
|
|
947
|
+
|
|
948
|
+
## 17.0.0-rc.0
|
|
949
|
+
|
|
950
|
+
### Minor Changes
|
|
951
|
+
|
|
952
|
+
- 879ea13: ADR-0105 Phase 0 + Phase 1: group tenancy posture; organization scope as a
|
|
953
|
+
first-class authorization dimension.
|
|
954
|
+
|
|
955
|
+
> This release carries BREAKING spec removals (see "Enforce-or-remove" below)
|
|
956
|
+
> but is recorded as `minor`: every publishable package is in the Changesets
|
|
957
|
+
> lockstep group, so one `major` would promote the whole monorepo. Breaking
|
|
958
|
+
> changes ship as `minor` during the launch window — the migration notes below
|
|
959
|
+
> are what reach consumers in `CHANGELOG.md`.
|
|
960
|
+
|
|
961
|
+
## Tenancy is now a spectrum (D1)
|
|
962
|
+
|
|
963
|
+
`single | group | isolated`, resolved by the `tenancy` service and selected with
|
|
964
|
+
the new `OS_TENANCY_POSTURE` env var. Existing deployments are unchanged:
|
|
965
|
+
`OS_TENANCY_POSTURE` unset derives the posture from `OS_MULTI_ORG_ENABLED`
|
|
966
|
+
(`true` ⇒ `isolated`, else `single`). An unrecognized value throws at boot
|
|
967
|
+
rather than silently landing in a posture with no organization wall.
|
|
968
|
+
|
|
969
|
+
- `single` — no wall (unchanged).
|
|
970
|
+
- `group` — **new.** Organizations are membership boundaries over one shared
|
|
971
|
+
dataset; Layer 0 becomes `organization_id IN accessible_org_ids` (union / MOAC
|
|
972
|
+
semantics). Enforced by the OPEN engine.
|
|
973
|
+
- `isolated` — today's `multi`, renamed. Behavior, enterprise `org-scoping`
|
|
974
|
+
probe and degraded-boot handling all unchanged.
|
|
975
|
+
|
|
976
|
+
## Organization scope is a first-class context field (D2)
|
|
977
|
+
|
|
978
|
+
`ExecutionContext.accessible_org_ids` — every organization the caller holds a
|
|
979
|
+
currently-valid membership in (ADR-0091 validity windows) — is resolved once by
|
|
980
|
+
`resolveAuthzContext` and carried by every transport. The `group` wall reads it
|
|
981
|
+
directly; RLS policies may reference it as
|
|
982
|
+
`organization_id IN (current_user.accessible_org_ids)`. An empty or absent set
|
|
983
|
+
fails the wall closed.
|
|
984
|
+
|
|
985
|
+
Only the Layer 0 PREDICATE widens. Composition is untouched: the wall is still
|
|
986
|
+
computed independently of the RLS compiler, AND-composed outermost, and
|
|
987
|
+
crossable only by a true `PLATFORM_ADMIN` on a posture-permitting object — so
|
|
988
|
+
ADR-0095's W1/W2 invariants hold in every posture.
|
|
989
|
+
|
|
990
|
+
## Two P0 correctness fixes (D3, D4) — behavior changes
|
|
991
|
+
|
|
992
|
+
**D3 — app-authored org-scoped RLS policies are no longer silently dropped**
|
|
993
|
+
(finding F1, framework#3539). `collectRLSPolicies` used to strip any policy whose
|
|
994
|
+
`using` contained the substring `current_user.organization_id` when isolation was
|
|
995
|
+
inactive, which swallowed app-authored policies as well as the platform's own.
|
|
996
|
+
Stripping is now decided by PROVENANCE (identity against the shipped
|
|
997
|
+
declaration). **Upgrade impact:** in a deployment with no organization wall, an
|
|
998
|
+
app-authored policy referencing the active organization is now RETAINED and
|
|
999
|
+
fails closed (zero rows) with a one-time warning, where it previously vanished
|
|
1000
|
+
and the object read unscoped. `getReadFilter` shared the defect, so analytics and
|
|
1001
|
+
raw-SQL consumers were affected too. If a policy was only ever meant for
|
|
1002
|
+
multi-org, delete it or install `@objectstack/organizations`.
|
|
1003
|
+
|
|
1004
|
+
**D4 — `viewAllRecords`/`modifyAllRecords` never cross an organization
|
|
1005
|
+
boundary** (finding F2, framework#3540). Under a wall-less posture nothing
|
|
1006
|
+
bounded the wildcard superuser bits `organization_admin` carries, so a
|
|
1007
|
+
deployment that accumulated organizations (personal orgs on signup) made every
|
|
1008
|
+
owner/admin an environment-wide superuser. `auto-org-admin-grant` now grants a
|
|
1009
|
+
de-VAMA'd `organization_admin_no_bypass` variant when no wall is enforced, and
|
|
1010
|
+
revokes the superseded variant whenever the posture changes. **Upgrade impact:**
|
|
1011
|
+
in `single` posture an org owner/admin keeps full CRUD but loses the blanket
|
|
1012
|
+
ownership/sharing/RLS bypass. Deliberate deployment-wide visibility remains
|
|
1013
|
+
available through `admin_full_access` or an explicitly authored permission set —
|
|
1014
|
+
it just stops being a side effect of a better-auth membership role.
|
|
1015
|
+
|
|
1016
|
+
## Engine-owned organization stamping (D5)
|
|
1017
|
+
|
|
1018
|
+
Under any wall-enforcing posture the engine stamps `organization_id` from the
|
|
1019
|
+
caller's active organization on an insert that omits it, and validates every
|
|
1020
|
+
supplied value against the wall. Idempotent with the enterprise auto-stamp
|
|
1021
|
+
(neither overwrites a supplied value). This also closes a real hole: the
|
|
1022
|
+
pre-existing post-image check required a non-array payload, so a BULK insert
|
|
1023
|
+
could carry a forged `organization_id` per row. One forged row now denies the
|
|
1024
|
+
whole write.
|
|
1025
|
+
|
|
1026
|
+
## Group structure, extension fields and red-line lints (D6, D7)
|
|
1027
|
+
|
|
1028
|
+
- `sys_organization` gains `parent_organization_id` and `sort_order` — a
|
|
1029
|
+
**reporting dimension only**.
|
|
1030
|
+
- New lint `validateOrgAxisRedLines` (`org-axis-permission-inheritance`,
|
|
1031
|
+
`org-axis-cross-org-bu-grant`), wired into `os lint` / `os compile` /
|
|
1032
|
+
`os validate`: an RLS policy or sharing rule that walks the org tree is an
|
|
1033
|
+
error, as is a business-unit grant on a platform-global object.
|
|
1034
|
+
- Extension fields on better-auth-managed objects ride the existing ADR-0092
|
|
1035
|
+
whitelist. A new guard derives better-auth's real field surface from
|
|
1036
|
+
`getAuthTables()` at the pinned version and fails the build on any name
|
|
1037
|
+
collision, so a library upgrade cannot silently take ownership of a column.
|
|
1038
|
+
|
|
1039
|
+
## Enforce-or-remove (D11) — BREAKING
|
|
1040
|
+
|
|
1041
|
+
Both removals are of surface that had **zero runtime consumers**, so no
|
|
1042
|
+
behavior changes; authoring them is now a no-op instead of a lint warning.
|
|
1043
|
+
|
|
1044
|
+
- **`PermissionSet.contextVariables` — REMOVED.** The RLS compiler never read
|
|
1045
|
+
it. FROM → TO: a set a policy needs as `field IN (current_user.<key>)` is now
|
|
1046
|
+
supplied by a registered membership resolver (below); a constant belongs in
|
|
1047
|
+
the policy itself as a literal (`status = 'published'`).
|
|
1048
|
+
- **`Territory` / `TerritoryModel` / `TerritoryType` (`security/territory.zod.ts`)
|
|
1049
|
+
— REMOVED.** No runtime object, stack field or resolver existed. FROM → TO:
|
|
1050
|
+
matrix requirements are served by multi-position × business-unit anchoring; a
|
|
1051
|
+
generalized dimension-security module will arrive with its own ADR.
|
|
1052
|
+
- **`ExecutionContext.rlsMembership` — PRODUCTIZED.** The bag the compiler has
|
|
1053
|
+
merged since ADR-0056 finally has a producer: register an
|
|
1054
|
+
`IRlsMembershipResolver` (`@objectstack/spec/contracts`) under the
|
|
1055
|
+
`rls-membership-resolver` service, declaring the keys it owns. Fail-closed by
|
|
1056
|
+
construction — an unresolved key makes its policies drop out. Kernel-owned
|
|
1057
|
+
keys (`accessible_org_ids`, `org_user_ids`, …) are reserved and cannot be
|
|
1058
|
+
overwritten from this seam.
|
|
1059
|
+
|
|
1060
|
+
## Edition boundary (D12)
|
|
1061
|
+
|
|
1062
|
+
The `group` posture's enforcement primitives ship OPEN — the union wall,
|
|
1063
|
+
`accessible_org_ids` resolution, D5 stamping/validation, the D3/D4 correctness
|
|
1064
|
+
fixes and the D6 lints — because the correctness of a wall is never a paid
|
|
1065
|
+
feature (cloud ADR-0016 铁律「强制免费、治理收费」). `isolated` keeps its existing
|
|
1066
|
+
enterprise `org-scoping` probe, so the current commercial boundary for
|
|
1067
|
+
legal-entity isolation is unchanged by this release.
|
|
1068
|
+
|
|
1069
|
+
- 763931e: feat(filters): evaluate `{filter-token}` placeholders server-side (#3582)
|
|
1070
|
+
|
|
1071
|
+
Filter values travel as JSON, so a time- or user-scoped slice writes a
|
|
1072
|
+
placeholder instead of code:
|
|
1073
|
+
|
|
1074
|
+
```ts
|
|
1075
|
+
filter: { close_date: { $gte: '{current_year_start}' }, owner: '{current_user_id}' }
|
|
1076
|
+
```
|
|
1077
|
+
|
|
1078
|
+
The vocabulary has been in `@objectstack/spec` for a while (`date-macros.zod.ts`,
|
|
1079
|
+
`context-tokens.zod.ts`) and `objectstack build` rejects tokens outside it
|
|
1080
|
+
(#3574). What was missing is the half that _substitutes a value_: **nothing on
|
|
1081
|
+
the server ever did**. A placeholder reached the driver as the literal string
|
|
1082
|
+
`'{current_year_start}'`, compared as text, and matched nothing.
|
|
1083
|
+
|
|
1084
|
+
That failure is invisible — an empty widget looks exactly like a metric that is
|
|
1085
|
+
legitimately zero — so apps worked around it by computing dates at module load,
|
|
1086
|
+
which freezes "this year" into the built artifact and quietly goes stale.
|
|
1087
|
+
|
|
1088
|
+
**New: `resolveFilterTokens()` in `@objectstack/core`**, wired into the two
|
|
1089
|
+
server-side seams every filter passes through:
|
|
1090
|
+
|
|
1091
|
+
- **ObjectQL read path** — `find` / `findOne` / `count` / `aggregate`, so REST
|
|
1092
|
+
queries, related lists, saved-view filters and flow `find_records` all resolve.
|
|
1093
|
+
It runs before the middleware chain, so only author-supplied filters are
|
|
1094
|
+
inspected; RLS/sharing filters are injected downstream from concrete values.
|
|
1095
|
+
- **Analytics dataset executor** — a dataset's intrinsic `filter`, a widget's
|
|
1096
|
+
`runtimeFilter`, measure-scoped filters, and time-dimension `dateRange`s.
|
|
1097
|
+
This path needs its own call: `NativeSQLStrategy` compiles raw SQL and binds
|
|
1098
|
+
comparands directly, so a dashboard widget never passes through `engine.find()`.
|
|
1099
|
+
|
|
1100
|
+
Behavioural notes:
|
|
1101
|
+
|
|
1102
|
+
- Date tokens resolve to ISO strings (`YYYY-MM-DD`, or a full timestamp for
|
|
1103
|
+
`{now}` / `{N_hours_ago}` / `{N_minutes_ago}`). Turning that into a column's
|
|
1104
|
+
on-disk form stays the driver's job (`SqlDriver.temporalFilterValue`), so
|
|
1105
|
+
there is still exactly one source of truth for the storage convention.
|
|
1106
|
+
- Calendar boundaries follow `ExecutionContext.timezone`; one instant is pinned
|
|
1107
|
+
per filter tree, so a `>= {current_month_start}` / `< {next_month_start}` pair
|
|
1108
|
+
can never straddle a boundary.
|
|
1109
|
+
- `{current_org_id}` reads `ExecutionContext.tenantId`; `{current_user_id}` reads
|
|
1110
|
+
`userId`. A request carrying neither now **throws** instead of resolving to
|
|
1111
|
+
`null` — a null comparand degrades to `IS NULL` on most drivers and would hand
|
|
1112
|
+
back the rows the filter was written to exclude.
|
|
1113
|
+
- An unrecognised placeholder **throws**, carrying the near-miss fix
|
|
1114
|
+
(`{current_user}` → `{current_user_id}`, `{this_quarter_start}` →
|
|
1115
|
+
`{current_quarter_start}`). This matches what `objectstack build` already
|
|
1116
|
+
enforces. Consequence, previously implicit and now load-bearing: a filter value
|
|
1117
|
+
that is _entirely_ `{...}` is always read as a placeholder, so a literal value
|
|
1118
|
+
of that shape is not expressible — rename the value.
|
|
1119
|
+
|
|
1120
|
+
Also in this change: `notify` no longer sends the six-character string
|
|
1121
|
+
`"undefined"` as an audience member. `to: ['{record.owner.manager}']` walks
|
|
1122
|
+
`.manager` on a scalar foreign-key id, resolves to nothing, and `String(undefined)`
|
|
1123
|
+
turned that into a phantom recipient — the emit "succeeded", addressed nobody,
|
|
1124
|
+
and said nothing. Unresolved recipients are now dropped, and a node with no
|
|
1125
|
+
recipient left fails naming the offending template and pointing at the start
|
|
1126
|
+
node's `config.expand` (#3475), which does hydrate the relation.
|
|
1127
|
+
|
|
1128
|
+
- 4cca74c: fix(i18n)!: the `translation` metadata type speaks the same `objects.` shape everything else does (#3778)
|
|
1129
|
+
|
|
1130
|
+
A translation authored in the product saved successfully and then rendered
|
|
1131
|
+
nothing. Not a resolver gap — a contract split. The `translation` metadata type
|
|
1132
|
+
(`allowRuntimeCreate: true`, so Studio/the metadata API/an agent can author it)
|
|
1133
|
+
was registered against `AppTranslationBundleSchema`, an object-first shape keyed
|
|
1134
|
+
on `o.<object>`. Every resolver, `os i18n extract`, `os i18n check`, the objectui
|
|
1135
|
+
hooks, and all nine shipped bundles read `objects.<object>`. Nothing bridged the
|
|
1136
|
+
two, so the save path and the read path never met.
|
|
1137
|
+
|
|
1138
|
+
**Why converge instead of bridge.** A converter was the obvious fix and the
|
|
1139
|
+
wrong one: it would be throwaway code, and it would start producing _working_
|
|
1140
|
+
`o.`-shaped rows — closing the migration-free window that exists precisely
|
|
1141
|
+
because the feature never functioned. The retired shape's real-world footprint
|
|
1142
|
+
was zero: all three `*.translation.ts` files in the tree (platform-objects,
|
|
1143
|
+
CRM and todo examples) were already `objects.`-shaped, contradicting the type's
|
|
1144
|
+
own registered schema. Converging is a registration fix, not a migration.
|
|
1145
|
+
|
|
1146
|
+
**Breaking.** `AppTranslationBundleSchema`, `ObjectTranslationNodeSchema`, and
|
|
1147
|
+
their types are **deleted** — no deprecation cycle. Nothing worked end-to-end
|
|
1148
|
+
through them, so there is no functioning consumer to protect, and a
|
|
1149
|
+
deprecated-but-present schema is exactly the exemplar an AI agent copies into
|
|
1150
|
+
new code. The optional `II18nService.getAppBundle` / `loadAppBundle` methods go
|
|
1151
|
+
with them: zero implementers, so they advertised a capability the runtime never
|
|
1152
|
+
delivered.
|
|
1153
|
+
|
|
1154
|
+
**The replacement.** `TranslationItemSchema` — one locale of the same
|
|
1155
|
+
`TranslationData` groups a file bundle uses, plus the `locale` it translates,
|
|
1156
|
+
with a `defineTranslation()` factory. An item is one entry of a
|
|
1157
|
+
`TranslationBundle`; that is the whole type.
|
|
1158
|
+
|
|
1159
|
+
Three details are deliberate, all aimed at the failure being silent rather than
|
|
1160
|
+
loud:
|
|
1161
|
+
|
|
1162
|
+
- **`locale` is required**, not inferred from the item name. The sync skips an
|
|
1163
|
+
item whose locale it cannot resolve, and a skip is invisible to whoever — or
|
|
1164
|
+
whatever — authored it. (The name fallback still covers rows written before
|
|
1165
|
+
this.)
|
|
1166
|
+
- **Retired keys are rejected, not stripped.** Zod drops undeclared keys
|
|
1167
|
+
silently, which would reproduce this bug exactly: save succeeds, nothing
|
|
1168
|
+
renders. A pre-parse guard turns that silence into a 422 naming the group to
|
|
1169
|
+
use (`'o' … — use 'objects.<object_name>'`). It runs ahead of the parse so the
|
|
1170
|
+
retired keys stay out of the schema itself — the generated JSON Schema and the
|
|
1171
|
+
Studio editor never advertise a shape that cannot work.
|
|
1172
|
+
- **`ObjectTranslationData.label` is now optional.** Partial translation is the
|
|
1173
|
+
normal state and every resolver already treats each key as independent.
|
|
1174
|
+
Requiring it forced authors to restate the source label just to validate,
|
|
1175
|
+
filling bundles with fake translations that mask real coverage gaps.
|
|
1176
|
+
|
|
1177
|
+
Also in this change: the authored-translation sync warns (naming the row and the
|
|
1178
|
+
fix) when it meets a row still in the retired shape instead of loading it into
|
|
1179
|
+
nowhere, and no longer merges publish bookkeeping (`_lockReason`,
|
|
1180
|
+
`_packageVersion`, …) into the translation layer. `GET
|
|
1181
|
+
/i18n/labels/:object/:locale`'s fallback now reads the nested
|
|
1182
|
+
`objects.<obj>.fields.<field>.label` data it is actually given — it scanned for
|
|
1183
|
+
flat dotted `o.<obj>.fields.<field>` keys, a third dialect no producer ever
|
|
1184
|
+
wrote, so it always returned `{}`.
|
|
1185
|
+
|
|
1186
|
+
Migration: author every translation — file or runtime item — under `objects.`.
|
|
1187
|
+
`o` → `objects`, `app` → `apps`, `nav` → `apps.<app>.navigation.<id>.label`,
|
|
1188
|
+
`dashboard` → `dashboards`, `_globalOptions` →
|
|
1189
|
+
`objects.<obj>.fields.<field>.options`, `_meta.locale` → top-level `locale`,
|
|
1190
|
+
`_actions.confirmMessage` → `_actions.confirmText`. `reports`, `notifications`,
|
|
1191
|
+
`errors`, and `namespace` had no runtime consumer and have no replacement.
|
|
1192
|
+
|
|
1193
|
+
### Patch Changes
|
|
1194
|
+
|
|
1195
|
+
- a227ed7: fix(objectql)!: one key for the empty group bucket — real `null`, on both aggregation paths (#3839)
|
|
1196
|
+
|
|
1197
|
+
A grouped row whose dimension value is empty now carries `null` for that
|
|
1198
|
+
dimension no matter which way the aggregate ran. Downstream code can test the
|
|
1199
|
+
empty bucket with a plain `value == null` again: charts render their own empty
|
|
1200
|
+
label, drill-through on that bucket builds `field = null` and returns the rows
|
|
1201
|
+
it should, and a dashboard no longer changes shape when the driver, the
|
|
1202
|
+
granularity or the reference timezone changes.
|
|
1203
|
+
|
|
1204
|
+
### What was wrong
|
|
1205
|
+
|
|
1206
|
+
`engine.aggregate` has two implementations of one feature. It pushes the
|
|
1207
|
+
aggregate down as SQL when the driver advertises every requested granularity and
|
|
1208
|
+
the reference timezone is UTC; otherwise it fetches rows and buckets them in JS.
|
|
1209
|
+
The two disagreed about how to spell "empty":
|
|
1210
|
+
|
|
1211
|
+
```
|
|
1212
|
+
--- same dataset, same query, one row with a NULL value ---
|
|
1213
|
+
pushed-down SQL : [{ "key": null, "type": "null", "total": 2 }, …]
|
|
1214
|
+
in-memory : [{ "key": "(null)", "type": "string", "total": 2 }, …]
|
|
1215
|
+
```
|
|
1216
|
+
|
|
1217
|
+
The measures were always right — only the key's type and literal differed —
|
|
1218
|
+
which is why this went unnoticed for so long: every total reconciled. But the
|
|
1219
|
+
engine picks a path per query, so the same data produced a different bucket key
|
|
1220
|
+
on SQLite-plus-UTC-plus-`month` than on `week` (which SQLite does not advertise),
|
|
1221
|
+
a non-UTC timezone, or `driver-rest` / `driver-memory` / a remote Turso, all of
|
|
1222
|
+
which bucket in memory unconditionally.
|
|
1223
|
+
|
|
1224
|
+
It was never date-specific either. A plain `groupBy: ['stage']` over a NULL
|
|
1225
|
+
column diverged the same way.
|
|
1226
|
+
|
|
1227
|
+
Consumers are written against `null` — they check `== null` and supply their own
|
|
1228
|
+
empty label ('—', '(empty)', a localized "Uncategorized"). The sentinel defeated
|
|
1229
|
+
every one of them: it rendered a raw English debug string in the UI, and a drill
|
|
1230
|
+
on the empty bucket compiled to `field = '(null)'` and matched nothing.
|
|
1231
|
+
|
|
1232
|
+
The in-memory path's comment justified the string as staying "consistent with
|
|
1233
|
+
the client `useReportData` hook". That hook was removed with ADR-0021, and the
|
|
1234
|
+
literal never appeared in it.
|
|
1235
|
+
|
|
1236
|
+
### What changed
|
|
1237
|
+
|
|
1238
|
+
- `applyInMemoryAggregation` and `bucketDateValue` (`@objectstack/objectql`) key
|
|
1239
|
+
the empty bucket as `null`. `bucketDateValue` now returns `string | null`. A
|
|
1240
|
+
null instant and an unparseable one still share one bucket, because SQL cannot
|
|
1241
|
+
tell them apart either (`strftime('%Y-%m', 'not-a-date')` is NULL).
|
|
1242
|
+
- The internal composite bucket id is JSON-encoded, so the empty bucket stays
|
|
1243
|
+
distinct from a row whose value is the literal string `"null"`.
|
|
1244
|
+
- `bucketKeyToCalendarRange` (`@objectstack/core`) accepts `string | null`. The
|
|
1245
|
+
empty bucket has no calendar span, so a drill on it opens the unscoped
|
|
1246
|
+
superset instead of an invented bound — unchanged behavior, honest signature.
|
|
1247
|
+
- The driver output contract in `@objectstack/spec` now states the rule: a row
|
|
1248
|
+
with no value keys as `null`, never a sentinel. Propagating NULL through the
|
|
1249
|
+
bucket expression is the whole of it; a driver only breaks it by adding a
|
|
1250
|
+
`COALESCE`.
|
|
1251
|
+
|
|
1252
|
+
### Gates
|
|
1253
|
+
|
|
1254
|
+
`checkDateBucketParity` (`@objectstack/verify`) deliberately carried no null
|
|
1255
|
+
instant, because the divergence would have failed it for a reason it was not
|
|
1256
|
+
about. Its fixture now has one, so the convergence is held in place — including
|
|
1257
|
+
for out-of-tree drivers that run the check against themselves.
|
|
1258
|
+
|
|
1259
|
+
Two fixes were needed to make that fixture meaningful:
|
|
1260
|
+
|
|
1261
|
+
- The check folded bucket labels through `String(value)`, which turns SQL NULL
|
|
1262
|
+
into `'null'` — a label a TEXT column can genuinely hold. A driver spelling
|
|
1263
|
+
"empty" as a string could compare equal to one returning real NULL. The empty
|
|
1264
|
+
bucket is now keyed out of band.
|
|
1265
|
+
- Label sets were compared with `JSON.stringify`, which is sensitive to key
|
|
1266
|
+
insertion order. Row order is not part of this contract and the two paths
|
|
1267
|
+
naturally differ (SQL sorts its groups; the in-memory path emits first-seen
|
|
1268
|
+
order), so a driver with entirely correct buckets could be reported as
|
|
1269
|
+
disagreeing — with an empty diff message, since nothing actually differed.
|
|
1270
|
+
The comparison is now order-insensitive.
|
|
1271
|
+
|
|
1272
|
+
A new dogfood check covers the non-date half against real drivers: same dataset,
|
|
1273
|
+
plain and date-bucketed `groupBy`, both paths, one key.
|
|
1274
|
+
|
|
1275
|
+
- Updated dependencies [50616d9]
|
|
1276
|
+
- Updated dependencies [08b5a3d]
|
|
1277
|
+
- Updated dependencies [d99aeb3]
|
|
1278
|
+
- Updated dependencies [4727eb8]
|
|
1279
|
+
- Updated dependencies [f63cd09]
|
|
1280
|
+
- Updated dependencies [fa3d0cf]
|
|
1281
|
+
- Updated dependencies [af5a224]
|
|
1282
|
+
- Updated dependencies [71f76e1]
|
|
1283
|
+
- Updated dependencies [37b1346]
|
|
1284
|
+
- Updated dependencies [99736a0]
|
|
1285
|
+
- Updated dependencies [fe67e34]
|
|
1286
|
+
- Updated dependencies [fdb4f50]
|
|
1287
|
+
- Updated dependencies [1bd5652]
|
|
1288
|
+
- Updated dependencies [14252d3]
|
|
1289
|
+
- Updated dependencies [7fb436c]
|
|
1290
|
+
- Updated dependencies [879ea13]
|
|
1291
|
+
- Updated dependencies [201b31f]
|
|
1292
|
+
- Updated dependencies [e2616e0]
|
|
1293
|
+
- Updated dependencies [6fdc5c6]
|
|
1294
|
+
- Updated dependencies [8b9d71e]
|
|
1295
|
+
- Updated dependencies [33f5e23]
|
|
1296
|
+
- Updated dependencies [259af21]
|
|
1297
|
+
- Updated dependencies [587fc91]
|
|
1298
|
+
- Updated dependencies [1986594]
|
|
1299
|
+
- Updated dependencies [ad4af62]
|
|
1300
|
+
- Updated dependencies [d44dbfa]
|
|
1301
|
+
- Updated dependencies [474fe39]
|
|
1302
|
+
- Updated dependencies [0bc685a]
|
|
1303
|
+
- Updated dependencies [b949059]
|
|
1304
|
+
- Updated dependencies [be1c52c]
|
|
1305
|
+
- Updated dependencies [c5ff96d]
|
|
1306
|
+
- Updated dependencies [84e7be9]
|
|
1307
|
+
- Updated dependencies [a6c3f38]
|
|
1308
|
+
- Updated dependencies [debc23a]
|
|
1309
|
+
- Updated dependencies [0f8ad09]
|
|
1310
|
+
- Updated dependencies [8f9689f]
|
|
1311
|
+
- Updated dependencies [57a3bb3]
|
|
1312
|
+
- Updated dependencies [5f9a987]
|
|
1313
|
+
- Updated dependencies [db02d47]
|
|
1314
|
+
- Updated dependencies [0bfdf46]
|
|
1315
|
+
- Updated dependencies [376a061]
|
|
1316
|
+
- Updated dependencies [7c7e246]
|
|
1317
|
+
- Updated dependencies [f35cdc5]
|
|
1318
|
+
- Updated dependencies [9ea2bc5]
|
|
1319
|
+
- Updated dependencies [c2d9098]
|
|
1320
|
+
- Updated dependencies [a227ed7]
|
|
1321
|
+
- Updated dependencies [9613396]
|
|
1322
|
+
- Updated dependencies [e47b342]
|
|
1323
|
+
- Updated dependencies [4ed7ed4]
|
|
1324
|
+
- Updated dependencies [2fa4ca1]
|
|
1325
|
+
- Updated dependencies [f5a2320]
|
|
1326
|
+
- Updated dependencies [deb538f]
|
|
1327
|
+
- Updated dependencies [5b89711]
|
|
1328
|
+
- Updated dependencies [0c8a22f]
|
|
1329
|
+
- Updated dependencies [763931e]
|
|
1330
|
+
- Updated dependencies [de9af8a]
|
|
1331
|
+
- Updated dependencies [c4df271]
|
|
1332
|
+
- Updated dependencies [a41ba5c]
|
|
1333
|
+
- Updated dependencies [189854c]
|
|
1334
|
+
- Updated dependencies [0e3a226]
|
|
1335
|
+
- Updated dependencies [1d4756e]
|
|
1336
|
+
- Updated dependencies [720c5ad]
|
|
1337
|
+
- Updated dependencies [a8d1e24]
|
|
1338
|
+
- Updated dependencies [41642b0]
|
|
1339
|
+
- Updated dependencies [4cca74c]
|
|
1340
|
+
- Updated dependencies [88ef03e]
|
|
1341
|
+
- Updated dependencies [9e2caf3]
|
|
1342
|
+
- Updated dependencies [81ce41a]
|
|
1343
|
+
- Updated dependencies [85e1e4e]
|
|
1344
|
+
- Updated dependencies [dac6a08]
|
|
1345
|
+
- Updated dependencies [394b7a1]
|
|
1346
|
+
- Updated dependencies [677b591]
|
|
1347
|
+
- Updated dependencies [d77d1b7]
|
|
1348
|
+
- Updated dependencies [5b79a34]
|
|
1349
|
+
- Updated dependencies [c757854]
|
|
1350
|
+
- Updated dependencies [0045682]
|
|
1351
|
+
- Updated dependencies [2a5f04a]
|
|
1352
|
+
- Updated dependencies [4f740b0]
|
|
1353
|
+
- Updated dependencies [67452d1]
|
|
1354
|
+
- Updated dependencies [0fc6219]
|
|
1355
|
+
- Updated dependencies [605e190]
|
|
1356
|
+
- Updated dependencies [c6c59f1]
|
|
1357
|
+
- Updated dependencies [b0e78a8]
|
|
1358
|
+
- Updated dependencies [f31cc8d]
|
|
1359
|
+
- Updated dependencies [f343dc4]
|
|
1360
|
+
- Updated dependencies [8269e32]
|
|
1361
|
+
- Updated dependencies [74f7339]
|
|
1362
|
+
- Updated dependencies [a6c35a2]
|
|
1363
|
+
- Updated dependencies [c2f1002]
|
|
1364
|
+
- Updated dependencies [f163028]
|
|
1365
|
+
- Updated dependencies [f07808c]
|
|
1366
|
+
- Updated dependencies [7ffc3d3]
|
|
1367
|
+
- Updated dependencies [88346ba]
|
|
1368
|
+
- Updated dependencies [4631592]
|
|
1369
|
+
- Updated dependencies [32ff033]
|
|
1370
|
+
- Updated dependencies [5ac93d4]
|
|
1371
|
+
- Updated dependencies [93f267f]
|
|
1372
|
+
- Updated dependencies [0024abf]
|
|
1373
|
+
- Updated dependencies [acbf364]
|
|
1374
|
+
- Updated dependencies [7687f7b]
|
|
1375
|
+
- Updated dependencies [1659072]
|
|
1376
|
+
- Updated dependencies [abceb0d]
|
|
1377
|
+
- Updated dependencies [0c302a7]
|
|
1378
|
+
- Updated dependencies [6633337]
|
|
1379
|
+
- Updated dependencies [f00d8d4]
|
|
1380
|
+
- Updated dependencies [503be86]
|
|
1381
|
+
- Updated dependencies [cde1975]
|
|
1382
|
+
- Updated dependencies [0bc685a]
|
|
1383
|
+
- Updated dependencies [11949fc]
|
|
1384
|
+
- Updated dependencies [b098b0e]
|
|
1385
|
+
- Updated dependencies [4d00b13]
|
|
1386
|
+
- Updated dependencies [57bab76]
|
|
1387
|
+
- Updated dependencies [b90086a]
|
|
1388
|
+
- Updated dependencies [b95577a]
|
|
1389
|
+
- Updated dependencies [83c161f]
|
|
1390
|
+
- Updated dependencies [d8c4957]
|
|
1391
|
+
- Updated dependencies [f24cb83]
|
|
1392
|
+
- Updated dependencies [5dbbb92]
|
|
1393
|
+
- Updated dependencies [69f1dfd]
|
|
1394
|
+
- @objectstack/spec@17.0.0-rc.0
|
|
1395
|
+
|
|
1396
|
+
## 16.1.0
|
|
1397
|
+
|
|
1398
|
+
### Minor Changes
|
|
1399
|
+
|
|
1400
|
+
- b20201f: fix(service-automation): `runAs:'user'` runs data ops with the triggering user's
|
|
1401
|
+
real permission sets + positions, not a bare member fallback (#3356, follow-up to
|
|
1402
|
+
#1888)
|
|
1403
|
+
|
|
1404
|
+
Since #1888 the automation engine honours `flow.runAs` (`system` elevates), but
|
|
1405
|
+
the `runAs:'user'` credential propagation was hollow. A record-change-triggered
|
|
1406
|
+
`runAs:'user'` flow ran its data nodes (`update_record`, …) with a **zero-grant**
|
|
1407
|
+
principal — only the `member`/`everyone` baseline — even when the triggering user
|
|
1408
|
+
was fully authorized. Two faces by object config: a `private` object 403'd the
|
|
1409
|
+
in-flow write (`not permitted for positions [org_member, everyone]` — the user's
|
|
1410
|
+
permission sets were invisible); a `public_read_write` object let the write
|
|
1411
|
+
through but **silently stripped** readonly/FLS-gated fields. The root cause: the
|
|
1412
|
+
ObjectQL record-change hook session carries only a `userId` — never the writer's
|
|
1413
|
+
positions/permission sets — and nothing in between resolved them, so the comment
|
|
1414
|
+
promising "enforces RLS exactly as the user who made the change" never held.
|
|
1415
|
+
|
|
1416
|
+
The fix resolves the triggering user's **actual** authorization at run setup, from
|
|
1417
|
+
the same tables a direct REST request resolves through:
|
|
1418
|
+
|
|
1419
|
+
- **`@objectstack/core`** factors the userId-driven core of `resolveAuthzContext`
|
|
1420
|
+
into a new exported `resolveUserAuthzGrants(ql, userId, opts)` — the single place
|
|
1421
|
+
that reads `sys_member` / `sys_user_position` / `sys_*_permission_set` and
|
|
1422
|
+
derives positions, permission-set names, `platform_admin`, and posture. The
|
|
1423
|
+
HTTP resolver now delegates to it (behaviour byte-identical; the full contract
|
|
1424
|
+
suite still passes), so a non-HTTP surface that already knows the user id builds
|
|
1425
|
+
the SAME envelope instead of re-implementing the reads.
|
|
1426
|
+
- **`@objectstack/service-automation`** gains `AutomationEngine.setUserGrantsResolver`,
|
|
1427
|
+
wired by the plugin to `resolveUserAuthzGrants` over the objectql/data engine.
|
|
1428
|
+
For a `runAs:'user'` run whose trigger left the authz envelope unresolved (no
|
|
1429
|
+
`permissions`), the engine now resolves the user's positions + permission sets
|
|
1430
|
+
once at run setup and threads them into every data node's ObjectQL context —
|
|
1431
|
+
so the run enforces RLS/FLS exactly as that user. Contexts that already carry
|
|
1432
|
+
`permissions` are left untouched (a REST trigger, and notably an ADR-0090 agent
|
|
1433
|
+
ceiling acting on-behalf-of a user — always non-empty — so a deliberately
|
|
1434
|
+
narrowed identity is never re-broadened). `runAs:'system'` is unchanged, and a
|
|
1435
|
+
resolver error fails safe (warns, keeps the bare user — never elevates).
|
|
1436
|
+
- **`@objectstack/trigger-record-change`** stops forwarding the misleading
|
|
1437
|
+
half-populated `positions` (empty in practice, and never `permissions`) from the
|
|
1438
|
+
hook session; it forwards `userId` + tenant only and lets the engine resolve the
|
|
1439
|
+
full grants authoritatively.
|
|
1440
|
+
|
|
1441
|
+
When no ObjectQL engine is present (bare engine / tests) the resolver is unwired
|
|
1442
|
+
and run identity is unchanged from before.
|
|
1443
|
+
|
|
1444
|
+
### Patch Changes
|
|
1445
|
+
|
|
1446
|
+
- Updated dependencies [9e45b63]
|
|
1447
|
+
- @objectstack/spec@16.1.0
|
|
1448
|
+
|
|
1449
|
+
## 16.0.0
|
|
1450
|
+
|
|
1451
|
+
### Minor Changes
|
|
1452
|
+
|
|
1453
|
+
- dd9f223: feat(analytics): scope a datetime date-bucket drill to the reference-tz midnight instants (#1752 follow-up)
|
|
1454
|
+
|
|
1455
|
+
Closes the one gap left by the initial #1752 change: a `datetime` date dimension
|
|
1456
|
+
bucketed under a **non-UTC reference timezone** previously fell back to a superset
|
|
1457
|
+
drill (its bucket boundary is that tz's midnight _instant_, which `YYYY-MM-DD`
|
|
1458
|
+
calendar bounds can't express).
|
|
1459
|
+
|
|
1460
|
+
- **`@objectstack/core`** adds `zonedDateStartToUtcMs(ymd, tz)` — the UTC instant
|
|
1461
|
+
at which a calendar day begins in a reference timezone (the inverse of
|
|
1462
|
+
`calendarPartsInTz`). DST-safe: the offset is read from the platform tz
|
|
1463
|
+
database via `Intl`, with a two-pass resolution for the rare offset-boundary
|
|
1464
|
+
case; an unset/`'UTC'`/invalid zone returns plain UTC midnight.
|
|
1465
|
+
- **`@objectstack/service-analytics`** now emits `drillRanges` bounds per the
|
|
1466
|
+
field's temporal type (ADR-0053): a `datetime` field → ISO **instant** bounds
|
|
1467
|
+
at the reference tz's midnight (works under any tz, incl. DST); a `date` field
|
|
1468
|
+
→ `YYYY-MM-DD` calendar bounds (tz-naive, exact under any tz). An unknown field
|
|
1469
|
+
type is still emitted only under UTC and omitted (superset) under a non-UTC tz.
|
|
1470
|
+
|
|
1471
|
+
No objectui change is needed — the client already forwards whatever bound values
|
|
1472
|
+
the server sends into the drill filter and the `filter[field][gte|lt]` URL.
|
|
1473
|
+
|
|
1474
|
+
- 290e2f0: feat(analytics): emit a half-open date-range drill scope for granularity-bucketed date dimensions (#1752)
|
|
1475
|
+
|
|
1476
|
+
A report/dashboard cell grouped by a `dateGranularity` date dimension ("2026-Q2")
|
|
1477
|
+
covers a SPAN of records, so drilling it needs a range (`>= start AND < nextStart`),
|
|
1478
|
+
which the equality drill contract (`drillRawRows`) can't express — date dims were
|
|
1479
|
+
therefore excluded from drill metadata and a drill landed on an unscoped superset.
|
|
1480
|
+
|
|
1481
|
+
- **`@objectstack/core`** adds `bucketKeyToCalendarRange(key, granularity)`, the
|
|
1482
|
+
inverse of `bucketDateValue`: it turns a canonical bucket key into its half-open
|
|
1483
|
+
`[start, end)` calendar span (`YYYY-MM-DD`, `end` exclusive). Pure, timezone-naive
|
|
1484
|
+
calendar arithmetic; returns `null` for unbucketable / out-of-range keys so the
|
|
1485
|
+
caller falls back to an unscoped (superset) drill rather than emit a wrong bound.
|
|
1486
|
+
- **`@objectstack/service-analytics`** emits a `drillRanges` sidecar (aligned to
|
|
1487
|
+
`rows` by index — the range companion to `drillRawRows`) for `date` +
|
|
1488
|
+
`dateGranularity` dimensions, computed from the canonical bucket key in the
|
|
1489
|
+
pre-label-resolution snapshot pass. A `datetime` field under a non-UTC reference
|
|
1490
|
+
timezone is omitted (host drills a superset) until instant-boundary support
|
|
1491
|
+
lands; a tz-naive `date` field is exact under any timezone (ADR-0053).
|
|
1492
|
+
|
|
1493
|
+
Consumed by objectui's report drill-through to scope the drilled record list to the
|
|
1494
|
+
clicked time bucket.
|
|
1495
|
+
|
|
1496
|
+
### Patch Changes
|
|
1497
|
+
|
|
1498
|
+
- e057f42: fix: harden the bulk-write path — retries, idempotency, contracts, and summary visibility (#3147–#3152)
|
|
1499
|
+
|
|
1500
|
+
Six reliability fixes to the batched seed/import + `engine.insert(array)` path
|
|
1501
|
+
introduced by the #2678 bulk-write rework:
|
|
1502
|
+
|
|
1503
|
+
- **#3151** `bulkWrite` validates that `writeBatch` returns one record per input
|
|
1504
|
+
row (a short/long/non-array return is degraded per-row, not backfilled as
|
|
1505
|
+
phantom success); `engine.insert(array)` likewise rejects a short driver
|
|
1506
|
+
`bulkCreate` return instead of padding afterInsert with `undefined`.
|
|
1507
|
+
- **#3150** wraps the two remaining un-retried write points (seed
|
|
1508
|
+
`writeRecord`/`resolveDeferredUpdates`, import's no-`createManyData`
|
|
1509
|
+
fallback) in `withTransientRetry`; `defaultIsTransientError` short-circuits
|
|
1510
|
+
definitive logical errors to non-transient.
|
|
1511
|
+
- **#3148** import `resolveRef` flushes pending creates on a same-object miss so
|
|
1512
|
+
a later row can reference an earlier same-file CREATE, and no longer
|
|
1513
|
+
negatively caches a miss.
|
|
1514
|
+
- **#3149** threads an `attempt` counter through `bulkWrite`; seed rechecks by
|
|
1515
|
+
`externalId` and import by `matchFields` before re-writing, so a
|
|
1516
|
+
commit-then-lost-response retry cannot duplicate a batch.
|
|
1517
|
+
- **#3147** `recomputeSummaries` retries transient failures and, on exhaustion,
|
|
1518
|
+
surfaces `SummaryRecomputeError` (`ERR_SUMMARY_RECOMPUTE`) instead of a
|
|
1519
|
+
silent warn; seed/import recover it to a warning without re-writing.
|
|
1520
|
+
- **#3152** autonumbers are assigned after validation, so a batch that dies in
|
|
1521
|
+
validation consumes no sequence value (no number-range gaps).
|
|
1522
|
+
|
|
1523
|
+
- 5f05de2: **`createLogger({ file })` now actually writes the file under ESM.** `openFileStream` loaded `fs` with a lazy `require()` to keep the browser-safe logger entry out of the `fs` bundle graph; esbuild rewrites that to its `__require` shim in the ESM output, which throws `Dynamic require of "fs" is not supported`, and a bare `catch {}` swallowed it. Since the workspace is `type: module`, every Node ESM consumer — `os serve`, `os dev` — silently got no file logging at all, while the CJS build kept working. The builtin now loads via `process.getBuiltinModule` (opaque to bundlers, works in both module systems, with a `require` fallback for Node < 20.16), and a `file` destination that cannot be opened reports itself on stderr instead of disappearing.
|
|
1524
|
+
|
|
1525
|
+
Turning the destination back on also fixed three faults that were unreachable while it never opened: `child()` opened a second stream per child and orphaned it, destroying a child logger closed the stream its parent and siblings were still writing to, and an async open failure (e.g. an unwritable path) hit an `'error'` event with no listener and took the process down.
|
|
1526
|
+
|
|
1527
|
+
- 021ba4c: fix(core): ObjectLogger honors NO_COLOR and TTY detection before emitting ANSI colors
|
|
1528
|
+
|
|
1529
|
+
The kernel/plugin logger (`ctx.logger`, wired by `os serve` / `os dev`) colorized its
|
|
1530
|
+
`pretty`-format level tags unconditionally, so `NO_COLOR=1` runs and piped/CI output
|
|
1531
|
+
still carried ANSI escapes (e.g. `\x1b[31m…ERROR\x1b[0m`), breaking plain-text log
|
|
1532
|
+
scanners (see scripts/publish-smoke.sh, which had to strip ANSI before grepping).
|
|
1533
|
+
|
|
1534
|
+
Per the no-color.org convention, color is now emitted only when the destination stream
|
|
1535
|
+
(stdout, or stderr for error/fatal) is an interactive TTY **and** `NO_COLOR` is unset or
|
|
1536
|
+
empty — any non-empty `NO_COLOR` value disables color. Interactive terminals keep the
|
|
1537
|
+
existing colorized output. The optional file destination now always receives plain text.
|
|
1538
|
+
|
|
1539
|
+
- Updated dependencies [f972574]
|
|
1540
|
+
- Updated dependencies [6289ec3]
|
|
1541
|
+
- Updated dependencies [22013aa]
|
|
1542
|
+
- Updated dependencies [3ad3dd5]
|
|
1543
|
+
- Updated dependencies [8efa395]
|
|
1544
|
+
- Updated dependencies [3a18b60]
|
|
1545
|
+
- Updated dependencies [a8aa34c]
|
|
1546
|
+
- Updated dependencies [a3823b2]
|
|
1547
|
+
- Updated dependencies [43a3efb]
|
|
1548
|
+
- Updated dependencies [524696a]
|
|
1549
|
+
- Updated dependencies [bfa3c3f]
|
|
1550
|
+
- Updated dependencies [5e3301d]
|
|
1551
|
+
- Updated dependencies [46e876c]
|
|
1552
|
+
- Updated dependencies [158aa14]
|
|
1553
|
+
- Updated dependencies [62a2117]
|
|
1554
|
+
- Updated dependencies [d2723e2]
|
|
1555
|
+
- Updated dependencies [fefcd54]
|
|
1556
|
+
- Updated dependencies [beaf2de]
|
|
1557
|
+
- Updated dependencies [369eb6e]
|
|
1558
|
+
- Updated dependencies [06ff734]
|
|
1559
|
+
- Updated dependencies [b659111]
|
|
1560
|
+
- Updated dependencies [5754a23]
|
|
1561
|
+
- Updated dependencies [6c270a6]
|
|
1562
|
+
- Updated dependencies [668dd17]
|
|
1563
|
+
- Updated dependencies [8abf133]
|
|
1564
|
+
- Updated dependencies [e0859b1]
|
|
1565
|
+
- Updated dependencies [04ecd4e]
|
|
1566
|
+
- Updated dependencies [4d5a892]
|
|
1567
|
+
- Updated dependencies [16cebeb]
|
|
1568
|
+
- Updated dependencies [86d30af]
|
|
1569
|
+
- Updated dependencies [8923843]
|
|
1570
|
+
- Updated dependencies [a2795f6]
|
|
1571
|
+
- Updated dependencies [f16b492]
|
|
1572
|
+
- Updated dependencies [4b6fde8]
|
|
1573
|
+
- Updated dependencies [2018df9]
|
|
1574
|
+
- Updated dependencies [fc5a3a2]
|
|
1575
|
+
- Updated dependencies [8ff9210]
|
|
1576
|
+
- @objectstack/spec@16.0.0
|
|
1577
|
+
|
|
1578
|
+
## 16.0.0-rc.1
|
|
1579
|
+
|
|
1580
|
+
### Patch Changes
|
|
1581
|
+
|
|
1582
|
+
- Updated dependencies [6289ec3]
|
|
1583
|
+
- Updated dependencies [8efa395]
|
|
1584
|
+
- Updated dependencies [bfa3c3f]
|
|
1585
|
+
- Updated dependencies [62a2117]
|
|
1586
|
+
- Updated dependencies [06ff734]
|
|
1587
|
+
- @objectstack/spec@16.0.0-rc.1
|
|
1588
|
+
|
|
1589
|
+
## 16.0.0-rc.0
|
|
1590
|
+
|
|
1591
|
+
### Minor Changes
|
|
1592
|
+
|
|
1593
|
+
- dd9f223: feat(analytics): scope a datetime date-bucket drill to the reference-tz midnight instants (#1752 follow-up)
|
|
1594
|
+
|
|
1595
|
+
Closes the one gap left by the initial #1752 change: a `datetime` date dimension
|
|
1596
|
+
bucketed under a **non-UTC reference timezone** previously fell back to a superset
|
|
1597
|
+
drill (its bucket boundary is that tz's midnight _instant_, which `YYYY-MM-DD`
|
|
1598
|
+
calendar bounds can't express).
|
|
1599
|
+
|
|
1600
|
+
- **`@objectstack/core`** adds `zonedDateStartToUtcMs(ymd, tz)` — the UTC instant
|
|
1601
|
+
at which a calendar day begins in a reference timezone (the inverse of
|
|
1602
|
+
`calendarPartsInTz`). DST-safe: the offset is read from the platform tz
|
|
1603
|
+
database via `Intl`, with a two-pass resolution for the rare offset-boundary
|
|
1604
|
+
case; an unset/`'UTC'`/invalid zone returns plain UTC midnight.
|
|
1605
|
+
- **`@objectstack/service-analytics`** now emits `drillRanges` bounds per the
|
|
1606
|
+
field's temporal type (ADR-0053): a `datetime` field → ISO **instant** bounds
|
|
1607
|
+
at the reference tz's midnight (works under any tz, incl. DST); a `date` field
|
|
1608
|
+
→ `YYYY-MM-DD` calendar bounds (tz-naive, exact under any tz). An unknown field
|
|
1609
|
+
type is still emitted only under UTC and omitted (superset) under a non-UTC tz.
|
|
1610
|
+
|
|
1611
|
+
No objectui change is needed — the client already forwards whatever bound values
|
|
1612
|
+
the server sends into the drill filter and the `filter[field][gte|lt]` URL.
|
|
1613
|
+
|
|
1614
|
+
- 290e2f0: feat(analytics): emit a half-open date-range drill scope for granularity-bucketed date dimensions (#1752)
|
|
1615
|
+
|
|
1616
|
+
A report/dashboard cell grouped by a `dateGranularity` date dimension ("2026-Q2")
|
|
1617
|
+
covers a SPAN of records, so drilling it needs a range (`>= start AND < nextStart`),
|
|
1618
|
+
which the equality drill contract (`drillRawRows`) can't express — date dims were
|
|
1619
|
+
therefore excluded from drill metadata and a drill landed on an unscoped superset.
|
|
1620
|
+
|
|
1621
|
+
- **`@objectstack/core`** adds `bucketKeyToCalendarRange(key, granularity)`, the
|
|
1622
|
+
inverse of `bucketDateValue`: it turns a canonical bucket key into its half-open
|
|
1623
|
+
`[start, end)` calendar span (`YYYY-MM-DD`, `end` exclusive). Pure, timezone-naive
|
|
1624
|
+
calendar arithmetic; returns `null` for unbucketable / out-of-range keys so the
|
|
1625
|
+
caller falls back to an unscoped (superset) drill rather than emit a wrong bound.
|
|
1626
|
+
- **`@objectstack/service-analytics`** emits a `drillRanges` sidecar (aligned to
|
|
1627
|
+
`rows` by index — the range companion to `drillRawRows`) for `date` +
|
|
1628
|
+
`dateGranularity` dimensions, computed from the canonical bucket key in the
|
|
1629
|
+
pre-label-resolution snapshot pass. A `datetime` field under a non-UTC reference
|
|
1630
|
+
timezone is omitted (host drills a superset) until instant-boundary support
|
|
1631
|
+
lands; a tz-naive `date` field is exact under any timezone (ADR-0053).
|
|
1632
|
+
|
|
1633
|
+
Consumed by objectui's report drill-through to scope the drilled record list to the
|
|
1634
|
+
clicked time bucket.
|
|
1635
|
+
|
|
1636
|
+
### Patch Changes
|
|
1637
|
+
|
|
1638
|
+
- e057f42: fix: harden the bulk-write path — retries, idempotency, contracts, and summary visibility (#3147–#3152)
|
|
1639
|
+
|
|
1640
|
+
Six reliability fixes to the batched seed/import + `engine.insert(array)` path
|
|
1641
|
+
introduced by the #2678 bulk-write rework:
|
|
1642
|
+
|
|
1643
|
+
- **#3151** `bulkWrite` validates that `writeBatch` returns one record per input
|
|
1644
|
+
row (a short/long/non-array return is degraded per-row, not backfilled as
|
|
1645
|
+
phantom success); `engine.insert(array)` likewise rejects a short driver
|
|
1646
|
+
`bulkCreate` return instead of padding afterInsert with `undefined`.
|
|
1647
|
+
- **#3150** wraps the two remaining un-retried write points (seed
|
|
1648
|
+
`writeRecord`/`resolveDeferredUpdates`, import's no-`createManyData`
|
|
1649
|
+
fallback) in `withTransientRetry`; `defaultIsTransientError` short-circuits
|
|
1650
|
+
definitive logical errors to non-transient.
|
|
1651
|
+
- **#3148** import `resolveRef` flushes pending creates on a same-object miss so
|
|
1652
|
+
a later row can reference an earlier same-file CREATE, and no longer
|
|
1653
|
+
negatively caches a miss.
|
|
1654
|
+
- **#3149** threads an `attempt` counter through `bulkWrite`; seed rechecks by
|
|
1655
|
+
`externalId` and import by `matchFields` before re-writing, so a
|
|
1656
|
+
commit-then-lost-response retry cannot duplicate a batch.
|
|
1657
|
+
- **#3147** `recomputeSummaries` retries transient failures and, on exhaustion,
|
|
1658
|
+
surfaces `SummaryRecomputeError` (`ERR_SUMMARY_RECOMPUTE`) instead of a
|
|
1659
|
+
silent warn; seed/import recover it to a warning without re-writing.
|
|
1660
|
+
- **#3152** autonumbers are assigned after validation, so a batch that dies in
|
|
1661
|
+
validation consumes no sequence value (no number-range gaps).
|
|
1662
|
+
|
|
1663
|
+
- 5f05de2: **`createLogger({ file })` now actually writes the file under ESM.** `openFileStream` loaded `fs` with a lazy `require()` to keep the browser-safe logger entry out of the `fs` bundle graph; esbuild rewrites that to its `__require` shim in the ESM output, which throws `Dynamic require of "fs" is not supported`, and a bare `catch {}` swallowed it. Since the workspace is `type: module`, every Node ESM consumer — `os serve`, `os dev` — silently got no file logging at all, while the CJS build kept working. The builtin now loads via `process.getBuiltinModule` (opaque to bundlers, works in both module systems, with a `require` fallback for Node < 20.16), and a `file` destination that cannot be opened reports itself on stderr instead of disappearing.
|
|
1664
|
+
|
|
1665
|
+
Turning the destination back on also fixed three faults that were unreachable while it never opened: `child()` opened a second stream per child and orphaned it, destroying a child logger closed the stream its parent and siblings were still writing to, and an async open failure (e.g. an unwritable path) hit an `'error'` event with no listener and took the process down.
|
|
1666
|
+
|
|
1667
|
+
- 021ba4c: fix(core): ObjectLogger honors NO_COLOR and TTY detection before emitting ANSI colors
|
|
1668
|
+
|
|
1669
|
+
The kernel/plugin logger (`ctx.logger`, wired by `os serve` / `os dev`) colorized its
|
|
1670
|
+
`pretty`-format level tags unconditionally, so `NO_COLOR=1` runs and piped/CI output
|
|
1671
|
+
still carried ANSI escapes (e.g. `\x1b[31m…ERROR\x1b[0m`), breaking plain-text log
|
|
1672
|
+
scanners (see scripts/publish-smoke.sh, which had to strip ANSI before grepping).
|
|
1673
|
+
|
|
1674
|
+
Per the no-color.org convention, color is now emitted only when the destination stream
|
|
1675
|
+
(stdout, or stderr for error/fatal) is an interactive TTY **and** `NO_COLOR` is unset or
|
|
1676
|
+
empty — any non-empty `NO_COLOR` value disables color. Interactive terminals keep the
|
|
1677
|
+
existing colorized output. The optional file destination now always receives plain text.
|
|
1678
|
+
|
|
1679
|
+
- Updated dependencies [f972574]
|
|
1680
|
+
- Updated dependencies [22013aa]
|
|
1681
|
+
- Updated dependencies [3ad3dd5]
|
|
1682
|
+
- Updated dependencies [3a18b60]
|
|
1683
|
+
- Updated dependencies [a8aa34c]
|
|
1684
|
+
- Updated dependencies [a3823b2]
|
|
1685
|
+
- Updated dependencies [43a3efb]
|
|
1686
|
+
- Updated dependencies [524696a]
|
|
1687
|
+
- Updated dependencies [5e3301d]
|
|
1688
|
+
- Updated dependencies [46e876c]
|
|
1689
|
+
- Updated dependencies [158aa14]
|
|
1690
|
+
- Updated dependencies [d2723e2]
|
|
1691
|
+
- Updated dependencies [fefcd54]
|
|
1692
|
+
- Updated dependencies [beaf2de]
|
|
1693
|
+
- Updated dependencies [369eb6e]
|
|
1694
|
+
- Updated dependencies [b659111]
|
|
1695
|
+
- Updated dependencies [5754a23]
|
|
1696
|
+
- Updated dependencies [6c270a6]
|
|
1697
|
+
- Updated dependencies [668dd17]
|
|
1698
|
+
- Updated dependencies [8abf133]
|
|
1699
|
+
- Updated dependencies [e0859b1]
|
|
1700
|
+
- Updated dependencies [04ecd4e]
|
|
1701
|
+
- Updated dependencies [4d5a892]
|
|
1702
|
+
- Updated dependencies [16cebeb]
|
|
1703
|
+
- Updated dependencies [86d30af]
|
|
1704
|
+
- Updated dependencies [8923843]
|
|
1705
|
+
- Updated dependencies [a2795f6]
|
|
1706
|
+
- Updated dependencies [f16b492]
|
|
1707
|
+
- Updated dependencies [4b6fde8]
|
|
1708
|
+
- Updated dependencies [2018df9]
|
|
1709
|
+
- Updated dependencies [fc5a3a2]
|
|
1710
|
+
- @objectstack/spec@16.0.0-rc.0
|
|
1711
|
+
|
|
1712
|
+
## 15.1.1
|
|
1713
|
+
|
|
1714
|
+
### Patch Changes
|
|
1715
|
+
|
|
1716
|
+
- @objectstack/spec@15.1.1
|
|
1717
|
+
|
|
1718
|
+
## 15.1.0
|
|
1719
|
+
|
|
1720
|
+
### Minor Changes
|
|
1721
|
+
|
|
1722
|
+
- f531a26: refactor(security): converge the anonymous-deny decision into one shared function + a source-enumerating ratchet (#2567 Phase 2)
|
|
1723
|
+
|
|
1724
|
+
Phase 1 gated every HTTP surface (REST `/data`, dispatcher `/graphql` + `/meta`,
|
|
1725
|
+
raw-hono `/data`) against the secure-by-default `requireAuth` posture, but each
|
|
1726
|
+
seam hand-rolled the same `!userId && !isSystem → 401` check. Phase 2 removes
|
|
1727
|
+
that duplication and pins the surfaces so a new ungated entry point fails CI.
|
|
1728
|
+
|
|
1729
|
+
- **New `shouldDenyAnonymous` in `@objectstack/core`** (`security/anonymous-deny.ts`)
|
|
1730
|
+
— the single anonymous-deny decision + shared 401 body/constants, mirroring the
|
|
1731
|
+
`auth-gate.ts` pattern (pure function so the seams can never drift). All five
|
|
1732
|
+
seams — REST `enforceAuth`, dispatcher `handleGraphQL` / `handleMetadata` /
|
|
1733
|
+
`handleAI`, hono `denyAnonymous` — now delegate to it. **Pure refactor: no
|
|
1734
|
+
runtime behavior change** (verified by the unchanged Phase-1 handler + e2e
|
|
1735
|
+
proofs). Identity resolution and the dynamic exemptions (public-form grants,
|
|
1736
|
+
share-link tokens) are untouched — they run upstream and only ever hand the
|
|
1737
|
+
seam an already-resolved context.
|
|
1738
|
+
- **A `discover()` ratchet on the authz-conformance matrix** — it statically
|
|
1739
|
+
enumerates the data/meta/graphql HTTP entry points from source (curated
|
|
1740
|
+
per-file probes, control-plane routes excluded) and asserts each is classified
|
|
1741
|
+
by a matrix `covers` key. A new `/data`/`/meta`/`/graphql` route (or a
|
|
1742
|
+
removed/stale `covers`) now fails CI as UNCLASSIFIED / STALE, not in review. A
|
|
1743
|
+
companion negative test proves the ratchet bites.
|
|
1744
|
+
|
|
1745
|
+
A design trap is guarded: `isAuthGateAllowlisted(undefined)` returns `true`, so a
|
|
1746
|
+
body-routed seam (GraphQL, which has no request path) must pass no path — the
|
|
1747
|
+
shared function's non-empty-path guard denies anonymous unconditionally there,
|
|
1748
|
+
never falling through to the control-plane allowlist.
|
|
1749
|
+
|
|
1750
|
+
- f531a26: feat(kernel): add `kernel:bootstrapped` lifecycle anchor — the phase that fires after every `kernel:ready` handler has settled but before `kernel:listening` (HTTP socket open). `kernel:ready` handlers run sequentially in plugin-registration order, so a handler that consumes data produced by a later-starting plugin (e.g. the security bootstrap seeds `sys_position`; the app plugin's seed loader inserts records) would race the very rows it needs. `kernel:bootstrapped` is the correct anchor for reconcile/backfill work: every producer's ready handler has finished by the time it fires. Both `ObjectKernel` and `LiteKernel` trigger it. The sharing-rule boot backfill moves from `kernel:listening` to `kernel:bootstrapped` (semantics-only; behaviour unchanged).
|
|
1751
|
+
|
|
1752
|
+
### Patch Changes
|
|
1753
|
+
|
|
1754
|
+
- Updated dependencies [f531a26]
|
|
1755
|
+
- Updated dependencies [f531a26]
|
|
1756
|
+
- Updated dependencies [f531a26]
|
|
1757
|
+
- Updated dependencies [f531a26]
|
|
1758
|
+
- Updated dependencies [f531a26]
|
|
1759
|
+
- Updated dependencies [f531a26]
|
|
1760
|
+
- Updated dependencies [3fe9df1]
|
|
1761
|
+
- Updated dependencies [f531a26]
|
|
1762
|
+
- Updated dependencies [f531a26]
|
|
1763
|
+
- Updated dependencies [f531a26]
|
|
1764
|
+
- Updated dependencies [f531a26]
|
|
1765
|
+
- Updated dependencies [f531a26]
|
|
1766
|
+
- Updated dependencies [f531a26]
|
|
1767
|
+
- Updated dependencies [f531a26]
|
|
1768
|
+
- Updated dependencies [f531a26]
|
|
1769
|
+
- Updated dependencies [f531a26]
|
|
1770
|
+
- Updated dependencies [f531a26]
|
|
1771
|
+
- Updated dependencies [f531a26]
|
|
1772
|
+
- Updated dependencies [4109153]
|
|
1773
|
+
- Updated dependencies [f531a26]
|
|
1774
|
+
- Updated dependencies [f531a26]
|
|
1775
|
+
- Updated dependencies [f531a26]
|
|
1776
|
+
- Updated dependencies [f531a26]
|
|
1777
|
+
- Updated dependencies [f531a26]
|
|
1778
|
+
- Updated dependencies [f531a26]
|
|
1779
|
+
- Updated dependencies [627f225]
|
|
1780
|
+
- Updated dependencies [f531a26]
|
|
1781
|
+
- Updated dependencies [f531a26]
|
|
1782
|
+
- Updated dependencies [f531a26]
|
|
1783
|
+
- @objectstack/spec@15.1.0
|
|
1784
|
+
|
|
1785
|
+
## 15.0.0
|
|
1786
|
+
|
|
1787
|
+
### Minor Changes
|
|
1788
|
+
|
|
1789
|
+
- 13749ec: ADR-0095 D2/D3: the authorization kernel now resolves an explicit **posture
|
|
1790
|
+
ladder** — a monotonic principal tier `PLATFORM_ADMIN > TENANT_ADMIN > MEMBER >
|
|
1791
|
+
EXTERNAL` — once, in `resolveAuthzContext`, and carries it on
|
|
1792
|
+
`ResolvedAuthzContext.posture`.
|
|
1793
|
+
|
|
1794
|
+
- **D2 — the ladder.** New `@objectstack/core/security` module `posture-ladder.ts`
|
|
1795
|
+
reuses the spec `AuthzPosture` enum and pins the rung → row-visibility
|
|
1796
|
+
injection-rule mapping (exactly one rule per rung) plus its two ADR-required
|
|
1797
|
+
invariants as unit-tested properties: strict nesting (rung _n_'s visible set ⊇
|
|
1798
|
+
rung _n−1_'s) and the `EXTERNAL` deny-by-default semantics (explicitly shared
|
|
1799
|
+
rows only — OWD baselines and sharing rules never widen it). `EXTERNAL` is
|
|
1800
|
+
defined and test-locked now but never resolved: no external principal type
|
|
1801
|
+
exists yet (portal/ADR-0093), so the resolver's floor is `MEMBER`.
|
|
1802
|
+
- **D3 — capability-derived, single track.** The rung derives from held
|
|
1803
|
+
**capability grants**, never a better-auth role: `PLATFORM_ADMIN` from the
|
|
1804
|
+
unscoped `admin_full_access` grant (the same `viewAllRecords`/`modifyAllRecords`
|
|
1805
|
+
evidence the superuser bypass trusts), `TENANT_ADMIN` from the
|
|
1806
|
+
`organization_admin` grant. The better-auth `role='admin'` remains only a
|
|
1807
|
+
_provisioning source_ of those grants (`auto-org-admin-grant.ts`,
|
|
1808
|
+
`mapMembershipRole`); no enforcement path reads the raw role, closing the
|
|
1809
|
+
#2836 dual-track adjudication class by construction.
|
|
1810
|
+
- New spec export `ORGANIZATION_ADMIN` (the org-admin capability-grant name),
|
|
1811
|
+
alongside the existing `ADMIN_FULL_ACCESS`.
|
|
1812
|
+
|
|
1813
|
+
**Behavior-preserving.** Enforcement is unchanged — the per-object Layer 0
|
|
1814
|
+
exemption and per-side superuser bypass still gate access exactly as before;
|
|
1815
|
+
`posture` is an additive, derived, explainable field. The `authz-matrix-gate`
|
|
1816
|
+
unit snapshot and the dogfood authz-conformance matrix stay green. No migration
|
|
1817
|
+
required.
|
|
1818
|
+
|
|
1819
|
+
### Patch Changes
|
|
1820
|
+
|
|
1821
|
+
- Updated dependencies [28b7c28]
|
|
1822
|
+
- Updated dependencies [13749ec]
|
|
1823
|
+
- Updated dependencies [e62c233]
|
|
1824
|
+
- Updated dependencies [ed61c9b]
|
|
1825
|
+
- Updated dependencies [31d04d4]
|
|
1826
|
+
- @objectstack/spec@15.0.0
|
|
1827
|
+
|
|
1828
|
+
## 14.8.0
|
|
1829
|
+
|
|
1830
|
+
### Patch Changes
|
|
1831
|
+
|
|
1832
|
+
- Updated dependencies [16b4bf6]
|
|
1833
|
+
- Updated dependencies [16b4bf6]
|
|
1834
|
+
- Updated dependencies [10e8983]
|
|
1835
|
+
- Updated dependencies [607aaf4]
|
|
1836
|
+
- Updated dependencies [bb71321]
|
|
1837
|
+
- @objectstack/spec@14.8.0
|
|
1838
|
+
|
|
1839
|
+
## 14.7.0
|
|
1840
|
+
|
|
1841
|
+
### Patch Changes
|
|
1842
|
+
|
|
1843
|
+
- Updated dependencies [d6a72eb]
|
|
1844
|
+
- @objectstack/spec@14.7.0
|
|
1845
|
+
|
|
1846
|
+
## 14.6.0
|
|
1847
|
+
|
|
1848
|
+
### Patch Changes
|
|
1849
|
+
|
|
1850
|
+
- Updated dependencies [609cb13]
|
|
1851
|
+
- Updated dependencies [ce6d151]
|
|
1852
|
+
- @objectstack/spec@14.6.0
|
|
1853
|
+
|
|
1854
|
+
## 14.5.0
|
|
1855
|
+
|
|
1856
|
+
### Patch Changes
|
|
1857
|
+
|
|
1858
|
+
- Updated dependencies [526805e]
|
|
1859
|
+
- Updated dependencies [d79ca07]
|
|
1860
|
+
- Updated dependencies [33ebd34]
|
|
1861
|
+
- Updated dependencies [c044f08]
|
|
1862
|
+
- Updated dependencies [01274eb]
|
|
1863
|
+
- @objectstack/spec@14.5.0
|
|
1864
|
+
|
|
1865
|
+
## 14.4.0
|
|
1866
|
+
|
|
1867
|
+
### Minor Changes
|
|
1868
|
+
|
|
1869
|
+
- 82e745e: ADR-0091 L1 — grant validity windows: effective-dated assignments, resolution-time filtering, explain expired state, authoring lint.
|
|
1870
|
+
|
|
1871
|
+
- **plugin-security (objects)**: `sys_user_position` and `sys_user_permission_set` gain the D1 lifecycle columns — `valid_from`, `valid_until` (half-open `[from, until)`, UTC; null = unbounded, existing rows unchanged), `reason`, `delegated_from`, `last_certified_at`, `certified_by`.
|
|
1872
|
+
- **core**: new shared predicate `isGrantActive` / `isGrantExpired` (`@objectstack/core`), and `resolveAuthzContext` now filters BOTH grant tables through it (D2, fail-closed — an expired unscoped `admin_full_access` grant no longer derives `platform_admin`). Present-but-unparseable bounds fail closed.
|
|
1873
|
+
- **plugin-security (explain)**: `buildContextForUser` applies the same filter and returns `expiredGrants`; the principal layer reports the dedicated "held until … — expired" contributor state so "why did access disappear" is self-answering. Spec `ExplainLayerSchema` contributors gain an optional `state: 'active' | 'expired'`.
|
|
1874
|
+
- **plugin-sharing**: `PositionGraphService.expandPositionUsers` filters expired holders — sharing-rule recipients stop including them at resolution time.
|
|
1875
|
+
- **lint (D7)**: two new error rules over seed data — `security-grant-expired-at-authoring` (a `valid_until` in the past, or unparseable, is a grant that can never resolve) and `security-delegation-missing-reason` (a `delegated_from` row without `reason` breaks the D3 dual audit). Also re-exported the missing `SECURITY_MASTER_DETAIL_UNGRANTED` constant.
|
|
1876
|
+
|
|
1877
|
+
No background job is involved anywhere — per ADR-0049, an expired grant simply stops resolving, in every edition.
|
|
1878
|
+
|
|
1879
|
+
### Patch Changes
|
|
1880
|
+
|
|
1881
|
+
- Updated dependencies [7953832]
|
|
1882
|
+
- Updated dependencies [82e745e]
|
|
1883
|
+
- Updated dependencies [f3035bd]
|
|
1884
|
+
- Updated dependencies [82c0d94]
|
|
1885
|
+
- Updated dependencies [7449476]
|
|
1886
|
+
- @objectstack/spec@14.4.0
|
|
1887
|
+
|
|
1888
|
+
## 14.3.0
|
|
1889
|
+
|
|
1890
|
+
### Patch Changes
|
|
1891
|
+
|
|
1892
|
+
- Updated dependencies [2a71f48]
|
|
1893
|
+
- Updated dependencies [02f6af4]
|
|
1894
|
+
- Updated dependencies [c1064f1]
|
|
1895
|
+
- @objectstack/spec@14.3.0
|
|
1896
|
+
|
|
1897
|
+
## 14.2.0
|
|
1898
|
+
|
|
1899
|
+
### Patch Changes
|
|
1900
|
+
|
|
1901
|
+
- Updated dependencies [ac8f029]
|
|
1902
|
+
- Updated dependencies [4ab9958]
|
|
1903
|
+
- @objectstack/spec@14.2.0
|
|
1904
|
+
|
|
1905
|
+
## 14.1.0
|
|
1906
|
+
|
|
1907
|
+
### Patch Changes
|
|
1908
|
+
|
|
1909
|
+
- Updated dependencies [5a8465f]
|
|
1910
|
+
- Updated dependencies [7f8620b]
|
|
1911
|
+
- Updated dependencies [82ba3a6]
|
|
1912
|
+
- @objectstack/spec@14.1.0
|
|
1913
|
+
|
|
1914
|
+
## 14.0.0
|
|
1915
|
+
|
|
1916
|
+
### Patch Changes
|
|
1917
|
+
|
|
1918
|
+
- Updated dependencies [0a8e685]
|
|
1919
|
+
- Updated dependencies [afa8115]
|
|
1920
|
+
- Updated dependencies [80f12ca]
|
|
1921
|
+
- Updated dependencies [e2fa074]
|
|
1922
|
+
- Updated dependencies [23c8668]
|
|
1923
|
+
- Updated dependencies [29f017d]
|
|
1924
|
+
- Updated dependencies [216fa9a]
|
|
1925
|
+
- Updated dependencies [6c22b12]
|
|
1926
|
+
- @objectstack/spec@14.0.0
|
|
1927
|
+
|
|
1928
|
+
## 13.0.0
|
|
1929
|
+
|
|
1930
|
+
### Major Changes
|
|
1931
|
+
|
|
1932
|
+
- 6d83431: ADR-0090 P1 breaking wave — permission model v2 concept convergence.
|
|
1933
|
+
|
|
1934
|
+
Pre-launch one-step renames and secure defaults (no compatibility aliases, per
|
|
1935
|
+
ADR-0090 D3/D4 superseding ADR-0057 D5/D7's alias discipline):
|
|
1936
|
+
|
|
1937
|
+
- `sys_role` → `sys_position`, `sys_user_role` → `sys_user_position` (field
|
|
1938
|
+
`role` → `position`), `sys_role_permission_set` → `sys_position_permission_set`
|
|
1939
|
+
(field `role_id` → `position_id`); `RoleSchema`/`defineRole` →
|
|
1940
|
+
`PositionSchema`/`definePosition` with **no `parent`** (positions are flat;
|
|
1941
|
+
hierarchy lives on the business-unit tree).
|
|
1942
|
+
- `ExecutionContext.roles[]` → `positions[]`; the EvalUser/CEL contract
|
|
1943
|
+
`current_user.roles` → `current_user.positions` (formula validators updated);
|
|
1944
|
+
stack property `roles:` → `positions:`; metadata kinds `role`/`profile` →
|
|
1945
|
+
`position` (profile kind removed).
|
|
1946
|
+
- `isProfile` removed from `PermissionSetSchema` (ADR-0090 D2); `isDefault`
|
|
1947
|
+
narrows to an install-time suggestion; `appDefaultProfileName` →
|
|
1948
|
+
`appDefaultPermissionSetName` (isDefault-only).
|
|
1949
|
+
- OWD enum drops legacy aliases `read`/`read_write`/`full`; new optional
|
|
1950
|
+
`externalSharingModel` (external dial, `private` default) lands as P1 spec
|
|
1951
|
+
shape (ADR-0090 D11).
|
|
1952
|
+
- **Secure default (D1)**: a custom object with an owner field and NO
|
|
1953
|
+
`sharingModel` now resolves `private` (was: fully public). System objects
|
|
1954
|
+
keep their explicit posture. Unrecognised stored values fail closed.
|
|
1955
|
+
- ExecutionContext gains the P1 principal-taxonomy shape (D10):
|
|
1956
|
+
`principalKind` / `audience` / `onBehalfOf` (optional, semantics phase in
|
|
1957
|
+
later).
|
|
1958
|
+
- Sharing recipients: `role` → `position` (expanded via `sys_user_position`
|
|
1959
|
+
∪ the better-auth membership transition source); `role_and_subordinates`
|
|
1960
|
+
removed — `unit_and_subordinates` now expands the business-unit subtree
|
|
1961
|
+
(finishes ADR-0057 D5's re-homing).
|
|
1962
|
+
|
|
1963
|
+
### Minor Changes
|
|
1964
|
+
|
|
1965
|
+
- 01917c2: ADR-0090 P2 — audience anchors: `everyone`/`guest` builtin positions.
|
|
1966
|
+
|
|
1967
|
+
- `EVERYONE_POSITION` / `GUEST_POSITION` constants in `@objectstack/spec`;
|
|
1968
|
+
both anchors seeded (system-managed) alongside the builtin identity names.
|
|
1969
|
+
- Every authenticated principal implicitly holds `everyone` in
|
|
1970
|
+
`ctx.positions`, so sets bound to it resolve as ordinary position-bound
|
|
1971
|
+
grants — ADDITIVE. The fallback CLIFF is abolished: the configured
|
|
1972
|
+
baseline (`fallbackPermissionSet`, default `member_default`) now applies
|
|
1973
|
+
in addition to explicit grants instead of only when the user had none,
|
|
1974
|
+
and is also seeded as an `everyone` binding (same table/audit/explain
|
|
1975
|
+
path as admin-authored defaults).
|
|
1976
|
+
- Sessionless HTTP principals resolve as `principalKind: 'guest'` holding
|
|
1977
|
+
exactly `['guest']`; internal bare contexts are untouched.
|
|
1978
|
+
- Audience-anchor binding gate: `sys_position_permission_set` writes that
|
|
1979
|
+
would bind a high-privilege set (VAMA, delete/purge/transfer, system
|
|
1980
|
+
permissions, `'*'` wildcard) to `everyone`/`guest` are rejected at the
|
|
1981
|
+
data layer, unconditionally (`describeHighPrivilegeBits` predicate is
|
|
1982
|
+
exported and shared with the seed-time validation).
|
|
1983
|
+
|
|
1984
|
+
### Patch Changes
|
|
1985
|
+
|
|
1986
|
+
- Updated dependencies [6d83431]
|
|
1987
|
+
- Updated dependencies [01917c2]
|
|
1988
|
+
- Updated dependencies [b271691]
|
|
1989
|
+
- Updated dependencies [a5a1e41]
|
|
1990
|
+
- Updated dependencies [466adf6]
|
|
1991
|
+
- Updated dependencies [5be00c3]
|
|
1992
|
+
- Updated dependencies [466adf6]
|
|
1993
|
+
- Updated dependencies [2bee609]
|
|
1994
|
+
- Updated dependencies [fc7e7f7]
|
|
1995
|
+
- @objectstack/spec@13.0.0
|
|
1996
|
+
|
|
1997
|
+
## 12.6.0
|
|
1998
|
+
|
|
1999
|
+
### Minor Changes
|
|
2000
|
+
|
|
2001
|
+
- 21420d9: Seed loader and data-import now route bulk writes through the engine's array-form `insert()` (one round-trip per batch, with parent-deduplicated summary recompute) instead of one `insert()`/`createData()` call per record, and both retry transient driver errors instead of silently dropping the row (#2678).
|
|
2002
|
+
|
|
2003
|
+
A new shared helper, `bulkWrite` (`@objectstack/core`), batches rows through a caller-supplied batch-write function, retries a whole-batch transient failure (network blip / timeout) with exponential backoff, and degrades to per-row writes (each itself retried) when a batch fails for a non-transient reason — so one bad row can't drop the other N-1. `withTransientRetry` wraps a single write (e.g. an update) with the same retry behavior.
|
|
2004
|
+
|
|
2005
|
+
- `SeedLoaderService.loadDataset()` (`@objectstack/metadata-protocol`) buffers insert-mode records and flushes them in batches of 200 via the engine's array `insert()`. Datasets with a self-referencing field (e.g. `employee.manager_id -> employee`) keep the historical per-record write path, since a later record may need an earlier one's freshly-assigned id.
|
|
2006
|
+
- `runImport()` (`@objectstack/rest`) buffers create-resolved rows and flushes them via `protocol.createManyData()` when the protocol supports it, falling back to the original per-row `createData()` call otherwise. `Protocol.createManyData` (`@objectstack/metadata-protocol`) now forwards `context` to `engine.insert()` like `createData` already did, so tenant-scoped bulk creates work correctly.
|
|
2007
|
+
|
|
2008
|
+
Previously, a 1000-row seed or import into an object with a rollup summary issued 1000+ round-trips and up to 1000 summary recomputes; a single transient network error on any one row silently dropped it with no retry (the 2026-07-06 HotCRM first-boot incident). A `bulkCreate`-capable driver now sees roughly `ceil(N/batch)` writes, and a transient error is retried before a row is ever reported as failed.
|
|
2009
|
+
|
|
2010
|
+
**Fix (`@objectstack/driver-sql`):** `SqlDriver.bulkCreate()` never generated a client-side id for a row missing one, unlike `create()` — a latent gap that this change is the first to exercise at scale (a bulk-inserted row without a driver-native id default silently landed with `id: NULL`). `bulkCreate()` now mirrors `create()`'s id/`_id` normalization per row.
|
|
2011
|
+
|
|
2012
|
+
### Patch Changes
|
|
2013
|
+
|
|
2014
|
+
- Updated dependencies [6cebf22]
|
|
2015
|
+
- @objectstack/spec@12.6.0
|
|
2016
|
+
|
|
2017
|
+
## 12.5.0
|
|
2018
|
+
|
|
2019
|
+
### Patch Changes
|
|
2020
|
+
|
|
2021
|
+
- Updated dependencies [8b3d363]
|
|
2022
|
+
- @objectstack/spec@12.5.0
|
|
2023
|
+
|
|
2024
|
+
## 12.4.0
|
|
2025
|
+
|
|
2026
|
+
### Patch Changes
|
|
2027
|
+
|
|
2028
|
+
- Updated dependencies [60dc3ba]
|
|
2029
|
+
- @objectstack/spec@12.4.0
|
|
2030
|
+
|
|
2031
|
+
## 12.3.0
|
|
2032
|
+
|
|
2033
|
+
### Patch Changes
|
|
2034
|
+
|
|
2035
|
+
- Updated dependencies [e7eceec]
|
|
2036
|
+
- @objectstack/spec@12.3.0
|
|
2037
|
+
|
|
2038
|
+
## 12.2.0
|
|
2039
|
+
|
|
2040
|
+
### Patch Changes
|
|
2041
|
+
|
|
2042
|
+
- 4f5b791: Wire three more Studio-authored metadata surfaces at runtime (#2605 — the
|
|
2043
|
+
"declared but never wired" family, following the #2596 hooks template).
|
|
2044
|
+
|
|
2045
|
+
**Authored actions now execute (#2605 item 1).** `engine.executeAction`'s map
|
|
2046
|
+
was only ever populated from the app bundle at boot, so a published `action`
|
|
2047
|
+
row (standalone or embedded in an authored object's `actions[]`) was stored
|
|
2048
|
+
and listed but never executable — before OR after a restart. Now:
|
|
2049
|
+
|
|
2050
|
+
- `AppPlugin` installs a QuickJS-sandboxed default action runner at boot
|
|
2051
|
+
(`engine.setDefaultActionRunner`), the action-path twin of the #2596 hook
|
|
2052
|
+
body runner. Opt out with `OS_DISABLE_AUTHORED_ACTIONS=1`.
|
|
2053
|
+
- `ObjectQLPlugin` re-registers runtime-authored actions from their
|
|
2054
|
+
`sys_metadata` rows under `packageId: 'metadata-service'` at
|
|
2055
|
+
`kernel:ready`, on `metadata:reloaded`, and on `action`/`object` protocol
|
|
2056
|
+
mutations — saves, publishes, edits, and deletes take effect live.
|
|
2057
|
+
Package-artifact actions are excluded (AppPlugin owns those; re-registering
|
|
2058
|
+
would clobber their handlers).
|
|
2059
|
+
|
|
2060
|
+
**Authored translations reach the i18n runtime (#2591).** `translation`
|
|
2061
|
+
metadata items (single-locale `AppTranslationBundle` payloads; locale from
|
|
2062
|
+
`_meta.locale`, a top-level `locale`, or a BCP-47-shaped item name) now load
|
|
2063
|
+
into the i18n service as a separate authored layer that overlays static
|
|
2064
|
+
bundles. Both adapters carry the layer — service-i18n's `FileI18nAdapter`
|
|
2065
|
+
AND the kernel's in-memory fallback (`createMemoryI18n`), which is what dev
|
|
2066
|
+
and standalone stacks actually run. The shared sync
|
|
2067
|
+
(`wireAuthoredTranslationSync`, exported from `@objectstack/core`, wired by
|
|
2068
|
+
the runtime's AppPlugin and by I18nServicePlugin with single-owner
|
|
2069
|
+
semantics) runs at `kernel:ready`, on `metadata:reloaded`, and on
|
|
2070
|
+
`translation` protocol mutations, with clear-then-reload semantics so
|
|
2071
|
+
deleted items/keys stop resolving instead of lingering in the deep-merged
|
|
2072
|
+
map.
|
|
2073
|
+
|
|
2074
|
+
**Sharing rules created at runtime bind without a restart (#2592).**
|
|
2075
|
+
`bindRuleHooks` was boot-only, so the first rule authored at runtime for an
|
|
2076
|
+
object with no boot-time rule silently never evaluated (rule authoring is a
|
|
2077
|
+
data insert — `metadata:reloaded` never fires). The sharing plugin now binds
|
|
2078
|
+
afterInsert/afterUpdate/afterDelete triggers on `sys_sharing_rule` that
|
|
2079
|
+
unbind + re-bind the rule-hook package from a fresh `listRules()`, serialized
|
|
2080
|
+
so overlapping writes can't leave a stale snapshot bound, and fail-safe so a
|
|
2081
|
+
rebind failure never fails the rule write.
|
|
2082
|
+
|
|
2083
|
+
- Updated dependencies [fce8ff4]
|
|
2084
|
+
- Updated dependencies [3962023]
|
|
2085
|
+
- Updated dependencies [2bb193d]
|
|
2086
|
+
- Updated dependencies [0426d27]
|
|
2087
|
+
- Updated dependencies [da807f7]
|
|
2088
|
+
- @objectstack/spec@12.2.0
|
|
2089
|
+
|
|
2090
|
+
## 12.1.0
|
|
2091
|
+
|
|
2092
|
+
### Patch Changes
|
|
2093
|
+
|
|
2094
|
+
- Updated dependencies [93e6d02]
|
|
2095
|
+
- @objectstack/spec@12.1.0
|
|
2096
|
+
|
|
2097
|
+
## 12.0.0
|
|
2098
|
+
|
|
2099
|
+
### Patch Changes
|
|
2100
|
+
|
|
2101
|
+
- Updated dependencies [a8df396]
|
|
2102
|
+
- Updated dependencies [e695fe0]
|
|
2103
|
+
- Updated dependencies [7c09621]
|
|
2104
|
+
- Updated dependencies [7709db4]
|
|
2105
|
+
- Updated dependencies [2082109]
|
|
2106
|
+
- Updated dependencies [7c09621]
|
|
2107
|
+
- Updated dependencies [9860de4]
|
|
2108
|
+
- Updated dependencies [069c205]
|
|
2109
|
+
- @objectstack/spec@12.0.0
|
|
2110
|
+
|
|
2111
|
+
## 11.10.0
|
|
2112
|
+
|
|
2113
|
+
### Patch Changes
|
|
2114
|
+
|
|
2115
|
+
- Updated dependencies [6a9397e]
|
|
2116
|
+
- Updated dependencies [c0efe5d]
|
|
2117
|
+
- @objectstack/spec@11.10.0
|
|
2118
|
+
|
|
2119
|
+
## 11.9.0
|
|
2120
|
+
|
|
2121
|
+
### Patch Changes
|
|
2122
|
+
|
|
2123
|
+
- Updated dependencies [d3595d9]
|
|
2124
|
+
- @objectstack/spec@11.9.0
|
|
2125
|
+
|
|
2126
|
+
## 11.8.0
|
|
2127
|
+
|
|
2128
|
+
### Patch Changes
|
|
2129
|
+
|
|
2130
|
+
- @objectstack/spec@11.8.0
|
|
2131
|
+
|
|
2132
|
+
## 11.7.0
|
|
2133
|
+
|
|
2134
|
+
### Patch Changes
|
|
2135
|
+
|
|
2136
|
+
- Updated dependencies [5178906]
|
|
2137
|
+
- @objectstack/spec@11.7.0
|
|
2138
|
+
|
|
2139
|
+
## 11.6.0
|
|
2140
|
+
|
|
2141
|
+
### Patch Changes
|
|
2142
|
+
|
|
2143
|
+
- @objectstack/spec@11.6.0
|
|
2144
|
+
|
|
2145
|
+
## 11.5.0
|
|
2146
|
+
|
|
2147
|
+
### Patch Changes
|
|
2148
|
+
|
|
2149
|
+
- Updated dependencies [6ee4f04]
|
|
2150
|
+
- Updated dependencies [c1e3a65]
|
|
2151
|
+
- @objectstack/spec@11.5.0
|
|
2152
|
+
|
|
2153
|
+
## 11.4.0
|
|
2154
|
+
|
|
2155
|
+
### Patch Changes
|
|
2156
|
+
|
|
2157
|
+
- Updated dependencies [5821c51]
|
|
2158
|
+
- Updated dependencies [a0fce3f]
|
|
2159
|
+
- @objectstack/spec@11.4.0
|
|
2160
|
+
|
|
2161
|
+
## 11.3.0
|
|
2162
|
+
|
|
2163
|
+
### Patch Changes
|
|
2164
|
+
|
|
2165
|
+
- Updated dependencies [58e8e31]
|
|
2166
|
+
- Updated dependencies [b4a5df0]
|
|
2167
|
+
- @objectstack/spec@11.3.0
|
|
2168
|
+
|
|
2169
|
+
## 11.2.0
|
|
2170
|
+
|
|
2171
|
+
### Patch Changes
|
|
2172
|
+
|
|
2173
|
+
- Updated dependencies [d0f4b13]
|
|
2174
|
+
- Updated dependencies [302bdab]
|
|
2175
|
+
- @objectstack/spec@11.2.0
|
|
2176
|
+
|
|
2177
|
+
## 11.1.0
|
|
2178
|
+
|
|
2179
|
+
### Minor Changes
|
|
2180
|
+
|
|
2181
|
+
- ce0b4f6: Auth: password expiry — the session-validation gate (ADR-0069 D1, P1)
|
|
2182
|
+
|
|
2183
|
+
Builds the **authentication-policy session gate** ADR-0069 needs and uses it for password expiry. When `password_expiry_days` (new `auth` setting, 0 = off) is exceeded, an authenticated user is blocked from protected REST resources with `403 PASSWORD_EXPIRED` until they change their password — while auth + remediation paths stay reachable.
|
|
2184
|
+
|
|
2185
|
+
- **core**: new pure `evaluateAuthGate` / `isAuthGateAllowlisted` helper (`@objectstack/core/security`) — single source of truth for the allow-list (auth endpoints, change-password, health, UI-bootstrap reads).
|
|
2186
|
+
- **plugin-auth**: `customSession` computes the gate posture once and attaches `user.authGate`; `computeAuthGate` reads `sys_user.password_changed_at` vs the configured window; `password_changed_at` is stamped on sign-up / change / reset; `isAuthGateActive()` keeps the gate **zero-overhead** when off.
|
|
2187
|
+
- **platform-objects**: new `sys_user.password_changed_at` column.
|
|
2188
|
+
- **rest**: `resolveExecCtx` carries `authGate`; `enforceAuth` blocks gated sessions (independent of `requireAuth`) using the core allow-list.
|
|
2189
|
+
- **service-settings**: new `password_expiry_days` field.
|
|
2190
|
+
|
|
2191
|
+
Default-off / additive (no upgrade behavior change); a null `password_changed_at` never expires (existing users). Per ADR-0049 the setting ships with its enforcement; timestamps written as `Date` (ADR-0074).
|
|
2192
|
+
|
|
2193
|
+
This gate is the shared seam for **enforced MFA** (ADR-0069 D3), which lands next as a small addition (a second `authGate` branch). The dispatcher/MCP path is a follow-up (tracked in #2375); the REST surface the Console uses is fully gated here.
|
|
2194
|
+
|
|
2195
|
+
- 3e593a7: Remove the deprecated `DriverInterface` type alias — use `IDataDriver` (11.0).
|
|
2196
|
+
|
|
2197
|
+
`DriverInterface` was a `@deprecated` alias of `IDataDriver` (the authoritative
|
|
2198
|
+
driver contract). It is removed from `@objectstack/spec/contracts` and
|
|
2199
|
+
`@objectstack/core`; `objectql`'s engine now types drivers as `IDataDriver`
|
|
2200
|
+
directly (a type-identical change, since the alias _was_ `IDataDriver`).
|
|
2201
|
+
|
|
2202
|
+
Driver authors: replace `DriverInterface` with `IDataDriver` (same shape).
|
|
2203
|
+
|
|
2204
|
+
Note: this is unrelated to the live `IDataEngine` interface (engine-layer
|
|
2205
|
+
contract, not deprecated) and to the separate zod-derived `DriverInterface` /
|
|
2206
|
+
`DriverInterfaceSchema` in `@objectstack/spec/data` (the runtime driver schema),
|
|
2207
|
+
both of which are unchanged.
|
|
2208
|
+
|
|
2209
|
+
### Patch Changes
|
|
2210
|
+
|
|
2211
|
+
- 9ccfcd6: perf(core): authenticated requests issued ~16 sequential queries — duplicate authz + repeated localization — now request-scoped memoized
|
|
2212
|
+
|
|
2213
|
+
An authenticated REST request resolves its execution context (identity +
|
|
2214
|
+
RBAC/RLS + localization) many times in a single handler — the data operation
|
|
2215
|
+
itself, app-nav RBAC filtering, dashboard widget gating, the ADR-0069 auth gate.
|
|
2216
|
+
Each `resolveExecCtx` pass is the full `resolveAuthzContext` aggregation plus the
|
|
2217
|
+
localization read (~16 sequential queries), and nothing memoized it, so a request
|
|
2218
|
+
that resolves twice paid for duplicate authz and repeated localization.
|
|
2219
|
+
|
|
2220
|
+
- **`@objectstack/rest`** — `resolveExecCtx` is now memoized per request, keyed by
|
|
2221
|
+
the request object (a `WeakMap`, so the entry is collected with the request — no
|
|
2222
|
+
TTL, no cross-request leak) and the input `environmentId`. The in-flight Promise
|
|
2223
|
+
is cached so concurrent callers share one resolution. The heavy path moved to
|
|
2224
|
+
`computeExecCtx`. Anonymous (`undefined`) resolutions are cached too.
|
|
2225
|
+
- **`@objectstack/core`** — within a single `resolveAuthzContext` pass, `sys_user`
|
|
2226
|
+
is now read at most once (the email fallback and the `ai_seat` synthesis shared a
|
|
2227
|
+
duplicate query on the API-key path); `resolveLocalizationContext`'s direct-read
|
|
2228
|
+
fallback batches `timezone`/`locale`/`currency` into one `sys_setting` query
|
|
2229
|
+
(`$in` on `key`) instead of three sequential reads.
|
|
2230
|
+
|
|
2231
|
+
No authorization-behavior change — the same roles/permissions/RLS context is
|
|
2232
|
+
resolved, just without the redundant reads. The `sys_member` reads (per-user roles
|
|
2233
|
+
vs. all-org-members) are intentionally left distinct (different filters/limits).
|
|
2234
|
+
|
|
2235
|
+
Tests: query-counting regressions assert `sys_user` reads once and localization
|
|
2236
|
+
reads once; new rest-server tests pin the per-request/per-environment memo contract.
|
|
2237
|
+
|
|
2238
|
+
- Updated dependencies [ecf193f]
|
|
2239
|
+
- Updated dependencies [51bec81]
|
|
2240
|
+
- Updated dependencies [3e593a7]
|
|
2241
|
+
- Updated dependencies [63d5403]
|
|
2242
|
+
- @objectstack/spec@11.1.0
|
|
2243
|
+
|
|
2244
|
+
## 11.0.0
|
|
2245
|
+
|
|
2246
|
+
### Patch Changes
|
|
2247
|
+
|
|
2248
|
+
- c715d25: chore(license): unify the framework repo to a single Apache-2.0 license
|
|
2249
|
+
|
|
2250
|
+
The repo was left in a half-finished, self-contradictory source-available
|
|
2251
|
+
transition: 44 package `LICENSE` files carried restrictive dual-license text
|
|
2252
|
+
(a Licensor of "ObjectStack AI LLC", a four-year conversion date, and an
|
|
2253
|
+
anti-competitive-hosting grant) while those same packages' `package.json`
|
|
2254
|
+
already declared `"license": "Apache-2.0"` — and that license text pointed at
|
|
2255
|
+
`LICENSING.md` for the authoritative list of restricted packages, which listed
|
|
2256
|
+
none. The root also carried a redundant `LICENSE.apache` left over from that
|
|
2257
|
+
transition.
|
|
2258
|
+
|
|
2259
|
+
The framework is deliberately permissive Apache-2.0 to maximize adoption; value
|
|
2260
|
+
capture lives in the separate closed-source cloud repo, not here. This change
|
|
2261
|
+
makes that unambiguous: every package `LICENSE` now contains the canonical
|
|
2262
|
+
Apache 2.0 text (copied from the root `LICENSE`), the redundant root
|
|
2263
|
+
`LICENSE.apache` is removed, and `LICENSING.md` states the entire repository is
|
|
2264
|
+
Apache-2.0 with no dual-license language. No restrictive-license residue remains
|
|
2265
|
+
anywhere outside `node_modules`.
|
|
2266
|
+
|
|
2267
|
+
This is a metadata-only change (license text and `package.json` already agreed);
|
|
2268
|
+
the patch bump republishes the affected packages with the corrected `LICENSE`.
|
|
2269
|
+
|
|
2270
|
+
- aa33b02: fix(security): single-source the request authorization resolver — REST no longer drops sys_user_position
|
|
2271
|
+
|
|
2272
|
+
The REST server and the runtime dispatcher each carried their own copy of the request → ExecutionContext identity/role resolver, and they drifted on a security path. The REST copy silently omitted `sys_user_position` (so custom roles granted via the ADR-0057 D4 platform-RBAC path did not apply over REST), `sys_position_permission_set`, the `owner→org_owner` membership normalization, the platform-admin derivation, and the `ai_seat` synthesis — fail-closed (legitimate access denied), not an escalation.
|
|
2273
|
+
|
|
2274
|
+
Both entry points now delegate to a single shared resolver, `resolveAuthzContext` in `@objectstack/core/security` (joining the API-key verifier that already lived there). A contract test locks every authorization source and a lint gate (`check:authz-resolver`) prevents a future duplicate resolver or a dropped delegation.
|
|
2275
|
+
|
|
2276
|
+
- Updated dependencies [ab5718a]
|
|
2277
|
+
- Updated dependencies [4845c12]
|
|
2278
|
+
- Updated dependencies [c1a754a]
|
|
2279
|
+
- Updated dependencies [6fbe91f]
|
|
2280
|
+
- Updated dependencies [715d667]
|
|
2281
|
+
- Updated dependencies [5eef4cf]
|
|
2282
|
+
- Updated dependencies [72759e1]
|
|
2283
|
+
- Updated dependencies [6c4fbd9]
|
|
2284
|
+
- Updated dependencies [ef3ed67]
|
|
2285
|
+
- Updated dependencies [cd51229]
|
|
2286
|
+
- Updated dependencies [7697a0e]
|
|
2287
|
+
- Updated dependencies [e7e04f1]
|
|
2288
|
+
- Updated dependencies [cfd5ac4]
|
|
2289
|
+
- Updated dependencies [2be5c1f]
|
|
2290
|
+
- Updated dependencies [ad143ce]
|
|
2291
|
+
- Updated dependencies [5c4a8c8]
|
|
2292
|
+
- Updated dependencies [3afaeed]
|
|
2293
|
+
- Updated dependencies [8801c02]
|
|
2294
|
+
- Updated dependencies [3d04e06]
|
|
2295
|
+
- Updated dependencies [4a84c98]
|
|
2296
|
+
- Updated dependencies [d980f0d]
|
|
2297
|
+
- Updated dependencies [a658523]
|
|
2298
|
+
- Updated dependencies [82ff91c]
|
|
2299
|
+
- Updated dependencies [638f472]
|
|
2300
|
+
- @objectstack/spec@11.0.0
|
|
2301
|
+
|
|
2302
|
+
## 10.3.0
|
|
2303
|
+
|
|
2304
|
+
### Patch Changes
|
|
2305
|
+
|
|
2306
|
+
- @objectstack/spec@10.3.0
|
|
2307
|
+
|
|
2308
|
+
## 10.2.0
|
|
2309
|
+
|
|
2310
|
+
### Patch Changes
|
|
2311
|
+
|
|
2312
|
+
- Updated dependencies [b496498]
|
|
2313
|
+
- @objectstack/spec@10.2.0
|
|
2314
|
+
|
|
2315
|
+
## 10.1.0
|
|
2316
|
+
|
|
2317
|
+
### Patch Changes
|
|
2318
|
+
|
|
2319
|
+
- Updated dependencies [49da36e]
|
|
2320
|
+
- Updated dependencies [ac79f16]
|
|
2321
|
+
- @objectstack/spec@10.1.0
|
|
2322
|
+
|
|
2323
|
+
## 10.0.0
|
|
2324
|
+
|
|
2325
|
+
### Patch Changes
|
|
2326
|
+
|
|
2327
|
+
- d5f6d29: fix(runtime): surface code-defined datasources at `GET /api/v1/datasources` and `GET /api/v1/meta/datasource` on the standalone / host-config boot path (ADR-0015 §18, follow-up to #2111).
|
|
2328
|
+
|
|
2329
|
+
A datasource declared in `defineStack({ datasources: [...] })` (e.g. the showcase's `showcase_external`) is stamped `origin: 'code'` and registered by `AppPlugin` via `metadata.registerInMemory('datasource', …)` — gated on `typeof metadata.registerInMemory === 'function'`. On the standalone / host-config path (`os dev`/`serve` for a config whose `plugins` are already instantiated — `isHostConfig` true — so no `MetadataPlugin` loads) the `metadata` service is an in-memory fallback that implemented `register`/`list`/`get` but **not** `registerInMemory`. The guard was therefore false, AppPlugin silently skipped the registration, and the datasource was absent from both REST surfaces (and Setup → Integrations → Datasources) even though the boot banner counted it and its federated objects were queryable.
|
|
2330
|
+
|
|
2331
|
+
Both in-memory `metadata` fallbacks (`@objectstack/core`'s `createMemoryMetadata` and `@objectstack/plugin-dev`'s dev stub) now implement `registerInMemory` (synchronous, no persistence — identical to `register` for these in-memory stores, matching `MetadataManager`'s signature). The read paths (`metadata.list`, datasource-admin `listDatasources`, and `protocol.getMetaItems` which merges `metadata.list`) were already correct; this restores the write-side registration they depend on. It also makes stack-declared security metadata (`roles`/`permissions`/`sharingRules`/`policies`, registered through the same guard) listable on this path.
|
|
2332
|
+
|
|
2333
|
+
- Updated dependencies [d7ff626]
|
|
2334
|
+
- Updated dependencies [2a1b16b]
|
|
2335
|
+
- Updated dependencies [e16f2a8]
|
|
2336
|
+
- Updated dependencies [e411a82]
|
|
2337
|
+
- Updated dependencies [a581385]
|
|
2338
|
+
- Updated dependencies [220ce5b]
|
|
2339
|
+
- Updated dependencies [3efe334]
|
|
2340
|
+
- Updated dependencies [feead7e]
|
|
2341
|
+
- Updated dependencies [6ca20b3]
|
|
2342
|
+
- Updated dependencies [5f875fe]
|
|
2343
|
+
- Updated dependencies [b469950]
|
|
2344
|
+
- @objectstack/spec@10.0.0
|
|
2345
|
+
|
|
2346
|
+
## 9.11.0
|
|
2347
|
+
|
|
2348
|
+
### Patch Changes
|
|
2349
|
+
|
|
2350
|
+
- Updated dependencies [e7f6539]
|
|
2351
|
+
- Updated dependencies [2365d07]
|
|
2352
|
+
- Updated dependencies [6595b53]
|
|
2353
|
+
- Updated dependencies [fa8964d]
|
|
2354
|
+
- Updated dependencies [36138c7]
|
|
2355
|
+
- Updated dependencies [a8e4f3b]
|
|
2356
|
+
- Updated dependencies [4c213c2]
|
|
2357
|
+
- Updated dependencies [2afb612]
|
|
2358
|
+
- @objectstack/spec@9.11.0
|
|
2359
|
+
|
|
2360
|
+
## 9.10.0
|
|
2361
|
+
|
|
2362
|
+
### Patch Changes
|
|
2363
|
+
|
|
2364
|
+
- Updated dependencies [db02bd5]
|
|
2365
|
+
- Updated dependencies [641675d]
|
|
2366
|
+
- Updated dependencies [94e9040]
|
|
2367
|
+
- Updated dependencies [1f88fd9]
|
|
2368
|
+
- Updated dependencies [1f88fd9]
|
|
2369
|
+
- @objectstack/spec@9.10.0
|
|
2370
|
+
|
|
2371
|
+
## 9.9.1
|
|
2372
|
+
|
|
2373
|
+
### Patch Changes
|
|
2374
|
+
|
|
2375
|
+
- @objectstack/spec@9.9.1
|
|
2376
|
+
|
|
2377
|
+
## 9.9.0
|
|
2378
|
+
|
|
2379
|
+
### Minor Changes
|
|
2380
|
+
|
|
2381
|
+
- 601cc11: feat(analytics): timezone-aware date bucketing (ADR-0053 Phase 2)
|
|
2382
|
+
|
|
2383
|
+
Analytics day/week/month/quarter/year buckets now resolve on a **reference timezone's** calendar days, so a row near a tz day-boundary lands in the bucket a user in that zone would expect — identically on SQLite and Postgres.
|
|
2384
|
+
|
|
2385
|
+
Per ADR-0053 decision **D2**, bucketing is done **in-memory, uniformly** for non-UTC zones rather than emitting dialect-specific `date_trunc … AT TIME ZONE` (SQLite has no tz database and MySQL needs tz tables loaded, so splitting by dialect would shift bucket boundaries for the same data). `engine.aggregate({ timezone })` therefore forces the in-memory aggregation path when a non-UTC reference tz is set — the date-range `where` still goes to the driver, so only matching rows are fetched. **UTC / unset keeps the native driver fast path unchanged.**
|
|
2386
|
+
|
|
2387
|
+
- New shared `calendarPartsInTz` / `calendarPartsInTzOrUtc` util in `@objectstack/core` (DST-safe via `Intl.DateTimeFormat`, never hand-rolled offset math; falls back to UTC for an unset/`'UTC'`/invalid zone).
|
|
2388
|
+
- `EngineAggregateOptions` and the analytics `executeAggregate` bridge / `ObjectQLStrategy` thread the reference timezone (sourced from the dataset selection / `ExecutionContext`) through to `applyInMemoryAggregation` → `bucketDateValue`, and the draft-preview evaluator's `bucketDate`.
|
|
2389
|
+
- `formatDateBucket` (dimension labels) stays UTC-only by design: it re-labels values that were _already_ bucketed upstream, so re-applying a timezone there would shift a correct bucket by a day.
|
|
2390
|
+
|
|
2391
|
+
### Patch Changes
|
|
2392
|
+
|
|
2393
|
+
- Updated dependencies [84249a4]
|
|
2394
|
+
- Updated dependencies [11af299]
|
|
2395
|
+
- Updated dependencies [d5774b5]
|
|
2396
|
+
- Updated dependencies [134043a]
|
|
2397
|
+
- Updated dependencies [90108e0]
|
|
2398
|
+
- Updated dependencies [9afeb2d]
|
|
2399
|
+
- Updated dependencies [6bec07e]
|
|
2400
|
+
- Updated dependencies [601cc11]
|
|
2401
|
+
- Updated dependencies [575448d]
|
|
2402
|
+
- @objectstack/spec@9.9.0
|
|
2403
|
+
|
|
2404
|
+
## 9.8.0
|
|
2405
|
+
|
|
2406
|
+
### Patch Changes
|
|
2407
|
+
|
|
2408
|
+
- Updated dependencies [97c55b3]
|
|
2409
|
+
- Updated dependencies [1b1f490]
|
|
2410
|
+
- @objectstack/spec@9.8.0
|
|
2411
|
+
|
|
2412
|
+
## 9.7.0
|
|
2413
|
+
|
|
2414
|
+
### Patch Changes
|
|
2415
|
+
|
|
2416
|
+
- @objectstack/spec@9.7.0
|
|
2417
|
+
|
|
2418
|
+
## 9.6.0
|
|
2419
|
+
|
|
2420
|
+
### Patch Changes
|
|
2421
|
+
|
|
2422
|
+
- Updated dependencies [d1e930a]
|
|
2423
|
+
- Updated dependencies [71578f2]
|
|
2424
|
+
- Updated dependencies [5e3a301]
|
|
2425
|
+
- Updated dependencies [5db2742]
|
|
2426
|
+
- @objectstack/spec@9.6.0
|
|
2427
|
+
|
|
2428
|
+
## 9.5.1
|
|
2429
|
+
|
|
2430
|
+
### Patch Changes
|
|
2431
|
+
|
|
2432
|
+
- Updated dependencies [ee72aae]
|
|
2433
|
+
- @objectstack/spec@9.5.1
|
|
2434
|
+
|
|
2435
|
+
## 9.5.0
|
|
2436
|
+
|
|
2437
|
+
### Patch Changes
|
|
2438
|
+
|
|
2439
|
+
- Updated dependencies [d08551c]
|
|
2440
|
+
- Updated dependencies [707aeed]
|
|
2441
|
+
- Updated dependencies [7a103d4]
|
|
2442
|
+
- Updated dependencies [4b01250]
|
|
2443
|
+
- @objectstack/spec@9.5.0
|
|
2444
|
+
|
|
2445
|
+
## 9.4.0
|
|
2446
|
+
|
|
2447
|
+
### Patch Changes
|
|
2448
|
+
|
|
2449
|
+
- Updated dependencies [060467a]
|
|
2450
|
+
- Updated dependencies [0856476]
|
|
2451
|
+
- Updated dependencies [b678d8c]
|
|
2452
|
+
- Updated dependencies [b678d8c]
|
|
2453
|
+
- Updated dependencies [b678d8c]
|
|
2454
|
+
- @objectstack/spec@9.4.0
|
|
2455
|
+
|
|
2456
|
+
## 9.3.0
|
|
2457
|
+
|
|
2458
|
+
### Patch Changes
|
|
2459
|
+
|
|
2460
|
+
- Updated dependencies [1ada658]
|
|
2461
|
+
- Updated dependencies [3219191]
|
|
2462
|
+
- Updated dependencies [290f631]
|
|
2463
|
+
- Updated dependencies [50b7b47]
|
|
2464
|
+
- Updated dependencies [f15d6f6]
|
|
2465
|
+
- Updated dependencies [f8684ea]
|
|
2466
|
+
- Updated dependencies [b4765be]
|
|
2467
|
+
- @objectstack/spec@9.3.0
|
|
2468
|
+
|
|
2469
|
+
## 9.2.0
|
|
2470
|
+
|
|
2471
|
+
### Patch Changes
|
|
2472
|
+
|
|
2473
|
+
- Updated dependencies [2f57b75]
|
|
2474
|
+
- Updated dependencies [2f57b75]
|
|
2475
|
+
- @objectstack/spec@9.2.0
|
|
2476
|
+
|
|
2477
|
+
## 9.1.0
|
|
2478
|
+
|
|
2479
|
+
### Patch Changes
|
|
2480
|
+
|
|
2481
|
+
- Updated dependencies [b9062c9]
|
|
2482
|
+
- @objectstack/spec@9.1.0
|
|
2483
|
+
|
|
2484
|
+
## 9.0.1
|
|
2485
|
+
|
|
2486
|
+
### Patch Changes
|
|
2487
|
+
|
|
2488
|
+
- Updated dependencies [1817845]
|
|
2489
|
+
- @objectstack/spec@9.0.1
|
|
2490
|
+
|
|
2491
|
+
## 9.0.0
|
|
2492
|
+
|
|
2493
|
+
### Patch Changes
|
|
2494
|
+
|
|
2495
|
+
- Updated dependencies [4c3f693]
|
|
2496
|
+
- Updated dependencies [0bf39f1]
|
|
2497
|
+
- Updated dependencies [f533f42]
|
|
2498
|
+
- Updated dependencies [1c83ee8]
|
|
2499
|
+
- @objectstack/spec@9.0.0
|
|
2500
|
+
|
|
2501
|
+
## 8.0.1
|
|
2502
|
+
|
|
2503
|
+
### Patch Changes
|
|
2504
|
+
|
|
2505
|
+
- @objectstack/spec@8.0.1
|
|
2506
|
+
|
|
2507
|
+
## 8.0.0
|
|
2508
|
+
|
|
2509
|
+
### Minor Changes
|
|
2510
|
+
|
|
2511
|
+
- c262301: fix(rest): REST data API honors sys_api_key — one shared verifier with MCP (closes #1633)
|
|
2512
|
+
|
|
2513
|
+
Staging e2e found the MCP surface authenticated a `sys_api_key` but the REST data
|
|
2514
|
+
API (`@objectstack/rest`) returned 401 for the same key — its `resolveExecCtx`
|
|
2515
|
+
only checked the better-auth session, never the API key.
|
|
2516
|
+
|
|
2517
|
+
Converged both surfaces onto ONE verifier so they can't drift:
|
|
2518
|
+
|
|
2519
|
+
- **`@objectstack/core/security`** now owns the shared `sys_api_key` primitives
|
|
2520
|
+
(`hashApiKey`, `generateApiKey`, `extractApiKey`, `parseScopes`, `isExpired`)
|
|
2521
|
+
plus a new `resolveApiKeyPrincipal(ql, headers, nowMs?)` that hashes the
|
|
2522
|
+
inbound key, looks it up by the indexed at-rest hash, and rejects unknown /
|
|
2523
|
+
revoked / expired / owner-less keys (fail-closed). `core` is the natural home:
|
|
2524
|
+
both `rest` and `runtime` depend on it, it depends on neither (no cycle), and
|
|
2525
|
+
it's server-side (already uses `node:crypto`).
|
|
2526
|
+
- **`@objectstack/runtime`** — `security/api-key.ts` re-exports the primitives
|
|
2527
|
+
from core (stable import surface) and `resolveExecutionContext` now delegates
|
|
2528
|
+
its API-key branch to `resolveApiKeyPrincipal`.
|
|
2529
|
+
- **`@objectstack/rest`** — `resolveExecCtx` resolves the data engine once and
|
|
2530
|
+
tries `resolveApiKeyPrincipal` (x-api-key / `Authorization: ApiKey`) BEFORE the
|
|
2531
|
+
session, so `/api/v1/data` + `/api/v1/meta` now authenticate an API key under
|
|
2532
|
+
the key's permissions + RLS, exactly like the dispatcher/MCP path.
|
|
2533
|
+
|
|
2534
|
+
Tests: core `api-key.test.ts` (primitives + verifier: valid / revoked / expired /
|
|
2535
|
+
unknown / owner-less / plaintext-not-matched / fail-closed-ql). runtime + rest
|
|
2536
|
+
suites green.
|
|
2537
|
+
|
|
2538
|
+
### Patch Changes
|
|
2539
|
+
|
|
2540
|
+
- Updated dependencies [a46c017]
|
|
2541
|
+
- Updated dependencies [b990b89]
|
|
2542
|
+
- Updated dependencies [99111ec]
|
|
2543
|
+
- Updated dependencies [d5a8161]
|
|
2544
|
+
- Updated dependencies [5cf1f1b]
|
|
2545
|
+
- Updated dependencies [9ef89d4]
|
|
2546
|
+
- Updated dependencies [3306d2f]
|
|
2547
|
+
- Updated dependencies [bc44195]
|
|
2548
|
+
- Updated dependencies [9e2e229]
|
|
2549
|
+
- @objectstack/spec@8.0.0
|
|
2550
|
+
|
|
2551
|
+
## 7.9.0
|
|
2552
|
+
|
|
2553
|
+
### Patch Changes
|
|
2554
|
+
|
|
2555
|
+
- @objectstack/spec@7.9.0
|
|
2556
|
+
|
|
2557
|
+
## 7.8.0
|
|
2558
|
+
|
|
2559
|
+
### Patch Changes
|
|
2560
|
+
|
|
2561
|
+
- Updated dependencies [06f2bbb]
|
|
2562
|
+
- Updated dependencies [36719db]
|
|
2563
|
+
- Updated dependencies [424ab26]
|
|
2564
|
+
- @objectstack/spec@7.8.0
|
|
2565
|
+
|
|
2566
|
+
## 7.7.0
|
|
2567
|
+
|
|
2568
|
+
### Patch Changes
|
|
2569
|
+
|
|
2570
|
+
- Updated dependencies [b391955]
|
|
2571
|
+
- Updated dependencies [f06b64e]
|
|
2572
|
+
- Updated dependencies [023bf93]
|
|
2573
|
+
- @objectstack/spec@7.7.0
|
|
2574
|
+
|
|
2575
|
+
## 7.6.0
|
|
2576
|
+
|
|
2577
|
+
### Patch Changes
|
|
2578
|
+
|
|
2579
|
+
- Updated dependencies [955d4c8]
|
|
2580
|
+
- Updated dependencies [c4a4cbd]
|
|
2581
|
+
- Updated dependencies [b046ec2]
|
|
2582
|
+
- Updated dependencies [2170ad9]
|
|
2583
|
+
- Updated dependencies [02d6359]
|
|
2584
|
+
- Updated dependencies [7648242]
|
|
2585
|
+
- Updated dependencies [8fa1e7f]
|
|
2586
|
+
- Updated dependencies [55866f5]
|
|
2587
|
+
- Updated dependencies [60f9c45]
|
|
2588
|
+
- @objectstack/spec@7.6.0
|
|
2589
|
+
|
|
2590
|
+
## 7.5.0
|
|
2591
|
+
|
|
2592
|
+
### Patch Changes
|
|
2593
|
+
|
|
2594
|
+
- @objectstack/spec@7.5.0
|
|
2595
|
+
|
|
2596
|
+
## 7.4.1
|
|
2597
|
+
|
|
2598
|
+
### Patch Changes
|
|
2599
|
+
|
|
2600
|
+
- @objectstack/spec@7.4.1
|
|
2601
|
+
|
|
2602
|
+
## 7.4.0
|
|
2603
|
+
|
|
2604
|
+
### Patch Changes
|
|
2605
|
+
|
|
2606
|
+
- Updated dependencies [23c7107]
|
|
2607
|
+
- Updated dependencies [c72daad]
|
|
2608
|
+
- Updated dependencies [f115182]
|
|
2609
|
+
- Updated dependencies [2faf9f2]
|
|
2610
|
+
- Updated dependencies [2faf9f2]
|
|
2611
|
+
- Updated dependencies [2faf9f2]
|
|
2612
|
+
- Updated dependencies [58b450b]
|
|
2613
|
+
- Updated dependencies [82eb6cf]
|
|
2614
|
+
- Updated dependencies [13d8653]
|
|
2615
|
+
- Updated dependencies [ff3d006]
|
|
2616
|
+
- Updated dependencies [5e831de]
|
|
2617
|
+
- @objectstack/spec@7.4.0
|
|
2618
|
+
|
|
2619
|
+
## 7.3.0
|
|
2620
|
+
|
|
2621
|
+
### Patch Changes
|
|
2622
|
+
|
|
2623
|
+
- 5e7c554: **Rename kernel plugin-sandbox permission schemas to remove a naming footgun** (issue #1383).
|
|
2624
|
+
|
|
2625
|
+
`@objectstack/spec/kernel` exported `PermissionSchema` / `PermissionSetSchema`
|
|
2626
|
+
(and the `Permission` / `PermissionSet` types) for the plugin-sandbox security
|
|
2627
|
+
model. Their names collided with the metadata-protocol permission set exported
|
|
2628
|
+
from `@objectstack/spec/security` (`PermissionSetSchema`), making it very easy
|
|
2629
|
+
to validate the `permission`/`profile` metadata type against the wrong schema
|
|
2630
|
+
and reject every legal payload.
|
|
2631
|
+
|
|
2632
|
+
The kernel symbols are now prefixed with `Plugin` to reflect their specialized
|
|
2633
|
+
semantics:
|
|
2634
|
+
|
|
2635
|
+
| Old (`@objectstack/spec/kernel`) | New |
|
|
2636
|
+
| :------------------------------- | :-------------------------- |
|
|
2637
|
+
| `PermissionSchema` | `PluginPermissionSchema` |
|
|
2638
|
+
| `PermissionSetSchema` | `PluginPermissionSetSchema` |
|
|
2639
|
+
| `Permission` (type) | `PluginPermission` |
|
|
2640
|
+
| `PermissionSet` (type) | `PluginPermissionSet` |
|
|
2641
|
+
|
|
2642
|
+
The metadata `permission`/`profile` types are unchanged — keep using
|
|
2643
|
+
`PermissionSetSchema` from `@objectstack/spec/security`.
|
|
2644
|
+
|
|
2645
|
+
- Updated dependencies [5e7c554]
|
|
2646
|
+
- @objectstack/spec@7.3.0
|
|
2647
|
+
|
|
2648
|
+
## 7.2.1
|
|
2649
|
+
|
|
2650
|
+
### Patch Changes
|
|
2651
|
+
|
|
2652
|
+
- @objectstack/spec@7.2.1
|
|
2653
|
+
|
|
2654
|
+
## 7.2.0
|
|
2655
|
+
|
|
2656
|
+
### Patch Changes
|
|
2657
|
+
|
|
2658
|
+
- @objectstack/spec@7.2.0
|
|
2659
|
+
|
|
2660
|
+
## 7.1.0
|
|
2661
|
+
|
|
2662
|
+
### Patch Changes
|
|
2663
|
+
|
|
2664
|
+
- Updated dependencies [47a92f4]
|
|
2665
|
+
- @objectstack/spec@7.1.0
|
|
2666
|
+
|
|
2667
|
+
## 7.0.0
|
|
2668
|
+
|
|
2669
|
+
### Patch Changes
|
|
2670
|
+
|
|
2671
|
+
- Updated dependencies [74470ad]
|
|
2672
|
+
- Updated dependencies [d29617e]
|
|
2673
|
+
- Updated dependencies [dc72172]
|
|
2674
|
+
- @objectstack/spec@7.0.0
|
|
2675
|
+
|
|
2676
|
+
## 6.9.0
|
|
2677
|
+
|
|
2678
|
+
### Patch Changes
|
|
2679
|
+
|
|
2680
|
+
- @objectstack/spec@6.9.0
|
|
2681
|
+
|
|
2682
|
+
## 6.8.1
|
|
2683
|
+
|
|
2684
|
+
### Patch Changes
|
|
2685
|
+
|
|
2686
|
+
- @objectstack/spec@6.8.1
|
|
2687
|
+
|
|
2688
|
+
## 6.8.0
|
|
2689
|
+
|
|
2690
|
+
### Patch Changes
|
|
2691
|
+
|
|
2692
|
+
- Updated dependencies [6e88f77]
|
|
2693
|
+
- Updated dependencies [c8b9f57]
|
|
2694
|
+
- @objectstack/spec@6.8.0
|
|
2695
|
+
|
|
2696
|
+
## 6.7.1
|
|
2697
|
+
|
|
2698
|
+
### Patch Changes
|
|
2699
|
+
|
|
2700
|
+
- @objectstack/spec@6.7.1
|
|
2701
|
+
|
|
2702
|
+
## 6.7.0
|
|
2703
|
+
|
|
2704
|
+
### Patch Changes
|
|
2705
|
+
|
|
2706
|
+
- Updated dependencies [430067b]
|
|
2707
|
+
- Updated dependencies [4f9e9d4]
|
|
2708
|
+
- @objectstack/spec@6.7.0
|
|
2709
|
+
|
|
2710
|
+
## 6.6.0
|
|
2711
|
+
|
|
2712
|
+
### Patch Changes
|
|
2713
|
+
|
|
2714
|
+
- Updated dependencies [a49cfc2]
|
|
2715
|
+
- @objectstack/spec@6.6.0
|
|
2716
|
+
|
|
2717
|
+
## 6.5.1
|
|
2718
|
+
|
|
2719
|
+
### Patch Changes
|
|
2720
|
+
|
|
2721
|
+
- @objectstack/spec@6.5.1
|
|
2722
|
+
|
|
2723
|
+
## 6.5.0
|
|
2724
|
+
|
|
2725
|
+
### Patch Changes
|
|
2726
|
+
|
|
2727
|
+
- @objectstack/spec@6.5.0
|
|
2728
|
+
|
|
2729
|
+
## 6.4.0
|
|
2730
|
+
|
|
2731
|
+
### Patch Changes
|
|
2732
|
+
|
|
2733
|
+
- Updated dependencies [f8651cc]
|
|
2734
|
+
- Updated dependencies [f8651cc]
|
|
2735
|
+
- Updated dependencies [0bf6f9a]
|
|
2736
|
+
- @objectstack/spec@6.4.0
|
|
2737
|
+
|
|
2738
|
+
## 6.3.0
|
|
2739
|
+
|
|
2740
|
+
### Patch Changes
|
|
2741
|
+
|
|
2742
|
+
- @objectstack/spec@6.3.0
|
|
2743
|
+
|
|
2744
|
+
## 6.2.0
|
|
2745
|
+
|
|
2746
|
+
### Patch Changes
|
|
2747
|
+
|
|
2748
|
+
- Updated dependencies [b4c74a9]
|
|
2749
|
+
- @objectstack/spec@6.2.0
|
|
2750
|
+
|
|
2751
|
+
## 6.1.1
|
|
2752
|
+
|
|
2753
|
+
### Patch Changes
|
|
2754
|
+
|
|
2755
|
+
- @objectstack/spec@6.1.1
|
|
2756
|
+
|
|
2757
|
+
## 6.1.0
|
|
2758
|
+
|
|
2759
|
+
### Patch Changes
|
|
2760
|
+
|
|
2761
|
+
- Updated dependencies [93c0589]
|
|
2762
|
+
- @objectstack/spec@6.1.0
|
|
2763
|
+
|
|
2764
|
+
## 6.0.0
|
|
2765
|
+
|
|
2766
|
+
### Patch Changes
|
|
2767
|
+
|
|
2768
|
+
- Updated dependencies [629a716]
|
|
2769
|
+
- Updated dependencies [dbc4f7d]
|
|
2770
|
+
- Updated dependencies [944f187]
|
|
2771
|
+
- @objectstack/spec@6.0.0
|
|
2772
|
+
|
|
2773
|
+
## 5.2.0
|
|
2774
|
+
|
|
2775
|
+
### Patch Changes
|
|
2776
|
+
|
|
2777
|
+
- Updated dependencies [bab2b20]
|
|
2778
|
+
- Updated dependencies [fa011d8]
|
|
2779
|
+
- Updated dependencies [b806f58]
|
|
2780
|
+
- @objectstack/spec@5.2.0
|
|
2781
|
+
|
|
2782
|
+
## 5.1.0
|
|
2783
|
+
|
|
2784
|
+
### Patch Changes
|
|
2785
|
+
|
|
2786
|
+
- Updated dependencies [75f4ee6]
|
|
2787
|
+
- Updated dependencies [823d559]
|
|
2788
|
+
- @objectstack/spec@5.1.0
|
|
2789
|
+
|
|
2790
|
+
## 5.0.0
|
|
2791
|
+
|
|
2792
|
+
### Patch Changes
|
|
2793
|
+
|
|
2794
|
+
- Updated dependencies [2f9073a]
|
|
2795
|
+
- @objectstack/spec@5.0.0
|
|
2796
|
+
|
|
2797
|
+
## 4.2.0
|
|
2798
|
+
|
|
2799
|
+
### Patch Changes
|
|
2800
|
+
|
|
2801
|
+
- Updated dependencies [2869891]
|
|
2802
|
+
- @objectstack/spec@4.2.0
|
|
2803
|
+
|
|
2804
|
+
## 4.1.1
|
|
2805
|
+
|
|
2806
|
+
### Patch Changes
|
|
2807
|
+
|
|
2808
|
+
- @objectstack/spec@4.1.1
|
|
2809
|
+
|
|
2810
|
+
## 4.1.0
|
|
2811
|
+
|
|
2812
|
+
### Patch Changes
|
|
2813
|
+
|
|
2814
|
+
- Updated dependencies [2108c30]
|
|
2815
|
+
- Updated dependencies [23db640]
|
|
2816
|
+
- @objectstack/spec@4.1.0
|
|
2817
|
+
|
|
2818
|
+
## 4.0.5
|
|
2819
|
+
|
|
2820
|
+
### Patch Changes
|
|
2821
|
+
|
|
2822
|
+
- 15e0df6: chore: unify all package versions to a single patch release
|
|
2823
|
+
- Updated dependencies [15e0df6]
|
|
2824
|
+
- @objectstack/spec@4.0.5
|
|
2825
|
+
|
|
2826
|
+
## 4.0.4
|
|
2827
|
+
|
|
2828
|
+
### Patch Changes
|
|
2829
|
+
|
|
2830
|
+
- Updated dependencies [326b66b]
|
|
2831
|
+
- @objectstack/spec@4.0.4
|
|
2832
|
+
|
|
2833
|
+
## 4.0.3
|
|
2834
|
+
|
|
2835
|
+
### Patch Changes
|
|
2836
|
+
|
|
2837
|
+
- @objectstack/spec@4.0.3
|
|
2838
|
+
|
|
2839
|
+
## 4.0.2
|
|
2840
|
+
|
|
2841
|
+
### Patch Changes
|
|
2842
|
+
|
|
2843
|
+
- Updated dependencies [5f659e9]
|
|
2844
|
+
- @objectstack/spec@4.0.2
|
|
2845
|
+
|
|
2846
|
+
## 4.0.0
|
|
2847
|
+
|
|
2848
|
+
### Minor Changes
|
|
2849
|
+
|
|
2850
|
+
- e0b0a78: Deprecate DataEngineQueryOptions in favor of QueryAST-aligned EngineQueryOptions.
|
|
2851
|
+
|
|
2852
|
+
Engine, Protocol, and Client now use standard QueryAST parameter names:
|
|
2853
|
+
|
|
2854
|
+
- `filter` → `where`
|
|
2855
|
+
- `select` → `fields`
|
|
2856
|
+
- `sort` → `orderBy`
|
|
2857
|
+
- `skip` → `offset`
|
|
2858
|
+
- `populate` → `expand`
|
|
2859
|
+
- `top` → `limit`
|
|
2860
|
+
|
|
2861
|
+
The old DataEngine\* schemas and types are preserved with `@deprecated` markers for backward compatibility.
|
|
2862
|
+
|
|
2863
|
+
### Patch Changes
|
|
2864
|
+
|
|
2865
|
+
- Updated dependencies [f08ffc3]
|
|
2866
|
+
- Updated dependencies [e0b0a78]
|
|
2867
|
+
- @objectstack/spec@4.0.0
|
|
2868
|
+
|
|
2869
|
+
## 3.3.1
|
|
2870
|
+
|
|
2871
|
+
### Patch Changes
|
|
2872
|
+
|
|
2873
|
+
- @objectstack/spec@3.3.1
|
|
2874
|
+
|
|
2875
|
+
## 3.3.0
|
|
2876
|
+
|
|
2877
|
+
### Patch Changes
|
|
2878
|
+
|
|
2879
|
+
- @objectstack/spec@3.3.0
|
|
2880
|
+
|
|
2881
|
+
## 3.2.9
|
|
2882
|
+
|
|
2883
|
+
### Patch Changes
|
|
2884
|
+
|
|
2885
|
+
- @objectstack/spec@3.2.9
|
|
2886
|
+
|
|
2887
|
+
## 3.2.8
|
|
2888
|
+
|
|
2889
|
+
### Patch Changes
|
|
2890
|
+
|
|
2891
|
+
- @objectstack/spec@3.2.8
|
|
2892
|
+
|
|
2893
|
+
## 3.2.7
|
|
2894
|
+
|
|
2895
|
+
### Patch Changes
|
|
2896
|
+
|
|
2897
|
+
- @objectstack/spec@3.2.7
|
|
2898
|
+
|
|
2899
|
+
## 3.2.6
|
|
2900
|
+
|
|
2901
|
+
### Patch Changes
|
|
2902
|
+
|
|
2903
|
+
- @objectstack/spec@3.2.6
|
|
2904
|
+
|
|
2905
|
+
## 3.2.5
|
|
2906
|
+
|
|
2907
|
+
### Patch Changes
|
|
2908
|
+
|
|
2909
|
+
- @objectstack/spec@3.2.5
|
|
2910
|
+
|
|
2911
|
+
## 3.2.4
|
|
2912
|
+
|
|
2913
|
+
### Patch Changes
|
|
2914
|
+
|
|
2915
|
+
- @objectstack/spec@3.2.4
|
|
2916
|
+
|
|
2917
|
+
## 3.2.3
|
|
2918
|
+
|
|
2919
|
+
### Patch Changes
|
|
2920
|
+
|
|
2921
|
+
- @objectstack/spec@3.2.3
|
|
2922
|
+
|
|
2923
|
+
## 3.2.2
|
|
2924
|
+
|
|
2925
|
+
### Patch Changes
|
|
2926
|
+
|
|
2927
|
+
- Updated dependencies [46defbb]
|
|
2928
|
+
- @objectstack/spec@3.2.2
|
|
2929
|
+
|
|
2930
|
+
## 3.2.1
|
|
2931
|
+
|
|
2932
|
+
### Patch Changes
|
|
2933
|
+
|
|
2934
|
+
- Updated dependencies [850b546]
|
|
2935
|
+
- @objectstack/spec@3.2.1
|
|
2936
|
+
|
|
2937
|
+
## 3.2.0
|
|
2938
|
+
|
|
2939
|
+
### Patch Changes
|
|
2940
|
+
|
|
2941
|
+
- Updated dependencies [5901c29]
|
|
2942
|
+
- @objectstack/spec@3.2.0
|
|
2943
|
+
|
|
2944
|
+
## 3.1.1
|
|
2945
|
+
|
|
2946
|
+
### Patch Changes
|
|
2947
|
+
|
|
2948
|
+
- Updated dependencies [953d667]
|
|
2949
|
+
- @objectstack/spec@3.1.1
|
|
2950
|
+
|
|
2951
|
+
## 3.1.0
|
|
2952
|
+
|
|
2953
|
+
### Patch Changes
|
|
2954
|
+
|
|
2955
|
+
- Updated dependencies [0088830]
|
|
2956
|
+
- @objectstack/spec@3.1.0
|
|
2957
|
+
|
|
2958
|
+
## 3.0.11
|
|
2959
|
+
|
|
2960
|
+
### Patch Changes
|
|
2961
|
+
|
|
2962
|
+
- Updated dependencies [92d9d99]
|
|
2963
|
+
- @objectstack/spec@3.0.11
|
|
2964
|
+
|
|
2965
|
+
## 3.0.10
|
|
2966
|
+
|
|
2967
|
+
### Patch Changes
|
|
2968
|
+
|
|
2969
|
+
- Updated dependencies [d1e5d31]
|
|
2970
|
+
- @objectstack/spec@3.0.10
|
|
2971
|
+
|
|
2972
|
+
## 3.0.9
|
|
2973
|
+
|
|
2974
|
+
### Patch Changes
|
|
2975
|
+
|
|
2976
|
+
- Updated dependencies [15e0df6]
|
|
2977
|
+
- @objectstack/spec@3.0.9
|
|
2978
|
+
|
|
2979
|
+
## 3.0.8
|
|
2980
|
+
|
|
2981
|
+
### Patch Changes
|
|
2982
|
+
|
|
2983
|
+
- Updated dependencies [5a968a2]
|
|
2984
|
+
- @objectstack/spec@3.0.8
|
|
2985
|
+
|
|
2986
|
+
## 3.0.7
|
|
2987
|
+
|
|
2988
|
+
### Patch Changes
|
|
2989
|
+
|
|
2990
|
+
- Updated dependencies [0119bd7]
|
|
2991
|
+
- Updated dependencies [5426bdf]
|
|
2992
|
+
- @objectstack/spec@3.0.7
|
|
2993
|
+
|
|
2994
|
+
## 3.0.6
|
|
2995
|
+
|
|
2996
|
+
### Patch Changes
|
|
2997
|
+
|
|
2998
|
+
- Updated dependencies [5df254c]
|
|
2999
|
+
- @objectstack/spec@3.0.6
|
|
3000
|
+
|
|
3001
|
+
## 3.0.5
|
|
3002
|
+
|
|
3003
|
+
### Patch Changes
|
|
3004
|
+
|
|
3005
|
+
- Updated dependencies [23a4a68]
|
|
3006
|
+
- @objectstack/spec@3.0.5
|
|
3007
|
+
|
|
3008
|
+
## 3.0.4
|
|
3009
|
+
|
|
3010
|
+
### Patch Changes
|
|
3011
|
+
|
|
3012
|
+
- Updated dependencies [d738987]
|
|
3013
|
+
- @objectstack/spec@3.0.4
|
|
3014
|
+
|
|
3015
|
+
## 3.0.3
|
|
3016
|
+
|
|
3017
|
+
### Patch Changes
|
|
3018
|
+
|
|
3019
|
+
- c7267f6: Patch release for maintenance updates and improvements.
|
|
3020
|
+
- Updated dependencies [c7267f6]
|
|
3021
|
+
- @objectstack/spec@3.0.3
|
|
3022
|
+
|
|
3023
|
+
## 3.0.2
|
|
3024
|
+
|
|
3025
|
+
### Patch Changes
|
|
3026
|
+
|
|
3027
|
+
- Updated dependencies [28985f5]
|
|
3028
|
+
- @objectstack/spec@3.0.2
|
|
3029
|
+
|
|
3030
|
+
## 3.0.1
|
|
3031
|
+
|
|
3032
|
+
### Patch Changes
|
|
3033
|
+
|
|
3034
|
+
- Updated dependencies [389725a]
|
|
3035
|
+
- @objectstack/spec@3.0.1
|
|
3036
|
+
|
|
3037
|
+
## 3.0.0
|
|
3038
|
+
|
|
3039
|
+
### Major Changes
|
|
3040
|
+
|
|
3041
|
+
- Release v3.0.0 — unified version bump for all ObjectStack packages.
|
|
3042
|
+
|
|
3043
|
+
### Patch Changes
|
|
3044
|
+
|
|
3045
|
+
- Updated dependencies
|
|
3046
|
+
- @objectstack/spec@3.0.0
|
|
3047
|
+
|
|
3048
|
+
## 2.0.7
|
|
3049
|
+
|
|
3050
|
+
### Patch Changes
|
|
3051
|
+
|
|
3052
|
+
- Updated dependencies
|
|
3053
|
+
- @objectstack/spec@2.0.7
|
|
3054
|
+
|
|
3055
|
+
## 2.0.6
|
|
3056
|
+
|
|
3057
|
+
### Patch Changes
|
|
3058
|
+
|
|
3059
|
+
- Patch release for maintenance and stability improvements
|
|
3060
|
+
- Updated dependencies
|
|
3061
|
+
- @objectstack/spec@2.0.6
|
|
3062
|
+
|
|
3063
|
+
## 2.0.5
|
|
3064
|
+
|
|
3065
|
+
### Patch Changes
|
|
3066
|
+
|
|
3067
|
+
- Updated dependencies
|
|
3068
|
+
- @objectstack/spec@2.0.5
|
|
3069
|
+
|
|
3070
|
+
## 2.0.4
|
|
3071
|
+
|
|
3072
|
+
### Patch Changes
|
|
3073
|
+
|
|
3074
|
+
- Patch release for maintenance and stability improvements
|
|
3075
|
+
- Updated dependencies
|
|
3076
|
+
- @objectstack/spec@2.0.4
|
|
3077
|
+
|
|
3078
|
+
## 2.0.3
|
|
3079
|
+
|
|
3080
|
+
### Patch Changes
|
|
3081
|
+
|
|
3082
|
+
- Patch release for maintenance and stability improvements
|
|
3083
|
+
- Updated dependencies
|
|
3084
|
+
- @objectstack/spec@2.0.3
|
|
3085
|
+
|
|
3086
|
+
## 2.0.2
|
|
3087
|
+
|
|
3088
|
+
### Patch Changes
|
|
3089
|
+
|
|
3090
|
+
- Updated dependencies [1db8559]
|
|
3091
|
+
- @objectstack/spec@2.0.2
|
|
3092
|
+
|
|
3093
|
+
## 2.0.1
|
|
3094
|
+
|
|
3095
|
+
### Patch Changes
|
|
3096
|
+
|
|
3097
|
+
- Patch release for maintenance and stability improvements
|
|
3098
|
+
- Updated dependencies
|
|
3099
|
+
- @objectstack/spec@2.0.1
|
|
3100
|
+
|
|
3101
|
+
## 2.0.0
|
|
3102
|
+
|
|
3103
|
+
### Patch Changes
|
|
3104
|
+
|
|
3105
|
+
- Updated dependencies [38e5dd5]
|
|
3106
|
+
- Updated dependencies [38e5dd5]
|
|
3107
|
+
- @objectstack/spec@2.0.0
|
|
3108
|
+
|
|
3109
|
+
## 1.0.12
|
|
3110
|
+
|
|
3111
|
+
### Patch Changes
|
|
3112
|
+
|
|
3113
|
+
- chore: add Vercel deployment configs, simplify console runtime configuration
|
|
3114
|
+
- Updated dependencies
|
|
3115
|
+
- @objectstack/spec@1.0.12
|
|
3116
|
+
|
|
3117
|
+
## 1.0.11
|
|
3118
|
+
|
|
3119
|
+
### Patch Changes
|
|
3120
|
+
|
|
3121
|
+
- @objectstack/spec@1.0.11
|
|
3122
|
+
|
|
3123
|
+
## 1.0.10
|
|
3124
|
+
|
|
3125
|
+
### Patch Changes
|
|
3126
|
+
|
|
3127
|
+
- 10f52e1: fix: silence unhandled promise rejections when checking for async services in kernel
|
|
3128
|
+
- @objectstack/spec@1.0.10
|
|
3129
|
+
|
|
3130
|
+
## 1.0.9
|
|
3131
|
+
|
|
3132
|
+
### Patch Changes
|
|
3133
|
+
|
|
3134
|
+
- @objectstack/spec@1.0.9
|
|
3135
|
+
|
|
3136
|
+
## 1.0.8
|
|
3137
|
+
|
|
3138
|
+
### Patch Changes
|
|
3139
|
+
|
|
3140
|
+
- @objectstack/spec@1.0.8
|
|
3141
|
+
|
|
3142
|
+
## 1.0.7
|
|
3143
|
+
|
|
3144
|
+
### Patch Changes
|
|
3145
|
+
|
|
3146
|
+
- @objectstack/spec@1.0.7
|
|
3147
|
+
|
|
3148
|
+
## 1.0.6
|
|
3149
|
+
|
|
3150
|
+
### Patch Changes
|
|
3151
|
+
|
|
3152
|
+
- Updated dependencies [a7f7b9d]
|
|
3153
|
+
- @objectstack/spec@1.0.6
|
|
3154
|
+
|
|
3155
|
+
## 1.0.5
|
|
3156
|
+
|
|
3157
|
+
### Patch Changes
|
|
3158
|
+
|
|
3159
|
+
- b1d24bd: refactor: migrate build system from tsc to tsup for faster builds
|
|
3160
|
+
- Replaced `tsc` with `tsup` (using esbuild) across all packages
|
|
3161
|
+
- Added shared `tsup.config.ts` in workspace root
|
|
3162
|
+
- Added `tsup` as workspace dev dependency
|
|
3163
|
+
- significantly improved build performance
|
|
3164
|
+
- Updated dependencies [b1d24bd]
|
|
3165
|
+
- @objectstack/spec@1.0.5
|
|
3166
|
+
|
|
3167
|
+
## 1.0.4
|
|
3168
|
+
|
|
3169
|
+
### Patch Changes
|
|
3170
|
+
|
|
3171
|
+
- @objectstack/spec@1.0.4
|
|
3172
|
+
|
|
3173
|
+
## 1.0.3
|
|
3174
|
+
|
|
3175
|
+
### Patch Changes
|
|
3176
|
+
|
|
3177
|
+
- fb2eabd: fix: resolve "process is not defined" runtime error in browser environments by adding safe environment detection and polyfills
|
|
3178
|
+
- @objectstack/spec@1.0.3
|
|
3179
|
+
|
|
3180
|
+
## 1.0.2
|
|
3181
|
+
|
|
3182
|
+
### Patch Changes
|
|
3183
|
+
|
|
3184
|
+
- a0a6c85: Infrastructure and development tooling improvements
|
|
3185
|
+
|
|
3186
|
+
- Add changeset configuration for automated version management
|
|
3187
|
+
- Add comprehensive GitHub Actions workflows (CI, CodeQL, linting, releases)
|
|
3188
|
+
- Add development configuration files (.cursorrules, .github/prompts)
|
|
3189
|
+
- Add documentation files (ARCHITECTURE.md, CONTRIBUTING.md, workflows docs)
|
|
3190
|
+
- Update test script configuration in package.json
|
|
3191
|
+
- Add @objectstack/cli to devDependencies for better development experience
|
|
3192
|
+
|
|
3193
|
+
- 109fc5b: Unified patch release to align all package versions.
|
|
3194
|
+
- Updated dependencies [a0a6c85]
|
|
3195
|
+
- Updated dependencies [109fc5b]
|
|
3196
|
+
- @objectstack/spec@1.0.2
|
|
3197
|
+
|
|
3198
|
+
## 1.0.1
|
|
3199
|
+
|
|
3200
|
+
### Patch Changes
|
|
3201
|
+
|
|
3202
|
+
- @objectstack/spec@1.0.1
|
|
3203
|
+
|
|
3204
|
+
## 1.0.0
|
|
3205
|
+
|
|
3206
|
+
### Major Changes
|
|
3207
|
+
|
|
3208
|
+
- Major version release for ObjectStack Protocol v1.0.
|
|
3209
|
+
- Stabilized Protocol Definitions
|
|
3210
|
+
- Enhanced Runtime Plugin Support
|
|
3211
|
+
- Fixed Type Compliance across Monorepo
|
|
3212
|
+
|
|
3213
|
+
### Patch Changes
|
|
3214
|
+
|
|
3215
|
+
- Updated dependencies
|
|
3216
|
+
- @objectstack/spec@1.0.0
|
|
3217
|
+
|
|
3218
|
+
## 0.9.2
|
|
3219
|
+
|
|
3220
|
+
### Patch Changes
|
|
3221
|
+
|
|
3222
|
+
- Updated dependencies
|
|
3223
|
+
- @objectstack/spec@0.9.2
|
|
3224
|
+
|
|
3225
|
+
## 0.9.1
|
|
3226
|
+
|
|
3227
|
+
### Patch Changes
|
|
3228
|
+
|
|
3229
|
+
- Patch release for maintenance and stability improvements. All packages updated with unified versioning.
|
|
3230
|
+
- Updated dependencies
|
|
3231
|
+
- @objectstack/spec@0.9.1
|
|
3232
|
+
|
|
3233
|
+
## 0.8.2
|
|
3234
|
+
|
|
3235
|
+
### Patch Changes
|
|
3236
|
+
|
|
3237
|
+
- Updated dependencies [555e6a7]
|
|
3238
|
+
- @objectstack/spec@0.8.2
|
|
3239
|
+
|
|
3240
|
+
## 0.8.1
|
|
3241
|
+
|
|
3242
|
+
### Patch Changes
|
|
3243
|
+
|
|
3244
|
+
- @objectstack/spec@0.8.1
|
|
3245
|
+
|
|
3246
|
+
## 1.0.0
|
|
3247
|
+
|
|
3248
|
+
### Minor Changes
|
|
3249
|
+
|
|
3250
|
+
- # Upgrade to Zod v4 and Protocol Improvements
|
|
3251
|
+
|
|
3252
|
+
This release includes a major upgrade to the core validation engine (Zod v4) and aligns all protocol definitions with stricter type safety.
|
|
3253
|
+
|
|
3254
|
+
### Patch Changes
|
|
3255
|
+
|
|
3256
|
+
- Updated dependencies
|
|
3257
|
+
- @objectstack/spec@1.0.0
|
|
3258
|
+
|
|
3259
|
+
## 0.7.2
|
|
3260
|
+
|
|
3261
|
+
### Patch Changes
|
|
3262
|
+
|
|
3263
|
+
- fb41cc0: Patch release: Updated documentation and JSON schemas
|
|
3264
|
+
- Updated dependencies [fb41cc0]
|
|
3265
|
+
- @objectstack/spec@0.7.2
|
|
3266
|
+
|
|
3267
|
+
## 0.7.1
|
|
3268
|
+
|
|
3269
|
+
### Patch Changes
|
|
3270
|
+
|
|
3271
|
+
- Updated dependencies
|
|
3272
|
+
- @objectstack/spec@0.7.1
|
|
3273
|
+
|
|
3274
|
+
## 0.6.1
|
|
3275
|
+
|
|
3276
|
+
### Patch Changes
|
|
3277
|
+
|
|
3278
|
+
- Patch release for maintenance and stability improvements
|
|
3279
|
+
- Updated dependencies
|
|
3280
|
+
- @objectstack/spec@0.6.1
|
|
3281
|
+
|
|
3282
|
+
## 0.6.0
|
|
3283
|
+
|
|
3284
|
+
### Minor Changes
|
|
3285
|
+
|
|
3286
|
+
- b2df5f7: Unified version bump to 0.5.0
|
|
3287
|
+
|
|
3288
|
+
- Standardized all package versions to 0.5.0 across the monorepo
|
|
3289
|
+
- Fixed driver-memory package.json paths for proper module resolution
|
|
3290
|
+
- Ensured all packages are in sync for the 0.5.0 release
|
|
3291
|
+
|
|
3292
|
+
### Patch Changes
|
|
3293
|
+
|
|
3294
|
+
- Updated dependencies [b2df5f7]
|
|
3295
|
+
- @objectstack/spec@0.6.0
|