Skip to content
Merged

wip #523

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 33 additions & 33 deletions apps/server-new/src/domain/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const InboxSenderAuthPolicy = Schema.Literal('requires_auth', 'anonymous'
/**
* Database entity schemas (Prisma-based)
*/
export const Account = Schema.Struct({
export class Account extends Schema.Class<Account>('Account')({
address: Schema.String,
connectAddress: Schema.String,
connectCiphertext: Schema.String,
Expand All @@ -30,9 +30,9 @@ export const Account = Schema.Struct({
connectAccountProof: Schema.String,
connectKeyProof: Schema.String,
connectSignerAddress: Schema.String,
});
}) {}

export const AppIdentity = Schema.Struct({
export class AppIdentity extends Schema.Class<AppIdentity>('AppIdentity')({
address: Schema.String,
ciphertext: Schema.String,
signaturePublicKey: Schema.String,
Expand All @@ -42,34 +42,34 @@ export const AppIdentity = Schema.Struct({
accountAddress: Schema.String,
appId: Schema.String,
sessionToken: Schema.String.pipe(Schema.NullOr),
sessionTokenExpires: Schema.DateFromSelf.pipe(Schema.NullOr),
});
sessionTokenExpires: Schema.Date.pipe(Schema.NullOr),
}) {}

export const Space = Schema.Struct({
export class Space extends Schema.Class<Space>('Space')({
id: Schema.String,
name: Schema.String,
infoContent: Schema.Uint8Array,
infoAuthorAddress: Schema.String,
infoSignatureHex: Schema.String,
infoSignatureRecovery: Schema.Number,
});
}) {}

export const SpaceEvent = Schema.Struct({
export class SpaceEvent extends Schema.Class<SpaceEvent>('SpaceEvent')({
id: Schema.String,
event: Schema.String,
state: Schema.String,
counter: Schema.Number,
spaceId: Schema.String,
createdAt: Schema.DateFromSelf,
});
}) {}

export const SpaceKey = Schema.Struct({
export class SpaceKey extends Schema.Class<SpaceKey>('SpaceKey')({
id: Schema.String,
spaceId: Schema.String,
createdAt: Schema.DateFromSelf,
});
}) {}

export const SpaceKeyBox = Schema.Struct({
export class SpaceKeyBox extends Schema.Class<SpaceKeyBox>('SpaceKeyBox')({
id: Schema.String,
spaceKeyId: Schema.String,
ciphertext: Schema.String,
Expand All @@ -78,19 +78,19 @@ export const SpaceKeyBox = Schema.Struct({
accountAddress: Schema.String,
appIdentityAddress: Schema.optional(Schema.String),
createdAt: Schema.DateFromSelf,
});
}) {}

export const Update = Schema.Struct({
export class Update extends Schema.Class<Update>('Update')({
spaceId: Schema.String,
clock: Schema.Number,
content: Schema.Uint8Array,
accountAddress: Schema.String,
signatureHex: Schema.String,
signatureRecovery: Schema.Number,
updateId: Schema.String,
});
}) {}

export const SpaceInbox = Schema.Struct({
export class SpaceInbox extends Schema.Class<SpaceInbox>('SpaceInbox')({
id: Schema.String,
spaceId: Schema.String,
isPublic: Schema.Boolean,
Expand All @@ -99,19 +99,19 @@ export const SpaceInbox = Schema.Struct({
encryptedSecretKey: Schema.String,
spaceEventId: Schema.String,
createdAt: Schema.DateFromSelf,
});
}) {}

export const SpaceInboxMessage = Schema.Struct({
export class SpaceInboxMessage extends Schema.Class<SpaceInboxMessage>('SpaceInboxMessage')({
id: Schema.String,
spaceInboxId: Schema.String,
ciphertext: Schema.String,
signatureHex: Schema.optional(Schema.String),
signatureRecovery: Schema.optional(Schema.Number),
authorAccountAddress: Schema.optional(Schema.String),
createdAt: Schema.DateFromSelf,
});
}) {}

export const AccountInbox = Schema.Struct({
export class AccountInbox extends Schema.Class<AccountInbox>('AccountInbox')({
id: Schema.String,
accountAddress: Schema.String,
isPublic: Schema.Boolean,
Expand All @@ -120,55 +120,55 @@ export const AccountInbox = Schema.Struct({
signatureHex: Schema.String,
signatureRecovery: Schema.Number,
createdAt: Schema.DateFromSelf,
});
}) {}

export const AccountInboxMessage = Schema.Struct({
export class AccountInboxMessage extends Schema.Class<AccountInboxMessage>('AccountInboxMessage')({
id: Schema.String,
accountInboxId: Schema.String,
ciphertext: Schema.String,
signatureHex: Schema.optional(Schema.String),
signatureRecovery: Schema.optional(Schema.Number),
authorAccountAddress: Schema.optional(Schema.String),
createdAt: Schema.DateFromSelf,
});
}) {}

export const Invitation = Schema.Struct({
export class Invitation extends Schema.Class<Invitation>('Invitation')({
id: Schema.String,
spaceId: Schema.String,
accountAddress: Schema.String,
inviteeAccountAddress: Schema.String,
createdAt: Schema.DateFromSelf,
});
}) {}

export const InvitationTargetApp = Schema.Struct({
export class InvitationTargetApp extends Schema.Class<InvitationTargetApp>('InvitationTargetApp')({
id: Schema.String,
invitationId: Schema.String,
});
}) {}

/**
* API response schemas
*/
export const SpaceInboxPublic = Schema.Struct({
export class SpaceInboxPublic extends Schema.Class<SpaceInboxPublic>('SpaceInboxPublic')({
id: Schema.String,
spaceId: Schema.String,
isPublic: Schema.Boolean,
authPolicy: InboxSenderAuthPolicy,
encryptionPublicKey: Schema.String,
});
}) {}

export const AccountInboxPublic = Schema.Struct({
export class AccountInboxPublic extends Schema.Class<AccountInboxPublic>('AccountInboxPublic')({
id: Schema.String,
accountAddress: Schema.String,
isPublic: Schema.Boolean,
authPolicy: InboxSenderAuthPolicy,
encryptionPublicKey: Schema.String,
});
}) {}

export const PublicIdentity = Schema.Struct({
export class PublicIdentity extends Schema.Class<PublicIdentity>('PublicIdentity')({
accountAddress: Schema.String,
signaturePublicKey: Schema.String,
encryptionPublicKey: Schema.String,
accountProof: Schema.String,
keyProof: Schema.String,
appId: Schema.optional(Schema.String),
});
}) {}
57 changes: 43 additions & 14 deletions apps/server-new/src/server.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,50 @@
import { createServer } from 'node:http';
import { HttpApiBuilder, HttpServer } from '@effect/platform';
import { NodeHttpServer } from '@effect/platform-node';
import { Effect, Layer } from 'effect';
import * as HttpApiScalar from '@effect/platform/HttpApiScalar';
import * as HttpLayerRouter from '@effect/platform/HttpLayerRouter';
import * as HttpMiddleware from '@effect/platform/HttpMiddleware';
import * as HttpServerRequest from '@effect/platform/HttpServerRequest';
import * as HttpServerResponse from '@effect/platform/HttpServerResponse';
import * as NodeHttpServer from '@effect/platform-node/NodeHttpServer';
import * as Effect from 'effect/Effect';
import * as Layer from 'effect/Layer';
import * as Schedule from 'effect/Schedule';
import * as Stream from 'effect/Stream';
import { serverPortConfig } from './config/server.ts';
import { hypergraphApi } from './http/api.ts';
import { HandlersLive } from './http/handlers.ts';

const apiLive = HttpApiBuilder.api(hypergraphApi).pipe(Layer.provide(HandlersLive));
// Create scalar openapi browser layer at /docs.
const DocsLayer = HttpApiScalar.layerHttpLayerRouter({
api: hypergraphApi,
path: '/docs',
});

export const server = Layer.unwrapEffect(
Effect.gen(function* () {
const port = yield* serverPortConfig;
return HttpApiBuilder.serve().pipe(
Layer.provide(HttpApiBuilder.middlewareCors()),
Layer.provide(apiLive),
HttpServer.withLogAddress,
Layer.provide(NodeHttpServer.layer(createServer, { port })),
);
}),
// Create api layer with openapi.json documentation generated at /docs/openapi.json.
const ApiLayer = HttpLayerRouter.addHttpApi(hypergraphApi, {
openapiPath: '/docs/openapi.json',
}).pipe(Layer.provide(HandlersLive));

// Create websocket layer at /ws.
const WebSocketLayer = HttpLayerRouter.add(
'GET',
'/ws',
// TODO: Implement actual websocket logic here.
Stream.fromSchedule(Schedule.spaced(1000)).pipe(
Stream.map(JSON.stringify),
Stream.pipeThroughChannel(HttpServerRequest.upgradeChannel()),
Stream.decodeText(),
Stream.runForEach((_) => Effect.log(_)),
Effect.as(HttpServerResponse.empty()),
),
);

// Merge router layers together and add the cors middleware layer.
const CorsMiddleware = HttpLayerRouter.middleware(HttpMiddleware.cors());
const AppLayer = Layer.mergeAll(ApiLayer, DocsLayer, WebSocketLayer).pipe(Layer.provide(CorsMiddleware.layer));

const HttpServerLayer = serverPortConfig.pipe(
Effect.map((port) => NodeHttpServer.layer(createServer, { port })),
Layer.unwrapEffect,
);

export const server = HttpLayerRouter.serve(AppLayer).pipe(Layer.provide(HttpServerLayer));
Loading