Skip to content

Commit 1236d5a

Browse files
committed
remove obsolete /partitions/create endpoint
Space + partition creation is handled by POST /sync/vault-key which inserts the space (triggering partition creation via DB trigger).
1 parent 14af467 commit 1236d5a

1 file changed

Lines changed: 1 addition & 78 deletions

File tree

src/routes/sync.vaults.ts

Lines changed: 1 addition & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { Hono } from 'hono'
22
import { zValidator } from '@hono/zod-validator'
33
import { db, vaultKeys, spaces, type NewVaultKey } from '../db'
4-
import { eq, and, sql } from 'drizzle-orm'
4+
import { eq, and } from 'drizzle-orm'
55
import { vaultKeySchema, updateVaultNameSchema } from './sync.schemas'
6-
import { getPartitionQuotaAsync } from '../services/quota'
76

87
const vaultRoutes = new Hono()
98

@@ -294,81 +293,5 @@ vaultRoutes.delete('/vaults', async (c) => {
294293
}
295294
})
296295

297-
/**
298-
* POST /partitions/create
299-
* Create a new sync_changes partition with a server-generated UUID.
300-
* The partition is created and committed before the response is sent,
301-
* ensuring Supabase Realtime can see it when the client subscribes.
302-
*
303-
* Creates a space (type='vault') and a corresponding partition.
304-
* Respects the user's tier limit for max partitions.
305-
*/
306-
vaultRoutes.post('/partitions/create', async (c) => {
307-
const spaceToken = c.get('spaceToken')
308-
if (spaceToken) {
309-
return c.json({ error: 'Space tokens cannot create partitions' }, 403)
310-
}
311-
const user = c.get('user')
312-
313-
try {
314-
// Check quota
315-
const quota = await getPartitionQuotaAsync(user.userId)
316-
if (!quota.canCreate) {
317-
return c.json({
318-
error: 'Partition limit reached',
319-
tier: quota.tier,
320-
maxPartitions: quota.maxPartitions,
321-
usedPartitions: quota.usedPartitions,
322-
}, 403)
323-
}
324-
325-
const partitionId = crypto.randomUUID()
326-
const partitionName = 'sync_changes_' + partitionId.replace(/-/g, '_')
327-
328-
// Insert space record (type='vault') — trigger creates partition
329-
await db.insert(spaces).values({
330-
id: partitionId,
331-
type: 'vault',
332-
ownerId: user.userId,
333-
})
334-
335-
// Create partition + RLS + replica identity
336-
// DDL statements don't support parameterized values, so we use sql.raw()
337-
// partitionId is crypto.randomUUID() — safe from injection
338-
await db.execute(sql`
339-
CREATE TABLE IF NOT EXISTS ${sql.raw(`public."${partitionName}"`)}
340-
PARTITION OF public.sync_changes FOR VALUES IN (${sql.raw(`'${partitionId}'`)})
341-
`)
342-
await db.execute(sql`
343-
ALTER TABLE ${sql.raw(`public."${partitionName}"`)} ENABLE ROW LEVEL SECURITY
344-
`)
345-
await db.execute(sql`
346-
CREATE POLICY "Users can only access their own sync changes"
347-
ON ${sql.raw(`public."${partitionName}"`)} FOR SELECT
348-
USING ((select auth.uid()) = user_id)
349-
`)
350-
await db.execute(sql`
351-
CREATE POLICY "Users can only insert their own sync changes"
352-
ON ${sql.raw(`public."${partitionName}"`)} FOR INSERT
353-
WITH CHECK ((select auth.uid()) = user_id)
354-
`)
355-
await db.execute(sql`
356-
ALTER TABLE ${sql.raw(`public."${partitionName}"`)} REPLICA IDENTITY FULL
357-
`)
358-
await db.execute(sql`
359-
ALTER PUBLICATION supabase_realtime ADD TABLE ${sql.raw(`public."${partitionName}"`)}
360-
`)
361-
362-
console.log(`[Partitions] Created ${partitionName} for user ${user.userId} (${quota.usedPartitions + 1}/${quota.maxPartitions})`)
363-
364-
return c.json({ partitionId }, 201)
365-
} catch (error: any) {
366-
if (error?.message?.includes('already exists')) {
367-
return c.json({ error: 'Partition already exists' }, 409)
368-
}
369-
console.error('Create partition error:', error)
370-
return c.json({ error: 'Internal server error' }, 500)
371-
}
372-
})
373296

374297
export default vaultRoutes

0 commit comments

Comments
 (0)