Skip to content

Commit eefd081

Browse files
committed
list invitations
1 parent e71b680 commit eefd081

File tree

7 files changed

+126
-10
lines changed

7 files changed

+126
-10
lines changed

apps/events/src/routes/playground.tsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@ import { assertExhaustive } from '@/lib/assertExhaustive';
55
import { createFileRoute } from '@tanstack/react-router';
66
import { Effect, Exit } from 'effect';
77
import * as Schema from 'effect/Schema';
8-
import type { EventMessage, RequestListSpaces, RequestSubscribeToSpace, SpaceEvent, SpaceState } from 'graph-framework';
8+
import type {
9+
EventMessage,
10+
RequestListInvitations,
11+
RequestListSpaces,
12+
RequestSubscribeToSpace,
13+
SpaceEvent,
14+
SpaceState,
15+
} from 'graph-framework';
916
import { ResponseMessage, applyEvent, createInvitation, createSpace } from 'graph-framework';
1017
import { useEffect, useState } from 'react';
1118

@@ -101,6 +108,10 @@ const App = ({ accountId, signaturePrivateKey }: { accountId: string; signatureP
101108
console.log('event', response);
102109
break;
103110
}
111+
case 'list-invitations': {
112+
console.log('list-invitations', response);
113+
break;
114+
}
104115
default:
105116
assertExhaustive(response);
106117
}
@@ -161,6 +172,15 @@ const App = ({ accountId, signaturePrivateKey }: { accountId: string; signatureP
161172
>
162173
List Spaces
163174
</Button>
175+
176+
<Button
177+
onClick={() => {
178+
const message: RequestListInvitations = { type: 'list-invitations' };
179+
websocketConnection?.send(JSON.stringify(message));
180+
}}
181+
>
182+
List Invitations
183+
</Button>
164184
</div>
165185
<h2>Spaces</h2>
166186
<ul>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
-- CreateTable
2+
CREATE TABLE "Invitation" (
3+
"id" TEXT NOT NULL PRIMARY KEY,
4+
"spaceId" TEXT NOT NULL,
5+
"accountId" TEXT NOT NULL,
6+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
7+
CONSTRAINT "Invitation_spaceId_fkey" FOREIGN KEY ("spaceId") REFERENCES "Space" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
8+
CONSTRAINT "Invitation_accountId_fkey" FOREIGN KEY ("accountId") REFERENCES "Account" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
9+
);

apps/server/prisma/schema.prisma

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,23 @@ model SpaceEvent {
2323
}
2424

2525
model Space {
26-
id String @id
27-
events SpaceEvent[]
28-
members Account[]
26+
id String @id
27+
events SpaceEvent[]
28+
members Account[]
29+
invitations Invitation[]
2930
}
3031

3132
model Account {
32-
id String @id
33-
spaces Space[]
33+
id String @id
34+
spaces Space[]
35+
invitations Invitation[]
36+
}
37+
38+
model Invitation {
39+
id String @id
40+
space Space @relation(fields: [spaceId], references: [id])
41+
spaceId String
42+
account Account @relation(fields: [accountId], references: [id])
43+
accountId String
44+
createdAt DateTime @default(now())
3445
}

apps/server/src/handlers/applySpaceEvent.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ export async function applySpaceEvent({ accountId, spaceId, event }: Params) {
3232
throw new Error('Invalid event');
3333
}
3434

35+
if (event.transaction.type === 'create-invitation') {
36+
await transaction.invitation.create({
37+
data: {
38+
id: event.transaction.id,
39+
spaceId,
40+
accountId: event.transaction.signaturePublicKey,
41+
},
42+
});
43+
}
44+
3545
return await transaction.spaceEvent.create({
3646
data: {
3747
spaceId,
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import type { SpaceState } from 'graph-framework-space-events';
2+
import { prisma } from '../prisma.js';
3+
4+
type Params = {
5+
accountId: string;
6+
};
7+
8+
export const listInvitations = async ({ accountId }: Params) => {
9+
const result = await prisma.invitation.findMany({
10+
where: {
11+
accountId,
12+
},
13+
include: {
14+
space: {
15+
include: {
16+
events: {
17+
orderBy: {
18+
counter: 'asc',
19+
},
20+
take: 1,
21+
},
22+
},
23+
},
24+
},
25+
});
26+
27+
return result.map((invitation) => {
28+
const state = JSON.parse(invitation.space.events[0].state) as SpaceState;
29+
return {
30+
id: invitation.id,
31+
previousEventHash: state.lastEventHash,
32+
spaceId: invitation.spaceId,
33+
};
34+
});
35+
};

apps/server/src/index.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import cors from 'cors';
22
import 'dotenv/config';
3+
import { parse } from 'node:url';
34
import { Effect, Exit, Schema } from 'effect';
45
import express from 'express';
5-
import type { ResponseListSpaces, ResponseSpace } from 'graph-framework-messages';
6+
import type { ResponseListInvitations, ResponseListSpaces, ResponseSpace } from 'graph-framework-messages';
67
import { RequestMessage } from 'graph-framework-messages';
78
import { type CreateSpaceEvent, applyEvent } from 'graph-framework-space-events';
8-
import { parse } from 'node:url';
99
import type WebSocket from 'ws';
1010
import { WebSocketServer } from 'ws';
1111
import { applySpaceEvent } from './handlers/applySpaceEvent.js';
1212
import { createSpace } from './handlers/createSpace.js';
1313
import { getSpace } from './handlers/getSpace.js';
14+
import { listInvitations } from './handlers/listInvitations.js';
1415
import { listSpaces } from './handlers/listSpaces.js';
1516
import { tmpInitAccount } from './handlers/tmpInitAccount.js';
1617
import { assertExhaustive } from './utils/assertExhaustive.js';
@@ -68,6 +69,12 @@ webSocketServer.on('connection', async (webSocket: WebSocket, request: Request)
6869
webSocket.send(JSON.stringify(outgoingMessage));
6970
break;
7071
}
72+
case 'list-invitations': {
73+
const invitations = await listInvitations({ accountId });
74+
const outgoingMessage: ResponseListInvitations = { type: 'list-invitations', invitations: invitations };
75+
webSocket.send(JSON.stringify(outgoingMessage));
76+
break;
77+
}
7178
case 'event': {
7279
switch (data.event.transaction.type) {
7380
case 'create-space': {

packages/graph-framework-messages/src/types.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,18 @@ export const RequestListSpaces = Schema.Struct({
2222

2323
export type RequestListSpaces = Schema.Schema.Type<typeof RequestListSpaces>;
2424

25-
export const RequestMessage = Schema.Union(EventMessage, RequestSubscribeToSpace, RequestListSpaces);
25+
export const RequestListInvitations = Schema.Struct({
26+
type: Schema.Literal('list-invitations'),
27+
});
28+
29+
export type RequestListInvitations = Schema.Schema.Type<typeof RequestListInvitations>;
30+
31+
export const RequestMessage = Schema.Union(
32+
EventMessage,
33+
RequestSubscribeToSpace,
34+
RequestListSpaces,
35+
RequestListInvitations,
36+
);
2637

2738
export type RequestMessage = Schema.Schema.Type<typeof RequestMessage>;
2839

@@ -37,6 +48,19 @@ export const ResponseListSpaces = Schema.Struct({
3748

3849
export type ResponseListSpaces = Schema.Schema.Type<typeof ResponseListSpaces>;
3950

51+
export const ResponseListInvitations = Schema.Struct({
52+
type: Schema.Literal('list-invitations'),
53+
invitations: Schema.Array(
54+
Schema.Struct({
55+
id: Schema.String,
56+
previousEventHash: Schema.String,
57+
spaceId: Schema.String,
58+
}),
59+
),
60+
});
61+
62+
export type ResponseListInvitations = Schema.Schema.Type<typeof ResponseListInvitations>;
63+
4064
export const ResponseSpace = Schema.Struct({
4165
type: Schema.Literal('space'),
4266
id: Schema.String,
@@ -45,6 +69,6 @@ export const ResponseSpace = Schema.Struct({
4569

4670
export type ResponseSpace = Schema.Schema.Type<typeof ResponseSpace>;
4771

48-
export const ResponseMessage = Schema.Union(EventMessage, ResponseListSpaces, ResponseSpace);
72+
export const ResponseMessage = Schema.Union(EventMessage, ResponseListSpaces, ResponseListInvitations, ResponseSpace);
4973

5074
export type ResponseMessage = Schema.Schema.Type<typeof ResponseMessage>;

0 commit comments

Comments
 (0)