@protobase/server 0.58.7 → 0.59.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/dist/assistant/query-runner/query-runner.d.ts +7 -2
- package/dist/assistant/query-runner/query-runner.js +8 -4
- package/dist/assistant/query-runner/runner-plan.js +4 -4
- package/dist/better-auth/auth-settings.d.ts +1 -0
- package/dist/better-auth/auth-tables.d.ts +13 -6
- package/dist/better-auth/auth-tables.js +9 -6
- package/dist/better-auth/create-auth.d.ts +1 -0
- package/dist/better-auth/store/resources-outside.d.ts +4 -1
- package/dist/better-auth/store/resources-outside.js +8 -3
- package/dist/better-auth/user-table.d.ts +6 -0
- package/dist/better-auth/user-table.js +3 -2
- package/dist/channels/channel-bounds.js +17 -0
- package/dist/channels/channel-name.d.ts +1 -0
- package/dist/channels/channel-name.js +30 -0
- package/dist/channels/channel-protocol.js +33 -0
- package/dist/channels/channel-refusals.js +26 -0
- package/dist/channels/channel-routes.js +98 -0
- package/dist/channels/channel-sender.d.ts +20 -0
- package/dist/channels/channel-sender.js +39 -0
- package/dist/channels/channel-socket.js +253 -0
- package/dist/channels/presence-entries.js +24 -0
- package/dist/channels/record-readable.js +28 -0
- package/dist/channels/sent.js +8 -0
- package/dist/create-admin.js +22 -2
- package/dist/functions/define-function.d.ts +3 -0
- package/dist/functions/routes.js +3 -1
- package/dist/index.d.ts +2 -1
- package/dist/package.js +1 -1
- package/dist/realtime/broadcast-hub.js +1 -1
- package/dist/realtime/broadcast-request.js +1 -1
- package/dist/realtime/database-broadcasts.js +1 -1
- package/dist/realtime/realtime-app.js +2 -18
- package/dist/realtime/realtime-hubs.js +30 -0
- package/dist/realtime/realtime-socket.js +2 -2
- package/dist/realtime/relay/realtime-options.d.ts +1 -1
- package/dist/realtime/relay/realtime-relay.js +2 -2
- package/dist/realtime/relay/relay-frame-sql.js +7 -4
- package/dist/realtime/relay/relay-presence-sql.js +13 -13
- package/dist/realtime/relay/relay-schema-sql.js +11 -2
- package/dist/realtime/relay/relay-schema.d.ts +1 -1
- package/dist/realtime/relay/relay-schema.js +4 -2
- package/dist/realtime/relay/relayed-hubs.js +63 -40
- package/dist/webhooks/attempt.js +1 -0
- package/dist/webhooks/webhooks.js +2 -1
- package/package.json +4 -4
|
@@ -12,7 +12,7 @@ const jsonOf = (payload) => payload instanceof ArrayBuffer ? null : JSON.stringi
|
|
|
12
12
|
* Counts the broadcasts into each topic's second, every process's together, and adds them as frames, all of them or,
|
|
13
13
|
* when a topic would take more than its broadcasts for this second, none: `false` then.
|
|
14
14
|
*/
|
|
15
|
-
const admitBroadcasts = async (db, statementTimeoutMs, self, publications) => {
|
|
15
|
+
const admitBroadcasts = async (db, statementTimeoutMs, self, space, publications) => {
|
|
16
16
|
if (publications.length === 0) return true;
|
|
17
17
|
const takes = /* @__PURE__ */ new Map();
|
|
18
18
|
for (const { topic } of publications) takes.set(topic, (takes.get(topic) ?? 0) + 1);
|
|
@@ -24,8 +24,8 @@ const admitBroadcasts = async (db, statementTimeoutMs, self, publications) => {
|
|
|
24
24
|
where r.second <> excluded.second or r.count + excluded.count <= ${realtimeLimits.topicBroadcastsPerSecond}
|
|
25
25
|
returning topic`.execute(trx);
|
|
26
26
|
if (rows.length < takes.size) throw new Refused();
|
|
27
|
-
await sql`insert into realtime_relay.frames (process, kind, topic, private, event, payload, bytes, meta)
|
|
28
|
-
select ${self}::uuid, 'broadcast', topic, private, event, payload::json, decode(bytes, 'base64'), meta::json
|
|
27
|
+
await sql`insert into realtime_relay.frames (process, kind, space, topic, private, event, payload, bytes, meta)
|
|
28
|
+
select ${self}::uuid, 'broadcast', ${space}::text, topic, private, event, payload::json, decode(bytes, 'base64'), meta::json
|
|
29
29
|
from unnest(${publications.map((p) => p.topic)}::text[], ${publications.map((p) => p.private)}::boolean[], ${publications.map((p) => p.event)}::text[],
|
|
30
30
|
${publications.map((p) => jsonOf(p.payload))}::text[], ${publications.map((p) => bytesOf(p.payload))}::text[], ${publications.map((p) => p.meta ? JSON.stringify(p.meta) : null)}::text[])
|
|
31
31
|
with ordinality as f(topic, private, event, payload, bytes, meta, position)
|
|
@@ -38,8 +38,10 @@ const admitBroadcasts = async (db, statementTimeoutMs, self, publications) => {
|
|
|
38
38
|
};
|
|
39
39
|
const frameOf = (row) => {
|
|
40
40
|
const id = BigInt(row.id);
|
|
41
|
+
const { space } = row;
|
|
41
42
|
if (row.kind === "presence") return {
|
|
42
43
|
id,
|
|
44
|
+
space,
|
|
43
45
|
kind: "presence",
|
|
44
46
|
topic: row.topic,
|
|
45
47
|
private: row.private,
|
|
@@ -48,6 +50,7 @@ const frameOf = (row) => {
|
|
|
48
50
|
const payload = row.bytes ? new Uint8Array(row.bytes).buffer : row.payload;
|
|
49
51
|
return {
|
|
50
52
|
id,
|
|
53
|
+
space,
|
|
51
54
|
kind: "broadcast",
|
|
52
55
|
publication: {
|
|
53
56
|
topic: row.topic,
|
|
@@ -63,7 +66,7 @@ const frameOf = (row) => {
|
|
|
63
66
|
* other processes' frames, to deliver.
|
|
64
67
|
*/
|
|
65
68
|
const readFrames = async (db, self, after, gaps) => {
|
|
66
|
-
const { rows } = await sql`select id::text as id, process = ${self}::uuid as own, kind, topic, private, event,
|
|
69
|
+
const { rows } = await sql`select id::text as id, process = ${self}::uuid as own, kind, space, topic, private, event,
|
|
67
70
|
case when process <> ${self}::uuid then payload end as payload, case when process <> ${self}::uuid then bytes end as bytes, meta
|
|
68
71
|
from realtime_relay.frames where id > ${String(after)}::bigint or id = any(${gaps.map(String)}::bigint[])
|
|
69
72
|
order by id limit ${frameBatch}`.execute(db);
|
|
@@ -12,23 +12,23 @@ const joinFrame = sql.raw(`json_build_object('joins', json_build_object(key, jso
|
|
|
12
12
|
* Keeps the change in `presences` and adds its frame, in one statement: a leave alone is sent only when the presence
|
|
13
13
|
* was there, as a process that was taken for stopped had its presences removed already.
|
|
14
14
|
*/
|
|
15
|
-
const writePresence = async (db, self, change) => {
|
|
15
|
+
const writePresence = async (db, self, space, change) => {
|
|
16
16
|
const ref = change.joined?.phx_ref ?? null;
|
|
17
17
|
await sql`with gone as (delete from realtime_relay.presences where process = ${self}::uuid and ref = ${change.left?.phx_ref ?? null}::text returning ref),
|
|
18
|
-
added as (insert into realtime_relay.presences (process, ref, topic, private, key, meta)
|
|
19
|
-
select ${self}::uuid, ${ref}::text, ${change.topic}::text, ${change.private}::boolean, ${change.key}::text, ${JSON.stringify(change.joined ?? null)}::json where ${ref}::text is not null)
|
|
20
|
-
insert into realtime_relay.frames (process, kind, topic, private, payload)
|
|
21
|
-
select ${self}::uuid, 'presence', ${change.topic}::text, ${change.private}::boolean, ${JSON.stringify(diffOf(change))}::json
|
|
18
|
+
added as (insert into realtime_relay.presences (process, ref, space, topic, private, key, meta)
|
|
19
|
+
select ${self}::uuid, ${ref}::text, ${space}::text, ${change.topic}::text, ${change.private}::boolean, ${change.key}::text, ${JSON.stringify(change.joined ?? null)}::json where ${ref}::text is not null)
|
|
20
|
+
insert into realtime_relay.frames (process, kind, space, topic, private, payload)
|
|
21
|
+
select ${self}::uuid, 'presence', ${space}::text, ${change.topic}::text, ${change.private}::boolean, ${JSON.stringify(diffOf(change))}::json
|
|
22
22
|
where ${ref}::text is not null or exists (select from gone)`.execute(db);
|
|
23
23
|
};
|
|
24
24
|
/** Adds the presences back, with their joins, for a process that was taken for stopped while it was not. */
|
|
25
25
|
const restorePresences = async (db, self, tracked) => {
|
|
26
26
|
if (tracked.length === 0) return;
|
|
27
|
-
await sql`with added as (insert into realtime_relay.presences (process, ref, topic, private, key, meta)
|
|
28
|
-
select ${self}::uuid, ref, topic, private, key, meta::json from unnest(${tracked.map((t) => t.meta.phx_ref)}::text[], ${tracked.map((t) => t.topic)}::text[],
|
|
29
|
-
${tracked.map((t) => t.private)}::boolean[], ${tracked.map((t) => t.key)}::text[], ${tracked.map((t) => JSON.stringify(t.meta))}::text[]) as t(ref, topic, private, key, meta)
|
|
30
|
-
on conflict do nothing returning process, topic, private, key, meta)
|
|
31
|
-
insert into realtime_relay.frames (process, kind, topic, private, payload) select process, 'presence', topic, private, ${joinFrame} from added`.execute(db);
|
|
27
|
+
await sql`with added as (insert into realtime_relay.presences (process, ref, space, topic, private, key, meta)
|
|
28
|
+
select ${self}::uuid, ref, space, topic, private, key, meta::json from unnest(${tracked.map((t) => t.meta.phx_ref)}::text[], ${tracked.map((t) => t.space)}::text[], ${tracked.map((t) => t.topic)}::text[],
|
|
29
|
+
${tracked.map((t) => t.private)}::boolean[], ${tracked.map((t) => t.key)}::text[], ${tracked.map((t) => JSON.stringify(t.meta))}::text[]) as t(ref, space, topic, private, key, meta)
|
|
30
|
+
on conflict do nothing returning process, space, topic, private, key, meta)
|
|
31
|
+
insert into realtime_relay.frames (process, kind, space, topic, private, payload) select process, 'presence', space, topic, private, ${joinFrame} from added`.execute(db);
|
|
32
32
|
};
|
|
33
33
|
/**
|
|
34
34
|
* Marks this process as running, by the database's clock: `true` when its row was not there, as at its start or once
|
|
@@ -41,8 +41,8 @@ const beat = async (db, self) => {
|
|
|
41
41
|
};
|
|
42
42
|
const retire = (db, dead) => sql`with dead as (delete from realtime_relay.processes where ${dead} returning id),
|
|
43
43
|
gone as (delete from realtime_relay.presences p where p.process in (select id from dead) or not exists (select from realtime_relay.processes q where q.id = p.process)
|
|
44
|
-
returning process, topic, private, key, meta)
|
|
45
|
-
insert into realtime_relay.frames (process, kind, topic, private, payload) select process, 'presence', topic, private, ${leaveFrame} from gone`.execute(db);
|
|
44
|
+
returning process, space, topic, private, key, meta)
|
|
45
|
+
insert into realtime_relay.frames (process, kind, space, topic, private, payload) select process, 'presence', space, topic, private, ${leaveFrame} from gone`.execute(db);
|
|
46
46
|
/** Removes the processes that have not beaten for `staleSeconds`, and their presences. */
|
|
47
47
|
const retireStale = async (db, staleSeconds) => {
|
|
48
48
|
await retire(db, sql`seen_at < now() - make_interval(secs => ${staleSeconds})`);
|
|
@@ -57,7 +57,7 @@ const retireSelf = async (db, self) => {
|
|
|
57
57
|
*/
|
|
58
58
|
const presenceSnapshot = (db, statementTimeoutMs, self) => db.transaction().setIsolationLevel("repeatable read").execute(async (trx) => {
|
|
59
59
|
await sql`select set_config('statement_timeout', ${String(statementTimeoutMs)}, true)`.execute(trx);
|
|
60
|
-
const presences = await sql`select topic, private, key, meta from realtime_relay.presences where process <> ${self}::uuid`.execute(trx);
|
|
60
|
+
const presences = await sql`select space, topic, private, key, meta from realtime_relay.presences where process <> ${self}::uuid`.execute(trx);
|
|
61
61
|
const newest = await sql`select coalesce(max(id), 0)::text as id from realtime_relay.frames`.execute(trx);
|
|
62
62
|
const recent = await sql`select id::text as id from realtime_relay.frames
|
|
63
63
|
where id >= (select min(id) from realtime_relay.frames where at > now() - interval '2 seconds') order by id`.execute(trx);
|
|
@@ -8,8 +8,12 @@ const relayTables = [
|
|
|
8
8
|
"processes",
|
|
9
9
|
"rates"
|
|
10
10
|
];
|
|
11
|
+
/** The tables with a `space` column, which a relay schema written before it lacks. */
|
|
12
|
+
const spacedTables = ["frames", "presences"];
|
|
11
13
|
/**
|
|
12
14
|
* - `frames`: what a process sends, a broadcast or a presence diff, read by the others and pruned after a minute.
|
|
15
|
+
* - `space` in `frames` and `presences`: the channels they are of (`RelaySpace`), `topics` for a row written without
|
|
16
|
+
* one, as by a process of a version before the record channels.
|
|
13
17
|
* - `presences`: what each process's channels track, which a process that starts reads.
|
|
14
18
|
* - `processes`: each process's last heartbeat; a process silent too long has its presences removed.
|
|
15
19
|
* - `rates`: each topic's broadcasts in the current second, every process's together.
|
|
@@ -22,6 +26,7 @@ create table if not exists ${relaySchema}.frames (
|
|
|
22
26
|
kind text not null check (kind in ('broadcast', 'presence')),
|
|
23
27
|
topic text not null,
|
|
24
28
|
private boolean not null,
|
|
29
|
+
space text not null default 'topics' check (space in ('topics', 'records')),
|
|
25
30
|
event text,
|
|
26
31
|
payload json,
|
|
27
32
|
bytes bytea,
|
|
@@ -41,6 +46,7 @@ create table if not exists ${relaySchema}.presences (
|
|
|
41
46
|
ref text not null,
|
|
42
47
|
topic text not null,
|
|
43
48
|
private boolean not null,
|
|
49
|
+
space text not null default 'topics' check (space in ('topics', 'records')),
|
|
44
50
|
key text not null,
|
|
45
51
|
meta json not null,
|
|
46
52
|
primary key (process, ref)
|
|
@@ -50,6 +56,9 @@ create table if not exists ${relaySchema}.rates (
|
|
|
50
56
|
topic text primary key,
|
|
51
57
|
second bigint not null,
|
|
52
58
|
count integer not null
|
|
53
|
-
)
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
-- A relay schema written before the record channels gets the column too.
|
|
62
|
+
${spacedTables.map((table) => `alter table ${relaySchema}.${table} add column if not exists space text not null default 'topics' check (space in ('topics', 'records'));`).join("\n")}`;
|
|
54
63
|
//#endregion
|
|
55
|
-
export { relaySchema, relaySchemaSql, relayTables };
|
|
64
|
+
export { relaySchema, relaySchemaSql, relayTables, spacedTables };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Db } from "@protobase/query";
|
|
2
2
|
//#region src/realtime/relay/relay-schema.d.ts
|
|
3
3
|
/** The SQL that adds the `realtime_relay` schema `realtime: { processes: 'many' }` needs; `undefined` when it is there. */
|
|
4
|
-
export declare const realtimeRelayMigration: (db: Db) => Promise<
|
|
4
|
+
export declare const realtimeRelayMigration: (db: Db) => Promise<string | undefined>;
|
|
5
5
|
/** Refuses to go on while the `realtime_relay` schema is missing; the project's migrations add it. */
|
|
6
6
|
export declare const checkRealtimeRelay: (db: Db) => Promise<void>;
|
|
7
7
|
//#endregion
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { migrationCommand } from "../../changes/capture-schema.js";
|
|
2
|
-
import { relaySchema, relaySchemaSql, relayTables } from "./relay-schema-sql.js";
|
|
2
|
+
import { relaySchema, relaySchemaSql, relayTables, spacedTables } from "./relay-schema-sql.js";
|
|
3
3
|
import { sql } from "kysely";
|
|
4
4
|
//#region src/realtime/relay/relay-schema.ts
|
|
5
5
|
const relayCurrent = async (db) => {
|
|
6
6
|
const names = relayTables.map((table) => `${relaySchema}.${table}`);
|
|
7
7
|
const { rows } = await sql`select bool_and(to_regclass(name) is not null) as found from unnest(${names}::text[]) as name`.execute(db);
|
|
8
|
-
|
|
8
|
+
if (!rows[0].found) return false;
|
|
9
|
+
return (await sql`select count(*)::int as count from information_schema.columns
|
|
10
|
+
where table_schema = ${relaySchema} and table_name = any(${[...spacedTables]}::text[]) and column_name = 'space'`.execute(db)).rows[0].count === spacedTables.length;
|
|
9
11
|
};
|
|
10
12
|
/** The SQL that adds the `realtime_relay` schema `realtime: { processes: 'many' }` needs; `undefined` when it is there. */
|
|
11
13
|
const realtimeRelayMigration = async (db) => await relayCurrent(db) ? void 0 : relaySchemaSql;
|
|
@@ -4,56 +4,79 @@ import { presenceReplica } from "./presence-replica.js";
|
|
|
4
4
|
import { realtimeRelay } from "./realtime-relay.js";
|
|
5
5
|
//#region src/realtime/relay/relayed-hubs.ts
|
|
6
6
|
/**
|
|
7
|
-
* The broadcast and presence hubs of `realtime: { processes: 'many' }
|
|
8
|
-
* process, and every broadcast and presence change written to the relay for
|
|
9
|
-
* channels here as the relay reads them
|
|
10
|
-
*
|
|
11
|
-
* relay while a socket is open.
|
|
7
|
+
* The broadcast and presence hubs of `realtime: { processes: 'many' }`, one pair for each space (`RelaySpace`): this
|
|
8
|
+
* process's channels in memory, as with one process, and every broadcast and presence change written to the relay for
|
|
9
|
+
* the other processes, whose own reach the channels here as the relay reads them, in the space they were sent in. A
|
|
10
|
+
* topic's private and public channels stay apart across processes too. A broadcast reaches this process's channels
|
|
11
|
+
* once the relay admitted it under the topic's rate. `follow` reads the relay while a socket is open.
|
|
12
12
|
*/
|
|
13
13
|
const relayedHubs = ({ db, statementTimeoutMs, report }) => {
|
|
14
|
-
const
|
|
15
|
-
const replica = presenceReplica();
|
|
14
|
+
const spaces = /* @__PURE__ */ new Map();
|
|
16
15
|
const relay = realtimeRelay({
|
|
17
16
|
db,
|
|
18
17
|
statementTimeoutMs,
|
|
19
18
|
report,
|
|
20
19
|
heard: (frame) => {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (
|
|
20
|
+
const space = spaces.get(frame.space);
|
|
21
|
+
if (!space) return;
|
|
22
|
+
if (frame.kind === "broadcast") return space.local.deliver(frame.publication);
|
|
23
|
+
const diff = space.replica.apply(frame.topic, frame.private, frame.diff);
|
|
24
|
+
if (diff) space.presences.hear(frame.topic, frame.private, diff);
|
|
24
25
|
},
|
|
25
|
-
loaded:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
changed: relay.changed,
|
|
33
|
-
ready: relay.ready
|
|
34
|
-
}
|
|
26
|
+
loaded: (tracked) => {
|
|
27
|
+
for (const [name, space] of spaces) space.replica.load(tracked.filter((presence) => presence.space === name));
|
|
28
|
+
},
|
|
29
|
+
tracked: () => [...spaces].flatMap(([name, space]) => space.presences.tracked().map((presence) => ({
|
|
30
|
+
space: name,
|
|
31
|
+
...presence
|
|
32
|
+
})))
|
|
35
33
|
});
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
},
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
34
|
+
const spaceOf = (name) => {
|
|
35
|
+
const local = broadcastHub();
|
|
36
|
+
const replica = presenceReplica();
|
|
37
|
+
return {
|
|
38
|
+
local,
|
|
39
|
+
replica,
|
|
40
|
+
presences: presenceHub({
|
|
41
|
+
refPrefix: `${relay.id}:`,
|
|
42
|
+
remote: {
|
|
43
|
+
state: replica.state,
|
|
44
|
+
changed: (change) => relay.changed(name, change),
|
|
45
|
+
ready: relay.ready
|
|
46
|
+
}
|
|
47
|
+
}),
|
|
48
|
+
broadcasts: {
|
|
49
|
+
join: local.join,
|
|
50
|
+
send: async (topic, from, event, payload) => {
|
|
51
|
+
const publication = {
|
|
52
|
+
topic,
|
|
53
|
+
event,
|
|
54
|
+
payload,
|
|
55
|
+
private: from.private
|
|
56
|
+
};
|
|
57
|
+
if (!await relay.broadcast(name, [publication])) return false;
|
|
58
|
+
local.deliver(publication, from);
|
|
59
|
+
return true;
|
|
60
|
+
},
|
|
61
|
+
publish: async (publications) => {
|
|
62
|
+
if (!await relay.broadcast(name, publications)) return false;
|
|
63
|
+
for (const publication of publications) local.deliver(publication);
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
54
66
|
}
|
|
55
|
-
}
|
|
56
|
-
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
for (const name of ["topics", "records"]) spaces.set(name, spaceOf(name));
|
|
70
|
+
const hubsOf = (name) => {
|
|
71
|
+
const { broadcasts, presences } = spaces.get(name);
|
|
72
|
+
return {
|
|
73
|
+
broadcasts,
|
|
74
|
+
presences
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
return {
|
|
78
|
+
topics: hubsOf("topics"),
|
|
79
|
+
records: hubsOf("records"),
|
|
57
80
|
follow: relay.follow
|
|
58
81
|
};
|
|
59
82
|
};
|
package/dist/webhooks/attempt.js
CHANGED
|
@@ -53,6 +53,7 @@ const callFunction = async (name, subscription, event, options, context, signal)
|
|
|
53
53
|
const functionContext = {
|
|
54
54
|
name,
|
|
55
55
|
db: context.db,
|
|
56
|
+
channels: context.channels,
|
|
56
57
|
caller: async () => caller,
|
|
57
58
|
acceptWebSocket,
|
|
58
59
|
calls: { join: async () => acceptWebSocket() }
|
|
@@ -60,7 +60,7 @@ const deliveryGroup = ({ subscription, change }) => `${subscription.name}:${chan
|
|
|
60
60
|
*
|
|
61
61
|
* No jobs without a resource with events or history; the subscriptions must name declared events.
|
|
62
62
|
*/
|
|
63
|
-
const createWebhooks = ({ deps, subscriptions, functions, schema, log, table }) => {
|
|
63
|
+
const createWebhooks = ({ deps, subscriptions, functions, channels, schema, log, table }) => {
|
|
64
64
|
const entries = deps.registry.entries;
|
|
65
65
|
const models = entries.map((entry) => entry.model);
|
|
66
66
|
const problems = subscriptionProblems(subscriptions, models, Object.keys(functions));
|
|
@@ -82,6 +82,7 @@ const createWebhooks = ({ deps, subscriptions, functions, schema, log, table })
|
|
|
82
82
|
db,
|
|
83
83
|
functions,
|
|
84
84
|
records,
|
|
85
|
+
channels,
|
|
85
86
|
attempt: tried,
|
|
86
87
|
signal,
|
|
87
88
|
...checkUrl && { checkUrl }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@protobase/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.59.0",
|
|
4
4
|
"description": "The Protobase REST API as a Hono app, with Better Auth sign-in.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
"@better-auth/sso": "^1.7.12",
|
|
43
43
|
"@livekit/protocol": "1.53.1",
|
|
44
44
|
"@modelcontextprotocol/server": "^2.3.1",
|
|
45
|
-
"@protobase/layout": "0.
|
|
46
|
-
"@protobase/query": "0.
|
|
47
|
-
"@protobase/schema": "0.
|
|
45
|
+
"@protobase/layout": "0.59.0",
|
|
46
|
+
"@protobase/query": "0.59.0",
|
|
47
|
+
"@protobase/schema": "0.59.0",
|
|
48
48
|
"@react-email/render": "^2.1.0",
|
|
49
49
|
"@scalar/hono-api-reference": "^0.12.10",
|
|
50
50
|
"@sentry/core": "^11.7.0",
|