diff --git a/apps/api/src/routes/avatar.ts b/apps/api/src/routes/avatar.ts index d43656a..77f3d79 100644 --- a/apps/api/src/routes/avatar.ts +++ b/apps/api/src/routes/avatar.ts @@ -116,6 +116,9 @@ export const avatarRoutes = new Hono({ strict: false }) // The featured custom-avatar-item feed. No curated items yet → an empty list. .get('/api/customAvatarItems/v1/featured', (c) => c.json([])) + // The "hot" (trending) custom-avatar-item feed. No items yet → an empty list. + .get('/api/customAvatarItems/v1/hot', (c) => c.json([])) + // Custom avatar items created by a given account. No storage yet → an empty // paginated result (matches the econ `customAvatarItems/v1/owned` shape). .get('/api/customAvatarItems/v2/fromCreator/:accountId{[0-9]+}', (c) => diff --git a/apps/api/src/test/integration/api.test.ts b/apps/api/src/test/integration/api.test.ts index afd88d0..d6ad854 100644 --- a/apps/api/src/test/integration/api.test.ts +++ b/apps/api/src/test/integration/api.test.ts @@ -373,6 +373,12 @@ describe('public endpoints', () => { expect(await res.json()).toEqual([]) }) + test('GET /api/customAvatarItems/v1/hot returns []', async () => { + const res = await exports.default.fetch(`${ORIGIN}/api/customAvatarItems/v1/hot`) + expect(res.status).toBe(200) + expect(await res.json()).toEqual([]) + }) + test('GET /api/customAvatarItems/v2/fromCreator/:id returns an empty paginated result', async () => { const res = await exports.default.fetch(`${ORIGIN}/api/customAvatarItems/v2/fromCreator/2`) expect(res.status).toBe(200) diff --git a/apps/commerce/src/commerce.app.ts b/apps/commerce/src/commerce.app.ts index da63307..b0739c3 100644 --- a/apps/commerce/src/commerce.app.ts +++ b/apps/commerce/src/commerce.app.ts @@ -41,4 +41,8 @@ const app = new Hono() // an empty list is the client's "no active campaigns" state. .get('/purchasecampaign/allcurrent/v2', (c) => c.json([])) + // Token-bundle purchase reminders (the "buy more tokens" nudge). None to show, + // and an empty list is the client's "no reminders" state. + .get('/reminder/currentTokenBundles/v2', (c) => c.json([])) + export default app diff --git a/apps/commerce/src/test/integration/api.test.ts b/apps/commerce/src/test/integration/api.test.ts index 593e95d..c1ae742 100644 --- a/apps/commerce/src/test/integration/api.test.ts +++ b/apps/commerce/src/test/integration/api.test.ts @@ -32,4 +32,10 @@ describe('commerce endpoints', () => { expect(res.status).toBe(200) expect(await res.json()).toEqual([]) }) + + it('GET /reminder/currentTokenBundles/v2 returns []', async () => { + const res = await SELF.fetch(`${ORIGIN}/reminder/currentTokenBundles/v2`) + expect(res.status).toBe(200) + expect(await res.json()).toEqual([]) + }) }) diff --git a/packages/domain/src/rooms-db.ts b/packages/domain/src/rooms-db.ts index ff7d176..0782870 100644 --- a/packages/domain/src/rooms-db.ts +++ b/packages/domain/src/rooms-db.ts @@ -78,9 +78,10 @@ export function canManageRoom(room: Room, accountId: number): boolean { /** * Clone an existing room into a new one owned by `accountId`. Copies the source * room's content (scene/subrooms/settings), assigning a fresh RoomId, the given - * name, and the new owner; the `base` template tag is dropped so user clones - * aren't themselves listed as base rooms. Returns the new room, or null when the - * source isn't in D1 or disallows cloning. + * name, and the new owner. The clone starts with an empty tag set — the source's + * tags (including the `base` template tag) do not carry over, so the owner tags the + * clone from scratch. Returns the new room, or null when the source isn't in D1 or + * disallows cloning. */ export async function cloneRoom( db: D1Database, @@ -96,12 +97,6 @@ export async function cloneRoom( .first<{ maxId: number | null }>() const newRoomId = (row?.maxId ?? 0) + 1 - const tags = Array.isArray(source.Tags) - ? (source.Tags as Array>).filter( - (t) => String(t?.Tag).toLowerCase() !== 'base' - ) - : source.Tags - // Ownership is reset to the cloner — the source room's Roles (its creator and // any co-owners, e.g. the seeded base-room roles for accounts 1/2) must NOT // carry over, or the clone would still list the template's owner as owner. @@ -115,7 +110,8 @@ export async function cloneRoom( Name: name, CreatorAccountId: accountId, IsDorm: false, - Tags: tags, + // Start fresh: drop every tag the source carried (including `base`). + Tags: [], Roles: roles, CreatedAt: new Date().toISOString(), }