@objectstack/plugin-webhooks 17.0.0-rc.0 → 17.0.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,86 +0,0 @@
1
- // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
2
-
3
- /**
4
- * [#3461] Provenance stamp for `sys_webhook`.
5
- *
6
- * `sys_webhook` is RECORD-AUTHORITATIVE: a code-declared webhook is a boot seed
7
- * (`bootstrapDeclaredWebhooks`), and the row — including any admin tuning such
8
- * as flipping a noisy webhook to `active: false` — is the authority. The seeder
9
- * skips rows marked `customized`, so this hook is the half that DETECTS the
10
- * admin edit: any non-system update touching a `package`/`platform`-seeded row
11
- * stamps `customized: true` onto the payload.
12
- *
13
- * Why a data hook (and not a write gate or the REST layer), verbatim to the
14
- * sys_sharing_rule rationale (#2909 T1):
15
- * - admins edit webhooks through several doors (Setup UI generic data door,
16
- * scripts, console) — an engine hook covers them all;
17
- * - there is deliberately NO write gate here: webhooks are a first-class admin
18
- * authoring surface, so edits are allowed — they just have to be remembered;
19
- * - both provenance columns are `readonly`, and the engine's readonly strip
20
- * exempts isSystem callers while snapshotting supplied keys BEFORE hooks run
21
- * — so a caller can never forge/clear `customized`, while this hook's stamp
22
- * survives.
23
- *
24
- * Known boundary: multi-row updates (no single `input.id`) are not stamped —
25
- * every webhook-editing UI path updates by id.
26
- */
27
-
28
- interface MinimalEngine {
29
- find(object: string, opts?: any): Promise<any[]>;
30
- registerHook(event: string, handler: (ctx: any) => any, options?: Record<string, any>): void;
31
- unregisterHooksByPackage(packageId: string): number;
32
- }
33
-
34
- interface MinimalLogger {
35
- info?: (msg: string, meta?: Record<string, any>) => void;
36
- warn?: (msg: string, meta?: Record<string, any>) => void;
37
- }
38
-
39
- export const WEBHOOK_PROVENANCE_PACKAGE = 'plugin-webhooks:provenance';
40
-
41
- const SYSTEM_CTX = { isSystem: true, positions: [], permissions: [] } as const;
42
-
43
- export function bindWebhookProvenanceStamp(engine: MinimalEngine, logger?: MinimalLogger): void {
44
- if (typeof engine?.registerHook !== 'function') return;
45
- engine.registerHook(
46
- 'beforeUpdate',
47
- async (ctx: any) => {
48
- // Seeder / boot reconcilers write with isSystem — the package door, not
49
- // an admin customization.
50
- if ((ctx?.session as any)?.isSystem) return;
51
- const id = ctx?.input?.id ?? (ctx?.input?.data as any)?.id;
52
- if (!id) return; // multi-row update — see boundary note above
53
- const data = ctx?.input?.data;
54
- if (!data || typeof data !== 'object') return;
55
- try {
56
- // `previous` is not resolved before beforeUpdate hooks run — read the
57
- // current row ourselves (system ctx: this is a provenance check, not
58
- // an authorization decision).
59
- const rows = await engine.find('sys_webhook', {
60
- filter: { id },
61
- fields: ['id', 'managed_by', 'customized'],
62
- limit: 1,
63
- context: SYSTEM_CTX,
64
- });
65
- const row = Array.isArray(rows) ? rows[0] : undefined;
66
- if (!row) return;
67
- if ((row.managed_by === 'package' || row.managed_by === 'platform') && row.customized !== true) {
68
- (data as any).customized = true;
69
- }
70
- } catch (err: any) {
71
- logger?.warn?.('[webhook] provenance stamp failed (edit proceeds unstamped)', {
72
- id,
73
- error: err?.message,
74
- });
75
- }
76
- },
77
- { object: 'sys_webhook', packageId: WEBHOOK_PROVENANCE_PACKAGE, priority: 150 },
78
- );
79
- logger?.info?.('[webhook] provenance stamp hook bound');
80
- }
81
-
82
- export function unbindWebhookProvenanceStamp(engine: MinimalEngine): void {
83
- if (typeof engine?.unregisterHooksByPackage === 'function') {
84
- engine.unregisterHooksByPackage(WEBHOOK_PROVENANCE_PACKAGE);
85
- }
86
- }
package/tsconfig.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "extends": "../../../tsconfig.json",
3
- "compilerOptions": {
4
- "outDir": "dist",
5
- "rootDir": "src",
6
- "types": ["node"]
7
- },
8
- "include": ["src"],
9
- "exclude": ["node_modules", "dist"]
10
- }
package/tsup.config.ts DELETED
@@ -1,14 +0,0 @@
1
- // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
2
-
3
- import { defineConfig } from 'tsup';
4
-
5
- export default defineConfig({
6
- entry: ['src/index.ts', 'src/schema.ts'],
7
- splitting: true,
8
- sourcemap: true,
9
- clean: true,
10
- dts: !process.env.OS_SKIP_DTS,
11
- format: ['esm', 'cjs'],
12
- target: 'es2020',
13
- external: ['vitest'],
14
- });