@everystack/events 0.3.1 → 0.4.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,47 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@everystack/events` are documented here.
4
+
5
+ Format based on [Keep a Changelog](https://keepachangelog.com/).
6
+
7
+ ## [0.4.1] - 2026-09-16
8
+
9
+ ### Added
10
+
11
+ - auto-generated changelogs from conventional commits
12
+ - automate the version-drift check — a manual note is not a gate
13
+
14
+ ## [0.4.0] - 2026-07-19
15
+
16
+ ### Added
17
+
18
+ - descriptors go live in the verbs — the B3 wiring (read-model-everywhere)
19
+
20
+ ### Fixed
21
+
22
+ - pin React to a single 19.2.0 across the monorepo
23
+ - guard npm publish on workspace-dep packages; cli 0.3.8
24
+
25
+ ## [0.3.1] - 2026-06-30
26
+
27
+ ### Added
28
+
29
+ - add @everystack/events package and wire real-time UI
30
+ - data-driven event actions for admin-configurable routing
31
+ - own ops.event_actions as a v3 Model + eventModule
32
+ - wire cache invalidation + event-driven jobs in example app
33
+
34
+ ### Fixed
35
+
36
+ - add AWS KVS + SigV4a as direct dependencies
37
+ - pin all dependency versions to lockfile-resolved values
38
+ - revert @aws-sdk/signature-v4a to 3.1031.0, fix KVS SigV4a signing
39
+ - everystack_notify guards NEW.id for composite-key tables
40
+ - extensionless relative imports (repo convention; Metro resolution)
41
+
42
+ ### Changed
43
+
44
+ - migrate all package schemas to everyschema canonical tables
45
+ - drop type module from all packages, switch Jest to CJS mode
46
+ - consolidate Jest configs into shared base
47
+ - route server imports through react-free package doors
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@everystack/events",
3
- "version": "0.3.1",
3
+ "version": "0.4.1",
4
4
  "description": "PostgreSQL LISTEN/NOTIFY bridge for serverless — WebSocket fan-out + Lambda invocation",
5
5
  "license": "AGPL-3.0-only",
6
6
  "author": "Scalable Technology, Inc. <licensing@scalable.technology>",
@@ -18,44 +18,53 @@
18
18
  },
19
19
  "files": [
20
20
  "src",
21
- "README.md"
21
+ "README.md",
22
+ "CHANGELOG.md"
22
23
  ],
23
24
  "exports": {
24
25
  ".": {
26
+ "source": "./src/index.ts",
25
27
  "types": "./src/index.ts",
26
28
  "default": "./src/index.ts"
27
29
  },
28
30
  "./triggers": {
31
+ "source": "./src/triggers.ts",
29
32
  "types": "./src/triggers.ts",
30
33
  "default": "./src/triggers.ts"
31
34
  },
32
35
  "./handler": {
36
+ "source": "./src/handler/index.ts",
33
37
  "types": "./src/handler/index.ts",
34
38
  "default": "./src/handler/index.ts"
35
39
  },
36
40
  "./schema": {
41
+ "source": "./src/schema.ts",
37
42
  "types": "./src/schema.ts",
38
43
  "default": "./src/schema.ts"
39
44
  },
40
45
  "./models": {
46
+ "source": "./src/models/index.ts",
41
47
  "types": "./src/models/index.ts",
42
48
  "default": "./src/models/index.ts"
43
49
  },
44
50
  "./client": {
51
+ "source": "./src/client/index.ts",
45
52
  "types": "./src/client/index.ts",
46
53
  "default": "./src/client/index.ts"
47
54
  },
48
55
  "./actions": {
56
+ "source": "./src/actions.ts",
49
57
  "types": "./src/actions.ts",
50
58
  "default": "./src/actions.ts"
51
59
  },
52
60
  "./listener": {
61
+ "source": "./src/listener.ts",
53
62
  "types": "./src/listener.ts",
54
63
  "default": "./src/listener.ts"
55
64
  }
56
65
  },
57
66
  "dependencies": {
58
- "@everystack/model": "0.3.3"
67
+ "@everystack/model": "0.4.18"
59
68
  },
60
69
  "peerDependencies": {
61
70
  "@aws-sdk/client-apigatewaymanagementapi": "3.1053.0",
@@ -64,7 +73,7 @@
64
73
  "@aws-sdk/signature-v4a": "3.1031.0",
65
74
  "@tanstack/react-query": "5.100.9",
66
75
  "drizzle-orm": "0.41.0",
67
- "react": "19.2.6"
76
+ "react": "19.2.0"
68
77
  },
69
78
  "peerDependenciesMeta": {
70
79
  "@aws-sdk/client-cloudfront-keyvaluestore": {
@@ -96,10 +105,10 @@
96
105
  "@types/react": "19.2.14",
97
106
  "drizzle-orm": "0.41.0",
98
107
  "jest": "29.7.0",
99
- "react": "19.2.6",
108
+ "react": "19.2.0",
100
109
  "ts-jest": "29.4.9",
101
110
  "typescript": "5.9.3",
102
- "@everystack/auth": "0.3.1"
111
+ "@everystack/auth": "0.4.5"
103
112
  },
104
113
  "scripts": {
105
114
  "test": "jest",
@@ -0,0 +1,77 @@
1
+ /**
2
+ * The events package's DECLARED derived layer — the notify functions and the trigger
3
+ * factory, as descriptors (docs/plans/read-model-everywhere.md). Supersedes the raw-SQL
4
+ * generators in `../triggers` (kept, deprecated, for the transition): declared objects
5
+ * are content-hashed, dependency-ordered, drift-checked by db:reconcile, and — because
6
+ * every compiled function revokes EXECUTE from PUBLIC — secure by default.
7
+ *
8
+ * Trigger attachment stays the APP's choice, now with owner consent visible in the
9
+ * model: each emitting table declares `triggers: [eventsTrigger('posts_events')]`
10
+ * itself — a package can offer a trigger, never silently attach one.
11
+ */
12
+
13
+ import { defineFunction, trigger, sql, type TriggerSpec } from '@everystack/model';
14
+
15
+ /** `everystack_notify()` — row-change events onto the `events` NOTIFY channel. */
16
+ export const notifyFunction = defineFunction('everystack_notify', {
17
+ returns: 'trigger',
18
+ language: 'plpgsql',
19
+ body: sql`
20
+ DECLARE
21
+ row_id text;
22
+ BEGIN
23
+ -- A composite-key table (e.g. likes (user_id, post_id)) has no id column, so NEW.id
24
+ -- raises undefined_column — emit a NULL id rather than fail the whole write.
25
+ BEGIN
26
+ row_id := COALESCE(NEW.id, OLD.id);
27
+ EXCEPTION WHEN undefined_column THEN
28
+ row_id := NULL;
29
+ END;
30
+ PERFORM pg_notify(
31
+ 'events',
32
+ json_build_object(
33
+ 'schema', TG_TABLE_SCHEMA,
34
+ 'table', TG_TABLE_NAME,
35
+ 'op', lower(TG_OP),
36
+ 'id', row_id
37
+ )::text
38
+ );
39
+ RETURN COALESCE(NEW, OLD);
40
+ END`,
41
+ });
42
+
43
+ /**
44
+ * The event trigger for one emitting table — declared ON the model
45
+ * (`triggers: [eventsTrigger('posts_events')]`). Convention: `<table>_events`,
46
+ * matching what `generateTriggerSQL` created, so an existing database adopts via
47
+ * `db:reconcile --baseline` instead of rebuilding.
48
+ */
49
+ export function eventsTrigger(name: string): TriggerSpec {
50
+ return trigger(name, {
51
+ timing: 'after',
52
+ events: ['insert', 'update', 'delete'],
53
+ forEach: 'row',
54
+ execute: notifyFunction,
55
+ });
56
+ }
57
+
58
+ /** `everystack_event_actions_notify()` — the rules table's self-notify (reload signal). */
59
+ export const eventActionsNotifyFunction = defineFunction('everystack_event_actions_notify', {
60
+ returns: 'trigger',
61
+ language: 'plpgsql',
62
+ body: sql`
63
+ BEGIN
64
+ PERFORM pg_notify('_event_actions', '{}');
65
+ RETURN COALESCE(NEW, OLD);
66
+ END`,
67
+ });
68
+
69
+ /** The self-notify trigger for ops.event_actions — declared on the EventAction model. */
70
+ export function eventActionsTrigger(): TriggerSpec {
71
+ return trigger('event_actions_notify', {
72
+ timing: 'after',
73
+ events: ['insert', 'update', 'delete'],
74
+ forEach: 'row',
75
+ execute: eventActionsNotifyFunction,
76
+ });
77
+ }
@@ -17,11 +17,14 @@
17
17
  */
18
18
 
19
19
  import { defineModel, field, can, index } from '@everystack/model';
20
+ import { eventActionsTrigger } from './descriptors';
20
21
 
21
22
  export const EventAction = defineModel('event_actions', {
22
23
  schema: 'ops',
23
24
  writtenBy: 'worker',
24
25
  private: true,
26
+ // Owner consent, visible in the model: the reload-signal trigger is declared HERE.
27
+ triggers: [eventActionsTrigger()],
25
28
  fields: {
26
29
  id: field.uuid().primaryKey().defaultRandom(),
27
30
  tenantId: field.uuid().nullable(), // NULL = platform-wide, non-NULL = tenant-scoped
@@ -9,9 +9,10 @@
9
9
 
10
10
  import { defineModule } from '@everystack/model';
11
11
  import { EventAction } from './event-action';
12
- import { generateEventActionsTriggerSQL } from '../triggers';
12
+ import { eventActionsNotifyFunction, notifyFunction } from './descriptors';
13
13
 
14
14
  export { EventAction } from './event-action';
15
+ export { notifyFunction, eventsTrigger, eventActionsNotifyFunction, eventActionsTrigger } from './descriptors';
15
16
 
16
17
  /** All events-owned models, for the app to spread into its db:generate model list. */
17
18
  export const eventModels = [EventAction];
@@ -22,5 +23,7 @@ export const eventModels = [EventAction];
22
23
  */
23
24
  export const eventModule = defineModule({
24
25
  models: eventModels,
25
- functions: generateEventActionsTriggerSQL,
26
+ // The notify functions are DECLARED now (content-hashed, drift-checked, PUBLIC-revoked);
27
+ // notifyFunction ships here so app models can reference it via eventsTrigger(...).
28
+ derived: [notifyFunction, eventActionsNotifyFunction],
26
29
  });