11import { HttpApiBuilder } from "@effect/platform" ;
22import { SyncApi , type Scope } from "@local/sync" ;
3- import { Config , Effect , Layer , Redacted , Schema } from "effect " ;
4- import * as jwt from "jsonwebtoken " ;
5- import { workspaceTable } from "../db/schema" ;
3+ import { eq } from "drizzle-orm " ;
4+ import { Effect , Layer , Schema } from "effect " ;
5+ import { tokenTable , workspaceTable } from "../db/schema" ;
66import { Drizzle } from "../drizzle" ;
7-
8- interface TokenPayload {
9- iat : number ; // Issued at (Unix timestamp)
10- exp ?: number ; // Expiration (optional for master tokens)
11- sub : string ; // Client ID
12- workspaceId : string ; // Workshop ID
13- scope : typeof Scope . Type ; // Permission scope
14- isMaster : boolean ; // Master token flag
15- }
7+ import { AuthorizationLive } from "../middleware/authorization" ;
8+ import { Jwt } from "../services/jwt" ;
169
1710export const SyncAuthGroupLive = HttpApiBuilder . group (
1811 SyncApi ,
1912 "syncAuth" ,
2013 ( handlers ) =>
2114 Effect . gen ( function * ( ) {
22- const secretKey = yield * Config . redacted ( "JWT_SECRET" ) ;
15+ const jwt = yield * Jwt ;
2316 const { query } = yield * Drizzle ;
2417
2518 return handlers
2619 . handle ( "generateToken" , ( { payload } ) =>
2720 Effect . gen ( function * ( ) {
28- const tokenPayload = {
29- iat : Math . floor ( Date . now ( ) / 1000 ) , // Current timestamp in seconds
30- sub : payload . clientId ,
31- workspaceId : payload . workspaceId ,
32- scope : "read_write" , // TODO
33- isMaster : true , // TODO
34- } satisfies TokenPayload ;
21+ const scope : typeof Scope . Type = "read_write" ;
22+ const isMaster = true ;
23+ const issuedAt = new Date ( ) ;
3524
36- yield * Effect . log ( tokenPayload ) ;
25+ yield * query ( {
26+ Request : Schema . Struct ( { workspaceId : Schema . String } ) ,
27+ execute : ( db , { workspaceId } ) =>
28+ db
29+ . select ( )
30+ . from ( workspaceTable )
31+ . where ( eq ( workspaceTable . workspaceId , workspaceId ) ) ,
32+ } ) ( { workspaceId : payload . workspaceId } ) . pipe (
33+ Effect . flatMap ( ( rows ) =>
34+ rows . length === 0
35+ ? Effect . void
36+ : Effect . fail ( { message : "Workspace already exists" } )
37+ )
38+ ) ;
3739
38- const token = jwt . sign ( tokenPayload , Redacted . value ( secretKey ) , {
39- algorithm : "HS256" ,
40+ const token = jwt . sign ( {
41+ clientId : payload . clientId ,
42+ workspaceId : payload . workspaceId ,
4043 } ) ;
4144
42- yield * query ( {
43- Request : Schema . Struct ( {
44- clientId : Schema . String ,
45- workspaceId : Schema . String ,
46- snapshot : Schema . Uint8ArrayFromSelf ,
45+ yield * Effect . all ( [
46+ query ( {
47+ Request : Schema . Struct ( {
48+ clientId : Schema . String ,
49+ workspaceId : Schema . String ,
50+ snapshot : Schema . Uint8ArrayFromSelf ,
51+ } ) ,
52+ execute : ( db , { clientId, snapshot, workspaceId } ) =>
53+ db . insert ( workspaceTable ) . values ( {
54+ snapshot,
55+ clientId,
56+ workspaceId,
57+ ownerClientId : clientId ,
58+ snapshotId : payload . snapshotId ,
59+ } ) ,
60+ } ) ( {
61+ clientId : payload . clientId ,
62+ snapshot : payload . snapshot ,
63+ workspaceId : payload . workspaceId ,
4764 } ) ,
48- execute : ( db , { clientId, snapshot, workspaceId } ) =>
49- db . insert ( workspaceTable ) . values ( {
50- snapshot,
51- clientId,
52- workspaceId,
53- ownerClientId : clientId ,
54- snapshotId : payload . snapshotId ,
65+ query ( {
66+ Request : Schema . Struct ( {
67+ clientId : Schema . String ,
68+ workspaceId : Schema . String ,
69+ tokenValue : Schema . String ,
5570 } ) ,
56- } ) ( {
57- clientId : payload . clientId ,
58- snapshot : payload . snapshot ,
59- workspaceId : payload . workspaceId ,
60- } ) ;
71+ execute : ( db , { clientId, tokenValue, workspaceId } ) =>
72+ db . insert ( tokenTable ) . values ( {
73+ clientId,
74+ scope,
75+ tokenValue,
76+ workspaceId,
77+ isMaster,
78+ issuedAt,
79+ expiresAt : null ,
80+ revokedAt : null ,
81+ } ) ,
82+ } ) ( {
83+ clientId : payload . clientId ,
84+ tokenValue : token ,
85+ workspaceId : payload . workspaceId ,
86+ } ) ,
87+ ] ) ;
6188
6289 return {
6390 token,
6491 workspaceId : payload . workspaceId ,
6592 snapshot : payload . snapshot ,
66- createdAt : new Date ( ) ,
93+ createdAt : issuedAt ,
6794 } ;
6895 } ) . pipe (
6996 Effect . tapErrorCause ( Effect . logError ) ,
@@ -80,4 +107,4 @@ export const SyncAuthGroupLive = HttpApiBuilder.group(
80107 Effect . fail ( "Not implemented" )
81108 ) ;
82109 } )
83- ) . pipe ( Layer . provide ( Drizzle . Default ) ) ;
110+ ) . pipe ( Layer . provide ( [ Drizzle . Default , AuthorizationLive , Jwt . Default ] ) ) ;
0 commit comments