@objectstack/plugin-reports 17.0.0 → 17.2.0
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 +240 -0
- package/dist/index.d.mts +71 -3
- package/dist/index.d.ts +71 -3
- package/dist/index.js +55 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +55 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,245 @@
|
|
|
1
1
|
# @objectstack/plugin-reports
|
|
2
2
|
|
|
3
|
+
## 17.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e222a53: **BREAKING** (compile-time only): twelve logger sink types that declared an
|
|
8
|
+
optional `error` now declare a **non-optional** `warn`, so a durability report
|
|
9
|
+
always has somewhere to land (#9754, #10556).
|
|
10
|
+
|
|
11
|
+
`minor`, not `major`: during the launch window this stack ships breaking changes
|
|
12
|
+
as `minor` — every publishable package versions in lockstep, so a `major` would
|
|
13
|
+
promote the whole release. `patch` would be wrong in the other direction, because
|
|
14
|
+
this *can* break a consumer's build.
|
|
15
|
+
|
|
16
|
+
`error` stays optional on every one of these types — hosts legitimately inject
|
|
17
|
+
reduced sinks, and requiring `error` was measured and rejected as #9754 option C.
|
|
18
|
+
What changes is that its *absence* now has a declared, guaranteed destination.
|
|
19
|
+
Call sites keep the `logger?.warn?.(…)` spelling as the backstop for hosts the
|
|
20
|
+
type cannot reach, so **no runtime behaviour changes**: nothing that printed
|
|
21
|
+
before stops printing, and nothing silent starts printing.
|
|
22
|
+
|
|
23
|
+
### Who has to change, and what to do
|
|
24
|
+
|
|
25
|
+
Only a caller that hands one of these sinks an object with **no `warn` method** —
|
|
26
|
+
for example `{ info }` or `{ error }` alone. Add a `warn` member; there is no
|
|
27
|
+
rename, no removal, and no stored value or metadata key to rewrite. Every
|
|
28
|
+
construction site inside this repo already supplied one, so the in-repo cost was
|
|
29
|
+
zero; the compile error is reserved for the callers that were silently discarding
|
|
30
|
+
these reports.
|
|
31
|
+
|
|
32
|
+
The affected types, by package:
|
|
33
|
+
|
|
34
|
+
- `@objectstack/cloud-connection` — the internal `PluginContext['logger']`
|
|
35
|
+
- `@objectstack/metadata-protocol` — `IndexMigrationLogger`
|
|
36
|
+
- `@objectstack/plugin-approvals` — the internal `MinimalLogger` of `lifecycle-hooks`
|
|
37
|
+
- `@objectstack/plugin-audit` — `AuthEventAuditLogger`, `ReadAuditLogger`
|
|
38
|
+
- `@objectstack/plugin-auth` — `ReconcileMembershipDeps['logger']`, the internal
|
|
39
|
+
`LoggerLike` of `member-role-canonical`, and `AuthManagerOptions['logger']`
|
|
40
|
+
- `@objectstack/plugin-email` — `ReclaimLogger`, via `ReclaimAttachmentContentOptions`
|
|
41
|
+
- `@objectstack/plugin-reports` — `ReportServiceOptions['logger']`
|
|
42
|
+
- `@objectstack/plugin-sharing` — the internal `MinimalLogger` of `bulk-recompute`,
|
|
43
|
+
`rule-hooks` and `record-share-cascade`
|
|
44
|
+
- `@objectstack/plugin-webhooks` — `OptionalLogger`, via `AutoEnqueuerOptions`
|
|
45
|
+
- `@objectstack/service-knowledge` — `KnowledgeLogger`
|
|
46
|
+
|
|
47
|
+
`AuthManagerOptions['logger']` is the one most likely to be reached from outside:
|
|
48
|
+
`AuthManager` is public surface, its `logger` option stays optional, and a logger
|
|
49
|
+
that *is* supplied must now carry `warn`. The only non-test construction site in
|
|
50
|
+
this repo passes the kernel `Logger`, whose `warn` is already required.
|
|
51
|
+
|
|
52
|
+
`ReportService` and `AutoEnqueuer` additionally stopped defaulting their logger
|
|
53
|
+
field to `{}`. The field is now honestly optional rather than holding an empty
|
|
54
|
+
object that declared it could report and discarded everything. Behaviour is
|
|
55
|
+
unchanged in both directions.
|
|
56
|
+
|
|
57
|
+
<!-- adr-0087: not-required (runtime-interface-only packages/plugins/plugin-auth/src/auth-manager.ts#AuthManagerOptions, packages/plugins/plugin-auth/src/reconcile-membership.ts#ReconcileMembershipDeps, packages/metadata-protocol/src/migrations/partial-index-probe.ts#IndexMigrationLogger, packages/plugins/plugin-audit/src/auth-event-audit.ts#AuthEventAuditLogger, packages/plugins/plugin-audit/src/read-audit.ts#ReadAuditLogger, packages/plugins/plugin-reports/src/report-service.ts#ReportServiceOptions, packages/services/service-knowledge/src/knowledge-service.ts#KnowledgeLogger) every tightened type is a plain TypeScript logger interface -- no Zod projection, no metadata surface, and none is referenced by one -- so `objectstack migrate meta` has nothing to rewrite. Nothing is removed or renamed and no stored value moves; the only consumer action is adding a `warn` member at a construction site the compiler names. -->
|
|
58
|
+
|
|
59
|
+
### Patch Changes
|
|
60
|
+
|
|
61
|
+
- 6d5c4fa: Release these plugins' resources from `destroy()`, the teardown hook the kernel
|
|
62
|
+
actually calls (#10371). `Plugin` declares `init()`, `start?(ctx)` and
|
|
63
|
+
`destroy?()` — and no `stop()` — so `ObjectKernel.performShutdown()` and
|
|
64
|
+
`LiteKernel.destroy()`, which walk the plugins in reverse calling
|
|
65
|
+
`plugin.destroy()`, walked straight past every plugin whose teardown was spelled
|
|
66
|
+
`stop()`. `await kernel.shutdown()` resolved with the reports dispatcher still
|
|
67
|
+
armed, the REST/OpenAPI/Slack connectors still registered on the automation
|
|
68
|
+
engine, the approvals SLA escalation job still scheduled, and the knowledge
|
|
69
|
+
event-sync subscription still open.
|
|
70
|
+
|
|
71
|
+
Each teardown body now lives in `destroy()`. `stop()` is retained as a
|
|
72
|
+
delegating alias with its parameter made optional, so an embedder that learned
|
|
73
|
+
to call it directly — precisely because the kernel never did — keeps working
|
|
74
|
+
unchanged. No export is removed and the `Plugin` interface is untouched.
|
|
75
|
+
|
|
76
|
+
Same defect as #9371 in `@objectstack/service-messaging`, which surfaced as
|
|
77
|
+
fully green test runs exiting 1 on `EnvironmentTeardownError` and being evicted
|
|
78
|
+
from the merge queue.
|
|
79
|
+
- Updated dependencies [8f04d9a]
|
|
80
|
+
- Updated dependencies [6936d07]
|
|
81
|
+
- Updated dependencies [59eb04d]
|
|
82
|
+
- Updated dependencies [9f05b7d]
|
|
83
|
+
- Updated dependencies [3b2af5e]
|
|
84
|
+
- Updated dependencies [7d2d112]
|
|
85
|
+
- Updated dependencies [5fa0d72]
|
|
86
|
+
- Updated dependencies [02b3b07]
|
|
87
|
+
- Updated dependencies [914c413]
|
|
88
|
+
- Updated dependencies [55809a0]
|
|
89
|
+
- Updated dependencies [ee2ff45]
|
|
90
|
+
- Updated dependencies [47cd3ec]
|
|
91
|
+
- Updated dependencies [52db1d1]
|
|
92
|
+
- Updated dependencies [5649efb]
|
|
93
|
+
- Updated dependencies [9d7d2de]
|
|
94
|
+
- Updated dependencies [c815c50]
|
|
95
|
+
- Updated dependencies [795ea05]
|
|
96
|
+
- Updated dependencies [2306a76]
|
|
97
|
+
- Updated dependencies [e5ea701]
|
|
98
|
+
- Updated dependencies [a40dcc1]
|
|
99
|
+
- Updated dependencies [def0d3e]
|
|
100
|
+
- Updated dependencies [8d0bb79]
|
|
101
|
+
- Updated dependencies [5acb58d]
|
|
102
|
+
- Updated dependencies [2e3cf95]
|
|
103
|
+
- Updated dependencies [4c93387]
|
|
104
|
+
- Updated dependencies [504c8d5]
|
|
105
|
+
- Updated dependencies [a037f7c]
|
|
106
|
+
- Updated dependencies [3ee8ddf]
|
|
107
|
+
- Updated dependencies [16cef97]
|
|
108
|
+
- Updated dependencies [a79bd35]
|
|
109
|
+
- Updated dependencies [6ceaa4b]
|
|
110
|
+
- Updated dependencies [15ea214]
|
|
111
|
+
- Updated dependencies [de19489]
|
|
112
|
+
- Updated dependencies [c684d00]
|
|
113
|
+
- Updated dependencies [923c424]
|
|
114
|
+
- Updated dependencies [0ab81d1]
|
|
115
|
+
- Updated dependencies [1ec36b7]
|
|
116
|
+
- Updated dependencies [5f2e54c]
|
|
117
|
+
- Updated dependencies [189373b]
|
|
118
|
+
- Updated dependencies [35ad101]
|
|
119
|
+
- Updated dependencies [ceb33a9]
|
|
120
|
+
- Updated dependencies [dccbcec]
|
|
121
|
+
- Updated dependencies [73d9795]
|
|
122
|
+
- Updated dependencies [8012960]
|
|
123
|
+
- Updated dependencies [266654d]
|
|
124
|
+
- Updated dependencies [f34f56b]
|
|
125
|
+
- Updated dependencies [f399618]
|
|
126
|
+
- Updated dependencies [75e9301]
|
|
127
|
+
- Updated dependencies [2810695]
|
|
128
|
+
- @objectstack/platform-objects@17.2.0
|
|
129
|
+
- @objectstack/spec@17.2.0
|
|
130
|
+
- @objectstack/core@17.2.0
|
|
131
|
+
|
|
132
|
+
## 17.1.0
|
|
133
|
+
|
|
134
|
+
### Patch Changes
|
|
135
|
+
|
|
136
|
+
- Updated dependencies [56656aa]
|
|
137
|
+
- Updated dependencies [c9f5950]
|
|
138
|
+
- Updated dependencies [d6e80b2]
|
|
139
|
+
- Updated dependencies [07e630e]
|
|
140
|
+
- Updated dependencies [66beee0]
|
|
141
|
+
- Updated dependencies [2f65b1b]
|
|
142
|
+
- Updated dependencies [720ee95]
|
|
143
|
+
- Updated dependencies [f287435]
|
|
144
|
+
- Updated dependencies [2782805]
|
|
145
|
+
- Updated dependencies [e43d63a]
|
|
146
|
+
- Updated dependencies [9aa8890]
|
|
147
|
+
- Updated dependencies [7c9c1dd]
|
|
148
|
+
- Updated dependencies [03520eb]
|
|
149
|
+
- Updated dependencies [75b7c24]
|
|
150
|
+
- Updated dependencies [d5552ca]
|
|
151
|
+
- Updated dependencies [d9813a9]
|
|
152
|
+
- Updated dependencies [8640fb2]
|
|
153
|
+
- Updated dependencies [2420641]
|
|
154
|
+
- Updated dependencies [2ad91c3]
|
|
155
|
+
- Updated dependencies [f57fb38]
|
|
156
|
+
- Updated dependencies [00777a0]
|
|
157
|
+
- Updated dependencies [d491625]
|
|
158
|
+
- Updated dependencies [420804d]
|
|
159
|
+
- Updated dependencies [716ac9b]
|
|
160
|
+
- Updated dependencies [a38408a]
|
|
161
|
+
- Updated dependencies [62b1427]
|
|
162
|
+
- Updated dependencies [7ea1372]
|
|
163
|
+
- Updated dependencies [23abe27]
|
|
164
|
+
- Updated dependencies [985a9cd]
|
|
165
|
+
- Updated dependencies [5f5e234]
|
|
166
|
+
- Updated dependencies [a8189ae]
|
|
167
|
+
- Updated dependencies [26e70fb]
|
|
168
|
+
- Updated dependencies [42b05af]
|
|
169
|
+
- Updated dependencies [2b292ce]
|
|
170
|
+
- Updated dependencies [abcf853]
|
|
171
|
+
- Updated dependencies [8b9eba5]
|
|
172
|
+
- Updated dependencies [d575779]
|
|
173
|
+
- Updated dependencies [94f7ef8]
|
|
174
|
+
- Updated dependencies [c5ac5e4]
|
|
175
|
+
- Updated dependencies [a777944]
|
|
176
|
+
- Updated dependencies [dd88e1c]
|
|
177
|
+
- Updated dependencies [856527c]
|
|
178
|
+
- Updated dependencies [870f710]
|
|
179
|
+
- Updated dependencies [79c46da]
|
|
180
|
+
- Updated dependencies [7ff3975]
|
|
181
|
+
- Updated dependencies [29d055b]
|
|
182
|
+
- Updated dependencies [65589d6]
|
|
183
|
+
- Updated dependencies [2c86fe3]
|
|
184
|
+
- Updated dependencies [e196c6a]
|
|
185
|
+
- Updated dependencies [24173e9]
|
|
186
|
+
- Updated dependencies [4ab7523]
|
|
187
|
+
- Updated dependencies [19539b4]
|
|
188
|
+
- Updated dependencies [f8eb736]
|
|
189
|
+
- Updated dependencies [11b779e]
|
|
190
|
+
- Updated dependencies [739fe5b]
|
|
191
|
+
- Updated dependencies [4bfe1a5]
|
|
192
|
+
- Updated dependencies [2065e31]
|
|
193
|
+
- Updated dependencies [b69d0f5]
|
|
194
|
+
- Updated dependencies [4d47afe]
|
|
195
|
+
- Updated dependencies [e4e5c6e]
|
|
196
|
+
- Updated dependencies [9a56784]
|
|
197
|
+
- Updated dependencies [d00d2f6]
|
|
198
|
+
- Updated dependencies [df0c12d]
|
|
199
|
+
- Updated dependencies [d31785f]
|
|
200
|
+
- Updated dependencies [c308a4f]
|
|
201
|
+
- Updated dependencies [e2899f6]
|
|
202
|
+
- Updated dependencies [3851f87]
|
|
203
|
+
- Updated dependencies [2a29caa]
|
|
204
|
+
- Updated dependencies [09a6eee]
|
|
205
|
+
- Updated dependencies [1a7f907]
|
|
206
|
+
- Updated dependencies [cd455c8]
|
|
207
|
+
- Updated dependencies [e1bb0ca]
|
|
208
|
+
- Updated dependencies [30d3752]
|
|
209
|
+
- Updated dependencies [c80e7ae]
|
|
210
|
+
- Updated dependencies [09a9a8a]
|
|
211
|
+
- Updated dependencies [07026cf]
|
|
212
|
+
- Updated dependencies [5d4f3d5]
|
|
213
|
+
- Updated dependencies [4d80e8b]
|
|
214
|
+
- Updated dependencies [30b1c63]
|
|
215
|
+
- Updated dependencies [079b457]
|
|
216
|
+
- Updated dependencies [e43b211]
|
|
217
|
+
- Updated dependencies [890b38f]
|
|
218
|
+
- Updated dependencies [8bee54b]
|
|
219
|
+
- Updated dependencies [04f8fdb]
|
|
220
|
+
- Updated dependencies [7a537ce]
|
|
221
|
+
- Updated dependencies [593c4bf]
|
|
222
|
+
- Updated dependencies [6158146]
|
|
223
|
+
- Updated dependencies [84cb121]
|
|
224
|
+
- Updated dependencies [ca19ee8]
|
|
225
|
+
- Updated dependencies [a675b4d]
|
|
226
|
+
- Updated dependencies [b887013]
|
|
227
|
+
- Updated dependencies [ff08691]
|
|
228
|
+
- Updated dependencies [60e0f90]
|
|
229
|
+
- Updated dependencies [90c5285]
|
|
230
|
+
- Updated dependencies [402c125]
|
|
231
|
+
- Updated dependencies [7901b2d]
|
|
232
|
+
- Updated dependencies [56bca91]
|
|
233
|
+
- Updated dependencies [b3f9831]
|
|
234
|
+
- Updated dependencies [79394d7]
|
|
235
|
+
- Updated dependencies [730fd9a]
|
|
236
|
+
- Updated dependencies [44bc51d]
|
|
237
|
+
- Updated dependencies [73cfddf]
|
|
238
|
+
- Updated dependencies [d634e66]
|
|
239
|
+
- @objectstack/spec@17.1.0
|
|
240
|
+
- @objectstack/platform-objects@17.1.0
|
|
241
|
+
- @objectstack/core@17.1.0
|
|
242
|
+
|
|
3
243
|
## 17.0.0
|
|
4
244
|
|
|
5
245
|
### Major Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -76,9 +76,16 @@ interface ReportServiceOptions {
|
|
|
76
76
|
engine: ReportEngine;
|
|
77
77
|
email?: ReportEmail;
|
|
78
78
|
clock?: ReportClock;
|
|
79
|
+
/**
|
|
80
|
+
* `warn` is GUARANTEED, `error` is not (#9754). Hosts do inject reduced sinks,
|
|
81
|
+
* so `error` stays optional — but a durability report that degrades to `warn`
|
|
82
|
+
* needs `warn` to actually be there, and this service degrades to it in eight
|
|
83
|
+
* places below. The whole `logger` stays optional; what is no longer
|
|
84
|
+
* representable is a sink that HAS the field and still prints nothing.
|
|
85
|
+
*/
|
|
79
86
|
logger?: {
|
|
80
87
|
info?: (msg: any, ...rest: any[]) => void;
|
|
81
|
-
warn
|
|
88
|
+
warn: (msg: any, ...rest: any[]) => void;
|
|
82
89
|
error?: (msg: any, ...rest: any[]) => void;
|
|
83
90
|
};
|
|
84
91
|
/** Cap rows per report to protect both DB and email size. */
|
|
@@ -109,7 +116,22 @@ declare class ReportService implements IReportService {
|
|
|
109
116
|
private readonly engine;
|
|
110
117
|
private readonly email?;
|
|
111
118
|
private readonly clock;
|
|
112
|
-
|
|
119
|
+
/**
|
|
120
|
+
* Optional, and deliberately NOT defaulted to `{}` (#10556).
|
|
121
|
+
*
|
|
122
|
+
* `ReportServiceOptions['logger']` guarantees a `warn` channel under #9754, so `{}` stopped being a
|
|
123
|
+
* legal value of the type — which is the gate working: an empty object is a
|
|
124
|
+
* sink that declares it can report and then discards everything. The repair
|
|
125
|
+
* is to say what is TRUE — there may be no logger at all — rather than to
|
|
126
|
+
* mint a sink that lies. Runtime behaviour is unchanged in both directions:
|
|
127
|
+
* absent logger and `{}` both printed nothing before, and print nothing now.
|
|
128
|
+
*
|
|
129
|
+
* ⛔ What this deliberately does NOT decide: whether an absent host sink should
|
|
130
|
+
* instead default to a `console`-backed one. That is the open design call the
|
|
131
|
+
* #9754 ledger records against `plugin-security`'s `= {}` field, and it is a
|
|
132
|
+
* maintainer decision — not something to settle here to make a checker green.
|
|
133
|
+
*/
|
|
134
|
+
private readonly logger?;
|
|
113
135
|
private readonly maxRows;
|
|
114
136
|
private readonly resolveOwnerContext?;
|
|
115
137
|
private readonly canExportFn?;
|
|
@@ -221,10 +243,56 @@ declare class ReportsServicePlugin implements Plugin {
|
|
|
221
243
|
private intervalHandle?;
|
|
222
244
|
private jobName?;
|
|
223
245
|
private jobService?;
|
|
246
|
+
/**
|
|
247
|
+
* Captured in `init()` because `destroy()` — the hook the kernel actually
|
|
248
|
+
* calls — takes NO `PluginContext` (`Plugin.destroy?(): Promise<void> | void`
|
|
249
|
+
* in core's `types.ts`). Teardown still needs somewhere to report a failed
|
|
250
|
+
* job cancellation, so the logger is held rather than resolved late.
|
|
251
|
+
*/
|
|
252
|
+
private logger?;
|
|
224
253
|
constructor(options?: ReportsPluginOptions);
|
|
225
254
|
init(ctx: PluginContext): Promise<void>;
|
|
226
255
|
start(ctx: PluginContext): Promise<void>;
|
|
227
|
-
|
|
256
|
+
/**
|
|
257
|
+
* The kernel's teardown hook (`Plugin.destroy?()`, core `types.ts`) — the
|
|
258
|
+
* ONLY teardown entry point `ObjectKernel.performShutdown()` and
|
|
259
|
+
* `LiteKernel.destroy()` invoke.
|
|
260
|
+
*
|
|
261
|
+
* [#10371] IT USED TO BE `stop()`, WHICH NOTHING CALLED. The body below was
|
|
262
|
+
* correct in every respect except its NAME: `Plugin` declares `init()`,
|
|
263
|
+
* `start?()` and `destroy?()` and no `stop()`, so the kernel walked straight
|
|
264
|
+
* past this plugin at shutdown and the dispatcher went on ticking after
|
|
265
|
+
* `await kernel.shutdown()` had resolved. The asymmetry is what hid it:
|
|
266
|
+
* `start()` IS on the interface and does fire, so a `start`/`stop` pair reads
|
|
267
|
+
* as symmetric in review.
|
|
268
|
+
*
|
|
269
|
+
* WHY IT STAYED INVISIBLE, AND WHERE THE BILL LANDS. `start()` `unref()`s the
|
|
270
|
+
* interval, so a long-lived host process still exits and nothing complains in
|
|
271
|
+
* production. Under vitest the worker is alive throughout teardown, so a tick
|
|
272
|
+
* fires after the test file is over, reads through a driver the suite already
|
|
273
|
+
* disconnected, and a console fallback warns; `console.*` inside a worker is
|
|
274
|
+
* an RPC (`onUserConsoleLog`) and one issued after `rpcDone()` snapshotted the
|
|
275
|
+
* pending set is rejected as `EnvironmentTeardownError`. Nothing awaits that
|
|
276
|
+
* promise, so it lands as an unhandled rejection and fails a run in which
|
|
277
|
+
* every test passed. That is the identical defect #9371 fixed in
|
|
278
|
+
* `MessagingServicePlugin` — measured there as two green PRs (334/334 and
|
|
279
|
+
* 337/337) evicted from the merge queue.
|
|
280
|
+
*
|
|
281
|
+
* The job-service branch matters as much as the timer: when `service-job` is
|
|
282
|
+
* installed the dispatcher is a scheduled job rather than a `setInterval`, so
|
|
283
|
+
* a teardown the kernel never reaches leaks whichever of the two this
|
|
284
|
+
* deployment happens to use.
|
|
285
|
+
*/
|
|
286
|
+
destroy(): Promise<void>;
|
|
287
|
+
/**
|
|
288
|
+
* Retained alias for {@link destroy}. Kept because it is public API of an
|
|
289
|
+
* exported class, and removing it would break an embedder who learned to call
|
|
290
|
+
* it directly precisely BECAUSE the kernel never did. The parameter is now
|
|
291
|
+
* optional and ignored: `destroy()` takes no context, so teardown reads the
|
|
292
|
+
* logger captured in `init()`. Prefer kernel shutdown; direct callers keep
|
|
293
|
+
* working unchanged.
|
|
294
|
+
*/
|
|
295
|
+
stop(_ctx?: PluginContext): Promise<void>;
|
|
228
296
|
}
|
|
229
297
|
|
|
230
298
|
export { type ReportClock, type ReportEmail, type ReportEngine, ReportService, type ReportServiceOptions, type ReportsPluginOptions, ReportsServicePlugin, renderReport };
|
package/dist/index.d.ts
CHANGED
|
@@ -76,9 +76,16 @@ interface ReportServiceOptions {
|
|
|
76
76
|
engine: ReportEngine;
|
|
77
77
|
email?: ReportEmail;
|
|
78
78
|
clock?: ReportClock;
|
|
79
|
+
/**
|
|
80
|
+
* `warn` is GUARANTEED, `error` is not (#9754). Hosts do inject reduced sinks,
|
|
81
|
+
* so `error` stays optional — but a durability report that degrades to `warn`
|
|
82
|
+
* needs `warn` to actually be there, and this service degrades to it in eight
|
|
83
|
+
* places below. The whole `logger` stays optional; what is no longer
|
|
84
|
+
* representable is a sink that HAS the field and still prints nothing.
|
|
85
|
+
*/
|
|
79
86
|
logger?: {
|
|
80
87
|
info?: (msg: any, ...rest: any[]) => void;
|
|
81
|
-
warn
|
|
88
|
+
warn: (msg: any, ...rest: any[]) => void;
|
|
82
89
|
error?: (msg: any, ...rest: any[]) => void;
|
|
83
90
|
};
|
|
84
91
|
/** Cap rows per report to protect both DB and email size. */
|
|
@@ -109,7 +116,22 @@ declare class ReportService implements IReportService {
|
|
|
109
116
|
private readonly engine;
|
|
110
117
|
private readonly email?;
|
|
111
118
|
private readonly clock;
|
|
112
|
-
|
|
119
|
+
/**
|
|
120
|
+
* Optional, and deliberately NOT defaulted to `{}` (#10556).
|
|
121
|
+
*
|
|
122
|
+
* `ReportServiceOptions['logger']` guarantees a `warn` channel under #9754, so `{}` stopped being a
|
|
123
|
+
* legal value of the type — which is the gate working: an empty object is a
|
|
124
|
+
* sink that declares it can report and then discards everything. The repair
|
|
125
|
+
* is to say what is TRUE — there may be no logger at all — rather than to
|
|
126
|
+
* mint a sink that lies. Runtime behaviour is unchanged in both directions:
|
|
127
|
+
* absent logger and `{}` both printed nothing before, and print nothing now.
|
|
128
|
+
*
|
|
129
|
+
* ⛔ What this deliberately does NOT decide: whether an absent host sink should
|
|
130
|
+
* instead default to a `console`-backed one. That is the open design call the
|
|
131
|
+
* #9754 ledger records against `plugin-security`'s `= {}` field, and it is a
|
|
132
|
+
* maintainer decision — not something to settle here to make a checker green.
|
|
133
|
+
*/
|
|
134
|
+
private readonly logger?;
|
|
113
135
|
private readonly maxRows;
|
|
114
136
|
private readonly resolveOwnerContext?;
|
|
115
137
|
private readonly canExportFn?;
|
|
@@ -221,10 +243,56 @@ declare class ReportsServicePlugin implements Plugin {
|
|
|
221
243
|
private intervalHandle?;
|
|
222
244
|
private jobName?;
|
|
223
245
|
private jobService?;
|
|
246
|
+
/**
|
|
247
|
+
* Captured in `init()` because `destroy()` — the hook the kernel actually
|
|
248
|
+
* calls — takes NO `PluginContext` (`Plugin.destroy?(): Promise<void> | void`
|
|
249
|
+
* in core's `types.ts`). Teardown still needs somewhere to report a failed
|
|
250
|
+
* job cancellation, so the logger is held rather than resolved late.
|
|
251
|
+
*/
|
|
252
|
+
private logger?;
|
|
224
253
|
constructor(options?: ReportsPluginOptions);
|
|
225
254
|
init(ctx: PluginContext): Promise<void>;
|
|
226
255
|
start(ctx: PluginContext): Promise<void>;
|
|
227
|
-
|
|
256
|
+
/**
|
|
257
|
+
* The kernel's teardown hook (`Plugin.destroy?()`, core `types.ts`) — the
|
|
258
|
+
* ONLY teardown entry point `ObjectKernel.performShutdown()` and
|
|
259
|
+
* `LiteKernel.destroy()` invoke.
|
|
260
|
+
*
|
|
261
|
+
* [#10371] IT USED TO BE `stop()`, WHICH NOTHING CALLED. The body below was
|
|
262
|
+
* correct in every respect except its NAME: `Plugin` declares `init()`,
|
|
263
|
+
* `start?()` and `destroy?()` and no `stop()`, so the kernel walked straight
|
|
264
|
+
* past this plugin at shutdown and the dispatcher went on ticking after
|
|
265
|
+
* `await kernel.shutdown()` had resolved. The asymmetry is what hid it:
|
|
266
|
+
* `start()` IS on the interface and does fire, so a `start`/`stop` pair reads
|
|
267
|
+
* as symmetric in review.
|
|
268
|
+
*
|
|
269
|
+
* WHY IT STAYED INVISIBLE, AND WHERE THE BILL LANDS. `start()` `unref()`s the
|
|
270
|
+
* interval, so a long-lived host process still exits and nothing complains in
|
|
271
|
+
* production. Under vitest the worker is alive throughout teardown, so a tick
|
|
272
|
+
* fires after the test file is over, reads through a driver the suite already
|
|
273
|
+
* disconnected, and a console fallback warns; `console.*` inside a worker is
|
|
274
|
+
* an RPC (`onUserConsoleLog`) and one issued after `rpcDone()` snapshotted the
|
|
275
|
+
* pending set is rejected as `EnvironmentTeardownError`. Nothing awaits that
|
|
276
|
+
* promise, so it lands as an unhandled rejection and fails a run in which
|
|
277
|
+
* every test passed. That is the identical defect #9371 fixed in
|
|
278
|
+
* `MessagingServicePlugin` — measured there as two green PRs (334/334 and
|
|
279
|
+
* 337/337) evicted from the merge queue.
|
|
280
|
+
*
|
|
281
|
+
* The job-service branch matters as much as the timer: when `service-job` is
|
|
282
|
+
* installed the dispatcher is a scheduled job rather than a `setInterval`, so
|
|
283
|
+
* a teardown the kernel never reaches leaks whichever of the two this
|
|
284
|
+
* deployment happens to use.
|
|
285
|
+
*/
|
|
286
|
+
destroy(): Promise<void>;
|
|
287
|
+
/**
|
|
288
|
+
* Retained alias for {@link destroy}. Kept because it is public API of an
|
|
289
|
+
* exported class, and removing it would break an embedder who learned to call
|
|
290
|
+
* it directly precisely BECAUSE the kernel never did. The parameter is now
|
|
291
|
+
* optional and ignored: `destroy()` takes no context, so teardown reads the
|
|
292
|
+
* logger captured in `init()`. Prefer kernel shutdown; direct callers keep
|
|
293
|
+
* working unchanged.
|
|
294
|
+
*/
|
|
295
|
+
stop(_ctx?: PluginContext): Promise<void>;
|
|
228
296
|
}
|
|
229
297
|
|
|
230
298
|
export { type ReportClock, type ReportEmail, type ReportEngine, ReportService, type ReportServiceOptions, type ReportsPluginOptions, ReportsServicePlugin, renderReport };
|
package/dist/index.js
CHANGED
|
@@ -154,7 +154,7 @@ var ReportService = class {
|
|
|
154
154
|
this.engine = opts.engine;
|
|
155
155
|
this.email = opts.email;
|
|
156
156
|
this.clock = opts.clock ?? { now: () => /* @__PURE__ */ new Date() };
|
|
157
|
-
this.logger = opts.logger
|
|
157
|
+
this.logger = opts.logger;
|
|
158
158
|
this.maxRows = Math.max(1, opts.maxRows ?? 5e3);
|
|
159
159
|
this.resolveOwnerContext = opts.resolveOwnerContext;
|
|
160
160
|
this.canExportFn = opts.canExport;
|
|
@@ -186,7 +186,7 @@ var ReportService = class {
|
|
|
186
186
|
try {
|
|
187
187
|
allowed = await this.canExportFn(object, context);
|
|
188
188
|
} catch (err) {
|
|
189
|
-
this.logger
|
|
189
|
+
this.logger?.warn?.("ReportService: canExport check failed \u2014 denying export", err);
|
|
190
190
|
allowed = false;
|
|
191
191
|
}
|
|
192
192
|
if (!allowed) {
|
|
@@ -382,7 +382,7 @@ var ReportService = class {
|
|
|
382
382
|
updated_at: ranAt
|
|
383
383
|
}, { context: SYSTEM_CTX });
|
|
384
384
|
} catch (err) {
|
|
385
|
-
this.logger
|
|
385
|
+
this.logger?.warn?.("ReportService: failed to stamp last_run_at", err);
|
|
386
386
|
}
|
|
387
387
|
}
|
|
388
388
|
return {
|
|
@@ -485,7 +485,7 @@ var ReportService = class {
|
|
|
485
485
|
const report = rowFromSaved(row);
|
|
486
486
|
const ownerId = report.owner_id;
|
|
487
487
|
const runContext = ownerId && this.resolveOwnerContext ? await this.resolveOwnerContext(ownerId).catch((err) => {
|
|
488
|
-
this.logger
|
|
488
|
+
this.logger?.warn?.("ReportService.dispatchDue: owner context resolution failed", err);
|
|
489
489
|
return null;
|
|
490
490
|
}) : null;
|
|
491
491
|
if (!runContext) {
|
|
@@ -531,7 +531,7 @@ var ReportService = class {
|
|
|
531
531
|
});
|
|
532
532
|
}
|
|
533
533
|
} else if (!this.email) {
|
|
534
|
-
this.logger
|
|
534
|
+
this.logger?.warn?.("ReportService.dispatchDue: no email service \u2014 schedule fired but mail not sent");
|
|
535
535
|
}
|
|
536
536
|
await this.advanceSchedule(schedule, ts);
|
|
537
537
|
fired++;
|
|
@@ -541,7 +541,7 @@ var ReportService = class {
|
|
|
541
541
|
last_status: "failed",
|
|
542
542
|
last_error: String(err?.message ?? err ?? "unknown").slice(0, 500)
|
|
543
543
|
});
|
|
544
|
-
this.logger
|
|
544
|
+
this.logger?.error?.("ReportService.dispatchDue: schedule failed", err);
|
|
545
545
|
}
|
|
546
546
|
}
|
|
547
547
|
return { fired, failed, skipped };
|
|
@@ -562,9 +562,9 @@ var ReportService = class {
|
|
|
562
562
|
try {
|
|
563
563
|
const next = new import_croner.Cron(cron, { timezone: schedule.timezone || "UTC" }).nextRun(from);
|
|
564
564
|
if (next) return next;
|
|
565
|
-
this.logger
|
|
565
|
+
this.logger?.warn?.(`ReportService: cron '${cron}' has no next occurrence; falling back to interval`);
|
|
566
566
|
} catch (err) {
|
|
567
|
-
this.logger
|
|
567
|
+
this.logger?.warn?.(`ReportService: invalid cron '${cron}'; falling back to interval`, err);
|
|
568
568
|
}
|
|
569
569
|
}
|
|
570
570
|
const interval = schedule.interval_minutes ?? DEFAULT_INTERVAL_MIN;
|
|
@@ -589,7 +589,7 @@ var ReportService = class {
|
|
|
589
589
|
updated_at: this.clock.now().toISOString()
|
|
590
590
|
}, { context: SYSTEM_CTX });
|
|
591
591
|
} catch (err) {
|
|
592
|
-
this.logger
|
|
592
|
+
this.logger?.warn?.("ReportService: failed to mark schedule", err);
|
|
593
593
|
}
|
|
594
594
|
}
|
|
595
595
|
};
|
|
@@ -605,6 +605,7 @@ var ReportsServicePlugin = class {
|
|
|
605
605
|
this.options = options;
|
|
606
606
|
}
|
|
607
607
|
async init(ctx) {
|
|
608
|
+
this.logger = ctx.logger;
|
|
608
609
|
ctx.getService("manifest").register({
|
|
609
610
|
id: "com.objectstack.service.reports",
|
|
610
611
|
name: "Reports Service",
|
|
@@ -696,16 +697,59 @@ var ReportsServicePlugin = class {
|
|
|
696
697
|
ctx.logger.info("ReportsServicePlugin: dispatcher registered (setInterval fallback)", { intervalMs });
|
|
697
698
|
});
|
|
698
699
|
}
|
|
699
|
-
|
|
700
|
+
/**
|
|
701
|
+
* The kernel's teardown hook (`Plugin.destroy?()`, core `types.ts`) — the
|
|
702
|
+
* ONLY teardown entry point `ObjectKernel.performShutdown()` and
|
|
703
|
+
* `LiteKernel.destroy()` invoke.
|
|
704
|
+
*
|
|
705
|
+
* [#10371] IT USED TO BE `stop()`, WHICH NOTHING CALLED. The body below was
|
|
706
|
+
* correct in every respect except its NAME: `Plugin` declares `init()`,
|
|
707
|
+
* `start?()` and `destroy?()` and no `stop()`, so the kernel walked straight
|
|
708
|
+
* past this plugin at shutdown and the dispatcher went on ticking after
|
|
709
|
+
* `await kernel.shutdown()` had resolved. The asymmetry is what hid it:
|
|
710
|
+
* `start()` IS on the interface and does fire, so a `start`/`stop` pair reads
|
|
711
|
+
* as symmetric in review.
|
|
712
|
+
*
|
|
713
|
+
* WHY IT STAYED INVISIBLE, AND WHERE THE BILL LANDS. `start()` `unref()`s the
|
|
714
|
+
* interval, so a long-lived host process still exits and nothing complains in
|
|
715
|
+
* production. Under vitest the worker is alive throughout teardown, so a tick
|
|
716
|
+
* fires after the test file is over, reads through a driver the suite already
|
|
717
|
+
* disconnected, and a console fallback warns; `console.*` inside a worker is
|
|
718
|
+
* an RPC (`onUserConsoleLog`) and one issued after `rpcDone()` snapshotted the
|
|
719
|
+
* pending set is rejected as `EnvironmentTeardownError`. Nothing awaits that
|
|
720
|
+
* promise, so it lands as an unhandled rejection and fails a run in which
|
|
721
|
+
* every test passed. That is the identical defect #9371 fixed in
|
|
722
|
+
* `MessagingServicePlugin` — measured there as two green PRs (334/334 and
|
|
723
|
+
* 337/337) evicted from the merge queue.
|
|
724
|
+
*
|
|
725
|
+
* The job-service branch matters as much as the timer: when `service-job` is
|
|
726
|
+
* installed the dispatcher is a scheduled job rather than a `setInterval`, so
|
|
727
|
+
* a teardown the kernel never reaches leaks whichever of the two this
|
|
728
|
+
* deployment happens to use.
|
|
729
|
+
*/
|
|
730
|
+
async destroy() {
|
|
700
731
|
if (this.intervalHandle) clearInterval(this.intervalHandle);
|
|
701
732
|
this.intervalHandle = void 0;
|
|
702
733
|
if (this.jobService && this.jobName && typeof this.jobService.cancel === "function") {
|
|
703
734
|
try {
|
|
704
735
|
await this.jobService.cancel(this.jobName);
|
|
705
736
|
} catch (err) {
|
|
706
|
-
|
|
737
|
+
this.logger?.warn("ReportsServicePlugin: failed to cancel job", err);
|
|
707
738
|
}
|
|
708
739
|
}
|
|
740
|
+
this.jobService = void 0;
|
|
741
|
+
this.jobName = void 0;
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* Retained alias for {@link destroy}. Kept because it is public API of an
|
|
745
|
+
* exported class, and removing it would break an embedder who learned to call
|
|
746
|
+
* it directly precisely BECAUSE the kernel never did. The parameter is now
|
|
747
|
+
* optional and ignored: `destroy()` takes no context, so teardown reads the
|
|
748
|
+
* logger captured in `init()`. Prefer kernel shutdown; direct callers keep
|
|
749
|
+
* working unchanged.
|
|
750
|
+
*/
|
|
751
|
+
async stop(_ctx) {
|
|
752
|
+
await this.destroy();
|
|
709
753
|
}
|
|
710
754
|
};
|
|
711
755
|
// Annotate the CommonJS export names for ESM import in node:
|