diff --git a/.env.example b/.env.example index e7dbc59ac..ac31e1dd9 100644 --- a/.env.example +++ b/.env.example @@ -239,6 +239,12 @@ GENARRATIVE_ENABLE_IMAGE_EDITOR_AGENT_SIDEBAR="false" # Windows/macOS 是系统维度,不填写 dev-win/dev-mac。 GENARRATIVE_CLIENT_DOWNLOAD_CHANNEL="dev" +# 客户端埋点接收绑定的公开 origin,由 API Server 运行时读取;修改后重启服务。 +# 必须与客户端登录地址一致,不带 /api、路径或尾部斜杠;未配置/非法时上传接口返回 503。 +# 本地端口按实际启动结果填写(端口漂移后需同步),localhost 与 127.0.0.1 不可混用。 +# dev 使用 https://dev.genarrative.world;release 使用 https://www.genarrative.world。 +GENARRATIVE_AGC_ANALYTICS_ORIGIN="http://127.0.0.1:8082" + # Optional: official VikingDB credentials for regenerating build-tag similarities # with the Python embedding script. The script auto-loads `.env.local` and uses # the fixed `bge-large-zh` embedding model. diff --git a/.gitea/workflows/project-ci.yml b/.gitea/workflows/project-ci.yml index b84b9f901..8338196cf 100644 --- a/.gitea/workflows/project-ci.yml +++ b/.gitea/workflows/project-ci.yml @@ -561,7 +561,9 @@ jobs: run: bash scripts/ci-npm-ci-with-retry.sh - name: Validate CI cache maintenance behavior - run: python3 -m unittest discover -s scripts -p 'test_gitea_cache_*.py' + run: | + python3 -m unittest discover -s scripts -p 'test_gitea_cache_*.py' + node --test scripts/export-ci-npm-download-cache.test.mjs - name: Run repository checks run: npm run check:repository-ci diff --git a/apps/admin-web/src/api/adminApiClient.test.ts b/apps/admin-web/src/api/adminApiClient.test.ts index a5c27f641..05cfdc10e 100644 --- a/apps/admin-web/src/api/adminApiClient.test.ts +++ b/apps/admin-web/src/api/adminApiClient.test.ts @@ -7,6 +7,7 @@ import { getAdminFeatureGateConfig, getAdminUserDetail, importAdminAgcTemplates, + listAdminAgcTrackingEvents, listAdminGameDistributionReviews, listAdminRechargeOrders, reconcileAdminUserConsumption, @@ -24,6 +25,30 @@ afterEach(() => { vi.unstubAllGlobals(); }); +test('客户端埋点查询传递筛选和游标并复用后台认证', async () => { + const payload = { entries: [], nextCursor: null }; + const fetchMock = vi.fn().mockResolvedValue( + new Response(JSON.stringify({ ok: true, data: payload }), { + status: 200, + }), + ); + vi.stubGlobal('fetch', fetchMock); + expect( + await listAdminAgcTrackingEvents('token', { + userId: 'user+1', + projectId: 'project-1', + cursor: 'page/2', + limit: 50, + }), + ).toEqual(payload); + expect(fetchMock).toHaveBeenCalledWith( + '/admin/api/agc/tracking-events?userId=user%2B1&projectId=project-1&cursor=page%2F2&limit=50', + expect.objectContaining({ + headers: expect.objectContaining({ Authorization: 'Bearer token' }), + }), + ); +}); + test('模板管理读取和更新复用认证封装,提交 revision 和封面但不提交 ZIP 或版本', async () => { const library = { revision: 'revision-new', writable: true, templates: [] }; const fetchMock = vi.fn().mockImplementation( diff --git a/apps/admin-web/src/api/adminApiClient.ts b/apps/admin-web/src/api/adminApiClient.ts index 4688975e0..da313c68b 100644 --- a/apps/admin-web/src/api/adminApiClient.ts +++ b/apps/admin-web/src/api/adminApiClient.ts @@ -1,6 +1,8 @@ import type { AdminAccountListResponse, AdminAgcTemplateLibraryResponse, + AdminAgcTrackingEventListResponse, + AdminAgcTrackingEventQuery, AdminConfirmEditorShowcaseCampaignImageUploadRequest, AdminCreateAccountRequest, AdminCreateAccountResponse, @@ -409,6 +411,31 @@ export function listAdminTrackingEventKeys(token: string) { ); } +export function listAdminAgcTrackingEvents( + token: string, + query: AdminAgcTrackingEventQuery = {}, +) { + return request( + `/admin/api/agc/tracking-events${buildQueryString((params) => { + for (const key of [ + 'userId', + 'projectId', + 'creativeTaskId', + 'agentRunId', + 'eventName', + 'clientVersion', + 'startTime', + 'endTime', + 'cursor', + ] as const) { + appendQueryParam(params, key, query[key]); + } + appendNumericQueryParam(params, 'limit', query.limit); + })}`, + { token }, + ); +} + export function listAdminErrorReports( token: string, query: { diff --git a/apps/admin-web/src/api/adminApiTypes.ts b/apps/admin-web/src/api/adminApiTypes.ts index 161ef7320..71159500c 100644 --- a/apps/admin-web/src/api/adminApiTypes.ts +++ b/apps/admin-web/src/api/adminApiTypes.ts @@ -820,6 +820,44 @@ export interface AdminTrackingEventListResponse { entries: AdminTrackingEventEntryPayload[]; } +export interface AdminAgcTrackingEventQuery { + userId?: string; + projectId?: string; + creativeTaskId?: string; + agentRunId?: string; + eventName?: string; + clientVersion?: string; + startTime?: string; + endTime?: string; + cursor?: string; + limit?: number; +} + +export interface AdminAgcTrackingEventEntry { + eventId: string; + schemaVersion: number; + eventName: string; + eventTime: string; + userId: string; + editorSessionId: string; + projectId: string | null; + creativeTaskId: string | null; + agentRunId: string | null; + agentTurnId: string | null; + status: string | null; + errorCode: string | null; + source: string; + clientVersion: string; + properties: Record; + batchId: string; + receivedAt: string; +} + +export interface AdminAgcTrackingEventListResponse { + entries: AdminAgcTrackingEventEntry[]; + nextCursor: string | null; +} + export interface AdminTrackingEventKeyPayload { eventKey: string; eventTitle: string; diff --git a/apps/admin-web/src/app/AdminApp.tsx b/apps/admin-web/src/app/AdminApp.tsx index e91c6ca8a..73b48d326 100644 --- a/apps/admin-web/src/app/AdminApp.tsx +++ b/apps/admin-web/src/app/AdminApp.tsx @@ -20,6 +20,7 @@ import { import { AdminAccountsPage } from '../pages/AdminAccountsPage'; import { AdminAgcModelsPage } from '../pages/AdminAgcModelsPage'; import { AdminAgcTemplatesPage } from '../pages/AdminAgcTemplatesPage'; +import { AdminAgcTrackingPage } from '../pages/AdminAgcTrackingPage'; import { AdminDashboardPage } from '../pages/AdminDashboardPage'; import { AdminDatabaseTablesPage } from '../pages/AdminDatabaseTablesPage'; import { AdminDebugHttpPage } from '../pages/AdminDebugHttpPage'; @@ -233,6 +234,12 @@ export function AdminApp() { onUnauthorized={handleUnauthorized} /> ) : null} + {activeRouteId === 'agc-tracking' ? ( + + ) : null} {activeRouteId === 'error-reports' ? ( { + expect(resolveAdminRoute('#agc-tracking')).toBe('agc-tracking'); + expect( + getAccessibleAdminRoutes({ + accountRole: 'member', + tabPermissions: ['agc-tracking'], + }).map((route) => route.id), + ).toEqual(['agc-tracking']); + expect( + getAccessibleAdminRoutes({ + accountRole: 'member', + tabPermissions: ['tracking'], + }).some((route) => route.id === 'agc-tracking'), + ).toBe(false); +}); + test('后台默认进入 Dashboard', () => { expect(adminRoutes[0]).toEqual({ id: 'dashboard', diff --git a/apps/admin-web/src/app/adminRoutes.ts b/apps/admin-web/src/app/adminRoutes.ts index 11764bbe9..46aa13750 100644 --- a/apps/admin-web/src/app/adminRoutes.ts +++ b/apps/admin-web/src/app/adminRoutes.ts @@ -5,6 +5,7 @@ export type AdminRouteId = | 'tables' | 'debug' | 'tracking' + | 'agc-tracking' | 'error-reports' | 'gray-release' | 'redeem' @@ -41,6 +42,7 @@ export const adminRoutes: AdminRouteDefinition[] = [ { id: 'tables', label: '表查询', hash: '#tables' }, { id: 'debug', label: 'API 调试', hash: '#debug' }, { id: 'tracking', label: '埋点数据', hash: '#tracking' }, + { id: 'agc-tracking', label: '客户端埋点', hash: '#agc-tracking' }, { id: 'error-reports', label: '错误报告', hash: '#error-reports' }, { id: 'gray-release', label: '灰度发布', hash: '#gray-release' }, { id: 'redeem', label: '兑换码', hash: '#redeem' }, diff --git a/apps/admin-web/src/pages/AdminAgcTrackingPage.test.tsx b/apps/admin-web/src/pages/AdminAgcTrackingPage.test.tsx new file mode 100644 index 000000000..8bbfb8dac --- /dev/null +++ b/apps/admin-web/src/pages/AdminAgcTrackingPage.test.tsx @@ -0,0 +1,129 @@ +// @vitest-environment jsdom +import { + cleanup, + fireEvent, + render, + screen, + waitFor, + within, +} from '@testing-library/react'; +import { afterEach, beforeEach, expect, test, vi } from 'vitest'; + +import { + AdminApiError, + listAdminAgcTrackingEvents, +} from '../api/adminApiClient'; +import type { AdminAgcTrackingEventEntry } from '../api/adminApiTypes'; +import { AdminAgcTrackingPage } from './AdminAgcTrackingPage'; + +vi.mock('../api/adminApiClient', async (original) => ({ + ...(await original()), + listAdminAgcTrackingEvents: vi.fn(), +})); +vi.mock('../components/AdminUserReferenceButton', () => ({ + AdminUserReferenceButton: () => null, +})); + +const entry: AdminAgcTrackingEventEntry = { + eventId: 'event-1', + schemaVersion: 1, + eventName: 'project_save', + eventTime: '2026-09-21T12:00:00.123Z', + userId: 'user-1', + editorSessionId: 'session-1', + projectId: 'project-1', + creativeTaskId: 'project-1', + agentRunId: null, + agentTurnId: null, + status: 'success', + errorCode: null, + source: 'gui', + clientVersion: '1.0', + properties: { reason: 'manual' }, + batchId: 'batch-1', + receivedAt: '2026-09-21T12:15:00.000Z', +}; + +beforeEach(() => { + vi.mocked(listAdminAgcTrackingEvents).mockReset(); +}); +afterEach(cleanup); + +test('翻页沿用游标,筛选和刷新从第一页重新查询,详情保留 null 和事件属性', async () => { + vi.mocked(listAdminAgcTrackingEvents) + .mockResolvedValueOnce({ entries: [entry], nextCursor: 'cursor-page-2' }) + .mockResolvedValueOnce({ + entries: [{ ...entry, eventId: 'event-2' }], + nextCursor: null, + }) + .mockResolvedValue({ entries: [entry], nextCursor: 'cursor-new' }); + render(); + await screen.findByText('保存项目', { selector: 'td' }); + expect(listAdminAgcTrackingEvents).toHaveBeenLastCalledWith('admin-token', { + cursor: undefined, + limit: 50, + }); + fireEvent.click(screen.getByText('查看详情')); + const dialog = screen.getByRole('dialog'); + expect(within(dialog).getAllByText('—').length).toBe(3); + expect(within(dialog).getByText(/"reason": "manual"/)).toBeTruthy(); + expect(within(dialog).getByText(entry.eventTime)).toBeTruthy(); + fireEvent.click(within(dialog).getByLabelText('关闭详情')); + fireEvent.click(screen.getByText('下一页')); + await waitFor(() => + expect(listAdminAgcTrackingEvents).toHaveBeenLastCalledWith('admin-token', { + cursor: 'cursor-page-2', + limit: 50, + }), + ); + await waitFor(() => + expect(screen.getByText('查询').closest('button')?.disabled).toBe(false), + ); + fireEvent.click(screen.getByText('上一页')); + await screen.findByText('第 1 页'); + expect(listAdminAgcTrackingEvents).toHaveBeenCalledTimes(2); + fireEvent.change(screen.getByLabelText('项目 ID'), { + target: { value: 'project-2' }, + }); + fireEvent.click(screen.getByText('查询')); + await waitFor(() => + expect(listAdminAgcTrackingEvents).toHaveBeenLastCalledWith( + 'admin-token', + expect.objectContaining({ + projectId: 'project-2', + cursor: undefined, + limit: 50, + }), + ), + ); + expect(screen.getByText('第 1 页')).toBeTruthy(); + await waitFor(() => + expect(screen.getByText('刷新').closest('button')?.disabled).toBe(false), + ); + fireEvent.click(screen.getByText('刷新')); + await waitFor(() => + expect(listAdminAgcTrackingEvents).toHaveBeenCalledTimes(4), + ); +}); + +test('空结果、权限失败与登录失效沿用后台反馈', async () => { + const unauthorized = vi.fn(); + vi.mocked(listAdminAgcTrackingEvents) + .mockResolvedValueOnce({ entries: [], nextCursor: null }) + .mockRejectedValueOnce( + new AdminApiError({ status: 403, message: '无权访问客户端埋点' }), + ) + .mockRejectedValueOnce( + new AdminApiError({ status: 401, message: '登录失效' }), + ); + render(); + await screen.findByText('暂无客户端埋点数据'); + fireEvent.click(screen.getByText('刷新')); + expect((await screen.findByRole('alert')).textContent).toContain( + '无权访问客户端埋点', + ); + fireEvent.click(screen.getByText('刷新')); + await waitFor(() => + expect(unauthorized).toHaveBeenCalledWith('登录状态已失效'), + ); +}); diff --git a/apps/admin-web/src/pages/AdminAgcTrackingPage.tsx b/apps/admin-web/src/pages/AdminAgcTrackingPage.tsx new file mode 100644 index 000000000..239270c42 --- /dev/null +++ b/apps/admin-web/src/pages/AdminAgcTrackingPage.tsx @@ -0,0 +1,379 @@ +import { Modal } from '@genarrative/shared/components'; +import { FormEvent, useEffect, useRef, useState } from 'react'; + +import { listAdminAgcTrackingEvents } from '../api/adminApiClient'; +import type { + AdminAgcTrackingEventEntry, + AdminAgcTrackingEventListResponse, + AdminAgcTrackingEventQuery, +} from '../api/adminApiTypes'; +import { AdminUserReferenceButton } from '../components/AdminUserReferenceButton'; +import { handlePageError } from './pageUtils'; + +const eventLabels: Record = { + editor_session_start: '编辑器会话开始', + editor_session_end: '编辑器会话结束', + editor_focus_start: '编辑器获得焦点', + editor_focus_end: '编辑器失去焦点', + project_create_success: '项目创建成功', + project_open: '打开项目', + creative_task_submit: '首次提交创作目标', + agent_run_completed: 'Agent 运行完成', + agent_run_failed: 'Agent 运行失败', + project_revision_created: '项目产生修改', + preview_ready: '预览就绪', + project_save: '保存项目', +}; + +const fieldLabels: Record = { + eventId: '事件 ID', + schemaVersion: '事件版本', + eventName: '事件类型', + eventTime: '发生时间', + userId: '用户 ID', + editorSessionId: '编辑器会话 ID', + projectId: '项目 ID', + creativeTaskId: '创作目标 ID', + agentRunId: 'Agent run ID', + agentTurnId: 'Agent turn ID', + status: '结果', + errorCode: '错误码', + source: '来源', + clientVersion: '客户端版本', + properties: '事件属性', + batchId: '批次 ID', + receivedAt: '入库时间', +}; + +function formatTime(value: string) { + const date = new Date(value); + return Number.isNaN(date.getTime()) ? value : date.toLocaleString('zh-CN'); +} + +export function AdminAgcTrackingPage({ + token, + onUnauthorized, +}: { + token: string; + onUnauthorized: (message?: string) => void; +}) { + const [filters, setFilters] = useState({ + userId: '', + projectId: '', + eventName: '', + startTime: '', + endTime: '', + }); + const [query, setQuery] = useState({}); + const [cursors, setCursors] = useState>([ + undefined, + ]); + const [page, setPage] = useState(0); + const [refresh, setRefresh] = useState(0); + const [entries, setEntries] = useState([]); + const [nextCursor, setNextCursor] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(''); + const [detail, setDetail] = useState(null); + const cursor = cursors[page]; + // 首页没有入站游标,返回首页时保留原快照,刷新才获取新数据。 + const firstPage = useRef<{ + token: string; + query: AdminAgcTrackingEventQuery; + response: AdminAgcTrackingEventListResponse; + } | null>(null); + + useEffect(() => { + const saved = firstPage.current; + if (!cursor && saved?.token === token && saved.query === query) { + setEntries(saved.response.entries); + setNextCursor(saved.response.nextCursor); + setError(''); + setLoading(false); + return; + } + let active = true; + setLoading(true); + setError(''); + setEntries([]); + setNextCursor(null); + void listAdminAgcTrackingEvents(token, { ...query, cursor, limit: 50 }) + .then((response) => { + if (!active) return; + if (!cursor) firstPage.current = { token, query, response }; + setEntries(response.entries); + setNextCursor(response.nextCursor); + }) + .catch((failure: unknown) => { + if (active) handlePageError(failure, onUnauthorized, setError); + }) + .finally(() => { + if (active) setLoading(false); + }); + return () => { + active = false; + }; + }, [token, query, cursor, refresh, onUnauthorized]); + + function resetPages() { + firstPage.current = null; + setCursors([undefined]); + setPage(0); + setDetail(null); + } + + function search(event: FormEvent) { + event.preventDefault(); + if ( + filters.startTime && + filters.endTime && + new Date(filters.startTime) >= new Date(filters.endTime) + ) { + setError('结束时间必须晚于开始时间'); + return; + } + resetPages(); + setQuery({ + userId: filters.userId.trim(), + projectId: filters.projectId.trim(), + eventName: filters.eventName, + startTime: filters.startTime + ? new Date(filters.startTime).toISOString() + : undefined, + endTime: filters.endTime + ? new Date(filters.endTime).toISOString() + : undefined, + }); + } + + function related( + key: 'creativeTaskId' | 'agentRunId' | 'clientVersion', + value: string, + ) { + resetPages(); + setFilters({ + userId: '', + projectId: '', + eventName: '', + startTime: '', + endTime: '', + }); + setQuery({ [key]: value }); + } + + return ( +
+
+
+

客户端埋点

+

按发生时间倒序展示

+
+ +
+
+
+ {(['userId', 'projectId'] as const).map((key) => ( + + ))} + + {(['startTime', 'endTime'] as const).map((key) => ( + + ))} +
+
+ +
+ {(['creativeTaskId', 'agentRunId', 'clientVersion'] as const) + .filter((key) => query[key]) + .map((key) => ( +

+ {fieldLabels[key]}:{query[key]}(重新查询可清除) +

+ ))} +
+ {error ? ( +

+ {error} +

+ ) : null} +
+
+ + + + {[ + '入库时间', + '发生时间', + '用户', + '事件名称', + '项目', + '来源', + '结果', + '客户端版本', + '详情', + ].map((label) => ( + + ))} + + + + {entries.map((entry) => ( + + + + + + + + + + + + ))} + +
{label}
{formatTime(entry.receivedAt)}{formatTime(entry.eventTime)} + {entry.userId} + + {eventLabels[entry.eventName] ?? entry.eventName}{entry.projectId ?? '—'}{entry.source}{entry.status ?? '—'}{entry.clientVersion} + +
+
+ {loading ? ( +

加载中…

+ ) : !error && entries.length === 0 ? ( +

暂无客户端埋点数据

+ ) : null} +
+ + 第 {page + 1} 页 + +
+
+ {detail ? ( + setDetail(null)} + className="genarrative-ui" + > +
+ {( + Object.keys(fieldLabels) as Array< + keyof AdminAgcTrackingEventEntry + > + ) + .filter((key) => key !== 'properties') + .map((key) => ( +
+
{fieldLabels[key]}
+
+ {detail[key] == null ? '—' : String(detail[key])} +
+
+ ))} +
+
+ {(['creativeTaskId', 'agentRunId', 'clientVersion'] as const).map( + (key) => + detail[key] ? ( + + ) : null, + )} +
+

事件属性

+
+            {JSON.stringify(detail.properties, null, 2)}
+          
+
+ ) : null} +
+ ); +} diff --git a/apps/admin-web/src/pages/AdminDatabaseTablesPage.tsx b/apps/admin-web/src/pages/AdminDatabaseTablesPage.tsx index 47659fd47..a032d4889 100644 --- a/apps/admin-web/src/pages/AdminDatabaseTablesPage.tsx +++ b/apps/admin-web/src/pages/AdminDatabaseTablesPage.tsx @@ -2641,48 +2641,6 @@ const databaseTableLabelMap: Record = { profile_recharge_order: '充值订单', profile_feedback_submission: '反馈提交', profile_save_archive: '存档记录', - story_session: '剧情会话', - story_event: '剧情事件', - npc_state: 'NPC 状态', - inventory_slot: '背包槽位', - battle_state: '战斗状态', - treasure_record: '宝藏记录', - quest_record: '任务记录', - quest_log: '任务日志', - player_progression: '玩家进度', - chapter_progression: '章节进度', - custom_world_profile: '自定义世界档案', - custom_world_session: '自定义世界会话', - custom_world_agent_session: '自定义世界 Agent 会话', - custom_world_agent_message: '自定义世界 Agent 消息', - custom_world_agent_operation: '自定义世界 Agent 操作', - custom_world_draft_card: '自定义世界草稿卡片', - custom_world_gallery_entry: '自定义世界画廊条目', - puzzle_agent_session: '拼图 Agent 会话', - puzzle_agent_message: '拼图 Agent 消息', - puzzle_work_profile: '拼图作品档案', - puzzle_event: '拼图事件', - puzzle_runtime_run: '拼图运行记录', - puzzle_leaderboard_entry: '拼图排行榜条目', - match3d_agent_session: '抓大鹅 Agent 会话', - match3d_agent_message: '抓大鹅 Agent 消息', - match3d_work_profile: '抓大鹅作品档案', - match3d_runtime_run: '抓大鹅运行记录', - square_hole_agent_session: '方洞挑战 Agent 会话', - square_hole_agent_message: '方洞挑战 Agent 消息', - square_hole_work_profile: '方洞挑战作品档案', - square_hole_runtime_run: '方洞挑战运行记录', - visual_novel_agent_session: '视觉小说 Agent 会话', - visual_novel_agent_message: '视觉小说 Agent 消息', - visual_novel_work_profile: '视觉小说作品档案', - visual_novel_runtime_run: '视觉小说运行记录', - visual_novel_runtime_history_entry: '视觉小说历史条目', - visual_novel_runtime_event: '视觉小说运行事件', - big_fish_creation_session: '大鱼吃小鱼创建会话', - big_fish_agent_message: '大鱼吃小鱼 Agent 消息', - big_fish_asset_slot: '大鱼吃小鱼资产槽位', - big_fish_event: '大鱼吃小鱼事件', - big_fish_runtime_run: '大鱼吃小鱼运行记录', asset_object: '资产对象', asset_entity_binding: '资产实体绑定', asset_event: '资产事件', @@ -2724,48 +2682,6 @@ const databaseTableDescriptionMap: Record = { profile_recharge_order: '充值订单表', profile_feedback_submission: '反馈提交记录表', profile_save_archive: '用户存档记录表', - story_session: '剧情会话表', - story_event: '剧情事件表', - npc_state: 'NPC 状态表', - inventory_slot: '背包槽位表', - battle_state: '战斗状态表', - treasure_record: '宝藏记录表', - quest_record: '任务记录表', - quest_log: '任务日志表', - player_progression: '玩家进度表', - chapter_progression: '章节进度表', - custom_world_profile: '自定义世界档案表', - custom_world_session: '自定义世界会话表', - custom_world_agent_session: '自定义世界 Agent 会话表', - custom_world_agent_message: '自定义世界 Agent 消息表', - custom_world_agent_operation: '自定义世界 Agent 操作表', - custom_world_draft_card: '自定义世界草稿卡片表', - custom_world_gallery_entry: '自定义世界画廊条目表', - puzzle_agent_session: '拼图 Agent 会话表', - puzzle_agent_message: '拼图 Agent 消息表', - puzzle_work_profile: '拼图作品档案表', - puzzle_event: '拼图事件表', - puzzle_runtime_run: '拼图运行记录表', - puzzle_leaderboard_entry: '拼图排行榜条目表', - match3d_agent_session: '抓大鹅 Agent 会话表', - match3d_agent_message: '抓大鹅 Agent 消息表', - match3d_work_profile: '抓大鹅作品档案表', - match3d_runtime_run: '抓大鹅运行记录表', - square_hole_agent_session: '方洞挑战 Agent 会话表', - square_hole_agent_message: '方洞挑战 Agent 消息表', - square_hole_work_profile: '方洞挑战作品档案表', - square_hole_runtime_run: '方洞挑战运行记录表', - visual_novel_agent_session: '视觉小说 Agent 会话表', - visual_novel_agent_message: '视觉小说 Agent 消息表', - visual_novel_work_profile: '视觉小说作品档案表', - visual_novel_runtime_run: '视觉小说运行记录表', - visual_novel_runtime_history_entry: '视觉小说历史条目表', - visual_novel_runtime_event: '视觉小说运行事件表', - big_fish_creation_session: '大鱼吃小鱼创建会话表', - big_fish_agent_message: '大鱼吃小鱼 Agent 消息表', - big_fish_asset_slot: '大鱼吃小鱼资产槽位表', - big_fish_event: '大鱼吃小鱼事件表', - big_fish_runtime_run: '大鱼吃小鱼运行记录表', asset_object: '资产对象表', asset_entity_binding: '资产实体绑定表', asset_event: '资产事件表', diff --git a/apps/admin-web/src/pages/AdminGrayReleaseConfigPage.test.tsx b/apps/admin-web/src/pages/AdminGrayReleaseConfigPage.test.tsx index ac4bb8e80..dc407ae28 100644 --- a/apps/admin-web/src/pages/AdminGrayReleaseConfigPage.test.tsx +++ b/apps/admin-web/src/pages/AdminGrayReleaseConfigPage.test.tsx @@ -175,6 +175,107 @@ test('灰度发布页可选择模板库并默认启用零比例灰度', async () ); }); +test('灰度发布页可选择游戏发布开关,默认保持「未开启即开放」语义', async () => { + const user = userEvent.setup(); + render( + , + ); + + await screen.findByRole('button', { name: 'editor.new-toolbar' }); + await user.selectOptions(screen.getByLabelText('Gate Key 前缀'), [ + 'game-distribution', + ]); + + expect((screen.getByLabelText('Gate Key') as HTMLInputElement).value).toBe( + 'game-distribution:publish', + ); + expect( + (screen.getByLabelText('Gate Key 目标') as HTMLSelectElement).value, + ).toBe('publish'); + // 该开关的语义是「未配置/关闭 = 默认开放」,所以选中后不能默认打开收紧。 + expect((screen.getByLabelText('启用') as HTMLInputElement).checked).toBe( + false, + ); + expect((screen.getByLabelText('灰度比例') as HTMLInputElement).value).toBe( + '0', + ); + expect( + (screen.getByLabelText('描述') as HTMLTextAreaElement).value, + ).toContain('游戏发布入口灰度'); +}); + +test('灰度发布页保存游戏发布开关时写入白名单与比例', async () => { + const user = userEvent.setup(); + vi.mocked(upsertAdminFeatureGateConfig).mockResolvedValueOnce({ + gates: [ + ...configResponse.gates, + { + gateKey: 'game-distribution:publish', + enabled: true, + rolloutPercent: 20, + allowUserIds: ['user-internal'], + allowUserTags: [], + denyUserIds: [], + description: '游戏发布入口灰度', + updatedAt: '2026-09-22T10:00:00Z', + }, + ], + }); + render( + , + ); + + await screen.findByRole('button', { name: 'editor.new-toolbar' }); + await user.selectOptions(screen.getByLabelText('Gate Key 前缀'), [ + 'game-distribution', + ]); + fireEvent.click(screen.getByLabelText('启用')); + fireEvent.change(screen.getByLabelText('灰度比例'), { + target: { value: '20' }, + }); + fireEvent.change(screen.getByLabelText('允许用户 ID'), { + target: { value: 'user-internal' }, + }); + fireEvent.change(screen.getByLabelText('描述'), { + target: { value: '游戏发布入口灰度' }, + }); + await user.click(screen.getByRole('button', { name: '保存配置' })); + await user.click(screen.getByRole('button', { name: '确认' })); + + await waitFor(() => + expect(upsertAdminFeatureGateConfig).toHaveBeenCalledWith('admin-token', { + gateKey: 'game-distribution:publish', + enabled: true, + rolloutPercent: 20, + allowUserIds: ['user-internal'], + allowUserTags: [], + denyUserIds: [], + description: '游戏发布入口灰度', + }), + ); +}); + +test('未创建的预设开关在后台可见并可一键配置', async () => { + const user = userEvent.setup(); + render( + , + ); + + const row = await screen.findByText('game-distribution:publish'); + expect(row).not.toBeNull(); + // 该开关默认未创建:列表里给出「配置」入口,点击后按默认关闭填充表单。 + const configureButton = row.closest('tr')?.querySelector('button'); + expect(configureButton).not.toBeNull(); + await user.click(configureButton!); + + expect((screen.getByLabelText('Gate Key') as HTMLInputElement).value).toBe( + 'game-distribution:publish', + ); + expect((screen.getByLabelText('启用') as HTMLInputElement).checked).toBe( + false, + ); +}); + test('灰度发布页保存时转换数组和百分比', async () => { const user = userEvent.setup(); vi.mocked(upsertAdminFeatureGateConfig).mockResolvedValueOnce({ diff --git a/apps/admin-web/src/pages/AdminGrayReleaseConfigPage.tsx b/apps/admin-web/src/pages/AdminGrayReleaseConfigPage.tsx index 814f2ac34..9dd2a0fba 100644 --- a/apps/admin-web/src/pages/AdminGrayReleaseConfigPage.tsx +++ b/apps/admin-web/src/pages/AdminGrayReleaseConfigPage.tsx @@ -28,6 +28,7 @@ interface GateTargetOption { const GATE_PREFIX_LABELS: Record = { 'image-editor': '画布', agc: '客户端', + 'game-distribution': '游戏分发', }; const FIXED_GATE_TARGETS: GateTargetOption[] = [ @@ -45,6 +46,14 @@ const FIXED_GATE_TARGETS: GateTargetOption[] = [ label: 'Agent 侧边栏', description: '画布 Agent 入口灰度', }, + { + prefix: 'game-distribution', + suffix: 'publish', + key: 'game-distribution:publish', + label: '游戏发布', + description: + '游戏发布入口灰度:未配置或关闭时对已登录作者默认开放,开启后只放行白名单 / 灰度命中', + }, ]; export function AdminGrayReleaseConfigPage({ @@ -197,6 +206,11 @@ export function AdminGrayReleaseConfigPage({ setErrorMessage(''); } + // 预设里尚未创建行的开关也要可见:运营需要先看到 key 才能配置灰度。 + const unconfiguredGateTargets = FIXED_GATE_TARGETS.filter( + (option) => !gates.some((gate) => gate.gateKey === option.key), + ); + function buildPayload(): AdminUpsertFeatureGateConfigRequest { return { gateKey: gateKey.trim(), @@ -443,6 +457,53 @@ export function AdminGrayReleaseConfigPage({ )} + +
+
+

可配置开关

+ {unconfiguredGateTargets.length} +
+ {unconfiguredGateTargets.length ? ( +
+ + + + + + + + + + {unconfiguredGateTargets.map((option) => ( + + + + + + ))} + +
Gate说明操作
+ {option.key} + + {GATE_PREFIX_LABELS[option.prefix] ?? option.prefix} ·{' '} + {option.label} + + {option.description} + +
+
+ ) : ( +
+ {isLoading ? '加载中' : '预设开关都已创建'} +
+ )} +
{confirmDialog} diff --git a/apps/ai-game-creator-shell/scripts/check-config.mjs b/apps/ai-game-creator-shell/scripts/check-config.mjs index 967bf3eb5..89edb4cf8 100644 --- a/apps/ai-game-creator-shell/scripts/check-config.mjs +++ b/apps/ai-game-creator-shell/scripts/check-config.mjs @@ -154,7 +154,6 @@ const allowedUncalledTauriCommands = [ 'steer_game_creator_agent_runtime_task', 'write_local_agent_memory', 'write_local_game_memory', - 'write_local_project_file', // Agent 运行时会话 / 目标 / 协作命令由 native 侧与 CLI swarm 驱动,前端没有调用方。 'archive_game_creator_agent_session', 'clear_game_creator_agent_goal', @@ -517,7 +516,7 @@ function parseTauriHandlerCommandNames(source) { throw new Error('AI game creator shell Tauri handler list is missing'); } return Array.from( - match[1].matchAll(/\b([a-z][a-z0-9_]+)\b/g), + match[1].matchAll(/\b(?:[a-z][a-z0-9_]*::)*([a-z][a-z0-9_]*)\b/g), ([, command]) => command, ); } @@ -550,6 +549,12 @@ function assertCommandNamesDisjoint(label, leftNames, rightNames) { } function runAppInvokeParserRegressionChecks() { + assert.deepEqual( + parseTauriHandlerCommandNames( + 'tauri::generate_handler![plain_command, analytics::gui::capture_analytics_context,]', + ), + ['plain_command', 'capture_analytics_context'], + ); assert.deepEqual( parseAppInvokeCommandNames(` invoke('direct_command', {}); diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/codex_cli.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/codex_cli.rs index e0ba84d09..707e5e29a 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/codex_cli.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/codex_cli.rs @@ -203,12 +203,51 @@ pub(in crate::agent) fn game_creator_codex_cli_version_at( Ok(version.to_string()) } +/// 开发态允许从宿主 PATH 里找到 Codex,但宿主必须持有可锚定的绝对文件: +/// 裸命令名按 PATH 解析成真实路径,否则 `bind_codex_executor` 的 canonicalize 会按 CWD 解析并失败。 +/// 发行构建不走这段,候选顺序、校验与返回值都与原先一致(打包环境用内置侧车/npm 绝对路径)。 +#[cfg(debug_assertions)] +fn anchor_codex_cli_executable_candidate( + candidate: &Path, + path: Option<&std::ffi::OsStr>, +) -> Option { + let is_bare_command_name = candidate + .parent() + .is_some_and(|parent| parent.as_os_str().is_empty()); + if !is_bare_command_name { + return candidate.is_file().then(|| candidate.to_path_buf()); + } + let name = candidate.as_os_str(); + for directory in path.into_iter().flat_map(std::env::split_paths) { + if directory.as_os_str().is_empty() { + continue; + } + let target = directory.join(name); + if target.is_file() { + // 第一个实际命中的项就是 OS 会执行的项;锚定失败时不再从 PATH 里换另一个。 + return target.canonicalize().ok(); + } + } + None +} + pub(crate) fn game_creator_codex_cli_executable_path() -> Result { let mut last_error = None; let mut seen = std::collections::HashSet::new(); let bundled = game_creator_bundled_codex_cli_path(game_creator_bundled_resource_dir().as_deref()); for candidate in game_creator_codex_cli_executable_candidates() { + #[cfg(debug_assertions)] + let candidate = match anchor_codex_cli_executable_candidate( + &candidate, + std::env::var_os("PATH").as_deref(), + ) { + Some(candidate) => candidate, + None => { + last_error = Some("候选执行器不是可锚定的文件".to_string()); + continue; + } + }; let identity = candidate.to_string_lossy().to_ascii_lowercase(); if !seen.insert(identity) { continue; diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/design_runtime.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/design_runtime.rs index e3c2c6f9e..bc53e4d73 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/design_runtime.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/design_runtime.rs @@ -1,12 +1,13 @@ use super::design_tools::*; use super::*; +use crate::analytics::contract::{ErrorCode, RunEndReason, RunSource, Source}; use futures::FutureExt; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; use std::fs::File; use std::path::{Path, PathBuf}; use std::sync::OnceLock; -use std::time::Duration; +use std::time::{Duration, Instant}; use tauri::Emitter; use uuid::Uuid; @@ -335,6 +336,7 @@ fn begin_design_turn(session: &mut DesignSession, id: &str) { request_index: 0, attempt: 0, model_selection: None, + analytics: None, }); session.last_error = None; session.updated_at = unix_timestamp(); @@ -725,12 +727,66 @@ fn design_debug(root: &Path, kind: &str, data: Value) { let _ = sender.try_send((path, data)); } +#[derive(Debug)] +struct DesignFailure { + message: String, + code: ErrorCode, +} + +impl From for DesignFailure { + fn from(message: String) -> Self { + Self { + message, + code: ErrorCode::RuntimeErrorUnclassified, + } + } +} + +impl From<&str> for DesignFailure { + fn from(message: &str) -> Self { + message.to_string().into() + } +} + +impl DesignFailure { + fn local_io(message: String) -> Self { + Self { + message, + code: ErrorCode::LocalIoFailed, + } + } +} + +fn design_provider_failure(error: &platform_llm::LlmError, message: String) -> DesignFailure { + use platform_llm::LlmError; + let code = match error { + LlmError::Timeout { .. } => ErrorCode::ProviderTimeout, + LlmError::Upstream { + status_code: 401 | 403, + .. + } => ErrorCode::ProviderAuthFailed, + LlmError::Upstream { + status_code: 429, .. + } => ErrorCode::ProviderRateLimited, + LlmError::Upstream { + status_code: 500..=599, + .. + } + | LlmError::Connectivity { .. } + | LlmError::Transport(_) + | LlmError::StreamUnavailable => ErrorCode::ProviderUnavailable, + LlmError::EmptyResponse | LlmError::Deserialize(_) => ErrorCode::ProviderInvalidResponse, + _ => ErrorCode::RuntimeErrorUnclassified, + }; + DesignFailure { message, code } +} + async fn request_design_provider( root: &Path, session: &mut DesignSession, resources: &DesignResources, emit: &mut (impl FnMut(DesignEvent) + Send), -) -> Result { +) -> Result { #[cfg(test)] if fake_provider::is_active() { return request_scripted_design_provider(root, session, emit).await; @@ -749,7 +805,7 @@ async fn request_design_provider( let message_id = format!("{}:response:{}", turn.id, turn.request_index); for attempt in 0..=max_retries { session.turn.as_mut().unwrap().attempt = attempt; - checkpoint_design(root, session)?; + checkpoint_design(root, session).map_err(DesignFailure::local_io)?; design_debug( root, "request", @@ -870,7 +926,7 @@ async fn request_design_provider( Some(&message_id), String::new(), )); - return Err(detail); + return Err(design_provider_failure(&error, detail)); } tokio::time::sleep(Duration::from_millis( game_creator_agent_runtime_transient_retry_backoff_ms( @@ -890,14 +946,14 @@ async fn request_scripted_design_provider( root: &Path, session: &mut DesignSession, emit: &mut (impl FnMut(DesignEvent) + Send), -) -> Result { +) -> Result { let max_retries = fake_provider::max_retries(); let turn = session.turn.as_ref().unwrap(); let turn_id = turn.id.clone(); let message_id = format!("{}:response:{}", turn.id, turn.request_index); for attempt in 0..=max_retries { session.turn.as_mut().unwrap().attempt = attempt; - checkpoint_design(root, session)?; + checkpoint_design(root, session).map_err(DesignFailure::local_io)?; emit(design_event( root, &turn_id, @@ -952,7 +1008,7 @@ async fn request_scripted_design_provider( Some(&message_id), String::new(), )); - return Err(detail); + return Err(design_provider_failure(&error, detail)); } } None => { @@ -1010,15 +1066,18 @@ async fn run_design_loop( resources: &DesignResources, session: &mut DesignSession, emit: &mut (impl FnMut(DesignEvent) + Send), -) -> Result<(), String> { +) -> Result<(), DesignFailure> { while session.turn.as_ref().is_some_and(|turn| turn.pending) { - process_design_batch(root, resources, session, emit)?; + process_design_batch(root, resources, session, emit).map_err(DesignFailure::local_io)?; if session.pending_approval.is_some() || session.pending_clarification.is_some() { break; } let response = request_design_provider(root, session, resources, emit).await?; - accept_design_response(session, response)?; - checkpoint_design(root, session)?; + accept_design_response(session, response).map_err(|message| DesignFailure { + message, + code: ErrorCode::ProviderInvalidResponse, + })?; + checkpoint_design(root, session).map_err(DesignFailure::local_io)?; let turn = session.turn.as_ref().unwrap(); emit(design_event( root, @@ -1032,14 +1091,28 @@ async fn run_design_loop( Ok(()) } +#[derive(Clone, Copy, PartialEq, Eq)] +enum DesignExecution { + Idle, + New, + Recovery, +} + async fn finish_design_command( root: &Path, resources: &DesignResources, mut session: DesignSession, active: File, - run: bool, + execution: DesignExecution, + phase_change: Option, + capture: Option<( + crate::analytics::contract::Context, + crate::analytics::store::AnalyticsWriter, + )>, mut emit: impl FnMut(DesignEvent) + Send, ) -> Result { + let run = execution != DesignExecution::Idle; + let new_run = execution == DesignExecution::New; if run && session .turn @@ -1049,6 +1122,25 @@ async fn finish_design_command( resolve_design_turn_llm_config(&mut session, &load_game_creator_app_config()?)?; } checkpoint_design(root, &session)?; + let started = (new_run && capture.is_some()).then(Instant::now); + let metadata = session + .turn + .as_ref() + .and_then(|turn| turn.analytics.clone()); + if new_run { + if let (Some(metadata), Some((_, writer))) = (&metadata, &capture) { + crate::analytics::run::accepted(writer, root, &session.project_id, metadata); + } + crate::analytics::goal::accepted( + capture.clone(), + root, + &session.project_id, + crate::analytics::contract::Source::DesignAgent, + ); + } + if let Some(change) = phase_change { + change.record(); + } let turn_id = session .turn .as_ref() @@ -1074,12 +1166,43 @@ async fn finish_design_command( let outcome = std::panic::AssertUnwindSafe(run).catch_unwind().await; let result = match outcome { Ok(result) => result, - Err(payload) => Err(design_panic_error(payload)), + Err(payload) => Err(DesignFailure { + message: design_panic_error(payload), + code: ErrorCode::RuntimeFailed, + }), }; + if let Some(metadata) = &metadata { + let end_reason = if result.is_err() { + RunEndReason::Failed + } else if session.pending_approval.is_some() { + RunEndReason::WaitingForApproval + } else if session.pending_clarification.is_some() { + RunEndReason::WaitingForUser + } else { + RunEndReason::Finished + }; + crate::analytics::run::finished( + capture + .clone() + .or_else(crate::analytics::gui::capture_writer_context), + root, + &session.project_id, + metadata, + crate::analytics::run::Outcome { + turn_id: Some(turn_id.clone()), + end_reason, + error_code: result.as_ref().err().map(|error| error.code), + duration_ms: started + .and_then(|start| u64::try_from(start.elapsed().as_millis()).ok()), + output_change_detected: metadata.output_revision.as_ref().map(|_| true), + revision_id: metadata.output_revision.clone(), + }, + ); + } if let Err(error) = result { // 从最后一个持久检查点恢复,防止写后未记结果被误认为已完成。 session = read_design_session(root)?.ok_or("策划会话丢失")?; - session.last_error = Some(redact_agent_runtime_error(root, &error, 1800)); + session.last_error = Some(redact_agent_runtime_error(root, &error.message, 1800)); checkpoint_design(root, &session)?; } } @@ -1108,6 +1231,21 @@ pub(crate) async fn continue_design_agent_at( id: &str, input: DesignInput, emit: impl FnMut(DesignEvent) + Send, +) -> Result { + let capture = crate::analytics::gui::capture_writer_context(); + continue_design_agent_with_capture_at(root, resources, id, input, capture, emit).await +} + +async fn continue_design_agent_with_capture_at( + root: &Path, + resources: &DesignResources, + id: &str, + input: DesignInput, + capture: Option<( + crate::analytics::contract::Context, + crate::analytics::store::AnalyticsWriter, + )>, + emit: impl FnMut(DesignEvent) + Send, ) -> Result { ensure_design_runtime_active(root)?; let project_id = design_project_id(root)?; @@ -1121,11 +1259,36 @@ pub(crate) async fn continue_design_agent_at( if session.project_id != project_id { return Err("策划会话与当前项目不匹配".into()); } + let run_source = match &input { + DesignInput::Retry => RunSource::UserRetry, + DesignInput::Clarification { .. } => RunSource::Clarification, + DesignInput::Message { .. } if session.pending_clarification.is_some() => { + RunSource::Clarification + } + DesignInput::Message { .. } => RunSource::UserSubmit, + }; let run = prepare_design_input(&mut session, id, input)?; if run { select_design_turn_model(&mut session, &load_game_creator_app_config()?)?; + session.turn.as_mut().unwrap().analytics = capture.as_ref().map(|(context, _)| { + crate::analytics::run::Metadata::new(context.clone(), Source::DesignAgent, run_source) + }); } - finish_design_command(root, resources, session, active, run, emit).await + finish_design_command( + root, + resources, + session, + active, + if run { + DesignExecution::New + } else { + DesignExecution::Idle + }, + None, + capture, + emit, + ) + .await } async fn recover_uncertain_design_batch( @@ -1134,7 +1297,18 @@ async fn recover_uncertain_design_batch( session: DesignSession, active: File, ) -> Result { - finish_design_command(root, resources, session, active, true, |_| {}).await + let capture = crate::analytics::gui::capture_writer_context(); + finish_design_command( + root, + resources, + session, + active, + DesignExecution::Recovery, + None, + capture, + |_| {}, + ) + .await } pub(crate) async fn decide_design_phase_at( @@ -1144,6 +1318,23 @@ pub(crate) async fn decide_design_phase_at( request_id: &str, approved: bool, emit: impl FnMut(DesignEvent) + Send, +) -> Result { + let capture = crate::analytics::gui::capture_writer_context(); + decide_design_phase_with_capture_at(root, resources, id, request_id, approved, capture, emit) + .await +} + +async fn decide_design_phase_with_capture_at( + root: &Path, + resources: &DesignResources, + id: &str, + request_id: &str, + approved: bool, + capture: Option<( + crate::analytics::contract::Context, + crate::analytics::store::AnalyticsWriter, + )>, + emit: impl FnMut(DesignEvent) + Send, ) -> Result { ensure_design_runtime_active(root)?; let project_id = design_project_id(root)?; @@ -1154,11 +1345,48 @@ pub(crate) async fn decide_design_phase_at( if session.project_id != project_id { return Err("策划会话与当前项目不匹配".into()); } + let previous_phase = session.current_phase.clone(); let run = prepare_design_decision(&mut session, id, request_id, approved)?; + let phase_change = run + .then(|| { + crate::analytics::design::PhaseChange::new( + capture.clone(), + &project_id, + &session.session_id, + &previous_phase, + &session.current_phase, + ) + }) + .flatten(); if run { select_design_turn_model(&mut session, &load_game_creator_app_config()?)?; + session.turn.as_mut().unwrap().analytics = capture.as_ref().map(|(context, _)| { + let mut metadata = crate::analytics::run::Metadata::new( + context.clone(), + Source::DesignAgent, + RunSource::Approval, + ); + metadata.output_revision = phase_change + .as_ref() + .map(|change| change.revision_id().to_string()); + metadata + }); } - finish_design_command(root, resources, session, active, run, emit).await + finish_design_command( + root, + resources, + session, + active, + if run { + DesignExecution::New + } else { + DesignExecution::Idle + }, + phase_change, + capture, + emit, + ) + .await } fn ensure_design_runtime_active(root: &Path) -> Result<(), String> { @@ -1392,12 +1620,20 @@ pub(crate) async fn continue_design_agent_session( client_turn_id: String, input: DesignInput, ) -> Result { + let capture = crate::analytics::gui::capture_writer_context(); let root = PathBuf::from(project_path.trim()); enforce_project_permission_policy(&root, "conversation.write")?; let resources = DesignResources::new(resolve_design_resources_root(&app)?)?; - continue_design_agent_at(&root, &resources, &client_turn_id, input, |event| { - let _ = app.emit("design-agent-update", event); - }) + continue_design_agent_with_capture_at( + &root, + &resources, + &client_turn_id, + input, + capture, + |event| { + let _ = app.emit("design-agent-update", event); + }, + ) .await } @@ -1409,15 +1645,17 @@ pub(crate) async fn decide_design_phase( request_id: String, approved: bool, ) -> Result { + let capture = crate::analytics::gui::capture_writer_context(); let root = PathBuf::from(project_path.trim()); enforce_project_permission_policy(&root, "conversation.write")?; let resources = DesignResources::new(resolve_design_resources_root(&app)?)?; - decide_design_phase_at( + decide_design_phase_with_capture_at( &root, &resources, &client_turn_id, &request_id, approved, + capture, |event| { let _ = app.emit("design-agent-update", event); }, @@ -1499,6 +1737,64 @@ mod fake_provider { mod tests { use super::*; + fn analytics_capture() -> ( + tempfile::TempDir, + crate::analytics::contract::Context, + crate::analytics::store::AnalyticsWriter, + ) { + let temp = tempfile::tempdir().unwrap(); + let context = crate::analytics::contract::Context { + route: crate::analytics::contract::Route::from_identity( + Some("approver-a".into()), + Some("https://example.com"), + ), + editor_session_id: Uuid::new_v4().to_string(), + client_version: "1.0.0".into(), + }; + let writer = crate::analytics::store::AnalyticsWriter::start( + temp.path().into(), + context.editor_session_id.clone(), + ); + (temp, context, writer) + } + + fn read_analytics_events( + config: &Path, + session: &str, + marker_id: &str, + ) -> Vec { + let deadline = std::time::Instant::now() + Duration::from_secs(5); + loop { + let mut events = Vec::new(); + if let Ok(batches) = fs::read_dir( + config + .join("analytics/instances") + .join(session) + .join("batches"), + ) { + for batch in batches.flatten() { + if Uuid::parse_str(&batch.file_name().to_string_lossy()).is_err() { + continue; + } + if let Ok(lines) = fs::read_to_string(batch.path().join("events.jsonl")) { + events.extend(lines.lines().map(|line| { + serde_json::from_str::(line).unwrap() + })); + } + } + } + if events.iter().any(|event| event.event_id == marker_id) { + return events; + } + assert!( + std::time::Instant::now() < deadline, + "等待 FIFO 哨兵超时,已读取 {} 条事件", + events.len() + ); + std::thread::sleep(Duration::from_millis(10)); + } + } + #[test] fn runtime_mode_restore_prefers_explicit_mode_over_existing_design_session() { let temporary = tempfile::tempdir().expect("tempdir"); @@ -1530,6 +1826,448 @@ mod tests { ); } + fn drain_analytics_with_marker( + config: &Path, + context: &crate::analytics::contract::Context, + writer: &crate::analytics::store::AnalyticsWriter, + ) -> Vec { + use crate::analytics::contract::*; + // 同一 FIFO 队列中的哨兵落盘后,之前可能误发的事件也一定已被处理。 + let marker = context + .capture( + EventData::EditorSessionStart(SessionStart { + entry_source: EntrySource::DirectLaunch, + first_project_id: None, + }), + None, + Source::Editor, + None, + ) + .unwrap(); + let marker_id = marker.event_id.clone(); + assert!(writer.try_record(context.route.clone(), marker, marker_id.clone())); + assert!(writer.flush()); + let events = read_analytics_events(config, &context.editor_session_id, &marker_id); + assert!(events.iter().any(|event| event.event_id == marker_id)); + events + } + + fn assert_revision_count_after_drain( + config: &Path, + context: &crate::analytics::contract::Context, + writer: &crate::analytics::store::AnalyticsWriter, + expected: usize, + ) { + let events = drain_analytics_with_marker(config, context, writer); + assert_eq!( + events + .iter() + .filter(|event| event.event_name == "project_revision_created") + .count(), + expected + ); + } + + #[tokio::test(flavor = "current_thread")] + async fn approved_phase_revision_survives_model_failure_and_command_replay() { + let (_temp, root, resources) = init_design_project(); + let (analytics_dir, context, writer) = analytics_capture(); + concept_artifacts(&root); + let mut session = new_design_session(design_project_id(&root).unwrap(), "quality"); + let approval = submit_design_phase_for_approval(&root, &mut session).unwrap(); + write_design_session(&root, &session).unwrap(); + let _fake = fake_provider::install( + vec![Err(platform_llm::LlmError::Upstream { + status_code: 500, + message: "test failure".into(), + })], + 0, + ); + let view = decide_design_phase_with_capture_at( + &root, + &resources, + "approval-once", + &approval.request_id, + true, + Some((context.clone(), writer.clone())), + |_| {}, + ) + .await + .unwrap(); + assert_eq!(view.session.current_phase, "top_design"); + assert!(view.session.last_error.is_some()); + let events = drain_analytics_with_marker(analytics_dir.path(), &context, &writer); + let revision_event = events + .iter() + .find(|event| event.event_name == "project_revision_created") + .unwrap(); + assert_eq!( + revision_event.properties["revision_id"], + format!("design:{}:top_design", session.session_id) + ); + assert_eq!(revision_event.user_id.as_deref(), Some("approver-a")); + let failed = events + .iter() + .find(|event| event.event_name == "agent_run_failed") + .unwrap(); + assert_eq!(failed.properties["output_change_detected"], true); + assert_eq!( + failed.properties["revision_id"], + revision_event.properties["revision_id"] + ); + assert_eq!(failed.error_code, Some(ErrorCode::ProviderUnavailable)); + assert_eq!(failed.properties["run_source"], "approval"); + + let mut another_user = context.clone(); + another_user.route.user_id = Some("approver-b".into()); + decide_design_phase_with_capture_at( + &root, + &resources, + "approval-once", + &approval.request_id, + true, + Some((another_user, writer.clone())), + |_| {}, + ) + .await + .unwrap(); + assert_revision_count_after_drain(analytics_dir.path(), &context, &writer, 1); + } + + #[tokio::test(flavor = "current_thread")] + async fn phase_checkpoint_failure_does_not_record_revision_or_start_model() { + let (_temp, root, resources) = init_design_project(); + let (analytics_dir, context, writer) = analytics_capture(); + concept_artifacts(&root); + let mut session = new_design_session(design_project_id(&root).unwrap(), "quality"); + crate::analytics::goal::created(Some(&writer), &root, &session.project_id); + let approval = submit_design_phase_for_approval(&root, &mut session).unwrap(); + let old_phase = session.current_phase.clone(); + assert!( + prepare_design_decision(&mut session, "approve", &approval.request_id, true).unwrap() + ); + select_design_turn_model(&mut session, &GameCreatorAppConfig::default()).unwrap(); + let change = crate::analytics::design::PhaseChange::new( + Some((context.clone(), writer.clone())), + &session.project_id, + &session.session_id, + &old_phase, + &session.current_phase, + ); + fs::create_dir_all(root.join(".agent/design-agent/session.json")).unwrap(); + let active = try_open_game_creator_agent_runtime_task_lock_file(&root, DESIGN_ACTIVE_LOCK) + .unwrap() + .unwrap(); + let _fake = fake_provider::install(vec![Ok(fake_response("unused", "unused", vec![]))], 0); + assert!(finish_design_command( + &root, + &resources, + session, + active, + DesignExecution::New, + change, + Some((context.clone(), writer.clone())), + |_| {} + ) + .await + .is_err()); + assert_revision_count_after_drain(analytics_dir.path(), &context, &writer, 0); + assert!(fake_provider::take().is_some()); + } + + #[tokio::test(flavor = "current_thread")] + async fn design_first_submit_keeps_accepting_user_after_model_failure_and_replay() { + let (_temp, root, resources) = init_design_project(); + let (analytics_dir, context, writer) = analytics_capture(); + crate::analytics::goal::created(Some(&writer), &root, &design_project_id(&root).unwrap()); + let _fake = fake_provider::install( + vec![Err(platform_llm::LlmError::Upstream { + status_code: 500, + message: "test failure".into(), + })], + 0, + ); + let input = || DesignInput::Message { + text: "设计一个游戏".into(), + }; + let view = continue_design_agent_with_capture_at( + &root, + &resources, + "first-submit", + input(), + Some((context.clone(), writer.clone())), + |_| {}, + ) + .await + .unwrap(); + assert!(view.session.last_error.is_some()); + let mut another_user = context.clone(); + another_user.route.user_id = Some("approver-b".into()); + continue_design_agent_with_capture_at( + &root, + &resources, + "first-submit", + input(), + Some((another_user, writer.clone())), + |_| {}, + ) + .await + .unwrap(); + let events = drain_analytics_with_marker(analytics_dir.path(), &context, &writer); + let submitted = events + .iter() + .find(|event| event.event_name == "creative_task_submit") + .unwrap(); + assert_eq!(submitted.user_id.as_deref(), Some("approver-a")); + assert_eq!( + submitted.source, + crate::analytics::contract::Source::DesignAgent + ); + assert_eq!(submitted.project_id, submitted.creative_task_id); + } + + #[tokio::test(flavor = "current_thread")] + async fn design_run_wait_failure_and_user_retry_have_distinct_stable_results() { + let (_temp, root, resources) = init_design_project(); + let (analytics_dir, context, writer) = analytics_capture(); + let _fake = fake_provider::install( + vec![ + Ok(fake_response( + "question", + "", + vec![platform_llm::LlmToolCall { + id: "ask".into(), + name: "ask_clarification".into(), + arguments: json!({"question":"选择方向?","options":["解谜"]}).to_string(), + }], + )), + Err(platform_llm::LlmError::Upstream { + status_code: 401, + message: "private provider detail".into(), + }), + Err(platform_llm::LlmError::Upstream { + status_code: 500, + message: "transient".into(), + }), + Ok(fake_response("answer", "完成本轮", vec![])), + ], + 1, + ); + let view = continue_design_agent_with_capture_at( + &root, + &resources, + "start", + DesignInput::Message { + text: "设计游戏".into(), + }, + Some((context.clone(), writer.clone())), + |_| {}, + ) + .await + .unwrap(); + assert!(view.session.pending_clarification.is_some()); + let failed = continue_design_agent_with_capture_at( + &root, + &resources, + "answer", + DesignInput::Message { + text: "解谜".into(), + }, + Some((context.clone(), writer.clone())), + |_| {}, + ) + .await + .unwrap(); + assert!(failed.session.last_error.is_some()); + continue_design_agent_with_capture_at( + &root, + &resources, + "retry", + DesignInput::Retry, + Some((context.clone(), writer.clone())), + |_| {}, + ) + .await + .unwrap(); + continue_design_agent_with_capture_at( + &root, + &resources, + "retry", + DesignInput::Retry, + Some((context.clone(), writer.clone())), + |_| {}, + ) + .await + .unwrap(); + let events = drain_analytics_with_marker(analytics_dir.path(), &context, &writer); + let runs: Vec<_> = events.iter().filter(|e| e.agent_run_id.is_some()).collect(); + assert_eq!(runs.len(), 3); + let find = |turn: &str| { + *runs + .iter() + .find(|e| e.agent_turn_id.as_deref() == Some(turn)) + .unwrap() + }; + let first = find("start"); + let failed = find("answer"); + let retry = find("retry"); + assert_eq!(first.properties["end_reason"], "waiting_for_user"); + assert_eq!(first.properties["run_source"], "user_submit"); + assert_eq!(failed.error_code, Some(ErrorCode::ProviderAuthFailed)); + assert_eq!(failed.properties["run_source"], "clarification"); + assert_eq!(failed.properties["retry_index"], 0); + assert_eq!(retry.properties["run_source"], "user_retry"); + assert_eq!(retry.properties["retry_index"], 1); + assert_eq!(retry.properties["end_reason"], "finished"); + assert_ne!(first.agent_run_id, failed.agent_run_id); + assert_ne!(failed.agent_run_id, retry.agent_run_id); + for event in runs { + assert!(event.properties["duration_ms"].is_u64()); + assert!(event.properties["output_change_detected"].is_null()); + assert!(!event + .properties + .to_string() + .contains("private provider detail")); + } + } + + #[tokio::test(flavor = "current_thread")] + async fn design_recovered_run_keeps_original_identity_and_has_unknown_duration() { + let (_temp, root, resources) = init_design_project(); + let (analytics_dir, context, writer) = analytics_capture(); + let mut session = new_design_session(&design_project_id(&root).unwrap(), ""); + begin_design_turn(&mut session, "recovered-turn"); + let metadata = crate::analytics::run::Metadata::new( + context.clone(), + Source::DesignAgent, + RunSource::UserSubmit, + ); + session.turn.as_mut().unwrap().analytics = Some(metadata.clone()); + write_design_session(&root, &session).unwrap(); + crate::analytics::run::accepted(&writer, &root, &session.project_id, &metadata); + drain_analytics_with_marker(analytics_dir.path(), &context, &writer); + let mut current = context.clone(); + current.editor_session_id = Uuid::new_v4().to_string(); + current.client_version = "2.0.0".into(); + current.route.user_id = Some("restoring-user".into()); + let current_writer = crate::analytics::store::AnalyticsWriter::start( + analytics_dir.path().into(), + current.editor_session_id.clone(), + ); + let _fake = + fake_provider::install(vec![Ok(fake_response("restored", "恢复后完成", vec![]))], 0); + let active = try_open_game_creator_agent_runtime_task_lock_file(&root, DESIGN_ACTIVE_LOCK) + .unwrap() + .unwrap(); + finish_design_command( + &root, + &resources, + read_design_session(&root).unwrap().unwrap(), + active, + DesignExecution::Recovery, + None, + Some((current.clone(), current_writer.clone())), + |_| {}, + ) + .await + .unwrap(); + let events = drain_analytics_with_marker(analytics_dir.path(), ¤t, ¤t_writer); + let result = events + .iter() + .find(|event| event.event_name == "agent_run_completed") + .unwrap(); + assert_eq!( + result.agent_run_id.as_deref(), + Some(metadata.run_id.as_str()) + ); + assert_eq!(result.event_id, metadata.terminal_event_id); + assert_eq!(result.user_id, context.route.user_id); + assert_eq!(result.editor_session_id, current.editor_session_id); + assert_eq!(result.client_version, "2.0.0"); + assert!(result.properties["duration_ms"].is_null()); + assert_eq!(result.properties["retry_index"], 0); + assert!(!events + .iter() + .any(|event| event.event_name == "creative_task_submit")); + } + + #[tokio::test(flavor = "current_thread")] + async fn design_old_command_replay_does_not_consume_newly_available_goal_qualification() { + let (_temp, root, resources) = init_design_project(); + let (analytics_dir, context, writer) = analytics_capture(); + let _fake = fake_provider::install(vec![Ok(fake_response("answer", "完成", vec![]))], 0); + let input = || DesignInput::Message { + text: "设计一个游戏".into(), + }; + continue_design_agent_with_capture_at( + &root, + &resources, + "old-command", + input(), + None, + |_| {}, + ) + .await + .unwrap(); + crate::analytics::goal::created(Some(&writer), &root, &design_project_id(&root).unwrap()); + continue_design_agent_with_capture_at( + &root, + &resources, + "old-command", + input(), + Some((context.clone(), writer.clone())), + |_| {}, + ) + .await + .unwrap(); + let events = drain_analytics_with_marker(analytics_dir.path(), &context, &writer); + assert!(!events + .iter() + .any(|event| event.event_name == "creative_task_submit")); + } + + #[tokio::test(flavor = "current_thread")] + async fn design_invalid_input_preserves_qualification_for_later_accepting_user() { + let (_temp, root, resources) = init_design_project(); + let (analytics_dir, context, writer) = analytics_capture(); + crate::analytics::goal::created(Some(&writer), &root, &design_project_id(&root).unwrap()); + assert!(continue_design_agent_with_capture_at( + &root, + &resources, + "invalid", + DesignInput::Message { text: " ".into() }, + Some((context.clone(), writer.clone())), + |_| {}, + ) + .await + .is_err()); + let mut accepting_user = context.clone(); + accepting_user.route.user_id = Some("approver-b".into()); + let _fake = fake_provider::install(vec![Ok(fake_response("answer", "完成", vec![]))], 0); + continue_design_agent_with_capture_at( + &root, + &resources, + "valid", + DesignInput::Message { + text: "设计游戏".into(), + }, + Some((accepting_user, writer.clone())), + |_| {}, + ) + .await + .unwrap(); + let events = drain_analytics_with_marker(analytics_dir.path(), &context, &writer); + assert_eq!( + events + .iter() + .find(|event| event.event_name == "creative_task_submit") + .unwrap() + .user_id + .as_deref(), + Some("approver-b") + ); + } + #[test] fn design_runtime_rejects_design_execution_in_game_mode() { let temporary = tempfile::tempdir().expect("create runtime mode root"); @@ -1818,6 +2556,7 @@ mod tests { request_index: 0, attempt: 0, model_selection: None, + analytics: None, }); session.pending_batch = Some(DesignToolBatch { calls: vec![ @@ -2228,6 +2967,7 @@ mod tests { #[tokio::test(flavor = "current_thread")] async fn fake_provider_walks_five_phases_and_enters_consultant() { let (_temp, root, resources) = init_design_project(); + let (analytics_dir, context, writer) = analytics_capture(); let _fake = fake_provider::install( vec![ Ok(phase_write_and_submit( @@ -2286,9 +3026,17 @@ mod tests { ("t-tdd", "tdd"), ("t-consultant", "consultant"), ] { - let view = decide_design_phase_at(&root, &resources, turn, &request, true, |_| {}) - .await - .expect("approve"); + let view = decide_design_phase_with_capture_at( + &root, + &resources, + turn, + &request, + true, + Some((context.clone(), writer.clone())), + |_| {}, + ) + .await + .expect("approve"); assert_eq!(view.session.current_phase, expected); if expected == "consultant" { assert!(view.session.pending_approval.is_none()); @@ -2308,11 +3056,60 @@ mod tests { design_workflow_status(&restored)["current_phase"], json!("consultant") ); + let events = drain_analytics_with_marker(analytics_dir.path(), &context, &writer); + let revisions: Vec<_> = events + .iter() + .filter(|event| event.event_name == "project_revision_created") + .collect(); + assert_eq!(revisions.len(), 5); + let completed: Vec<_> = events + .iter() + .filter(|event| event.event_name == "agent_run_completed") + .collect(); + assert_eq!(completed.len(), 5); + assert_eq!( + completed + .iter() + .filter(|e| e.properties["end_reason"] == "waiting_for_approval") + .count(), + 4 + ); + assert_eq!( + completed + .iter() + .filter(|e| e.properties["end_reason"] == "finished") + .count(), + 1 + ); + assert!(completed + .iter() + .all(|e| e.properties["output_change_detected"] == true + && e.properties["retry_index"] == 0)); + for phase in &DESIGN_PHASES[1..] { + let revision = format!("design:{}:{phase}", restored.session_id); + let event = revisions + .iter() + .find(|event| event.properties["revision_id"] == revision) + .unwrap(); + assert_eq!(event.event_name, "project_revision_created"); + assert_eq!(event.user_id.as_deref(), Some("approver-a")); + assert_eq!(event.project_id, Some(restored.project_id.clone())); + assert_eq!(event.creative_task_id, event.project_id); + assert_eq!( + event.source, + crate::analytics::contract::Source::DesignAgent + ); + assert_eq!(event.properties["revision_source"], "agent"); + assert_eq!(event.properties["change_kind"], "design_document"); + assert!(event.properties.get("files_changed_count").is_none()); + assert!(event.agent_run_id.is_none() && event.agent_turn_id.is_none()); + } } #[tokio::test(flavor = "current_thread")] async fn fake_provider_reject_does_not_wake_and_session_survives_restart() { let (_temp, root, resources) = init_design_project(); + let (analytics_dir, context, writer) = analytics_capture(); let _fake = fake_provider::install( vec![Ok(phase_write_and_submit( "concept", @@ -2344,14 +3141,23 @@ mod tests { .map(|item| item.request_id.as_str()), Some(request.as_str()) ); - let rejected = - decide_design_phase_at(&root, &resources, "t-reject", &request, false, |_| {}) - .await - .expect("reject"); + crate::analytics::goal::created(Some(&writer), &root, &persisted.project_id); + let rejected = decide_design_phase_with_capture_at( + &root, + &resources, + "t-reject", + &request, + false, + Some((context.clone(), writer.clone())), + |_| {}, + ) + .await + .expect("reject"); assert_eq!(rejected.session.current_phase, "concept"); assert!(rejected.session.pending_approval.is_none()); assert!(rejected.session.approved_phases.is_empty()); assert!(fake_provider::take().is_none()); + assert_revision_count_after_drain(analytics_dir.path(), &context, &writer, 0); let debug = root.join(".debug/design-agent"); if debug.exists() { @@ -2469,6 +3275,7 @@ mod tests { request_index: 0, attempt: 0, model_selection: None, + analytics: None, }); session.pending_batch = Some(DesignToolBatch { calls: vec![call], diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_execution.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_execution.rs index 8f276ad31..a31c360f1 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_execution.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_execution.rs @@ -93,6 +93,8 @@ pub(super) struct ExecutionLedger { pub(super) plan: Option, #[serde(default)] pub(super) last_failed_write_revision: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub(super) analytics_run: Option, } struct SessionData { @@ -106,6 +108,17 @@ struct SessionData { elapsed_offset_ms: u64, } +// 与业务持久化锁分离;只保存内存状态,持锁期间不执行 I/O 或投递事件。 +struct SessionAnalytics { + project_id: String, + route: Option, + capture: Option<( + crate::analytics::contract::Context, + crate::analytics::store::AnalyticsWriter, + )>, + output_revision: Option, +} + #[derive(Clone, PartialEq, Eq)] struct CodexExecutorIdentity { path: PathBuf, @@ -153,9 +166,12 @@ fn executor_digest(path: &Path) -> Result { pub(super) struct ExecutionSession { pub(super) root: PathBuf, + /// 本次确实新建执行账本;恢复和旧预算迁移均不构成新的用户受理。 + pub(super) newly_accepted: bool, state_path: PathBuf, _owner: File, data: Mutex, + analytics: Mutex, changed: tokio::sync::watch::Sender, cancellation: Arc, abort_requested: std::sync::atomic::AtomicBool, @@ -216,6 +232,16 @@ pub(crate) struct WritePermit { id: String, } impl WritePermit { + pub(super) fn record_analytics_revision( + &self, + revision: u64, + change_kind: crate::analytics::contract::ChangeKind, + files_changed_count: u64, + ) { + self.session + .record_analytics_revision(revision, change_kind, files_changed_count); + } + pub(crate) fn run(&self, write: impl FnOnce() -> Result) -> Result { let mut data = self.session.lock()?; self.session.tick_locked(&mut data)?; @@ -401,6 +427,7 @@ pub(super) async fn begin( prompt: &str, requires_contract: bool, config: DirectValidationConfig, + analytics_run: Option, ) -> Result { let root = root.to_path_buf(); let prompt_hash = hash(prompt.as_bytes()); @@ -408,13 +435,14 @@ pub(super) async fn begin( let turn = super::direct_taonier_active_invocation_id_at(&root)?; let host = crate::game_creator_runtime_config_dir() .ok_or("direct-execution-host: 需要客户端私有配置目录,CLI 请提供 --config-dir")?; - open_at( + open_with_analytics_at( &host.join("direct-executions"), &root, &turn, &prompt_hash, requires_contract, &config, + analytics_run, ) }) .await @@ -462,6 +490,26 @@ pub(super) fn open_at( request_hash: &str, requires_contract: bool, config: &DirectValidationConfig, +) -> Result, String> { + open_with_analytics_at( + host, + root, + turn, + request_hash, + requires_contract, + config, + None, + ) +} + +pub(super) fn open_with_analytics_at( + host: &Path, + root: &Path, + turn: &str, + request_hash: &str, + requires_contract: bool, + config: &DirectValidationConfig, + analytics_run: Option, ) -> Result, String> { config.validate()?; let root = root @@ -521,6 +569,7 @@ pub(super) fn open_at( }; let project_id = super::read_existing_manifest_for_project(&root)?.project_id; let is_new = existing.is_none(); + let mut newly_accepted = is_new; let mut ledger = existing.unwrap_or_else(|| ExecutionLedger { schema_version: SCHEMA.into(), client_turn_id: turn.into(), @@ -546,6 +595,7 @@ pub(super) fn open_at( delivery_reviews: 0, plan: None, last_failed_write_revision: None, + analytics_run, }); if is_new { // 只继承旧项目账本的消费量,绝不把可编辑的旧成功回执提升为宿主证据。 @@ -558,6 +608,8 @@ pub(super) fn open_at( 512 * 1024, )?; if let Some(legacy) = legacy { + newly_accepted = false; + ledger.analytics_run = None; let used = legacy["usedRuns"] .as_u64() .and_then(|n| u32::try_from(n).ok()); @@ -614,8 +666,18 @@ pub(super) fn open_at( let (changed, _) = tokio::sync::watch::channel(ledger.revision); let session = Arc::new(ExecutionSession { root, + newly_accepted, state_path, _owner: owner, + analytics: Mutex::new(SessionAnalytics { + project_id: ledger.project_id.clone(), + route: ledger + .analytics_run + .as_ref() + .map(|run| run.context.route.clone()), + capture: None, + output_revision: None, + }), data: Mutex::new(SessionData { ledger, started: Instant::now(), @@ -738,6 +800,10 @@ impl ExecutionSession { pub(super) fn cancel_flag(&self) -> Arc { Arc::clone(&self.cancellation) } + pub(super) fn was_aborted(&self) -> bool { + self.abort_requested + .load(std::sync::atomic::Ordering::Acquire) + } pub(super) fn record_delivery_review(&self) -> Result { let mut data = self.lock()?; if data.ledger.phase.is_terminal() { @@ -765,6 +831,73 @@ impl ExecutionSession { self.commit(&mut data, next)?; Ok(json!({"plan":plan,"revision":data.ledger.revision,"acceptancePassed":false})) } + pub(super) fn set_analytics_capture( + &self, + capture: Option<( + crate::analytics::contract::Context, + crate::analytics::store::AnalyticsWriter, + )>, + ) { + let Ok(mut analytics) = self.analytics.lock() else { + return; + }; + analytics.capture = capture.and_then(|(mut context, writer)| { + // 恢复或账号切换后仍归属于真实受理的原 run。 + context.route = analytics.route.clone()?; + Some((context, writer)) + }); + } + + pub(super) fn analytics_capture( + &self, + ) -> Option<( + crate::analytics::contract::Context, + crate::analytics::store::AnalyticsWriter, + )> { + self.analytics.lock().ok()?.capture.clone() + } + + pub(super) fn record_analytics_revision( + &self, + revision: u64, + change_kind: crate::analytics::contract::ChangeKind, + files_changed_count: u64, + ) { + use crate::analytics::contract::{RevisionCreated, RevisionSource, Source}; + if files_changed_count == 0 { + return; + } + let Ok(mut analytics) = self.analytics.lock() else { + return; + }; + if analytics.route.is_none() { + return; + } + analytics.output_revision = Some(analytics.output_revision.unwrap_or(0).max(revision)); + let capture = analytics.capture.clone(); + let project_id = analytics.project_id.clone(); + drop(analytics); + crate::analytics::project::revision( + capture, + &project_id, + Source::Direct, + RevisionCreated { + revision_id: revision.to_string(), + revision_source: RevisionSource::Agent, + change_kind, + files_changed_count: Some(files_changed_count), + }, + ); + } + + pub(super) fn analytics_output_revision(&self) -> Option { + self.analytics + .lock() + .ok()? + .output_revision + .map(|revision| revision.to_string()) + } + pub(super) fn snapshot(&self) -> Result { let data = self.lock()?; let mut state = data.ledger.clone(); diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_execution/tests.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_execution/tests.rs index af4503af2..9f8ddb1f6 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_execution/tests.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_execution/tests.rs @@ -1,5 +1,192 @@ use super::*; +fn analytics_metadata(user: &str) -> crate::analytics::run::Metadata { + use crate::analytics::contract::{Context, Route, RunSource, Source}; + crate::analytics::run::Metadata::new( + Context { + route: Route::from_identity(Some(user.into()), Some("https://example.com")), + editor_session_id: uuid::Uuid::new_v4().to_string(), + client_version: "1.0.0".into(), + }, + Source::Direct, + RunSource::UserSubmit, + ) +} + +#[test] +fn analytics_survives_business_lock_contention_and_preserves_replayed_run_identity() { + use crate::analytics::{contract::ChangeKind, store::AnalyticsWriter}; + let temp = tempfile::tempdir().unwrap(); + let root = temp.path().join("project"); + let host = temp.path().join("host"); + crate::init_local_game_project_at(&root, "analytics-lock", "采集锁隔离").unwrap(); + let original = open_with_analytics_at( + &host, + &root, + "turn", + &hash(b"request"), + false, + &Default::default(), + Some(analytics_metadata("A")), + ) + .unwrap(); + drop(original); + let current = analytics_metadata("B"); + let session = open_with_analytics_at( + &host, + &root, + "turn", + &hash(b"request"), + false, + &Default::default(), + Some(current.clone()), + ) + .unwrap(); + let config = temp.path().join("config"); + std::fs::create_dir_all(&config).unwrap(); + let writer = AnalyticsWriter::start(config.clone(), current.context.editor_session_id.clone()); + let capture = (current.context.clone(), writer.clone()); + // 模拟业务提交长期占锁;采集必须在释放该锁之前完成。 + let business_lock = session.data.lock().unwrap(); + let task_session = session.clone(); + let (sender, receiver) = std::sync::mpsc::channel(); + let worker = std::thread::spawn(move || { + task_session.set_analytics_capture(Some(capture)); + task_session.record_analytics_revision(7, ChangeKind::Code, 1); + task_session.record_analytics_revision(5, ChangeKind::Code, 1); + task_session.record_analytics_revision(99, ChangeKind::Code, 0); + sender + .send(( + task_session.analytics_capture(), + task_session.analytics_output_revision(), + )) + .unwrap(); + }); + let result = receiver.recv_timeout(std::time::Duration::from_secs(5)); + // 即使回归成等待业务锁,也先释放锁和回收线程,让测试明确失败而非挂死。 + drop(business_lock); + worker.join().unwrap(); + let (capture, revision) = result.expect("采集不得等待业务持久化锁"); + let (context, _) = capture.expect("锁竞争不得丢失采集身份"); + assert_eq!(context.route.user_id.as_deref(), Some("A")); + assert_eq!(context.editor_session_id, current.context.editor_session_id); + assert_eq!(revision.as_deref(), Some("7")); + assert!(writer.flush()); + let batches = config + .join("analytics/instances") + .join(¤t.context.editor_session_id) + .join("batches"); + let deadline = Instant::now() + std::time::Duration::from_secs(5); + loop { + let events: Vec = std::fs::read_dir(&batches) + .into_iter() + .flatten() + .flatten() + .filter(|entry| !entry.file_name().to_string_lossy().starts_with('.')) + .filter_map(|entry| std::fs::read_to_string(entry.path().join("events.jsonl")).ok()) + .flat_map(|text| { + text.lines() + .map(|line| serde_json::from_str::(line).unwrap()) + .collect::>() + }) + .collect(); + if events.len() == 2 { + for (event, expected_revision) in events.iter().zip(["7", "5"]) { + assert_eq!(event["event_name"], "project_revision_created"); + assert_eq!(event["user_id"], "A"); + assert_eq!(event["project_id"], "analytics-lock"); + assert_eq!(event["properties"]["revision_id"], expected_revision); + } + break; + } + assert!(Instant::now() < deadline, "成果事件未落盘"); + std::thread::sleep(std::time::Duration::from_millis(5)); + } + drop(session); + let resumed = open_with_analytics_at( + &host, + &root, + "turn", + &hash(b"request"), + false, + &Default::default(), + Some(current), + ) + .unwrap(); + assert_eq!( + resumed.analytics_output_revision(), + None, + "恢复不补造历史成果编号" + ); +} + +#[test] +fn run_metadata_is_persisted_with_new_ledger_and_replay_keeps_original_identity() { + let temp = tempfile::tempdir().unwrap(); + let root = temp.path().join("project"); + crate::init_local_game_project_at(&root, "analytics-run", "执行身份").unwrap(); + let original = analytics_metadata("A"); + let host = temp.path().join("host"); + let session = open_with_analytics_at( + &host, + &root, + "turn", + &hash(b"request"), + false, + &Default::default(), + Some(original.clone()), + ) + .unwrap(); + assert!(session.newly_accepted); + assert_eq!( + session.snapshot().unwrap().analytics_run, + Some(original.clone()) + ); + drop(session); + let replay = open_with_analytics_at( + &host, + &root, + "turn", + &hash(b"request"), + false, + &Default::default(), + Some(analytics_metadata("B")), + ) + .unwrap(); + assert!(!replay.newly_accepted); + assert_eq!(replay.snapshot().unwrap().analytics_run, Some(original)); +} + +#[test] +fn legacy_run_without_metadata_is_not_assigned_current_users_identity() { + let (temp, session) = fixture(Default::default()); + let root = session.root.clone(); + assert!(session.snapshot().unwrap().analytics_run.is_none()); + drop(session); + let replay = open_with_analytics_at( + &temp.path().join("host"), + &root, + "turn-test", + &hash(b"request"), + false, + &Default::default(), + Some(analytics_metadata("B")), + ) + .unwrap(); + assert!(replay.snapshot().unwrap().analytics_run.is_none()); + let config = temp.path().join("config"); + std::fs::create_dir_all(&config).unwrap(); + let current = analytics_metadata("B"); + let writer = crate::analytics::store::AnalyticsWriter::start( + config, + current.context.editor_session_id.clone(), + ); + replay.set_analytics_capture(Some((current.context, writer))); + replay.record_analytics_revision(1, crate::analytics::contract::ChangeKind::Code, 1); + assert!(replay.analytics_capture().is_none()); + assert!(replay.analytics_output_revision().is_none()); +} + fn fixture(config: DirectValidationConfig) -> (tempfile::TempDir, Arc) { let temp = tempfile::tempdir().unwrap(); let root = temp.path().join("project"); @@ -13,6 +200,7 @@ fn fixture(config: DirectValidationConfig) -> (tempfile::TempDir, Arc BTreeMap>, + after: &BTreeMap>, +) -> Option<(crate::analytics::contract::ChangeKind, u64)> { + use crate::analytics::contract::ChangeKind; + let mut result = None; + for (path, before) in before { + let Some((before, after)) = before + .as_ref() + .zip(after.get(path).and_then(Option::as_ref)) + else { + continue; + }; + if before == after { + continue; + } + let Some(kind) = crate::analytics::project::file_change_kind(path) else { + continue; + }; + result = Some(match result { + None => (kind, 1), + Some((current, count)) => ( + if current == kind { + current + } else { + ChangeKind::Mixed + }, + count + 1, + ), + }); + } + result +} + fn run_transaction( root: &Path, parsed: codex_patch_parser::ApplyPatchArgs, @@ -319,6 +353,13 @@ fn run_transaction( None }; lease.finish(passed && !uncertain, changed, None)?; + if passed && !uncertain { + if let (Some(revision), Some((kind, count))) = + (revision, analytics_patch_changes(&before, &after)) + { + session.record_analytics_revision(revision, kind, count); + } + } Ok(json!({ "status": if passed && !uncertain { "completed" } else { "failed" }, "changedPaths": if started { changed_paths } else { BTreeSet::new() }, @@ -351,6 +392,47 @@ pub(super) async fn apply(root: &Path, arguments: &Value) -> Result)]| { + entries + .iter() + .map(|(path, value)| (path.to_string(), value.map(str::to_string))) + .collect() + }; + let before = fingerprints(&[ + ("game/a.js", Some("a")), + ("game/same.js", Some("same")), + ("game/unknown.js", None), + ("game/unreadable.js", Some("old")), + (".agent/state.json", Some("old")), + ]); + let after = fingerprints(&[ + ("game/a.js", Some("b")), + ("game/same.js", Some("same")), + ("game/unknown.js", Some("new")), + ("game/unreadable.js", None), + (".agent/state.json", Some("new")), + ]); + assert_eq!( + analytics_patch_changes(&before, &after), + Some((crate::analytics::contract::ChangeKind::Code, 1)) + ); + assert_eq!(analytics_patch_changes(&before, &before), None); + let before = fingerprints(&[ + ("game/a.js", Some("missing")), + ("assets/a.png", Some("old")), + ]); + let after = fingerprints(&[ + ("game/a.js", Some("new")), + ("assets/a.png", Some("missing")), + ]); + assert_eq!( + analytics_patch_changes(&before, &after), + Some((crate::analytics::contract::ChangeKind::Mixed, 2)) + ); + } + fn project() -> (tempfile::TempDir, PathBuf) { let temp = tempfile::tempdir().unwrap(); let root = temp.path().join("project"); @@ -415,15 +497,20 @@ mod tests { #[tokio::test] async fn bundled_patch_roundtrip_preserves_partial_failure_and_rejects_closed_turn() { let (temp, root) = project(); - let session = direct_execution::open_at( + let config = temp.path().join("analytics-config"); + let (metadata, context, writer) = + super::super::direct_tool_bridge::analytics_test_writer(&config); + let session = direct_execution::open_with_analytics_at( &temp.path().join("host"), &root, "patch-roundtrip", &format!("{:x}", Sha256::digest(b"request")), false, &direct_validation::DirectValidationConfig::default(), + Some(metadata), ) .unwrap(); + session.set_analytics_capture(Some((context.clone(), writer.clone()))); session .freeze_contract(json!({"fixture":"patch protocol only"})) .unwrap(); @@ -499,6 +586,29 @@ mod tests { "writes do not invent execution passes" ); assert!(session.snapshot().unwrap().active.is_empty()); + assert_eq!( + session.analytics_output_revision(), + None, + "text fixture files are not classified as成果" + ); + let outputs = apply(&root, &json!({"patch":"*** Begin Patch\n*** Add File: game/result.js\n+const result = 1;\n*** Add File: game/style.css\n+body { color: red; }\n*** End Patch"})).await.unwrap(); + assert_eq!(outputs["status"], "completed", "{outputs}"); + let revision = outputs["revision"].as_u64().unwrap().to_string(); + assert_eq!(session.analytics_output_revision(), Some(revision.clone())); + let partial_output = apply(&root, &json!({"patch":"*** Begin Patch\n*** Add File: game/partial.js\n+const partial = 1;\n*** Update File: game/absent.js\n@@\n-old\n+new\n*** End Patch"})).await.unwrap(); + assert_eq!(partial_output["status"], "failed"); + assert_eq!(session.analytics_output_revision(), Some(revision.clone())); + let events = super::super::direct_tool_bridge::drain_analytics_test_writer( + &config, &context, &writer, + ); + let revisions: Vec<_> = events + .iter() + .filter(|event| event["event_name"] == "project_revision_created") + .collect(); + assert_eq!(revisions.len(), 1); + assert_eq!(revisions[0]["user_id"], "A"); + assert_eq!(revisions[0]["properties"]["revision_id"], revision); + assert_eq!(revisions[0]["properties"]["files_changed_count"], 2); session.interrupt("fixture stopped".into()).unwrap(); assert!(apply( &root, diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_runtime/mod.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_runtime/mod.rs index 26b97678f..b7d19cda3 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_runtime/mod.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_runtime/mod.rs @@ -4243,7 +4243,44 @@ pub(crate) async fn run_direct_browser_evidence_with_cancellation_at( advisory_interaction: bool, cancellation: Option>, ) -> Result { + run_direct_browser_evidence_with_analytics_at( + root, + evidence_root, + scenario, + advisory_interaction, + cancellation, + None, + ) + .await +} + +pub(crate) async fn run_direct_browser_evidence_with_analytics_at( + root: &Path, + evidence_root: PathBuf, + scenario: Option, + advisory_interaction: bool, + cancellation: Option>, + capture: Option<( + crate::analytics::contract::Context, + crate::analytics::store::AnalyticsWriter, + )>, +) -> Result { + let observation = crate::analytics::preview::prepare( + root, + capture, + crate::analytics::contract::Source::Direct, + crate::analytics::contract::PreviewSource::Agent, + ); + let (_analytics_lease, observation) = match observation { + Some((lease, observation)) => (Some(lease), Some(observation)), + None => (None, None), + }; let (preview, stop_sender) = start_local_game_preview_for_project(root)?; + if let Some(observation) = observation { + observation + .with_cancellation(cancellation.clone()) + .schedule(preview.port); + } let validation = crate::browser::validate_local_preview_in_browser_with_cancellation( BrowserValidationInput { url: preview.url, @@ -4261,6 +4298,7 @@ pub(crate) async fn run_direct_browser_evidence_with_cancellation_at( cancellation, ) .await; + drop(_analytics_lease); let _ = stop_sender.send(()); validation } @@ -4781,6 +4819,8 @@ pub(crate) async fn run_direct_game_creator_turn_at_with_creation_type( None, None, None, + None, + None, ) .await } @@ -4792,6 +4832,11 @@ async fn run_direct_game_creator_turn_at_with_creation_type_and_emitter( turn_emitter: Option<&DirectGameCreatorTurnUpdateEmitter>, audit: Option<&mut DirectCodexTurnAudit>, direct_user_item: Option, + capture: Option<( + crate::analytics::contract::Context, + crate::analytics::store::AnalyticsWriter, + )>, + analytics_attempt_id: Option<&str>, ) -> Result { if !root.is_absolute() || !root.is_dir() { return Err("当前项目目录不存在或不是绝对路径".to_string()); @@ -4814,6 +4859,8 @@ async fn run_direct_game_creator_turn_at_with_creation_type_and_emitter( turn_emitter, audit, direct_user_item, + capture, + analytics_attempt_id, ) .await { @@ -5014,6 +5061,11 @@ async fn run_direct_game_creator_turn_inner( turn_emitter: Option<&DirectGameCreatorTurnUpdateEmitter>, audit: Option<&mut DirectCodexTurnAudit>, direct_user_item: Option, + capture: Option<( + crate::analytics::contract::Context, + crate::analytics::store::AnalyticsWriter, + )>, + analytics_attempt_id: Option<&str>, ) -> Result { let requires_contract = super::direct_delivery::requires_new_web_contract( root, @@ -5035,16 +5087,49 @@ async fn run_direct_game_creator_turn_inner( DirectCodexTurnFailure::new(DirectCodexFailureStage::CodeGeneration, error) })? .validation; - let execution_guard = - super::direct_execution::begin(root, prompt, requires_contract, execution_config) - .await - .map_err(|error| { - DirectCodexTurnFailure::new(DirectCodexFailureStage::CodeGeneration, error) - })?; + let analytics_run = capture.as_ref().map(|(context, _)| { + crate::analytics::run::Metadata::new( + context.clone(), + crate::analytics::contract::Source::Direct, + crate::analytics::contract::RunSource::UserSubmit, + ) + }); + let execution_guard = super::direct_execution::begin( + root, + prompt, + requires_contract, + execution_config, + analytics_run, + ) + .await + .map_err(|error| DirectCodexTurnFailure::new(DirectCodexFailureStage::CodeGeneration, error))?; let execution_session = execution_guard.session(); + execution_session.set_analytics_capture(capture.clone()); + let started = execution_session + .newly_accepted + .then(std::time::Instant::now); + if execution_session.newly_accepted { + if let Ok(ledger) = execution_session.snapshot() { + if let (Some((_, writer)), Some(metadata)) = (&capture, &ledger.analytics_run) { + crate::analytics::run::accepted(writer, root, &ledger.project_id, metadata); + } + } + } + // 在 guard 仍存活时冻结整体结果,避免 Drop 的中断收尾覆盖真实失败原因。 + let result: Result = async { if let Some(report) = super::direct_delivery::terminal_report(&execution_session) { return Ok(report); } + if execution_session.newly_accepted { + if let Ok(ledger) = execution_session.snapshot() { + crate::analytics::goal::accepted( + capture.clone(), + root, + &ledger.project_id, + crate::analytics::contract::Source::Direct, + ); + } + } emit_direct_game_creator_progress(root, "codex.turn", "陶泥儿正在处理这条消息"); if let Some(emitter) = turn_emitter { emitter.emit("running", Some("preparing"), None, None); @@ -5334,6 +5419,118 @@ async fn run_direct_game_creator_turn_inner( })?; } Ok(visible_reply) + }.await; + if let Ok(ledger) = execution_session.snapshot() { + if let (Some(metadata), Some((end_reason, error_code))) = ( + &ledger.analytics_run, + direct_analytics_outcome( + ledger.phase, + ledger.requires_contract || ledger.contract.is_some(), + result.is_err(), + execution_session.was_aborted(), + ), + ) { + let output_revision = execution_session.analytics_output_revision(); + crate::analytics::run::direct_finished( + capture, + root, + &ledger.project_id, + metadata, + analytics_attempt_id, + crate::analytics::run::Outcome { + turn_id: Some(ledger.client_turn_id.clone()), + end_reason, + error_code, + duration_ms: started + .and_then(|start| u64::try_from(start.elapsed().as_millis()).ok()), + output_change_detected: output_revision.as_ref().map(|_| true), + revision_id: output_revision, + }, + ); + } + } + result +} + +fn direct_analytics_outcome( + phase: super::direct_execution::ExecutionPhase, + has_contract: bool, + failed: bool, + aborted: bool, +) -> Option<( + crate::analytics::contract::RunEndReason, + Option, +)> { + use super::direct_execution::ExecutionPhase; + use crate::analytics::contract::{ErrorCode, RunEndReason}; + if phase == ExecutionPhase::Interrupted || aborted { + return None; + } + if phase == ExecutionPhase::Exhausted { + return Some((RunEndReason::Failed, Some(ErrorCode::RuntimeFailed))); + } + if failed { + // Direct 当前只保留 stage 和展示错误字符串,不从正文猜 Provider 错误类别。 + return Some(( + RunEndReason::Failed, + Some(ErrorCode::RuntimeErrorUnclassified), + )); + } + if phase == ExecutionPhase::Completed || !has_contract { + return Some((RunEndReason::Finished, None)); + } + None +} + +#[cfg(test)] +mod direct_analytics_tests { + use super::*; + use crate::agent::direct_execution::ExecutionPhase; + use crate::analytics::contract::{ErrorCode, RunEndReason}; + + #[test] + fn terminal_reports_do_not_turn_exhaustion_or_cancellation_into_success() { + assert_eq!( + direct_analytics_outcome(ExecutionPhase::Exhausted, true, false, false), + Some((RunEndReason::Failed, Some(ErrorCode::RuntimeFailed))) + ); + for failed in [true, false] { + assert_eq!( + direct_analytics_outcome(ExecutionPhase::Interrupted, true, failed, false), + None + ); + assert_eq!( + direct_analytics_outcome(ExecutionPhase::Working, false, failed, true), + None + ); + } + } + + #[test] + fn complete_delivery_does_not_hide_later_projection_failure() { + assert_eq!( + direct_analytics_outcome(ExecutionPhase::Completed, true, true, false), + Some(( + RunEndReason::Failed, + Some(ErrorCode::RuntimeErrorUnclassified) + )) + ); + assert_eq!( + direct_analytics_outcome(ExecutionPhase::Completed, true, false, false), + Some((RunEndReason::Finished, None)) + ); + assert_eq!( + direct_analytics_outcome(ExecutionPhase::Working, false, false, false), + Some((RunEndReason::Finished, None)) + ); + for phase in [ + ExecutionPhase::Working, + ExecutionPhase::Draining, + ExecutionPhase::Sealing, + ] { + assert_eq!(direct_analytics_outcome(phase, true, false, false), None); + } + } } #[cfg(test)] diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_runtime/user_input.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_runtime/user_input.rs index 43554cd85..6b3a85455 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_runtime/user_input.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_runtime/user_input.rs @@ -33,7 +33,9 @@ pub(crate) async fn chat_with_game_creator_direct_codex( user_item: DirectCodexUserItem, creation_type: Option, client_turn_id: Option, + analytics_attempt_id: Option, ) -> Result { + let capture = crate::analytics::gui::capture_writer_context(); let root = Path::new(project_path.trim()); let turn_id = normalize_direct_client_turn_id(client_turn_id.as_deref())?; let _active_invocation = DirectTaonierActiveInvocationGuard::enter(root, &turn_id)?; @@ -62,6 +64,8 @@ pub(crate) async fn chat_with_game_creator_direct_codex( // DirectProject 的完整回合权威已经落在 project.jsonl;不再创建平行审计日志。 None, canonical_user_item, + capture, + analytics_attempt_id.as_deref(), ) .await { diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tool_bridge.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tool_bridge.rs index 19790ef61..25224ba5d 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tool_bridge.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tool_bridge.rs @@ -1600,6 +1600,15 @@ fn bridge_write_file(root: &Path, arguments: &Value) -> Value { bridge_write_file_with_permit(root, arguments, None) } +fn bridge_file_content_changed(root: &Path, path: &str, content: &[u8]) -> Option { + crate::analytics::project::file_content_changed( + root, + path, + content, + DIRECT_TOOL_BRIDGE_MAX_WRITE_CONTENT_BYTES as u64, + ) +} + fn bridge_write_file_with_permit( root: &Path, arguments: &Value, @@ -1641,6 +1650,11 @@ fn bridge_write_file_with_permit( "direct-codex.file.write", )?; let lock_wait_ms = acquire_started.elapsed().as_millis(); + let analytics_change_kind = write_permit.and_then(|_| { + let kind = crate::analytics::project::file_change_kind(&path)?; + (bridge_file_content_changed(root, &path, content.as_bytes()) == Some(true)) + .then_some(kind) + }); let write_started = std::time::Instant::now(); let commit = || { let written = write_local_project_file_at(root, &path, content)?; @@ -1653,6 +1667,9 @@ fn bridge_write_file_with_permit( Some(permit) => permit.run(commit)?, None => commit()?, }; + if let (Some(permit), Some(kind)) = (write_permit, analytics_change_kind) { + permit.record_analytics_revision(revision, kind, 1); + } // 现场一次 2.6KB 写入实测 5.5 秒。只在明显偏慢时记账,正常写入不刷日志。 if lock_wait_ms + write_ms > 200 { app_log!( @@ -3473,6 +3490,82 @@ pub(in crate::agent) async fn generate_images_concurrently_for_test( .await } +#[cfg(test)] +pub(super) fn analytics_test_writer( + config: &Path, +) -> ( + crate::analytics::run::Metadata, + crate::analytics::contract::Context, + crate::analytics::store::AnalyticsWriter, +) { + use crate::analytics::{ + contract::{Context, Route, RunSource, Source}, + run, + store::AnalyticsWriter, + }; + let mut context = Context { + route: Route::from_identity(Some("A".into()), Some("https://example.com")), + editor_session_id: uuid::Uuid::new_v4().to_string(), + client_version: "1.0.0".into(), + }; + fs::create_dir_all(config).expect("create analytics test config directory"); + let metadata = run::Metadata::new(context.clone(), Source::Direct, RunSource::UserSubmit); + context.route.user_id = Some("B".into()); + let writer = AnalyticsWriter::start(config.into(), context.editor_session_id.clone()); + (metadata, context, writer) +} + +#[cfg(test)] +pub(super) fn drain_analytics_test_writer( + config: &Path, + context: &crate::analytics::contract::Context, + writer: &crate::analytics::store::AnalyticsWriter, +) -> Vec { + use crate::analytics::contract::{EntrySource, EventData, SessionStart, Source}; + let marker = context + .capture( + EventData::EditorSessionStart(SessionStart { + entry_source: EntrySource::DirectLaunch, + first_project_id: None, + }), + None, + Source::Editor, + None, + ) + .unwrap(); + let marker_id = marker.event_id.clone(); + assert!(writer.try_record(context.route.clone(), marker, marker_id.clone())); + assert!(writer.flush()); + let batches = config + .join("analytics/instances") + .join(&context.editor_session_id) + .join("batches"); + let deadline = std::time::Instant::now() + std::time::Duration::from_secs(5); + loop { + let events: Vec = fs::read_dir(&batches) + .into_iter() + .flatten() + .flatten() + .filter(|entry| !entry.file_name().to_string_lossy().starts_with('.')) + .filter_map(|entry| fs::read_to_string(entry.path().join("events.jsonl")).ok()) + .flat_map(|contents| { + contents + .lines() + .filter_map(|line| serde_json::from_str::(line).ok()) + .collect::>() + }) + .collect(); + if events.iter().any(|event| event["event_id"] == marker_id) { + return events; + } + assert!( + std::time::Instant::now() < deadline, + "analytics FIFO sentinel timed out" + ); + std::thread::sleep(std::time::Duration::from_millis(5)); + } +} + #[cfg(test)] mod tests { #[tokio::test] @@ -4262,6 +4355,293 @@ mod tests { assert_eq!(importability.get("assets/vector.svg"), Some(&true)); } + #[tokio::test] + async fn analytics_real_file_write_preserves_original_identity_and_failed_run_revision() { + use crate::analytics::{ + contract::{ErrorCode, RunEndReason}, + run, + }; + let temporary = tempfile::tempdir().unwrap(); + let root = temporary.path().join("project"); + let config = temporary.path().join("config"); + let (metadata, context, writer) = analytics_test_writer(&config); + let original_capture = Some((metadata.context.clone(), writer.clone())); + let mut lifecycle = crate::analytics::gui::LifecycleFixture::start( + metadata.context.clone(), + writer.clone(), + ); + lifecycle.create_and_open(&root, "direct-analytics"); + let session = super::super::direct_execution::open_with_analytics_at( + &temporary.path().join("host"), + &root, + "analytics-write", + &format!("{:x}", Sha256::digest(b"request")), + false, + &Default::default(), + Some(metadata.clone()), + ) + .unwrap(); + session.set_analytics_capture(Some((context.clone(), writer.clone()))); + super::super::direct_delivery::register_contract( + &root, + &session, + &json!({ + "scope": "核对当前项目宿主写入的成果采集", + "changeKind": "project", + "requirements": [{"id": "analytics-output", "kind": "artifact", "path": "game/index.html"}] + }), + ) + .await + .expect("freeze a validated delivery contract before writing"); + let project_id = session.snapshot().unwrap().project_id; + run::accepted(&writer, &root, &project_id, &metadata); + crate::analytics::goal::accepted( + original_capture.clone(), + &root, + &project_id, + crate::analytics::contract::Source::Direct, + ); + let lease = session + .admit(super::super::direct_execution::EffectKind::Write, None) + .unwrap(); + let permit = lease.write_permit().unwrap(); + let arguments = json!({"path":"game/index.html", "content":"真实预览"}); + let changed = bridge_write_file_with_permit(&root, &arguments, Some(&permit)); + assert_eq!(changed["isError"], false); + let payload: Value = + serde_json::from_str(changed["content"][0]["text"].as_str().unwrap()).unwrap(); + let revision = payload["revision"].as_u64().unwrap().to_string(); + assert_eq!(session.analytics_output_revision(), Some(revision.clone())); + assert_eq!( + bridge_write_file_with_permit(&root, &arguments, Some(&permit))["isError"], + false + ); + assert_eq!( + bridge_write_file_with_permit( + &root, + &json!({"path":"../bad.js","content":"bad"}), + Some(&permit) + )["isError"], + true + ); + assert_eq!(session.analytics_output_revision(), Some(revision.clone())); + lease.finish(true, true, None).unwrap(); + let attempt = uuid::Uuid::new_v4().to_string(); + run::direct_finished( + Some((context.clone(), writer.clone())), + &root, + &project_id, + &metadata, + Some(&attempt), + run::Outcome { + turn_id: Some("analytics-write".into()), + end_reason: RunEndReason::Failed, + error_code: Some(ErrorCode::RuntimeErrorUnclassified), + duration_ms: None, + output_change_detected: Some(true), + revision_id: session.analytics_output_revision(), + }, + ); + run::settle(Some((context.clone(), writer.clone())), &attempt, false); + // 默认项目使用 npm:预览服务读取真实构建目录,夹具提供构建入口,不调用构建器。 + let served_root = crate::project_game_root(&root); + fs::create_dir_all(&served_root).unwrap(); + fs::write( + served_root.join("index.html"), + "真实预览构建", + ) + .unwrap(); + let (preview_lease, observation) = crate::analytics::preview::prepare( + &root, + original_capture.clone(), + crate::analytics::contract::Source::Editor, + crate::analytics::contract::PreviewSource::User, + ) + .unwrap(); + let (preview, stop) = crate::start_local_game_preview_for_project(&root).unwrap(); + observation.observe(preview.port).await; + let preview_revision = crate::read_game_creator_agent_runtime_project_revision(&root) + .unwrap() + .revision + .to_string(); + drop(preview_lease); + let _ = stop.send(()); + let checkpoint = crate::commands::checkpoint_with_capture_for_test( + root.to_string_lossy().into_owned(), + original_capture, + ) + .unwrap(); + lifecycle.exit(); + let events = drain_analytics_test_writer(&config, &context, &writer); + let ids: std::collections::HashSet<_> = events + .iter() + .map(|event| event["event_id"].as_str().unwrap()) + .collect(); + assert_eq!(ids.len(), events.len()); + let chain: Vec<_> = events + .iter() + .filter(|event| event["user_id"] == "A") + .collect(); + for name in [ + "editor_session_start", + "editor_focus_start", + "project_create_success", + "project_open", + "creative_task_submit", + "project_revision_created", + "agent_run_failed", + "preview_ready", + "project_save", + "editor_focus_end", + "editor_session_end", + ] { + assert_eq!( + chain + .iter() + .filter(|event| event["event_name"] == name) + .count(), + 1, + "{name}" + ); + } + for event in &chain { + assert_eq!( + event["editor_session_id"], + metadata.context.editor_session_id + ); + if !event["project_id"].is_null() { + assert_eq!(event["project_id"], project_id); + } + if !event["creative_task_id"].is_null() { + assert_eq!(event["creative_task_id"], project_id); + } + if !event["agent_run_id"].is_null() { + assert_eq!(event["agent_run_id"], metadata.run_id); + } + let name = event["event_name"].as_str().unwrap(); + if matches!( + name, + "project_create_success" + | "project_open" + | "creative_task_submit" + | "project_revision_created" + | "agent_run_failed" + | "preview_ready" + | "project_save" + ) { + assert_eq!( + event["project_id"], project_id, + "{name} must identify its project" + ); + } + if matches!( + name, + "creative_task_submit" + | "project_revision_created" + | "agent_run_failed" + | "preview_ready" + | "project_save" + ) { + assert_eq!( + event["creative_task_id"], project_id, + "{name} must identify its goal" + ); + } + if name == "agent_run_failed" { + assert_eq!(event["agent_run_id"], metadata.run_id); + assert_eq!(event["agent_turn_id"], "analytics-write"); + } + } + let save = chain + .iter() + .find(|event| event["event_name"] == "project_save") + .unwrap(); + assert_eq!(save["properties"]["save_source"], "checkpoint"); + assert!(Path::new(&checkpoint.checkpoint_path).is_dir()); + let mut digest = Sha256::new(); + digest.update(serde_json::to_vec(&metadata.context.route).unwrap()); + digest.update([0]); + digest.update(format!("{project_id}:{}:project_save", checkpoint.checkpoint_id).as_bytes()); + let checkpoint_fact = format!("{:x}", digest.finalize()); + let batches = config + .join("analytics/instances") + .join(&context.editor_session_id) + .join("batches"); + let checkpoint_fact_matches = fs::read_dir(batches) + .unwrap() + .flatten() + .filter_map(|entry| fs::read(entry.path().join("meta.json")).ok()) + .filter_map(|bytes| serde_json::from_slice::(&bytes).ok()) + .filter(|batch| batch["facts"][&checkpoint_fact] == save["event_id"]) + .count(); + assert_eq!( + checkpoint_fact_matches, 1, + "save fact must use the actual checkpoint ID" + ); + let ready = chain + .iter() + .find(|event| event["event_name"] == "preview_ready") + .unwrap(); + assert_eq!(ready["properties"]["preview_version"], preview_revision); + let focus_start = chain + .iter() + .find(|event| event["event_name"] == "editor_focus_start") + .unwrap(); + let focus_end = chain + .iter() + .find(|event| event["event_name"] == "editor_focus_end") + .unwrap(); + assert_eq!( + focus_start["properties"]["focus_interval_id"], + focus_end["properties"]["focus_interval_id"] + ); + let revisions: Vec<_> = events + .iter() + .filter(|event| event["event_name"] == "project_revision_created") + .collect(); + assert_eq!(revisions.len(), 1); + assert_eq!(revisions[0]["user_id"], "A"); + assert_eq!(revisions[0]["properties"]["revision_id"], revision); + let failed: Vec<_> = events + .iter() + .filter(|event| event["event_name"] == "agent_run_failed") + .collect(); + assert_eq!(failed.len(), 1); + assert_eq!(failed[0]["user_id"], "A"); + assert_eq!(failed[0]["properties"]["revision_id"], revision); + assert_eq!(failed[0]["properties"]["output_change_detected"], true); + } + + #[test] + fn analytics_file_comparison_requires_known_bounded_content() { + let temporary = tempfile::tempdir().unwrap(); + let root = temporary.path(); + assert_eq!( + bridge_file_content_changed(root, "new.js", b"new"), + Some(true) + ); + fs::write(root.join("new.js"), b"new").unwrap(); + assert_eq!( + bridge_file_content_changed(root, "new.js", b"new"), + Some(false) + ); + assert_eq!( + bridge_file_content_changed(root, "new.js", b"changed"), + Some(true) + ); + fs::create_dir(root.join("directory.js")).unwrap(); + assert_eq!( + bridge_file_content_changed(root, "directory.js", b"new"), + None + ); + fs::write( + root.join("large.js"), + vec![0; DIRECT_TOOL_BRIDGE_MAX_WRITE_CONTENT_BYTES + 1], + ) + .unwrap(); + assert_eq!(bridge_file_content_changed(root, "large.js", b"new"), None); + } + #[test] fn bridge_write_file_writes_project_relative_text_without_runtime_tasks() { let temporary = tempfile::tempdir().expect("create direct write root"); diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_validation.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_validation.rs index 2c62c5b18..33b849435 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_validation.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_validation.rs @@ -453,12 +453,15 @@ async fn run_browser_with_budget( sequence, ), )?; - let evidence = super::direct_runtime::run_direct_browser_evidence_with_cancellation_at( + let evidence = super::direct_runtime::run_direct_browser_evidence_with_analytics_at( root, evidence_root, scenario, false, reservation.as_ref().map(|r| r.session.cancel_flag()), + reservation + .as_ref() + .and_then(|r| r.session.analytics_capture()), ) .await; let (result, passed) = match evidence { diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/design_session.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/design_session.rs index 10f26a650..2b1833ef9 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/design_session.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/design_session.rs @@ -126,6 +126,9 @@ pub(crate) struct DesignTurn { pub(crate) attempt: u32, #[serde(default, skip_serializing_if = "Option::is_none")] pub(crate) model_selection: Option, + /// 仅持久化埋点关联,旧回合缺失时不补历史执行。 + #[serde(default, skip_serializing_if = "Option::is_none")] + pub(crate) analytics: Option, } /// 仅保存恢复所需的用户选择,不包含连接配置或凭据。 diff --git a/apps/ai-game-creator-shell/src-tauri/src/analytics/contract.rs b/apps/ai-game-creator-shell/src-tauri/src/analytics/contract.rs new file mode 100644 index 000000000..2c3e38b94 --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/src/analytics/contract.rs @@ -0,0 +1,529 @@ +//! 产品事件合同。正文和凭据不属于此模块的输入,nullable 字段仍必须显式存在。 +use chrono::{DateTime, SecondsFormat, Utc}; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_json::Value; +use std::time::{SystemTime, UNIX_EPOCH}; +use uuid::Uuid; + +const MAX_SAFE_INTEGER: u64 = 9_007_199_254_740_991; + +fn required_nullable<'de, D, T>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, + T: Deserialize<'de>, +{ + Option::::deserialize(deserializer) +} + +macro_rules! values { + ($name:ident { $($variant:ident),+ $(,)? }) => { + #[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)] + #[serde(rename_all = "snake_case")] + pub(crate) enum $name { $($variant),+ } + }; +} + +values!(Source { + Editor, + Direct, + DesignAgent, + AssetCanvas, + ResourceEditor, + UiEditor, + Manual, + System +}); +values!(Status { Success, Failed }); +values!(EntrySource { + DirectLaunch, + ProjectAssociation, + AppRestore +}); +values!(SessionEndReason { + UserExit, + AppRestart +}); +values!(FocusReason { + InitialFocus, + WindowFocus, + Restore, + AccountChange +}); +values!(BlurReason { + WindowBlur, + Minimized, + AppExit, + SystemSuspend, + AccountChange +}); +values!(CreationSource { + HomeGame, + HomeDesign, + Template, + SelectedDirectory +}); +values!(OpenSource { + Create, + Picker, + Recent, + AppRestore, + ProjectAssociation +}); +values!(AgentType { + GameAgent, + DesignAgent +}); +values!(RunSource { + UserSubmit, + UserContinue, + Clarification, + Approval, + UserRetry +}); +values!(RunEndReason { + Finished, + WaitingForUser, + WaitingForApproval, + Failed +}); +values!(ErrorCode { + ProviderAuthFailed, + ProviderRateLimited, + ProviderUnavailable, + ProviderTimeout, + ProviderInvalidResponse, + LocalIoFailed, + RuntimeFailed, + RuntimeErrorUnclassified +}); +values!(RevisionSource { + Agent, + AssetCanvas, + ResourceEditor, + UiEditor, + ManualEdit, + SystemProjection +}); +values!(ChangeKind { + Code, + Asset, + Ui, + DesignDocument, + Mixed +}); +values!(PreviewSource { + User, + Agent, + AutoRestore +}); +values!(SaveSource { + Manual, + Auto, + Checkpoint +}); +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] +#[serde(deny_unknown_fields)] +pub(crate) struct Route { + #[serde(deserialize_with = "required_nullable")] + pub destination_origin: Option, + #[serde(deserialize_with = "required_nullable")] + pub user_id: Option, +} + +impl Route { + pub fn from_identity(user_id: Option, api_base_url: Option<&str>) -> Self { + let destination_origin = api_base_url.and_then(|raw| { + let parsed = url::Url::parse(raw).ok()?; + (matches!(parsed.scheme(), "http" | "https") + && parsed.host_str().is_some() + && parsed.username().is_empty() + && parsed.password().is_none()) + .then(|| parsed.origin().ascii_serialization()) + }); + Self { + user_id, + destination_origin, + } + } + + pub fn validate(&self) -> bool { + optional_id(&self.user_id) + && self.destination_origin.as_ref().is_none_or(|origin| { + origin.len() <= 2048 + && Self::from_identity(None, Some(origin)) + .destination_origin + .as_ref() + == Some(origin) + }) + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub(crate) struct SessionStart { + pub entry_source: EntrySource, + #[serde(deserialize_with = "required_nullable")] + pub first_project_id: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub(crate) struct SessionEnd { + pub end_reason: SessionEndReason, + #[serde(deserialize_with = "required_nullable")] + pub session_duration_ms: Option, + #[serde(deserialize_with = "required_nullable")] + pub last_project_id: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub(crate) struct FocusStart { + pub focus_interval_id: String, + pub focus_reason: FocusReason, + #[serde(deserialize_with = "required_nullable")] + pub active_project_id: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub(crate) struct FocusEnd { + pub focus_interval_id: String, + pub blur_reason: BlurReason, + #[serde(deserialize_with = "required_nullable")] + pub focus_duration_ms: Option, + #[serde(deserialize_with = "required_nullable")] + pub active_project_id: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub(crate) struct ProjectCreated { + pub creation_source: CreationSource, + #[serde(skip_serializing_if = "Option::is_none")] + pub project_template_id: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub(crate) struct ProjectOpened { + pub open_source: OpenSource, + #[serde(deserialize_with = "required_nullable")] + pub is_first_open: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub(crate) struct EmptyProperties {} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub(crate) struct RunFinished { + pub agent_type: AgentType, + pub run_source: RunSource, + #[serde(deserialize_with = "required_nullable")] + pub duration_ms: Option, + pub retry_index: u64, + #[serde(deserialize_with = "required_nullable")] + pub output_change_detected: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub revision_id: Option, + pub end_reason: RunEndReason, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub(crate) struct RevisionCreated { + pub revision_id: String, + pub revision_source: RevisionSource, + pub change_kind: ChangeKind, + #[serde(skip_serializing_if = "Option::is_none")] + pub files_changed_count: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub(crate) struct PreviewReady { + pub preview_source: PreviewSource, + pub preview_version: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub ready_duration_ms: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub(crate) struct ProjectSaved { + pub save_source: SaveSource, + #[serde(skip_serializing_if = "Option::is_none")] + pub revision_id: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde( + tag = "event_name", + content = "properties", + rename_all = "snake_case", + deny_unknown_fields +)] +pub(crate) enum EventData { + EditorSessionStart(SessionStart), + EditorSessionEnd(SessionEnd), + EditorFocusStart(FocusStart), + EditorFocusEnd(FocusEnd), + ProjectCreateSuccess(ProjectCreated), + ProjectOpen(ProjectOpened), + CreativeTaskSubmit(EmptyProperties), + AgentRunCompleted(RunFinished), + AgentRunFailed(RunFinished), + ProjectRevisionCreated(RevisionCreated), + PreviewReady(PreviewReady), + ProjectSave(ProjectSaved), +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub(crate) struct Event { + pub schema_version: u32, + pub event_id: String, + pub event_name: String, + pub event_time: String, + #[serde(deserialize_with = "required_nullable")] + pub user_id: Option, + pub editor_session_id: String, + #[serde(deserialize_with = "required_nullable")] + pub project_id: Option, + #[serde(deserialize_with = "required_nullable")] + pub creative_task_id: Option, + #[serde(deserialize_with = "required_nullable")] + pub agent_run_id: Option, + #[serde(deserialize_with = "required_nullable")] + pub agent_turn_id: Option, + #[serde(deserialize_with = "required_nullable")] + pub status: Option, + #[serde(deserialize_with = "required_nullable")] + pub error_code: Option, + pub source: Source, + pub client_version: String, + pub properties: Value, +} + +/// 每次操作先冻结此上下文。它不持有登录凭据,也不在后台重新读取当前账号。 +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[serde(deny_unknown_fields)] +pub(crate) struct Context { + pub route: Route, + pub editor_session_id: String, + pub client_version: String, +} + +#[derive(Clone, Debug)] +pub(crate) struct RunIdentity { + pub run_id: String, + pub turn_id: Option, + pub error_code: Option, +} + +impl Context { + pub fn capture( + &self, + data: EventData, + project_id: Option, + source: Source, + run: Option, + ) -> Result { + if !self.route.validate() { + return Err("invalid_route"); + } + let status = data.status(); + let creative_task_id = data.has_goal().then(|| project_id.clone()).flatten(); + let payload = serde_json::to_value(data).map_err(|_| "serialize_failed")?; + let event = Event { + schema_version: 1, + event_id: Uuid::new_v4().to_string(), + event_name: payload["event_name"] + .as_str() + .ok_or("invalid_event")? + .to_string(), + event_time: timestamp_now(), + user_id: self.route.user_id.clone(), + editor_session_id: self.editor_session_id.clone(), + project_id, + creative_task_id, + agent_run_id: run.as_ref().map(|r| r.run_id.clone()), + agent_turn_id: run.as_ref().and_then(|r| r.turn_id.clone()), + error_code: run.and_then(|r| r.error_code), + status, + source, + client_version: self.client_version.clone(), + properties: payload["properties"].clone(), + }; + event.validate()?; + Ok(event) + } +} + +impl EventData { + fn status(&self) -> Option { + match self { + Self::EditorFocusStart(_) | Self::EditorFocusEnd(_) => None, + Self::AgentRunFailed(_) => Some(Status::Failed), + _ => Some(Status::Success), + } + } + + fn has_goal(&self) -> bool { + matches!( + self, + Self::CreativeTaskSubmit(_) + | Self::AgentRunCompleted(_) + | Self::AgentRunFailed(_) + | Self::ProjectRevisionCreated(_) + | Self::PreviewReady(_) + | Self::ProjectSave(_) + ) + } +} + +impl Event { + pub fn data(&self) -> Result { + // 可选字段不可得时省略;显式 null 仅用于合同指定的 nullable 字段。 + let optional = match self.event_name.as_str() { + "project_create_success" => &["project_template_id"][..], + "agent_run_completed" | "agent_run_failed" | "project_save" => &["revision_id"][..], + "project_revision_created" => &["files_changed_count"][..], + "preview_ready" => &["ready_duration_ms"][..], + _ => &[][..], + }; + if optional + .iter() + .any(|key| self.properties.get(key).is_some_and(Value::is_null)) + { + return Err("invalid_optional_property"); + } + serde_json::from_value(serde_json::json!({ + "event_name": self.event_name, + "properties": self.properties, + })) + .map_err(|_| "invalid_properties") + } + + pub fn validate(&self) -> Result<(), &'static str> { + if self.schema_version != 1 + || !uuid(&self.event_id) + || !uuid(&self.editor_session_id) + || !id(&self.client_version) + || !optional_id(&self.user_id) + || !optional_id(&self.project_id) + || !optional_id(&self.creative_task_id) + || !optional_id(&self.agent_turn_id) + || !valid_time(&self.event_time) + { + return Err("invalid_envelope"); + } + let data = self.data()?; + if self.status != data.status() + || self.error_code.is_some() != matches!(data, EventData::AgentRunFailed(_)) + { + return Err("invalid_status"); + } + if data.has_goal() { + if self.project_id.is_none() || self.creative_task_id != self.project_id { + return Err("invalid_goal"); + } + } else if self.creative_task_id.is_some() { + return Err("unexpected_goal"); + } + let is_run = matches!( + data, + EventData::AgentRunCompleted(_) | EventData::AgentRunFailed(_) + ); + if is_run { + if !self.agent_run_id.as_deref().is_some_and(uuid) { + return Err("invalid_run"); + } + } else if self.agent_run_id.is_some() || self.agent_turn_id.is_some() { + return Err("unexpected_run"); + } + let editor = self.source == Source::Editor; + let agent = matches!(self.source, Source::Direct | Source::DesignAgent); + let valid = match data { + EventData::EditorSessionStart(p) => editor && p.first_project_id == self.project_id, + EventData::EditorSessionEnd(p) => { + editor && p.last_project_id == self.project_id && safe(p.session_duration_ms) + } + EventData::EditorFocusStart(p) => { + editor && uuid(&p.focus_interval_id) && p.active_project_id == self.project_id + } + EventData::EditorFocusEnd(p) => { + editor + && uuid(&p.focus_interval_id) + && p.active_project_id == self.project_id + && safe(p.focus_duration_ms) + } + EventData::ProjectCreateSuccess(p) => { + editor && self.project_id.is_some() && optional_id(&p.project_template_id) + } + EventData::ProjectOpen(_) => editor && self.project_id.is_some(), + EventData::CreativeTaskSubmit(_) => agent, + EventData::AgentRunCompleted(p) | EventData::AgentRunFailed(p) => { + agent + && ((self.source == Source::Direct) == (p.agent_type == AgentType::GameAgent)) + && ((self.status == Some(Status::Failed)) + == (p.end_reason == RunEndReason::Failed)) + && safe(p.duration_ms) + && safe(Some(p.retry_index)) + && optional_id(&p.revision_id) + } + EventData::ProjectRevisionCreated(p) => { + id(&p.revision_id) + && safe(p.files_changed_count) + && match p.revision_source { + RevisionSource::Agent => agent, + RevisionSource::AssetCanvas => self.source == Source::AssetCanvas, + RevisionSource::ResourceEditor => self.source == Source::ResourceEditor, + RevisionSource::UiEditor => self.source == Source::UiEditor, + RevisionSource::ManualEdit => self.source == Source::Manual, + RevisionSource::SystemProjection => self.source == Source::System, + } + } + EventData::PreviewReady(p) => id(&p.preview_version) && safe(p.ready_duration_ms), + EventData::ProjectSave(p) => optional_id(&p.revision_id), + }; + if valid { + Ok(()) + } else { + Err("invalid_event_fields") + } + } +} + +fn id(value: &str) -> bool { + !value.trim().is_empty() && value.len() <= 256 && !value.chars().any(char::is_control) +} +fn optional_id(value: &Option) -> bool { + value.as_deref().is_none_or(id) +} +fn uuid(value: &str) -> bool { + Uuid::parse_str(value).is_ok_and(|v| v.get_version_num() == 4 && v.to_string() == value) +} +fn safe(value: Option) -> bool { + value.is_none_or(|v| v <= MAX_SAFE_INTEGER) +} +pub(super) fn valid_time(value: &str) -> bool { + DateTime::parse_from_rfc3339(value) + .is_ok_and(|v| v.to_utc().to_rfc3339_opts(SecondsFormat::Millis, true) == value) +} + +pub(crate) fn timestamp_now() -> String { + let ms = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_millis(); + DateTime::::from_timestamp_millis(ms.min(i64::MAX as u128) as i64) + .unwrap_or_default() + .to_rfc3339_opts(SecondsFormat::Millis, true) +} + +#[cfg(test)] +#[path = "contract_tests.rs"] +mod tests; diff --git a/apps/ai-game-creator-shell/src-tauri/src/analytics/contract_tests.rs b/apps/ai-game-creator-shell/src-tauri/src/analytics/contract_tests.rs new file mode 100644 index 000000000..25eacdf5c --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/src/analytics/contract_tests.rs @@ -0,0 +1,277 @@ +use super::*; +use serde_json::json; + +fn context() -> Context { + Context { + route: Route::from_identity(Some("123".into()), Some("https://example.com/api")), + editor_session_id: Uuid::new_v4().to_string(), + client_version: "0.1.67".into(), + } +} + +fn run() -> RunFinished { + RunFinished { + agent_type: AgentType::GameAgent, + run_source: RunSource::UserSubmit, + duration_ms: None, + retry_index: 0, + output_change_detected: None, + revision_id: None, + end_reason: RunEndReason::Finished, + } +} + +fn samples() -> Vec { + let mut failed = run(); + failed.end_reason = RunEndReason::Failed; + let values = vec![ + ( + EventData::EditorSessionStart(SessionStart { + entry_source: EntrySource::DirectLaunch, + first_project_id: None, + }), + None, + Source::Editor, + ), + ( + EventData::EditorSessionEnd(SessionEnd { + end_reason: SessionEndReason::UserExit, + session_duration_ms: Some(10), + last_project_id: None, + }), + None, + Source::Editor, + ), + ( + EventData::EditorFocusStart(FocusStart { + focus_interval_id: Uuid::new_v4().to_string(), + focus_reason: FocusReason::InitialFocus, + active_project_id: None, + }), + None, + Source::Editor, + ), + ( + EventData::EditorFocusEnd(FocusEnd { + focus_interval_id: Uuid::new_v4().to_string(), + blur_reason: BlurReason::WindowBlur, + focus_duration_ms: None, + active_project_id: None, + }), + None, + Source::Editor, + ), + ( + EventData::ProjectCreateSuccess(ProjectCreated { + creation_source: CreationSource::HomeGame, + project_template_id: None, + }), + Some("project".into()), + Source::Editor, + ), + ( + EventData::ProjectOpen(ProjectOpened { + open_source: OpenSource::Recent, + is_first_open: None, + }), + Some("project".into()), + Source::Editor, + ), + ( + EventData::CreativeTaskSubmit(EmptyProperties {}), + Some("project".into()), + Source::Direct, + ), + ( + EventData::AgentRunCompleted(run()), + Some("project".into()), + Source::Direct, + ), + ( + EventData::AgentRunFailed(failed), + Some("project".into()), + Source::Direct, + ), + ( + EventData::ProjectRevisionCreated(RevisionCreated { + revision_id: "42".into(), + revision_source: RevisionSource::UiEditor, + change_kind: ChangeKind::Ui, + files_changed_count: Some(1), + }), + Some("project".into()), + Source::UiEditor, + ), + ( + EventData::PreviewReady(PreviewReady { + preview_source: PreviewSource::User, + preview_version: "42".into(), + ready_duration_ms: None, + }), + Some("project".into()), + Source::Editor, + ), + ( + EventData::ProjectSave(ProjectSaved { + save_source: SaveSource::Checkpoint, + revision_id: Some("42".into()), + }), + Some("project".into()), + Source::Manual, + ), + ]; + values + .into_iter() + .map(|(data, project, source)| { + let identity = matches!( + data, + EventData::AgentRunCompleted(_) | EventData::AgentRunFailed(_) + ) + .then(|| RunIdentity { + run_id: Uuid::new_v4().to_string(), + turn_id: Some("real-turn".into()), + error_code: matches!(data, EventData::AgentRunFailed(_)) + .then_some(ErrorCode::RuntimeErrorUnclassified), + }); + context().capture(data, project, source, identity).unwrap() + }) + .collect() +} + +#[test] +fn all_events_round_trip_with_explicit_nullable_envelopes() { + let events = samples(); + assert_eq!(events.len(), 12); + for event in events { + let value = serde_json::to_value(&event).unwrap(); + assert_eq!(value.as_object().unwrap().len(), 15); + let decoded: Event = serde_json::from_value(value).unwrap(); + decoded.validate().unwrap(); + assert_eq!(decoded.event_id, event.event_id); + assert_eq!(decoded.event_time, event.event_time); + } +} + +#[test] +fn missing_top_level_fields_and_extra_fields_are_rejected() { + for event in samples() { + let value = serde_json::to_value(event).unwrap(); + for field in value.as_object().unwrap().keys() { + let mut missing = value.clone(); + missing.as_object_mut().unwrap().remove(field); + assert!( + serde_json::from_value::(missing).is_err(), + "missing {field}" + ); + } + let mut extra = value; + extra["prompt"] = json!("must not be accepted"); + assert!(serde_json::from_value::(extra).is_err()); + } +} + +#[test] +fn event_properties_are_closed_and_nullable_fields_are_required() { + for event in samples() { + let mut extra = event.clone(); + extra.properties["access_token"] = json!("never collected"); + assert!(extra.validate().is_err()); + for (field, value) in event.properties.as_object().unwrap() { + if !value.is_null() { + continue; + } + let mut missing = event.clone(); + missing.properties.as_object_mut().unwrap().remove(field); + assert!( + missing.validate().is_err(), + "{} missing {field}", + event.event_name + ); + } + } + let mut nested = samples().pop().unwrap(); + nested.properties["pending_approval"] = + json!({"request_id":"a", "phase":"concept", "question":"private"}); + assert!(nested.validate().is_err()); + nested.properties["pending_approval"] = Value::Null; + nested.properties["pending_clarification"] = json!({"request_id":"a", "options":[]}); + assert!(nested.validate().is_err()); +} + +#[test] +fn inconsistent_identity_status_and_numbers_are_rejected() { + let event = samples() + .into_iter() + .find(|e| e.event_name == "agent_run_completed") + .unwrap(); + let mutate: Vec<(&str, Value)> = vec![ + ("creative_task_id", json!("other-project")), + ("project_id", Value::Null), + ("agent_run_id", json!("project")), + ("status", json!("failed")), + ("source", json!("design_agent")), + ("error_code", json!("runtime_failed")), + ("schema_version", json!(2)), + ("event_time", json!("2026-09-21T00:00:00Z")), + ("event_id", json!("not-a-uuid")), + ("user_id", json!("")), + ]; + for (key, value) in mutate { + let mut raw = serde_json::to_value(&event).unwrap(); + raw[key] = value; + let invalid: Event = serde_json::from_value(raw).unwrap(); + assert!(invalid.validate().is_err(), "{key}"); + } + for (key, value) in [ + ("duration_ms", json!(-1)), + ("retry_index", json!(MAX_SAFE_INTEGER + 1)), + ("duration_ms", json!(1.5)), + ] { + let mut invalid = event.clone(); + invalid.properties[key] = value; + assert!(invalid.validate().is_err()); + } +} + +#[test] +fn frozen_context_and_origin_do_not_inherit_new_account() { + let a = context(); + let mut b = a.clone(); + b.route = Route::from_identity( + Some("456".into()), + Some("https://other.example.com/api?token=private"), + ); + let event = a + .capture( + EventData::CreativeTaskSubmit(EmptyProperties {}), + Some("p".into()), + Source::Direct, + None, + ) + .unwrap(); + assert_eq!(event.user_id.as_deref(), Some("123")); + assert_eq!( + a.route.destination_origin.as_deref(), + Some("https://example.com") + ); + assert_eq!( + b.route.destination_origin.as_deref(), + Some("https://other.example.com") + ); + assert_eq!( + Route::from_identity(None, Some("file:///private")).destination_origin, + None + ); + assert_eq!( + Route::from_identity(None, Some("https://user:secret@example.com")).destination_origin, + None + ); + assert!( + Route { + user_id: None, + destination_origin: Some("https://example.com/api".into()) + } + .validate() + == false + ); +} diff --git a/apps/ai-game-creator-shell/src-tauri/src/analytics/design.rs b/apps/ai-game-creator-shell/src-tauri/src/analytics/design.rs new file mode 100644 index 000000000..e3c4d42c3 --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/src/analytics/design.rs @@ -0,0 +1,55 @@ +//! 策划阶段推进按约定视为成果变化;不检查文档版本或记录工作流快照。 +use super::contract::{ChangeKind, Context, EventData, RevisionCreated, RevisionSource, Source}; +use super::store::AnalyticsWriter; + +pub(crate) struct PhaseChange { + context: Context, + writer: AnalyticsWriter, + project_id: String, + revision_id: String, +} + +impl PhaseChange { + pub(crate) fn new( + capture: Option<(Context, AnalyticsWriter)>, + project_id: &str, + session_id: &str, + previous_phase: &str, + phase: &str, + ) -> Option { + if previous_phase == phase { + return None; + } + let (context, writer) = capture?; + Some(Self { + context, + writer, + project_id: project_id.to_string(), + revision_id: format!("design:{session_id}:{phase}"), + }) + } + + pub(crate) fn revision_id(&self) -> &str { + &self.revision_id + } + + // 必须在阶段与审批命令成功持久化后调用,时间与事件 ID 在此刻生成。 + pub(crate) fn record(self) { + let key = format!( + "{}:{}:project_revision_created", + self.project_id, self.revision_id + ); + let data = EventData::ProjectRevisionCreated(RevisionCreated { + revision_id: self.revision_id, + revision_source: RevisionSource::Agent, + change_kind: ChangeKind::DesignDocument, + files_changed_count: None, + }); + if let Ok(event) = + self.context + .capture(data, Some(self.project_id), Source::DesignAgent, None) + { + self.writer.try_record(self.context.route, event, key); + } + } +} diff --git a/apps/ai-game-creator-shell/src-tauri/src/analytics/goal.rs b/apps/ai-game-creator-shell/src-tauri/src/analytics/goal.rs new file mode 100644 index 000000000..c01db32bd --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/src/analytics/goal.rs @@ -0,0 +1,285 @@ +//! 新建项目的目标采集资格。只在后台持锁读改写,不等待业务线程。 +use super::contract::{Context, EmptyProperties, Event, EventData, Route, Source}; +use super::store::AnalyticsWriter; +use serde::{Deserialize, Serialize}; +use std::collections::HashSet; +use std::path::{Path, PathBuf}; +use std::sync::{Mutex, OnceLock}; + +const MARKER: &str = ".agent/analytics-goal.json"; +const MAX_MARKER_BYTES: usize = 4096; +const MAX_PENDING_PROJECTS: usize = 1024; +const MAX_PENDING_BYTES: usize = 1024 * 1024; + +#[derive(Default)] +struct PendingGoals { + projects: HashSet<(PathBuf, String)>, + bytes: usize, +} + +impl PendingGoals { + fn remember(&mut self, root: &Path, project_id: &str) { + let key = (root.to_path_buf(), project_id.to_owned()); + let bytes = root.as_os_str().as_encoded_bytes().len() + project_id.len(); + if self.projects.len() < MAX_PENDING_PROJECTS + && self.bytes.saturating_add(bytes) <= MAX_PENDING_BYTES + && self.projects.insert(key) + { + self.bytes += bytes; + } + } + + fn forget(&mut self, root: &Path, project_id: &str) { + if let Some((root, project_id)) = self + .projects + .take(&(root.to_path_buf(), project_id.to_owned())) + { + self.bytes -= root.as_os_str().as_encoded_bytes().len() + project_id.len(); + } + } +} + +fn pending() -> &'static Mutex { + static PENDING: OnceLock> = OnceLock::new(); + PENDING.get_or_init(|| Mutex::new(PendingGoals::default())) +} + +fn forget_pending(root: &Path, project_id: &str) { + pending() + .lock() + .unwrap_or_else(|error| error.into_inner()) + .forget(root, project_id); +} + +#[derive(Serialize)] +pub(super) enum Request { + Created { + root: PathBuf, + project_id: String, + }, + Accepted { + root: PathBuf, + route: Route, + event: Event, + }, +} + +impl Request { + pub(super) fn validate(&self) -> bool { + let (root, project_id) = match self { + Self::Created { root, project_id } => (root, Some(project_id.as_str())), + Self::Accepted { root, route, event } => { + if !route.validate() + || route.user_id != event.user_id + || event.event_name != "creative_task_submit" + || event.validate().is_err() + || !matches!(event.source, Source::Direct | Source::DesignAgent) + { + return false; + } + (root, event.project_id.as_deref()) + } + }; + root.is_absolute() + && root.as_os_str().len() <= 32768 + && project_id.is_some_and(|id| { + !id.trim().is_empty() && id.len() <= 256 && !id.chars().any(char::is_control) + }) + } +} + +#[derive(Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +struct Marker { + schema_version: u32, + project_id: String, + submitted: bool, +} + +pub(crate) fn created(writer: Option<&AnalyticsWriter>, root: &Path, project_id: &str) { + let request = Request::Created { + root: root.into(), + project_id: project_id.into(), + }; + if !request.validate() { + return; + } + // 只串行修改有界内存;任何路径检查、文件锁和落盘均留在后台。 + pending() + .lock() + .unwrap_or_else(|error| error.into_inner()) + .remember(root, project_id); + if let Some(writer) = writer { + writer.try_goal(request); + } +} + +pub(super) fn retry_pending(writer: &AnalyticsWriter) { + let projects: Vec<_> = pending() + .lock() + .unwrap_or_else(|error| error.into_inner()) + .projects + .iter() + .cloned() + .collect(); + for (root, project_id) in projects { + // 投递失败不移除资格;后续真实受理仍可重试。 + writer.try_goal(Request::Created { root, project_id }); + } +} + +// 调用方已取得项目独立埋点锁;不得在文件 I/O 期间持有 pending 内存锁。 +fn initialize_pending(root: &Path, project_id: &str, path: &Path) -> Result<(), String> { + let known_created = pending() + .lock() + .unwrap_or_else(|error| error.into_inner()) + .projects + .contains(&(root.to_path_buf(), project_id.to_owned())); + if !known_created { + return Ok(()); + } + let backup = crate::agent::agent_runtime_json_sidecar_backup_path(path); + for candidate in [path, backup.as_path()] { + match std::fs::symlink_metadata(candidate) { + Ok(_) => { + // 已有主标记或恢复副本,无论完好与否都不重授资格。 + forget_pending(root, project_id); + return Ok(()); + } + Err(error) if error.kind() == std::io::ErrorKind::NotFound => {} + Err(error) => return Err(error.to_string()), + } + } + crate::agent::write_agent_runtime_json_sidecar_with_max_bytes( + root, + MARKER, + "埋点目标资格", + &Marker { + schema_version: 1, + project_id: project_id.into(), + submitted: false, + }, + MAX_MARKER_BYTES, + )?; + forget_pending(root, project_id); + Ok(()) +} + +pub(crate) fn accepted( + capture: Option<(Context, AnalyticsWriter)>, + root: &Path, + project_id: &str, + source: Source, +) { + if !matches!(source, Source::Direct | Source::DesignAgent) { + return; + } + let Some((context, writer)) = capture else { + return; + }; + let Ok(event) = context.capture( + EventData::CreativeTaskSubmit(EmptyProperties {}), + Some(project_id.into()), + source, + None, + ) else { + return; + }; + writer.try_goal(Request::Accepted { + root: root.into(), + route: context.route, + event, + }); +} + +/// 成功消费资格才返回事件;消费后队列落盘失败允许漏记。 +pub(super) fn process(request: Request) -> Result, String> { + if !request.validate() { + return Err("invalid analytics goal request".into()); + } + let (root, project_id) = match &request { + Request::Created { root, project_id } => (root, project_id.as_str()), + Request::Accepted { root, event, .. } => (root, event.project_id.as_deref().unwrap()), + }; + let Some(_lock) = + crate::agent::try_acquire_game_creator_agent_runtime_task_lock(root, "analytics-goal")? + else { + return Ok(None); + }; + let manifest_path = crate::project::resolve_local_project_path(root, ".agent/manifest.json")?; + if crate::project::read_manifest(&manifest_path)?.project_id != project_id { + forget_pending(root, project_id); + return Ok(None); + } + let path = root.join(MARKER); + initialize_pending(root, project_id, &path)?; + let path = crate::project::resolve_local_project_path(root, MARKER)?; + match &request { + Request::Created { .. } => Ok(None), + Request::Accepted { .. } => { + // 明确要求主文件存在,不启用 sidecar 的 previous 自动回退。 + let Ok(metadata) = std::fs::symlink_metadata(&path) else { + return Ok(None); + }; + if !metadata.is_file() || metadata.file_type().is_symlink() { + return Ok(None); + } + let Some(mut marker): Option = + crate::agent::read_agent_runtime_json_sidecar_with_max_bytes( + root, + MARKER, + "埋点目标资格", + MAX_MARKER_BYTES, + )? + else { + return Ok(None); + }; + if marker.schema_version != 1 || marker.project_id != project_id || marker.submitted { + return Ok(None); + } + marker.submitted = true; + crate::agent::write_agent_runtime_json_sidecar_with_max_bytes( + root, + MARKER, + "埋点目标资格", + &marker, + MAX_MARKER_BYTES, + )?; + match request { + Request::Accepted { route, event, .. } => Ok(Some((route, event))), + _ => unreachable!(), + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn pending_goals_are_bounded_and_duplicate_creation_does_not_charge_bytes() { + let mut pending = PendingGoals::default(); + let root = std::env::temp_dir().join("analytics-pending-bound"); + pending.remember(&root, "project"); + let bytes = pending.bytes; + pending.remember(&root, "project"); + assert_eq!(pending.bytes, bytes); + pending.forget(&root, "other-project"); + assert_eq!(pending.bytes, bytes); + pending.forget(&root, "project"); + assert_eq!(pending.bytes, 0); + for index in 0..MAX_PENDING_PROJECTS + 1 { + pending.remember(&root.join(index.to_string()), "project"); + } + assert_eq!(pending.projects.len(), MAX_PENDING_PROJECTS); + + let mut pending = PendingGoals::default(); + let large_root = root.join("x".repeat(30_000)); + for index in 0..100 { + pending.remember(&large_root, &index.to_string()); + } + assert!(pending.bytes <= MAX_PENDING_BYTES); + assert!(pending.projects.len() < 100); + } +} diff --git a/apps/ai-game-creator-shell/src-tauri/src/analytics/gui.rs b/apps/ai-game-creator-shell/src-tauri/src/analytics/gui.rs new file mode 100644 index 000000000..71e58c272 --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/src/analytics/gui.rs @@ -0,0 +1,648 @@ +//! GUI 生命周期的内存状态。仅串行捕获事实,所有文件操作交给现有后台写入器。 +use super::contract::*; +use super::session::{LifecycleState, SessionRecord}; +use super::store::AnalyticsWriter; +use std::collections::HashMap; +use std::path::PathBuf; +use std::sync::{Mutex, OnceLock}; +use std::time::Instant; +use tauri::Manager; +use uuid::Uuid; + +struct OpenProject { + id: String, + path: String, + operation_id: String, +} + +struct Focus { + id: String, + started: Instant, +} + +struct GuiState { + context: Context, + identity_sequence: u64, + writer: AnalyticsWriter, + started: Instant, + focus: Option, + focused_window: Option, + active_project: Option, + last_project: Option, + projects: HashMap, + pending_open: HashMap, + navigation_time: HashMap, + restart: bool, + closed: bool, +} + +struct Service { + session_id: String, + version: String, + writer: AnalyticsWriter, + state: Mutex, +} + +static GUI: OnceLock = OnceLock::new(); +// 仅串行化发布服务与退出;后台等待认证状态时不占此锁。 +static EXITING: Mutex = Mutex::new(false); + +#[cfg(test)] +pub(crate) struct LifecycleFixture(GuiState); + +#[cfg(test)] +impl LifecycleFixture { + pub(crate) fn start(context: Context, writer: AnalyticsWriter) -> Self { + let mut state = GuiState::new(context, 1, writer); + state.start(); + state.windows(Some("main".into()), false, true); + Self(state) + } + + pub(crate) fn create_and_open(&mut self, root: &std::path::Path, project_id: &str) { + crate::init_local_game_project_at(root, project_id, "采集完整链路测试").unwrap(); + super::goal::created(Some(&self.0.writer), root, project_id); + self.0.emit( + EventData::ProjectCreateSuccess(ProjectCreated { + creation_source: CreationSource::HomeGame, + project_template_id: None, + }), + Some(project_id.into()), + format!("{project_id}:project-create"), + ); + self.0.project_opened( + "main".into(), + self.0.context.clone(), + OpenProject { + id: project_id.into(), + path: root.to_string_lossy().into_owned(), + operation_id: Uuid::new_v4().to_string(), + }, + OpenSource::Create, + timestamp_now(), + ); + } + + pub(crate) fn exit(&mut self) { + self.0.exit(); + } +} + +impl GuiState { + fn new(context: Context, identity_sequence: u64, writer: AnalyticsWriter) -> Self { + Self { + context, + identity_sequence, + writer, + started: Instant::now(), + focus: None, + focused_window: None, + active_project: None, + last_project: None, + projects: HashMap::new(), + pending_open: HashMap::new(), + navigation_time: HashMap::new(), + restart: false, + closed: false, + } + } + + fn emit(&self, data: EventData, project: Option, key: String) { + if let Ok(event) = self.context.capture(data, project, Source::Editor, None) { + self.writer + .try_record(self.context.route.clone(), event, key); + } + } + + fn persist(&self) { + self.writer.try_session(SessionRecord { + schema_version: 1, + editor_session_id: self.context.editor_session_id.clone(), + route: self.context.route.clone(), + lifecycle_state: if self.closed { + LifecycleState::Closed + } else { + LifecycleState::Active + }, + focus_interval_id: self.focus.as_ref().map(|f| f.id.clone()), + updated_at: timestamp_now(), + incomplete_detected_at: None, + }); + } + + fn start(&self) { + self.emit( + EventData::EditorSessionStart(SessionStart { + entry_source: EntrySource::DirectLaunch, + first_project_id: None, + }), + None, + format!("{}:session-start", self.context.editor_session_id), + ); + self.persist(); + } + + fn begin_focus(&mut self, reason: FocusReason) { + if self.focus.is_some() || self.closed { + return; + } + let id = Uuid::new_v4().to_string(); + self.emit( + EventData::EditorFocusStart(FocusStart { + focus_interval_id: id.clone(), + focus_reason: reason, + active_project_id: self.active_project.clone(), + }), + self.active_project.clone(), + format!("{id}:focus-start"), + ); + self.focus = Some(Focus { + id, + started: Instant::now(), + }); + } + + fn end_focus(&mut self, reason: BlurReason) { + let Some(focus) = self.focus.take() else { + return; + }; + self.emit( + EventData::EditorFocusEnd(FocusEnd { + focus_interval_id: focus.id.clone(), + blur_reason: reason, + focus_duration_ms: Some(elapsed_ms(focus.started)), + active_project_id: self.active_project.clone(), + }), + self.active_project.clone(), + format!("{}:focus-end", focus.id), + ); + } + + fn windows(&mut self, focused: Option, minimized: bool, initial: bool) { + if self.closed { + return; + } + let changed = self.focused_window.is_some() != focused.is_some(); + if let Some(label) = &focused { + self.active_project = self.projects.get(label).map(|p| p.id.clone()); + if self.active_project.is_some() { + self.last_project = self.active_project.clone(); + } + } + match (self.focused_window.is_some(), focused.is_some()) { + (false, true) => self.begin_focus(if initial { + FocusReason::InitialFocus + } else { + FocusReason::WindowFocus + }), + (true, false) => self.end_focus(if minimized { + BlurReason::Minimized + } else { + BlurReason::WindowBlur + }), + _ => {} + } + // A 窗口切到 B 窗口时整体仍为前台,不生成重叠区间。 + self.focused_window = focused; + if changed { + self.persist(); + } + } + + fn identity(&mut self, route: Route, sequence: u64) { + if self.closed || sequence <= self.identity_sequence || !route.validate() { + return; + } + self.identity_sequence = sequence; + if route == self.context.route { + return; + } + self.end_focus(BlurReason::AccountChange); + // 身份切换会卸载旧工作区,旧项目不能归入新账号的前台区间。 + let left_at = timestamp_now(); + for time in self.navigation_time.values_mut() { + *time = left_at.clone(); + } + self.projects.clear(); + self.pending_open.clear(); + self.active_project = None; + self.last_project = None; + self.context.route = route; + if self.focused_window.is_some() { + self.begin_focus(FocusReason::AccountChange); + } + self.persist(); + } + + fn reserve_open(&mut self, window: &str, operation: &str, path: &str, time: &str) { + match self + .navigation_time + .get(window) + .map(|previous| time.cmp(previous.as_str())) + { + None | Some(std::cmp::Ordering::Greater) => { + self.navigation_time + .insert(window.to_string(), time.to_string()); + self.pending_open.insert( + window.to_string(), + (operation.to_string(), path.to_string()), + ); + } + Some(std::cmp::Ordering::Equal) + if self + .pending_open + .get(window) + .is_none_or(|(id, _)| id != operation) + && self + .projects + .get(window) + .is_none_or(|project| project.operation_id != operation) => + { + // 同一毫秒但投递次序不确定时保留事件,不猜当前项目归属。 + self.pending_open.remove(window); + self.projects.remove(window); + if self.focused_window.as_deref() == Some(window) { + self.active_project = None; + } + } + _ => {} + } + } + + fn project_opened( + &mut self, + window: String, + context: Context, + project: OpenProject, + source: OpenSource, + time: String, + ) { + if self.closed + || self + .projects + .get(&window) + .is_some_and(|old| old.operation_id == project.operation_id) + { + return; + } + let same_identity = context.route == self.context.route; + if let Ok(mut event) = context.capture( + EventData::ProjectOpen(ProjectOpened { + open_source: source, + is_first_open: None, // 后台依据有界的历史观察补充;未知仍保留 null。 + }), + Some(project.id.clone()), + Source::Editor, + None, + ) { + event.event_time = time; + event.event_id = project.operation_id.clone(); + if event.validate().is_err() { + return; + } + self.writer.try_record( + context.route, + event, + format!("{}:project-open", project.operation_id), + ); + } + // 身份捕获或 manifest 读取较慢时,仍记录当时已成功的事实,但不倒退当前工作区。 + if !same_identity + || self + .pending_open + .get(&window) + .is_none_or(|(id, _)| id != &project.operation_id) + { + return; + } + self.pending_open.remove(&window); + self.last_project = Some(project.id.clone()); + if self.focused_window.as_deref() == Some(&window) { + self.active_project = Some(project.id.clone()); + } + self.projects.insert(window, project); + } + + fn leave(&mut self, window: &str, expected_path: Option<&str>) { + self.navigation_time + .insert(window.to_string(), timestamp_now()); + if expected_path.is_none() + || self + .pending_open + .get(window) + .is_some_and(|(_, path)| Some(path.as_str()) == expected_path) + { + self.pending_open.remove(window); + } + if expected_path + .is_some_and(|path| self.projects.get(window).is_none_or(|p| p.path != path)) + { + return; + } + self.projects.remove(window); + if self.focused_window.as_deref() == Some(window) { + self.active_project = None; + } + } + + fn exit(&mut self) { + if self.closed { + return; + } + self.end_focus(BlurReason::AppExit); + self.emit( + EventData::EditorSessionEnd(SessionEnd { + end_reason: if self.restart { + SessionEndReason::AppRestart + } else { + SessionEndReason::UserExit + }, + session_duration_ms: Some(elapsed_ms(self.started)), + last_project_id: self.last_project.clone(), + }), + self.last_project.clone(), + format!("{}:session-end", self.context.editor_session_id), + ); + self.closed = true; + self.persist(); + self.writer.flush(); + } +} + +fn elapsed_ms(start: Instant) -> u64 { + start.elapsed().as_millis().min(9_007_199_254_740_991) as u64 +} + +pub(crate) fn initialize(app: tauri::AppHandle, config_dir: PathBuf, version: String) { + tauri::async_runtime::spawn_blocking(move || { + crate::platform_session::initialize_analytics_identity(|route, sequence| { + let Ok(exiting) = EXITING.lock() else { + return; + }; + if !*exiting { + initialize_with_identity(config_dir, version, route, sequence); + } + }); + if let Some(gui) = GUI.get() { + super::goal::retry_pending(&gui.writer); + } + let handle = app.clone(); + let _ = app.run_on_main_thread(move || observe_windows(&handle, None, false, true)); + }); +} + +fn initialize_with_identity(config_dir: PathBuf, version: String, route: Route, sequence: u64) { + if GUI.get().is_some() { + return; + } + let session_id = Uuid::new_v4().to_string(); + let writer = AnalyticsWriter::start(config_dir.clone(), session_id.clone()); + let context = Context { + route, + editor_session_id: session_id.clone(), + client_version: version.clone(), + }; + let state = GuiState::new(context, sequence, writer.clone()); + if GUI + .set(Service { + session_id, + version, + writer, + state: Mutex::new(state), + }) + .is_ok() + { + with_state(|state| state.start()); + super::upload::start(config_dir); + } +} + +fn with_state(f: impl FnOnce(&mut GuiState) -> T) -> Option { + let gui = GUI.get()?; + // 临界区只更新内存并 try_send,不做磁盘/网络操作,也不重新取得业务锁。 + // 必须串行处理身份与退出通知,不能因瞬时竞争丢失后持续使用旧身份。 + let mut state = gui.state.lock().ok()?; + Some(f(&mut state)) +} + +pub(crate) fn identity_changed(route: Route, sequence: u64) { + with_state(|state| state.identity(route, sequence)); +} + +#[tauri::command] +pub(crate) fn capture_analytics_context() -> Option { + let gui = GUI.get()?; + let (route, _) = crate::platform_session::analytics_identity_snapshot()?; + Some(Context { + route, + editor_session_id: gui.session_id.clone(), + client_version: gui.version.clone(), + }) +} + +pub(crate) fn capture_writer_context() -> Option<(Context, AnalyticsWriter)> { + Some((capture_analytics_context()?, GUI.get()?.writer.clone())) +} + +#[tauri::command] +pub(crate) fn settle_direct_run_analytics(attempt_id: String, discard: bool) { + super::run::settle(capture_writer_context(), &attempt_id, discard); +} + +fn valid_context(context: &Context) -> bool { + GUI.get().is_some_and(|gui| { + context.editor_session_id == gui.session_id + && context.client_version == gui.version + && context.route.validate() + }) +} + +pub(crate) fn created( + context: Option, + project_root: &std::path::Path, + project_id: String, + source: CreationSource, + template_id: Option, +) { + super::goal::created(GUI.get().map(|gui| &gui.writer), project_root, &project_id); + let (Some(context), Some(gui)) = (context, GUI.get()) else { + return; + }; + if !valid_context(&context) { + return; + } + if let Ok(event) = context.capture( + EventData::ProjectCreateSuccess(ProjectCreated { + creation_source: source, + project_template_id: template_id, + }), + Some(project_id.clone()), + Source::Editor, + None, + ) { + gui.writer + .try_record(context.route, event, format!("{project_id}:project-create")); + } +} + +#[tauri::command] +pub(crate) async fn record_analytics_project_open( + window: tauri::Window, + context: Context, + project_path: String, + operation_id: String, + open_source: OpenSource, + event_time: String, +) { + if !valid_context(&context) + || Uuid::parse_str(&operation_id).is_err() + || project_path.len() > 32768 + || !valid_time(&event_time) + { + return; + } + let label = window.label().to_string(); + if with_state(|state| { + state.reserve_open(&label, &operation_id, &project_path, &event_time); + }) + .is_none() + { + return; + } + // 目录/manifest 读取不占用 GUI 线程,也不会把读失败返回给业务操作。 + let _ = tauri::async_runtime::spawn_blocking(move || { + let Ok(root) = crate::validated_local_project_directory_path(&project_path) else { + return; + }; + let Ok(manifest) = crate::read_existing_manifest_for_project(&root) else { + return; + }; + let project = OpenProject { + id: manifest.project_id, + path: project_path, + operation_id, + }; + with_state(|state| state.project_opened(label, context, project, open_source, event_time)); + }) + .await; +} + +#[tauri::command] +pub(crate) fn record_analytics_project_leave(window: tauri::Window, project_path: String) { + with_state(|state| state.leave(window.label(), Some(&project_path))); +} + +#[tauri::command] +pub(crate) async fn record_analytics_ui_save( + context: Context, + project_path: String, + operation_id: String, + save_source: SaveSource, + changed: bool, + event_time: String, +) { + if !valid_context(&context) + || Uuid::parse_str(&operation_id).is_err() + || project_path.len() > 32768 + || !valid_time(&event_time) + || !matches!(save_source, SaveSource::Manual | SaveSource::Auto) + || (save_source == SaveSource::Auto && !changed) + { + return; + } + let Some(gui) = GUI.get() else { return }; + let writer = gui.writer.clone(); + let _ = tauri::async_runtime::spawn_blocking(move || { + let Ok(root) = crate::validated_local_project_directory_path(&project_path) else { + return; + }; + let Ok(manifest) = crate::read_existing_manifest_for_project(&root) else { + return; + }; + super::project::saved( + Some((context, writer)), + &manifest.project_id, + Source::UiEditor, + &operation_id, + ProjectSaved { + save_source, + revision_id: None, + }, + Some(&event_time), + ); + }) + .await; +} + +pub(crate) fn mark_restart() { + with_state(|state| state.restart = true); +} + +pub(crate) fn page_loading(window: &str) { + with_state(|state| state.leave(window, None)); +} + +pub(crate) fn exit() { + if let Ok(mut exiting) = EXITING.lock() { + *exiting = true; + } + with_state(GuiState::exit); +} + +pub(crate) fn observe_windows( + app: &tauri::AppHandle, + excluded: Option<&str>, + minimized: bool, + initial: bool, +) { + if GUI.get().is_none() { + return; + } + let mut focused = None; + let mut unknown = false; + for (label, window) in app.webview_windows() { + if excluded == Some(label.as_str()) { + continue; + } + match ( + window.is_focused(), + window.is_minimized(), + window.is_visible(), + ) { + (Ok(true), Ok(false), Ok(true)) => { + focused = Some(label); + break; + } + (Ok(_), Ok(_), Ok(_)) => {} + _ => unknown = true, + } + } + if focused.is_none() && unknown { + return; + } + with_state(|state| state.windows(focused, minimized, initial)); +} + +pub(crate) fn window_event(window: &tauri::Window, event: &tauri::WindowEvent) { + let destroyed = matches!(event, tauri::WindowEvent::Destroyed); + if destroyed { + with_state(|state| state.leave(window.label(), None)); + } + if destroyed + || matches!( + event, + tauri::WindowEvent::Focused(_) | tauri::WindowEvent::Resized(_) + ) + { + observe_windows( + window.app_handle(), + destroyed.then_some(window.label()), + window.is_minimized().unwrap_or(false), + false, + ); + } +} + +#[cfg(test)] +#[path = "gui_tests.rs"] +mod tests; diff --git a/apps/ai-game-creator-shell/src-tauri/src/analytics/gui_tests.rs b/apps/ai-game-creator-shell/src-tauri/src/analytics/gui_tests.rs new file mode 100644 index 000000000..8c584e9fd --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/src/analytics/gui_tests.rs @@ -0,0 +1,189 @@ +use super::*; +use std::fs; +use std::time::Duration; + +fn state() -> (tempfile::TempDir, GuiState) { + let dir = tempfile::tempdir().unwrap(); + let context = Context { + route: Route::from_identity(Some("A".into()), Some("https://example.com")), + editor_session_id: Uuid::new_v4().to_string(), + client_version: "1.0.0".into(), + }; + let writer = AnalyticsWriter::start(dir.path().into(), context.editor_session_id.clone()); + (dir, GuiState::new(context, 1, writer)) +} + +fn read_events(dir: &std::path::Path, session: &str, expected: usize) -> Vec { + let until = Instant::now() + Duration::from_secs(5); + loop { + let mut events = Vec::new(); + let batches = dir + .join("analytics/instances") + .join(session) + .join("batches"); + if let Ok(entries) = fs::read_dir(batches) { + for entry in entries.flatten() { + if Uuid::parse_str(&entry.file_name().to_string_lossy()).is_err() { + continue; + } + if let Ok(text) = fs::read_to_string(entry.path().join("events.jsonl")) { + events.extend( + text.lines() + .map(|line| serde_json::from_str::(line).unwrap()), + ); + } + } + } + if events.len() == expected { + return events; + } + assert!( + Instant::now() < until, + "expected {expected} events, found {}", + events.len() + ); + std::thread::sleep(Duration::from_millis(10)); + } +} + +#[test] +fn window_union_and_repeated_notifications_form_one_interval() { + let (dir, mut state) = state(); + state.start(); + state.windows(Some("main".into()), false, true); + let interval = state.focus.as_ref().unwrap().id.clone(); + state.windows(Some("launcher".into()), false, false); + state.windows(Some("launcher".into()), false, false); + assert_eq!(state.focus.as_ref().unwrap().id, interval); + state.windows(None, true, false); + state.windows(None, true, false); + state.exit(); + state.exit(); + let events = read_events(dir.path(), &state.context.editor_session_id, 4); + let end = events + .iter() + .find(|e| e.event_name == "editor_focus_end") + .unwrap(); + assert_eq!(end.properties["focus_interval_id"], interval); + assert_eq!(end.properties["blur_reason"], "minimized"); + assert_eq!( + events + .iter() + .filter(|e| e.event_name == "editor_session_end") + .count(), + 1 + ); +} + +#[test] +fn identity_change_splits_focus_but_refresh_and_stale_notice_do_not() { + let (dir, mut state) = state(); + state.start(); + state.windows(Some("main".into()), false, true); + let first = state.focus.as_ref().unwrap().id.clone(); + open( + &mut state, + "project-a", + &Uuid::new_v4().to_string(), + "2000-01-01T00:00:00.000Z", + ); + state.identity(state.context.route.clone(), 2); + assert_eq!(state.focus.as_ref().unwrap().id, first); + let route_b = Route::from_identity(Some("B".into()), Some("https://example.com")); + state.identity(route_b.clone(), 4); + state.identity( + Route::from_identity(Some("A".into()), Some("https://example.com")), + 3, + ); + assert_eq!(state.context.route, route_b); + assert!(state.projects.is_empty()); + assert!(state.active_project.is_none()); + assert_ne!(state.focus.as_ref().unwrap().id, first); + state.restart = true; + state.exit(); + let events = read_events(dir.path(), &state.context.editor_session_id, 7); + let old_end = events + .iter() + .find(|e| e.event_name == "editor_focus_end" && e.user_id.as_deref() == Some("A")) + .unwrap(); + assert_eq!(old_end.properties["blur_reason"], "account_change"); + let new_start = events + .iter() + .find(|e| e.event_name == "editor_focus_start" && e.user_id.as_deref() == Some("B")) + .unwrap(); + assert_eq!(new_start.properties["focus_reason"], "account_change"); + assert!(new_start.project_id.is_none()); + let end = events + .iter() + .find(|e| e.event_name == "editor_session_end") + .unwrap(); + assert_eq!(end.properties["end_reason"], "app_restart"); +} + +fn open(state: &mut GuiState, project_id: &str, operation: &str, time: &str) { + state.reserve_open("main", operation, project_id, time); + state.project_opened( + "main".into(), + state.context.clone(), + OpenProject { + id: project_id.into(), + path: project_id.into(), + operation_id: operation.into(), + }, + OpenSource::Recent, + time.into(), + ); +} + +#[test] +fn explicit_reopen_records_new_operation_and_duplicate_delivery_does_not() { + let (dir, mut state) = state(); + let id = Uuid::new_v4().to_string(); + open(&mut state, "project", &id, "2026-09-21T12:00:00.001Z"); + // 同一次已采纳操作的重复回执由幂等事实键抑制。 + open(&mut state, "project", &id, "2026-09-21T12:00:00.001Z"); + let next = Uuid::new_v4().to_string(); + assert_eq!(state.projects.get("main").unwrap().operation_id, id); + open(&mut state, "project", &next, "2026-09-21T12:00:00.002Z"); + state.writer.flush(); + let events = read_events(dir.path(), &state.context.editor_session_id, 2); + assert!(events.iter().any(|e| e.event_id == id)); + assert!(events.iter().any(|e| e.event_id == next)); + assert!(events[0].properties["is_first_open"].is_null()); + assert_eq!(events[1].properties["is_first_open"], false); +} + +#[test] +fn delayed_capture_or_manifest_read_does_not_restore_a_left_project() { + let (dir, mut state) = state(); + state.windows(Some("main".into()), false, true); + let old = Uuid::new_v4().to_string(); + state.reserve_open("main", &old, "old", "2026-09-21T12:00:00.001Z"); + let new = Uuid::new_v4().to_string(); + open(&mut state, "new", &new, "2026-09-21T12:00:00.002Z"); + state.project_opened( + "main".into(), + state.context.clone(), + OpenProject { + id: "old".into(), + path: "old".into(), + operation_id: old, + }, + OpenSource::Recent, + "2026-09-21T12:00:00.001Z".into(), + ); + assert_eq!(state.active_project.as_deref(), Some("new")); + state.leave("main", Some("new")); + let late = Uuid::new_v4().to_string(); + open(&mut state, "old", &late, "2000-01-01T00:00:00.000Z"); + assert!(state.active_project.is_none()); + state.writer.flush(); + let events = read_events(dir.path(), &state.context.editor_session_id, 4); + assert_eq!( + events + .iter() + .filter(|e| e.event_name == "project_open") + .count(), + 3 + ); +} diff --git a/apps/ai-game-creator-shell/src-tauri/src/analytics/mod.rs b/apps/ai-game-creator-shell/src-tauri/src/analytics/mod.rs new file mode 100644 index 000000000..59398e170 --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/src/analytics/mod.rs @@ -0,0 +1,11 @@ +//! 客户端产品埋点:本地采集、持久化与确认后上传清理。 +pub(crate) mod contract; +pub(crate) mod design; +pub(crate) mod goal; +pub(crate) mod gui; +pub(crate) mod preview; +pub(crate) mod project; +pub(crate) mod run; +pub(crate) mod session; +pub(crate) mod store; +pub(crate) mod upload; diff --git a/apps/ai-game-creator-shell/src-tauri/src/analytics/preview.rs b/apps/ai-game-creator-shell/src-tauri/src/analytics/preview.rs new file mode 100644 index 000000000..3b73b042b --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/src/analytics/preview.rs @@ -0,0 +1,146 @@ +//! 正式 Web 预览的短时可访问性观察;不影响预览业务生命周期。 +use super::{ + contract::{Context, EventData, PreviewReady, PreviewSource, Source}, + store::AnalyticsWriter, +}; +use std::{ + path::{Path, PathBuf}, + sync::{Arc, Weak}, + time::{Duration, Instant}, +}; + +pub(crate) struct Lease { + _alive: Arc<()>, +} + +pub(crate) struct Observation { + alive: Weak<()>, + instance_id: String, + root: PathBuf, + entry: PathBuf, + project_id: String, + revision: u64, + context: Context, + writer: AnalyticsWriter, + source: Source, + preview_source: PreviewSource, + started: Instant, + cancellation: Option>, +} + +fn nonempty_entry(entry: &Path) -> bool { + std::fs::metadata(entry).is_ok_and(|metadata| metadata.is_file() && metadata.len() > 0) +} + +pub(crate) fn prepare( + root: &Path, + capture: Option<(Context, AnalyticsWriter)>, + source: Source, + preview_source: PreviewSource, +) -> Option<(Lease, Observation)> { + let (context, writer) = capture?; + let entry = crate::project_game_root(root).join("index.html"); + if !nonempty_entry(&entry) { + return None; + } + let project_id = crate::read_existing_manifest_for_project(root) + .ok()? + .project_id; + let revision = crate::read_game_creator_agent_runtime_project_revision(root) + .ok()? + .revision; + let alive = Arc::new(()); + let observation = Observation { + alive: Arc::downgrade(&alive), + instance_id: uuid::Uuid::new_v4().to_string(), + root: root.into(), + entry, + project_id, + revision, + context, + writer, + source, + preview_source, + started: Instant::now(), + cancellation: None, + }; + Some((Lease { _alive: alive }, observation)) +} + +impl Observation { + pub(crate) fn with_cancellation( + mut self, + cancellation: Option>, + ) -> Self { + self.cancellation = cancellation; + self + } + + fn current(&self) -> bool { + !self + .cancellation + .as_ref() + .is_some_and(|flag| flag.load(std::sync::atomic::Ordering::Acquire)) + && self.alive.strong_count() > 0 + && self.entry == crate::project_game_root(&self.root).join("index.html") + && nonempty_entry(&self.entry) + && crate::read_game_creator_agent_runtime_project_revision(&self.root) + .is_ok_and(|revision| revision.revision == self.revision) + && crate::read_existing_manifest_for_project(&self.root) + .is_ok_and(|manifest| manifest.project_id == self.project_id) + } + + pub(crate) fn schedule(self, port: u16) { + tauri::async_runtime::spawn(self.observe(port)); + } + + pub(crate) async fn observe(self, port: u16) { + if !self.current() { + return; + } + let reachable = tokio::time::timeout(Duration::from_secs(2), async { + let client = reqwest::Client::builder() + .no_proxy() + .redirect(reqwest::redirect::Policy::none()) + .build() + .ok()?; + let mut response = client + .get(format!("http://127.0.0.1:{port}/")) + .send() + .await + .ok()?; + if !response.status().is_success() { + return None; + } + while let Some(chunk) = response.chunk().await.ok()? { + if !chunk.is_empty() { + return Some(()); + } + } + None + }) + .await; + if !matches!(reachable, Ok(Some(()))) || !self.current() { + return; + } + let event = self.context.capture( + EventData::PreviewReady(PreviewReady { + preview_source: self.preview_source, + preview_version: self.revision.to_string(), + ready_duration_ms: u64::try_from(self.started.elapsed().as_millis()).ok(), + }), + Some(self.project_id.clone()), + self.source, + None, + ); + if let Ok(event) = event { + if self.current() { + let key = format!( + "{}:{}:{}:preview_ready", + self.project_id, self.instance_id, self.revision + ); + self.writer.try_record(self.context.route, event, key); + } + } + } +} diff --git a/apps/ai-game-creator-shell/src-tauri/src/analytics/project.rs b/apps/ai-game-creator-shell/src-tauri/src/analytics/project.rs new file mode 100644 index 000000000..1a8defebc --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/src/analytics/project.rs @@ -0,0 +1,104 @@ +//! 正式项目成果事件。只接收宿主已提交的版本,不参与业务写入。 +use super::contract::{ChangeKind, Context, EventData, ProjectSaved, RevisionCreated, Source}; +use super::store::AnalyticsWriter; +use std::io::Read; +use std::path::Path; + +pub(crate) fn saved( + capture: Option<(Context, AnalyticsWriter)>, + project_id: &str, + source: Source, + operation_id: &str, + data: ProjectSaved, + event_time: Option<&str>, +) { + let Some((context, writer)) = capture else { + return; + }; + if let Ok(mut event) = context.capture( + EventData::ProjectSave(data), + Some(project_id.into()), + source, + None, + ) { + if let Some(time) = event_time { + event.event_time = time.into(); + } + writer.try_record( + context.route, + event, + format!("{project_id}:{operation_id}:project_save"), + ); + } +} + +pub(crate) fn file_content_changed( + root: &Path, + path: &str, + content: &[u8], + max_bytes: u64, +) -> Option { + let target = crate::resolve_local_project_path(root, path).ok()?; + match std::fs::symlink_metadata(&target) { + Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Some(true), + Err(_) => return None, + Ok(_) => {} + } + let (file, metadata) = + crate::open_project_snapshot_regular_file(&target, "成果内容比较").ok()?; + if metadata.len() > max_bytes { + return None; + } + let mut before = Vec::new(); + file.take(max_bytes.saturating_add(1)) + .read_to_end(&mut before) + .ok()?; + (before.len() as u64 <= max_bytes).then(|| before != content) +} + +pub(crate) fn revision( + capture: Option<(Context, AnalyticsWriter)>, + project_id: &str, + source: Source, + data: RevisionCreated, +) { + let Some((context, writer)) = capture else { + return; + }; + let key = format!("{project_id}:{}:project_revision_created", data.revision_id); + if let Ok(event) = context.capture( + EventData::ProjectRevisionCreated(data), + Some(project_id.into()), + source, + None, + ) { + writer.try_record(context.route, event, key); + } +} + +// 只给已知成果分类;未知文件不猜字段,控制面和构建缓存不计成果。 +pub(crate) fn file_change_kind(path: &str) -> Option { + let path = path.to_ascii_lowercase(); + if crate::should_skip_project_snapshot_path(&path) + || path.split('/').any(|part| part.starts_with('.')) + { + return None; + } + if path.starts_with("design_artifacts/") { + return Some(ChangeKind::DesignDocument); + } + if path.starts_with("ui/") { + return Some(ChangeKind::Ui); + } + let extension = path.rsplit_once('.')?.1; + match extension { + "png" | "jpg" | "jpeg" | "webp" | "gif" | "svg" | "avif" | "mp3" | "wav" | "ogg" + | "flac" | "mp4" | "webm" | "glb" | "gltf" | "ttf" | "woff" | "woff2" => { + Some(ChangeKind::Asset) + } + "js" | "jsx" | "ts" | "tsx" | "mjs" | "cjs" | "html" | "css" | "scss" | "json" | "vue" + | "svelte" | "gd" | "tscn" | "tres" | "cs" | "shader" | "glsl" | "wgsl" | "vert" + | "frag" | "rs" | "py" | "lua" | "cpp" | "h" | "c" | "hpp" => Some(ChangeKind::Code), + _ => None, + } +} diff --git a/apps/ai-game-creator-shell/src-tauri/src/analytics/run.rs b/apps/ai-game-creator-shell/src-tauri/src/analytics/run.rs new file mode 100644 index 000000000..49673bb20 --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/src/analytics/run.rs @@ -0,0 +1,400 @@ +//! 可观测运行序号和终态消费。双 Agent 各保留一个槽位,不保存历史或身份。 +use super::contract::{ + self, AgentType, Context, ErrorCode, Event, EventData, Route, RunEndReason, RunFinished, + RunIdentity, RunSource, Source, +}; +use super::store::AnalyticsWriter; +use serde::{Deserialize, Serialize}; +use std::path::{Path, PathBuf}; + +const PATH: &str = ".agent/analytics-runs.json"; +const MAX_BYTES: usize = 4096; +const MAX_INTEGER: u64 = 9_007_199_254_740_991; + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[serde(deny_unknown_fields)] +pub(crate) struct Metadata { + pub context: Context, + pub run_id: String, + pub terminal_event_id: String, + pub source: Source, + pub run_source: RunSource, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub output_revision: Option, +} + +impl Metadata { + pub(crate) fn new(context: Context, source: Source, run_source: RunSource) -> Self { + Self { + context, + source, + run_source, + run_id: uuid::Uuid::new_v4().to_string(), + terminal_event_id: uuid::Uuid::new_v4().to_string(), + output_revision: None, + } + } + fn validate(&self) -> bool { + matches!(self.source, Source::Direct | Source::DesignAgent) + && uuid::Uuid::parse_str(&self.run_id).is_ok() + && uuid::Uuid::parse_str(&self.terminal_event_id).is_ok() + && self.context.route.validate() + && self.output_revision.as_deref().is_none_or(valid_id) + } +} + +#[derive(Clone, Debug, Serialize)] +pub(crate) struct Outcome { + pub turn_id: Option, + pub end_reason: RunEndReason, + pub error_code: Option, + pub duration_ms: Option, + pub output_change_detected: Option, + pub revision_id: Option, +} + +#[derive(Serialize)] +pub(super) enum Request { + DirectCandidate { + attempt_id: String, + terminal: Box, + }, + Settle { + editor_session_id: String, + attempt_id: String, + discard: bool, + }, + Accepted { + root: PathBuf, + project_id: String, + metadata: Metadata, + }, + Terminal { + root: PathBuf, + project_id: String, + metadata: Metadata, + context: Context, + event_time: String, + outcome: Outcome, + }, +} + +impl Request { + pub(super) fn session_id(&self) -> &str { + match self { + Self::DirectCandidate { terminal, .. } => terminal.session_id(), + Self::Settle { + editor_session_id, .. + } => editor_session_id, + Self::Accepted { metadata, .. } => &metadata.context.editor_session_id, + Self::Terminal { context, .. } => &context.editor_session_id, + } + } + pub(super) fn validate(&self) -> bool { + match self { + Self::DirectCandidate { + attempt_id, + terminal, + } => { + return uuid::Uuid::parse_str(attempt_id).is_ok() + && matches!(terminal.as_ref(), Self::Terminal { metadata, .. } if metadata.source == Source::Direct) + && terminal.validate(); + } + Self::Settle { + editor_session_id, + attempt_id, + .. + } => { + return uuid::Uuid::parse_str(editor_session_id).is_ok() + && uuid::Uuid::parse_str(attempt_id).is_ok(); + } + _ => {} + } + let (root, project_id, metadata) = match self { + Self::Accepted { + root, + project_id, + metadata, + } => (root, project_id, metadata), + Self::Terminal { + root, + project_id, + metadata, + .. + } => (root, project_id, metadata), + _ => return false, + }; + root.is_absolute() + && root.as_os_str().len() <= 32768 + && valid_id(project_id) + && metadata.validate() + } +} + +pub(crate) fn accepted( + writer: &AnalyticsWriter, + root: &Path, + project_id: &str, + metadata: &Metadata, +) { + writer.try_run(Request::Accepted { + root: root.into(), + project_id: project_id.into(), + metadata: metadata.clone(), + }); +} + +pub(crate) fn finished( + capture: Option<(Context, AnalyticsWriter)>, + root: &Path, + project_id: &str, + metadata: &Metadata, + outcome: Outcome, +) { + let Some((mut context, writer)) = capture else { + return; + }; + // 恢复后的 GUI 会话属于新实例,但账号和目标平台仍属于原运行。 + context.route = metadata.context.route.clone(); + writer.try_run(Request::Terminal { + root: root.into(), + project_id: project_id.into(), + metadata: metadata.clone(), + context, + event_time: contract::timestamp_now(), + outcome, + }); +} + +pub(crate) fn direct_finished( + capture: Option<(Context, AnalyticsWriter)>, + root: &Path, + project_id: &str, + metadata: &Metadata, + attempt_id: Option<&str>, + outcome: Outcome, +) { + let Some(attempt_id) = attempt_id else { return }; + let Some((mut context, writer)) = capture else { + return; + }; + if metadata.source != Source::Direct { + return; + } + context.route = metadata.context.route.clone(); + writer.try_run(Request::DirectCandidate { + attempt_id: attempt_id.into(), + terminal: Box::new(Request::Terminal { + root: root.into(), + project_id: project_id.into(), + metadata: metadata.clone(), + context, + event_time: contract::timestamp_now(), + outcome, + }), + }); +} + +pub(crate) fn settle(capture: Option<(Context, AnalyticsWriter)>, attempt_id: &str, discard: bool) { + let Some((context, writer)) = capture else { + return; + }; + writer.try_run(Request::Settle { + editor_session_id: context.editor_session_id, + attempt_id: attempt_id.into(), + discard, + }); +} + +#[derive(Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +struct Slot { + run_id: String, + retry_index: u64, + terminal_consumed: bool, +} + +#[derive(Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +struct State { + schema_version: u32, + project_id: String, + retry_count: u64, + direct: Option, + design: Option, +} + +impl State { + fn slot(&mut self, source: Source) -> &mut Option { + if source == Source::Direct { + &mut self.direct + } else { + &mut self.design + } + } + fn validate(&self, project_id: &str) -> bool { + self.schema_version == 1 + && self.project_id == project_id + && self.retry_count <= MAX_INTEGER + && [&self.direct, &self.design] + .into_iter() + .flatten() + .all(|slot| { + uuid::Uuid::parse_str(&slot.run_id).is_ok() + && slot.retry_index <= self.retry_count + }) + } +} + +fn valid_id(value: &str) -> bool { + !value.trim().is_empty() && value.len() <= 256 && !value.chars().any(char::is_control) +} + +pub(super) fn process(request: Request) -> Result, String> { + if !request.validate() { + return Ok(None); + } + let (root, project_id, metadata) = match &request { + Request::Accepted { + root, + project_id, + metadata, + } + | Request::Terminal { + root, + project_id, + metadata, + .. + } => (root, project_id, metadata), + _ => return Ok(None), + }; + let Some(_lock) = + crate::agent::try_acquire_game_creator_agent_runtime_task_lock(root, "analytics-runs")? + else { + return Ok(None); + }; + let manifest_path = crate::project::resolve_local_project_path(root, ".agent/manifest.json")?; + if crate::project::read_manifest(&manifest_path)?.project_id != *project_id { + return Ok(None); + } + let path = crate::project::resolve_local_project_path(root, PATH)?; + let mut state = match std::fs::symlink_metadata(&path) { + Ok(meta) if meta.is_file() && !meta.file_type().is_symlink() => { + let Some(state): Option = + crate::agent::read_agent_runtime_json_sidecar_with_max_bytes( + root, + PATH, + "运行埋点序号", + MAX_BYTES, + )? + else { + return Ok(None); + }; + if !state.validate(project_id) { + return Ok(None); + } + state + } + Err(error) if error.kind() == std::io::ErrorKind::NotFound => { + if !matches!(request, Request::Accepted { .. }) { + return Ok(None); + } + let backup = crate::agent::agent_runtime_json_sidecar_backup_path(&path); + if !matches!(std::fs::symlink_metadata(backup), Err(ref e) if e.kind() == std::io::ErrorKind::NotFound) + { + return Ok(None); + } + State { + schema_version: 1, + project_id: project_id.clone(), + retry_count: 0, + direct: None, + design: None, + } + } + _ => return Ok(None), + }; + let event = match &request { + Request::Accepted { .. } => { + if state + .slot(metadata.source) + .as_ref() + .is_some_and(|slot| slot.run_id == metadata.run_id) + { + return Ok(None); + } + if metadata.run_source == RunSource::UserRetry { + if state.retry_count == MAX_INTEGER { + return Ok(None); + } + state.retry_count += 1; + } + let ordinal = state.retry_count; + *state.slot(metadata.source) = Some(Slot { + run_id: metadata.run_id.clone(), + retry_index: ordinal, + terminal_consumed: false, + }); + None + } + Request::Terminal { + context, + event_time, + outcome, + .. + } => { + let Some(slot) = state.slot(metadata.source) else { + return Ok(None); + }; + if slot.run_id != metadata.run_id || slot.terminal_consumed { + return Ok(None); + } + let data = RunFinished { + agent_type: if metadata.source == Source::Direct { + AgentType::GameAgent + } else { + AgentType::DesignAgent + }, + run_source: metadata.run_source, + duration_ms: outcome.duration_ms, + retry_index: slot.retry_index, + output_change_detected: outcome.output_change_detected, + revision_id: outcome.revision_id.clone(), + end_reason: outcome.end_reason, + }; + let data = if outcome.end_reason == RunEndReason::Failed { + EventData::AgentRunFailed(data) + } else { + EventData::AgentRunCompleted(data) + }; + let Ok(mut event) = context.capture( + data, + Some(project_id.clone()), + metadata.source, + Some(RunIdentity { + run_id: metadata.run_id.clone(), + turn_id: outcome.turn_id.clone(), + error_code: outcome.error_code, + }), + ) else { + return Ok(None); + }; + event.event_id = metadata.terminal_event_id.clone(); + event.event_time = event_time.clone(); + if event.validate().is_err() { + return Ok(None); + } + slot.terminal_consumed = true; + Some((context.route.clone(), event)) + } + _ => return Ok(None), + }; + crate::agent::write_agent_runtime_json_sidecar_with_max_bytes( + root, + PATH, + "运行埋点序号", + &state, + MAX_BYTES, + )?; + Ok(event) +} diff --git a/apps/ai-game-creator-shell/src-tauri/src/analytics/session.rs b/apps/ai-game-creator-shell/src-tauri/src/analytics/session.rs new file mode 100644 index 000000000..9c86a3590 --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/src/analytics/session.rs @@ -0,0 +1,248 @@ +//! 实例所有权与本地会话状态;仅后台 writer 访问磁盘。 +use super::contract::Route; +use super::store::{invalid_data, read_bounded, safe_metadata}; +use serde::{Deserialize, Serialize}; +use std::fs::{self, File, OpenOptions}; +use std::io::{self, Write}; +use std::path::Path; +use std::time::{Duration, SystemTime}; + +#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "snake_case")] +pub(crate) enum LifecycleState { + Active, + Closed, + Incomplete, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub(crate) struct SessionRecord { + pub schema_version: u32, + pub editor_session_id: String, + pub route: Route, + pub lifecycle_state: LifecycleState, + pub focus_interval_id: Option, + pub updated_at: String, + pub incomplete_detected_at: Option, +} + +impl SessionRecord { + pub(crate) fn validate(&self) -> bool { + self.updated_at.len() <= 64 + && self + .incomplete_detected_at + .as_ref() + .is_none_or(|s| s.len() <= 64) + && self.route.user_id.as_ref().is_none_or(|s| s.len() <= 4096) + && self + .route + .destination_origin + .as_ref() + .is_none_or(|s| s.len() <= 4096) + && self.schema_version == 1 + && uuid::Uuid::parse_str(&self.editor_session_id).is_ok() + && self.route.validate() + && self + .focus_interval_id + .as_ref() + .is_none_or(|id| uuid::Uuid::parse_str(id).is_ok()) + && chrono::DateTime::parse_from_rfc3339(&self.updated_at).is_ok() + && self + .incomplete_detected_at + .as_ref() + .is_none_or(|s| chrono::DateTime::parse_from_rfc3339(s).is_ok()) + && (self.lifecycle_state == LifecycleState::Incomplete) + == self.incomplete_detected_at.is_some() + } +} + +pub(super) fn claim(instance: &Path) -> io::Result { + let path = instance.join("owner.lock"); + if path.exists() { + safe_metadata(&path)?; + } + let file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(false) + .open(path)?; + file.try_lock().map_err(|_| invalid_data())?; + Ok(file) +} + +fn existing_owner(instance: &Path) -> io::Result { + let path = instance.join("owner.lock"); + if !safe_metadata(&path)?.is_file() { + return Err(invalid_data()); + } + let file = OpenOptions::new().read(true).write(true).open(path)?; + file.try_lock().map_err(|_| invalid_data())?; + Ok(file) +} + +pub(super) fn write(instance: &Path, record: &SessionRecord, session: &str) -> io::Result<()> { + if !record.validate() || record.editor_session_id != session { + return Err(invalid_data()); + } + let bytes = serde_json::to_vec(record)?; + if bytes.len() > 16 * 1024 { + return Err(invalid_data()); + } + let target = instance.join("session.json"); + if target.exists() { + safe_metadata(&target)?; + } + let temporary = instance.join(format!(".session-{}.tmp", uuid::Uuid::new_v4())); + let result = (|| { + let mut file = OpenOptions::new() + .write(true) + .create_new(true) + .open(&temporary)?; + file.write_all(&bytes)?; + file.sync_all()?; + drop(file); + fs::rename(&temporary, target) + })(); + if result.is_err() { + let _ = fs::remove_file(temporary); + } + result +} + +fn read(instance: &Path) -> io::Result { + let record: SessionRecord = + serde_json::from_slice(&read_bounded(&instance.join("session.json"), 16 * 1024)?)?; + if !record.validate() + || instance.file_name().and_then(|s| s.to_str()) != Some(record.editor_session_id.as_str()) + { + return Err(invalid_data()); + } + Ok(record) +} + +pub(super) fn recover(instances: &Path, current: &str) { + let Ok(entries) = fs::read_dir(instances) else { + return; + }; + for entry in entries.flatten() { + if entry.file_name() == current || !safe_metadata(&entry.path()).is_ok_and(|m| m.is_dir()) { + continue; + } + let Ok(_owner) = existing_owner(&entry.path()) else { + continue; + }; + let Ok(mut record) = read(&entry.path()) else { + continue; + }; + if record.lifecycle_state != LifecycleState::Active { + continue; + } + record.lifecycle_state = LifecycleState::Incomplete; + record.incomplete_detected_at = Some(super::contract::timestamp_now()); + let _ = write(&entry.path(), &record, &record.editor_session_id); + } +} + +pub(super) fn prune( + instances: &Path, + current: &str, + reserve: u64, + limit: u64, + retention: Duration, + size: impl Fn() -> u64, +) { + let Ok(entries) = fs::read_dir(instances) else { + return; + }; + let mut candidates = Vec::new(); + let mut inactive = Vec::new(); + for entry in entries.flatten() { + if entry.file_name() == current + || uuid::Uuid::parse_str(&entry.file_name().to_string_lossy()).is_err() + || !safe_metadata(&entry.path()).is_ok_and(|m| m.is_dir()) + { + continue; + } + // 文件锁是存活证明;损坏或未写完的 JSON 不能永久阻止队列清理。 + let Ok(_owner) = existing_owner(&entry.path()) else { + continue; + }; + let Ok(files) = fs::read_dir(entry.path()) else { + continue; + }; + for file in files.flatten() { + let name = file.file_name(); + let name = name.to_string_lossy(); + let temporary = name + .strip_prefix(".session-") + .and_then(|name| name.strip_suffix(".tmp")) + .is_some_and(|id| uuid::Uuid::parse_str(id).is_ok()); + if name != "session.json" && !temporary { + continue; + } + let Ok(meta) = safe_metadata(&file.path()) else { + continue; + }; + if !meta.is_file() { + continue; + } + let Ok(modified) = meta.modified() else { + continue; + }; + candidates.push((modified, entry.path(), file.path())); + } + inactive.push(entry.path()); + } + candidates.sort_by_key(|(modified, _, _)| *modified); + for (modified, instance, path) in candidates { + let expired = SystemTime::now() + .duration_since(modified) + .is_ok_and(|age| age >= retention); + if !expired && size().saturating_add(reserve) <= limit { + continue; + } + let Ok(_owner) = existing_owner(&instance) else { + continue; + }; + if safe_metadata(&path).is_ok_and(|meta| meta.is_file()) { + let _ = fs::remove_file(path); + } + } + for instance in inactive { + let Ok(_owner) = existing_owner(&instance) else { + continue; + }; + remove_empty_instance(&instance); + } +} + +fn remove_empty_instance(instance: &Path) { + // 只删除空目录及普通 owner.lock,不递归删除未知文件或跟随链接。 + let batches = instance.join("batches"); + if safe_metadata(&batches).is_ok_and(|meta| meta.is_dir()) { + let _ = fs::remove_dir(&batches); + } + let Ok(entries) = fs::read_dir(instance) else { + return; + }; + let Ok(entries) = entries.collect::, _>>() else { + return; + }; + if entries.len() != 1 || entries[0].file_name() != "owner.lock" { + return; + } + let owner = instance.join("owner.lock"); + if !safe_metadata(&owner).is_ok_and(|meta| meta.is_file()) { + return; + } + // 调用者仍持有锁;实例 UUID 不复用,其他清理者不能同时取得所有权。 + if fs::remove_file(owner).is_ok() { + let _ = fs::remove_dir(instance); + } +} + +#[cfg(test)] +#[path = "session_tests.rs"] +mod tests; diff --git a/apps/ai-game-creator-shell/src-tauri/src/analytics/session_tests.rs b/apps/ai-game-creator-shell/src-tauri/src/analytics/session_tests.rs new file mode 100644 index 000000000..fd4c84c9b --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/src/analytics/session_tests.rs @@ -0,0 +1,101 @@ +use super::*; + +fn fixture() -> (tempfile::TempDir, std::path::PathBuf, SessionRecord) { + let dir = tempfile::tempdir().unwrap(); + let id = uuid::Uuid::new_v4().to_string(); + let instance = dir.path().join(&id); + fs::create_dir(&instance).unwrap(); + let record = SessionRecord { + schema_version: 1, + editor_session_id: id, + route: Route { + user_id: Some("user".into()), + destination_origin: Some("https://example.com".into()), + }, + lifecycle_state: LifecycleState::Active, + focus_interval_id: None, + updated_at: "2026-09-21T00:00:00.000Z".into(), + incomplete_detected_at: None, + }; + (dir, instance, record) +} + +#[test] +fn locked_owner_is_live_and_released_owner_is_recovered_once() { + let (dir, path, record) = fixture(); + let owner = claim(&path).unwrap(); + write(&path, &record, &record.editor_session_id).unwrap(); + recover(dir.path(), "another"); + assert_eq!(read(&path).unwrap().lifecycle_state, LifecycleState::Active); + drop(owner); + recover(dir.path(), "another"); + let recovered = read(&path).unwrap(); + assert_eq!(recovered.lifecycle_state, LifecycleState::Incomplete); + assert_eq!(recovered.updated_at, record.updated_at); + let bytes = fs::read(path.join("session.json")).unwrap(); + recover(dir.path(), "another"); + assert_eq!(fs::read(path.join("session.json")).unwrap(), bytes); +} + +#[test] +fn missing_proof_and_wrong_identity_are_untouched() { + let (dir, path, record) = fixture(); + write(&path, &record, &record.editor_session_id).unwrap(); + recover(dir.path(), "another"); + assert_eq!(read(&path).unwrap().lifecycle_state, LifecycleState::Active); + drop(claim(&path).unwrap()); + let mut wrong = record.clone(); + wrong.editor_session_id = uuid::Uuid::new_v4().to_string(); + fs::write( + path.join("session.json"), + serde_json::to_vec(&wrong).unwrap(), + ) + .unwrap(); + let before = fs::read(path.join("session.json")).unwrap(); + recover(dir.path(), "another"); + assert_eq!(fs::read(path.join("session.json")).unwrap(), before); +} + +#[test] +fn metadata_prune_skips_live_owner_and_removes_inactive_record() { + let (dir, path, mut record) = fixture(); + let owner = claim(&path).unwrap(); + record.lifecycle_state = LifecycleState::Closed; + write(&path, &record, &record.editor_session_id).unwrap(); + prune(dir.path(), "other", 0, 0, Duration::ZERO, || 100); + assert!(path.join("session.json").exists()); + drop(owner); + prune(dir.path(), "other", 0, 0, Duration::ZERO, || 100); + assert!(!path.join("session.json").exists()); +} + +#[test] +fn corrupt_and_abandoned_session_files_are_bounded_and_empty_instance_is_removed() { + let (dir, path, _) = fixture(); + drop(claim(&path).unwrap()); + fs::create_dir(path.join("batches")).unwrap(); + fs::write(path.join("session.json"), b"broken-json").unwrap(); + let temporary = path.join(format!(".session-{}.tmp", uuid::Uuid::new_v4())); + fs::write(&temporary, b"unfinished").unwrap(); + prune(dir.path(), "other", 0, u64::MAX, Duration::ZERO, || 100); + assert!(!path.exists()); +} + +#[test] +fn pressure_prunes_corrupt_metadata_but_keeps_live_and_unknown_files() { + let (dir, path, _) = fixture(); + let owner = claim(&path).unwrap(); + fs::write(path.join("session.json"), b"broken").unwrap(); + let temporary = path.join(format!(".session-{}.tmp", uuid::Uuid::new_v4())); + fs::write(&temporary, b"unfinished").unwrap(); + fs::write(path.join("unknown.json"), b"untouched").unwrap(); + prune(dir.path(), "other", 1, 0, Duration::MAX, || 100); + assert!(path.join("session.json").exists()); + assert!(temporary.exists()); + drop(owner); + prune(dir.path(), "other", 1, 0, Duration::MAX, || 100); + assert!(!path.join("session.json").exists()); + assert!(!temporary.exists()); + assert!(path.join("unknown.json").exists()); + assert!(path.join("owner.lock").exists()); +} diff --git a/apps/ai-game-creator-shell/src-tauri/src/analytics/store.rs b/apps/ai-game-creator-shell/src-tauri/src/analytics/store.rs new file mode 100644 index 000000000..f9bb615be --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/src/analytics/store.rs @@ -0,0 +1,1027 @@ +//! 本地产品事件队列。业务调用只投递有界通道,磁盘工作由单独线程完成。 +use super::contract::{Event, Route}; +use super::session::{self, SessionRecord}; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; +use std::collections::{HashMap, HashSet, VecDeque}; +use std::fs::{self, File}; +use std::io::{self, Read, Write}; +use std::path::{Path, PathBuf}; +use std::sync::atomic::{AtomicU64, Ordering}; +use std::sync::{mpsc, Arc}; +use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; + +const MAX_EVENTS: usize = 500; +const MAX_BYTES: usize = 1024 * 1024; +const MAX_TOTAL_BYTES: u64 = 20 * 1024 * 1024; +const RETENTION: Duration = Duration::from_secs(7 * 24 * 60 * 60); +const SEAL_AFTER: Duration = Duration::from_secs(5 * 60); +const QUEUE_CAPACITY: usize = 1024; +const MAX_META_BYTES: usize = 256 * 1024; +const MAX_LIVE_OBSERVATIONS: usize = 16_384; + +#[derive(Clone, Copy, Debug, Default)] +pub(crate) struct StoreCounters { + pub accepted: u64, + pub dropped: u64, + pub duplicate: u64, + pub corrupt_batches: u64, + pub io_errors: u64, +} + +#[derive(Default)] +struct Counters { + queued_bytes: AtomicU64, + accepted: AtomicU64, + dropped: AtomicU64, + duplicate: AtomicU64, + corrupt_batches: AtomicU64, + io_errors: AtomicU64, +} + +enum Command { + Record(Route, Event, String, u64), + Session(SessionRecord, u64), + Goal(super::goal::Request, u64), + Run(super::run::Request, u64), + Flush, +} + +#[derive(Clone)] +pub(crate) struct AnalyticsWriter { + sender: mpsc::SyncSender, + counters: Arc, +} + +impl AnalyticsWriter { + pub(crate) fn start(config_dir: PathBuf, session_id: String) -> Self { + let (sender, receiver) = mpsc::sync_channel(QUEUE_CAPACITY); + let counters = Arc::new(Counters::default()); + let worker_counters = counters.clone(); + let result = std::thread::Builder::new() + .name("local-analytics".into()) + .spawn(move || { + let mut store = match Store::open(config_dir, session_id, worker_counters.clone()) { + Ok(store) => store, + Err(_) => { + worker_counters.io_errors.fetch_add(1, Ordering::Relaxed); + return; + } + }; + loop { + if store + .started + .is_some_and(|start| start.elapsed() >= SEAL_AFTER) + { + store.seal(); + } + let wait = store + .started + .map(|start| SEAL_AFTER.saturating_sub(start.elapsed())) + .unwrap_or(SEAL_AFTER); + match receiver.recv_timeout(wait) { + Ok(Command::Record(route, event, key, bytes)) => { + worker_counters + .queued_bytes + .fetch_sub(bytes, Ordering::Relaxed); + store.record(route, event, &key); + } + Ok(Command::Run(request, bytes)) => { + worker_counters + .queued_bytes + .fetch_sub(bytes, Ordering::Relaxed); + store.run_request(request, bytes); + } + Ok(Command::Goal(request, bytes)) => { + worker_counters + .queued_bytes + .fetch_sub(bytes, Ordering::Relaxed); + // 身份校验必须发生在消费资格前。 + let valid_session = match &request { + super::goal::Request::Accepted { event, .. } => { + event.editor_session_id == store.session_id + } + _ => true, + }; + if valid_session { + match super::goal::process(request) { + Ok(Some((route, event))) => { + let fact = format!( + "{}:creative_task_submit", + event.project_id.as_deref().unwrap() + ); + store.record(route, event, &fact); + } + Ok(None) => {} + Err(_) => { + worker_counters.io_errors.fetch_add(1, Ordering::Relaxed); + } + } + } else { + worker_counters.dropped.fetch_add(1, Ordering::Relaxed); + } + } + Ok(Command::Session(record, bytes)) => { + worker_counters + .queued_bytes + .fetch_sub(bytes, Ordering::Relaxed); + if store.write_session(&record, bytes).is_err() { + worker_counters.io_errors.fetch_add(1, Ordering::Relaxed); + } + } + Ok(Command::Flush) | Err(mpsc::RecvTimeoutError::Timeout) => store.seal(), + Err(mpsc::RecvTimeoutError::Disconnected) => { + store.seal(); + break; + } + } + } + }); + if result.is_err() { + counters.io_errors.fetch_add(1, Ordering::Relaxed); + } + Self { sender, counters } + } + + /// 不等待队列、磁盘或后台线程;调用方不得将 false 转成业务错误。 + pub(crate) fn try_record(&self, route: Route, event: Event, fact_key: String) -> bool { + // 同时限制条数与字节数,巨型输入不得先占满队列再交给后台拒绝。 + let mut size = LimitedSize(1); + if fact_key.is_empty() + || fact_key.len() > 4096 + || !route.validate() + || event.validate().is_err() + || route.user_id != event.user_id + || serde_json::to_writer(&mut size, &event).is_err() + || serde_json::to_writer(&mut size, &route).is_err() + { + self.counters.dropped.fetch_add(1, Ordering::Relaxed); + return false; + } + let bytes = (size.0 + fact_key.len()) as u64; + if self + .counters + .queued_bytes + .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |current| { + (current.saturating_add(bytes) <= MAX_BYTES as u64).then_some(current + bytes) + }) + .is_err() + { + self.counters.dropped.fetch_add(1, Ordering::Relaxed); + return false; + } + if self + .sender + .try_send(Command::Record(route, event, fact_key, bytes)) + .is_ok() + { + true + } else { + self.counters + .queued_bytes + .fetch_sub(bytes, Ordering::Relaxed); + self.counters.dropped.fetch_add(1, Ordering::Relaxed); + false + } + } + + pub(crate) fn try_session(&self, record: SessionRecord) -> bool { + let mut size = LimitedSize(0); + if !record.validate() + || serde_json::to_writer(&mut size, &record).is_err() + || size.0 > 16 * 1024 + { + self.counters.dropped.fetch_add(1, Ordering::Relaxed); + return false; + } + let bytes = size.0 as u64; + if self + .counters + .queued_bytes + .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |current| { + (current.saturating_add(bytes) <= MAX_BYTES as u64).then_some(current + bytes) + }) + .is_err() + { + self.counters.dropped.fetch_add(1, Ordering::Relaxed); + return false; + } + if self + .sender + .try_send(Command::Session(record, bytes)) + .is_ok() + { + true + } else { + self.counters + .queued_bytes + .fetch_sub(bytes, Ordering::Relaxed); + self.counters.dropped.fetch_add(1, Ordering::Relaxed); + false + } + } + + pub(super) fn try_goal(&self, request: super::goal::Request) -> bool { + let mut size = LimitedSize(0); + if !request.validate() || serde_json::to_writer(&mut size, &request).is_err() { + self.counters.dropped.fetch_add(1, Ordering::Relaxed); + return false; + } + let bytes = size.0 as u64; + if self + .counters + .queued_bytes + .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |current| { + (current.saturating_add(bytes) <= MAX_BYTES as u64).then_some(current + bytes) + }) + .is_err() + { + self.counters.dropped.fetch_add(1, Ordering::Relaxed); + return false; + } + if self.sender.try_send(Command::Goal(request, bytes)).is_ok() { + true + } else { + self.counters + .queued_bytes + .fetch_sub(bytes, Ordering::Relaxed); + self.counters.dropped.fetch_add(1, Ordering::Relaxed); + false + } + } + + pub(super) fn try_run(&self, request: super::run::Request) -> bool { + let mut size = LimitedSize(0); + if !request.validate() || serde_json::to_writer(&mut size, &request).is_err() { + self.counters.dropped.fetch_add(1, Ordering::Relaxed); + return false; + } + let bytes = size.0 as u64; + if self + .counters + .queued_bytes + .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |current| { + (current.saturating_add(bytes) <= MAX_BYTES as u64).then_some(current + bytes) + }) + .is_err() + { + self.counters.dropped.fetch_add(1, Ordering::Relaxed); + return false; + } + if self.sender.try_send(Command::Run(request, bytes)).is_ok() { + true + } else { + self.counters + .queued_bytes + .fetch_sub(bytes, Ordering::Relaxed); + self.counters.dropped.fetch_add(1, Ordering::Relaxed); + false + } + } + + pub(crate) fn flush(&self) -> bool { + self.sender.try_send(Command::Flush).is_ok() + } + + pub(crate) fn counters(&self) -> StoreCounters { + StoreCounters { + accepted: self.counters.accepted.load(Ordering::Relaxed), + dropped: self.counters.dropped.load(Ordering::Relaxed), + duplicate: self.counters.duplicate.load(Ordering::Relaxed), + corrupt_batches: self.counters.corrupt_batches.load(Ordering::Relaxed), + io_errors: self.counters.io_errors.load(Ordering::Relaxed), + } + } +} + +struct LimitedSize(usize); + +impl Write for LimitedSize { + fn write(&mut self, bytes: &[u8]) -> io::Result { + if self.0.saturating_add(bytes.len()) > MAX_BYTES { + return Err(invalid_data()); + } + self.0 += bytes.len(); + Ok(bytes.len()) + } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[derive(Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +struct BatchMeta { + schema_version: u32, + batch_id: String, + editor_session_id: String, + route: Route, + created_at_ms: u64, + event_count: usize, + event_ids: Vec, + facts: HashMap, +} + +struct Batch { + path: PathBuf, + modified: SystemTime, +} + +struct Store { + pending_runs: VecDeque<(String, super::run::Request, u64)>, + pending_run_bytes: u64, + root: PathBuf, + _owner: File, + projects: HashMap, + batches: PathBuf, + session_id: String, + route: Option, + events: Vec<(Event, String, Vec)>, + bytes: usize, + started: Option, + live_facts: VecDeque<(Instant, String, String)>, + live_projects: HashMap, + known: HashMap, + known_ids: HashSet, + counters: Arc, +} + +impl Store { + fn open(config: PathBuf, session_id: String, counters: Arc) -> io::Result { + if uuid::Uuid::parse_str(&session_id).is_err() { + return Err(invalid_data()); + } + let root = config.join("analytics"); + let instances = root.join("instances"); + let instance = instances.join(&session_id); + let batches = instance.join("batches"); + for directory in [&root, &instances, &instance, &batches] { + ensure_directory(directory)?; + } + let owner = session::claim(&instance)?; + session::recover(&instances, &session_id); + let mut store = Self { + pending_runs: VecDeque::new(), + pending_run_bytes: 0, + root, + _owner: owner, + projects: HashMap::new(), + batches, + session_id, + route: None, + events: Vec::new(), + bytes: 0, + started: None, + live_facts: VecDeque::new(), + live_projects: HashMap::new(), + known: HashMap::new(), + known_ids: HashSet::new(), + counters, + }; + // session UUID 必须由 GUI 为本次新实例生成;不触碰其他实例的临时目录。 + for entry in fs::read_dir(&store.batches)? { + let entry = entry?; + if entry.file_name().to_string_lossy().starts_with(".tmp-") { + let _ = remove_batch(&entry.path()); + } + } + store.prune(0)?; + Ok(store) + } + + fn run_request(&mut self, request: super::run::Request, bytes: u64) { + use super::run::Request; + if !request.validate() || request.session_id() != self.session_id { + self.counters.dropped.fetch_add(1, Ordering::Relaxed); + return; + } + let request = match request { + Request::DirectCandidate { + attempt_id, + terminal, + } => { + if bytes > MAX_BYTES as u64 { + return; + } + if self.pending_runs.iter().any(|(id, _, _)| id == &attempt_id) { + return; + } + while self.pending_runs.len() >= 16 + || self.pending_run_bytes + bytes > MAX_BYTES as u64 + { + let Some((_, _, removed)) = self.pending_runs.pop_front() else { + break; + }; + self.pending_run_bytes -= removed; + self.counters.dropped.fetch_add(1, Ordering::Relaxed); + } + self.pending_run_bytes += bytes; + self.pending_runs.push_back((attempt_id, *terminal, bytes)); + return; + } + Request::Settle { + attempt_id, + discard, + .. + } => { + let Some(index) = self + .pending_runs + .iter() + .position(|(id, _, _)| id == &attempt_id) + else { + return; + }; + let (_, terminal, removed) = self.pending_runs.remove(index).unwrap(); + self.pending_run_bytes -= removed; + if discard { + return; + } + terminal + } + other => other, + }; + match super::run::process(request) { + Ok(Some((route, event))) => { + let fact = format!("{}:terminal", event.agent_run_id.as_deref().unwrap()); + self.record(route, event, &fact); + } + Ok(None) => {} + Err(_) => { + self.counters.io_errors.fetch_add(1, Ordering::Relaxed); + } + } + } + + fn write_session(&mut self, record: &SessionRecord, bytes: u64) -> io::Result<()> { + // 原子替换期间旧文件与临时文件同时存在,预留完整新文件大小。 + self.prune(bytes)?; + session::write(self.batches.parent().unwrap(), record, &self.session_id) + } + + fn recover(&mut self) { + let Ok(batches) = list_batches(&self.root) else { + return; + }; + for batch in batches { + match read_batch(&batch.path) { + Ok(meta) => { + if meta.facts.iter().any(|(key, id)| { + self.known.contains_key(key) || self.known_ids.contains(id) + }) { + self.counters + .corrupt_batches + .fetch_add(1, Ordering::Relaxed); + continue; + } + if let Ok(events) = read_events(&batch.path) { + for event in events { + observe_project(&mut self.projects, &meta.route, &event); + } + } + self.known_ids.extend(meta.event_ids); + self.known.extend(meta.facts); + } + Err(_) => { + // 已发布批次不重写、不重新生成事件;其他实例的文件只读跳过。 + self.counters + .corrupt_batches + .fetch_add(1, Ordering::Relaxed); + } + } + } + } + + fn record(&mut self, route: Route, mut event: Event, fact: &str) { + if event.validate().is_err() + || !route.validate() + || route.user_id != event.user_id + || event.editor_session_id != self.session_id + || fact.is_empty() + || fact.len() > 4096 + { + self.counters.dropped.fetch_add(1, Ordering::Relaxed); + return; + } + let digest = fact_digest(&route, fact); + if self.known.contains_key(&digest) || self.events.iter().any(|(_, key, _)| key == &digest) + { + self.counters.duplicate.fetch_add(1, Ordering::Relaxed); + return; + } + if self.known_ids.contains(&event.event_id) + || self + .events + .iter() + .any(|(old, _, _)| old.event_id == event.event_id) + { + self.counters.dropped.fetch_add(1, Ordering::Relaxed); + return; + } + if event.event_name == "project_open" { + if let Some(project) = &event.project_id { + let key = fact_digest(&route, project); + let mut opened = self.projects.get(&key).copied(); + if self.route.as_ref() == Some(&route) { + for (pending, _, _) in &self.events { + if pending.project_id.as_ref() != Some(project) { + continue; + } + match pending.event_name.as_str() { + "project_open" => opened = Some(true), + "project_create_success" if opened.is_none() => opened = Some(false), + _ => {} + } + } + } + event.properties["is_first_open"] = opened.map(|opened| !opened).into(); + } + } + if event.validate().is_err() { + self.counters.dropped.fetch_add(1, Ordering::Relaxed); + return; + } + let Ok(mut line) = serde_json::to_vec(&event) else { + self.counters.dropped.fetch_add(1, Ordering::Relaxed); + return; + }; + line.push(b'\n'); + if line.len() > MAX_BYTES { + self.counters.dropped.fetch_add(1, Ordering::Relaxed); + return; + } + if self.route.as_ref().is_some_and(|current| current != &route) + || self.bytes + line.len() > MAX_BYTES + || self + .started + .is_some_and(|start| start.elapsed() >= SEAL_AFTER) + { + self.seal(); + } + self.route = Some(route); + self.started.get_or_insert_with(Instant::now); + self.bytes += line.len(); + self.events.push((event, digest, line)); + self.counters.accepted.fetch_add(1, Ordering::Relaxed); + if self.events.len() >= MAX_EVENTS || self.bytes >= MAX_BYTES { + self.seal(); + } + } + + fn seal(&mut self) { + if self.events.is_empty() { + if self.prune(0).is_err() { + self.counters.io_errors.fetch_add(1, Ordering::Relaxed); + } + return; + } + let events = std::mem::take(&mut self.events); + let route = self.route.take().expect("nonempty batch has route"); + self.started = None; + self.bytes = 0; + let id = uuid::Uuid::new_v4().to_string(); + let meta = BatchMeta { + schema_version: 1, + batch_id: id.clone(), + editor_session_id: self.session_id.clone(), + route, + created_at_ms: now_ms(), + event_count: events.len(), + event_ids: events + .iter() + .map(|(event, _, _)| event.event_id.clone()) + .collect(), + facts: events + .iter() + .map(|(event, key, _)| (key.clone(), event.event_id.clone())) + .collect(), + }; + let temporary = self.batches.join(format!(".tmp-{id}")); + let result = (|| -> io::Result<()> { + let meta_bytes = serde_json::to_vec(&meta)?; + if meta_bytes.len() > MAX_META_BYTES { + return Err(invalid_data()); + } + let event_bytes: usize = events.iter().map(|(_, _, line)| line.len()).sum(); + self.prune((event_bytes + meta_bytes.len()) as u64)?; + fs::create_dir(&temporary)?; + let mut file = File::create(temporary.join("events.jsonl"))?; + for (_, _, line) in &events { + file.write_all(line)?; + } + file.sync_all()?; + let mut metadata = File::create(temporary.join("meta.json"))?; + metadata.write_all(&meta_bytes)?; + metadata.sync_all()?; + drop(file); + drop(metadata); + fs::rename(&temporary, self.batches.join(&id))?; + Ok(()) + })(); + if result.is_ok() { + for (event, _, _) in &events { + observe_project(&mut self.projects, &meta.route, event); + if let Some(project) = &event.project_id { + let key = fact_digest(&meta.route, project); + if let Some(opened) = self.projects.get(&key) { + self.live_projects.insert(key, (Instant::now(), *opened)); + } + } + } + self.live_facts.extend( + meta.facts + .iter() + .map(|(key, id)| (Instant::now(), key.clone(), id.clone())), + ); + self.trim_live(); + self.known_ids.extend(meta.event_ids); + self.known.extend(meta.facts); + } else { + let _ = remove_batch(&temporary); + self.counters.io_errors.fetch_add(1, Ordering::Relaxed); + self.counters + .dropped + .fetch_add(events.len() as u64, Ordering::Relaxed); + } + } + + fn prune(&mut self, reserve: u64) -> io::Result<()> { + let result = self.prune_files(reserve); + // 重建磁盘索引,但保留当前实例已观测事实,上传删除不能重授回调资格。 + self.projects.clear(); + self.known.clear(); + self.known_ids.clear(); + self.recover(); + self.trim_live(); + for (_, key, id) in &self.live_facts { + self.known.insert(key.clone(), id.clone()); + self.known_ids.insert(id.clone()); + } + for (key, (_, opened)) in &self.live_projects { + self.projects + .entry(key.clone()) + .and_modify(|known| *known |= *opened) + .or_insert(*opened); + } + result + } + + fn trim_live(&mut self) { + self.trim_live_at(Instant::now()); + } + + fn trim_live_at(&mut self, now: Instant) { + // 仅当前进程内保留近期观测,固定条数上限;不形成永久历史账本。 + while self.live_facts.len() > MAX_LIVE_OBSERVATIONS + || self + .live_facts + .front() + .is_some_and(|(time, _, _)| now.saturating_duration_since(*time) >= RETENTION) + { + self.live_facts.pop_front(); + } + self.live_projects + .retain(|_, (time, _)| now.saturating_duration_since(*time) < RETENTION); + while self.live_projects.len() > MAX_LIVE_OBSERVATIONS { + let oldest = self + .live_projects + .iter() + .min_by_key(|(_, (time, _))| *time) + .map(|(key, _)| key.clone()) + .unwrap(); + self.live_projects.remove(&oldest); + } + } + + fn prune_files(&mut self, reserve: u64) -> io::Result<()> { + session::prune( + &self.root.join("instances"), + &self.session_id, + reserve, + MAX_TOTAL_BYTES, + RETENTION, + || directory_size(&self.root, 0, &self.counters), + ); + let mut bytes = directory_size(&self.root, 0, &self.counters); + let mut batches = list_batches(&self.root)?; + batches.sort_by_key(|batch| batch.modified); + for batch in batches { + let expired = SystemTime::now() + .duration_since(batch.modified) + .is_ok_and(|age| age >= RETENTION); + if !expired && bytes.saturating_add(reserve) <= MAX_TOTAL_BYTES { + continue; + } + let size = directory_size(&batch.path, 0, &self.counters); + let meta = read_batch(&batch.path).ok(); + if remove_batch(&batch.path).is_err() { + self.counters.io_errors.fetch_add(1, Ordering::Relaxed); + continue; + } + bytes = bytes.saturating_sub(size); + if let Some(meta) = meta { + self.counters + .dropped + .fetch_add(meta.event_count as u64, Ordering::Relaxed); + } + } + if bytes.saturating_add(reserve) > MAX_TOTAL_BYTES { + return Err(invalid_data()); + } + Ok(()) + } +} + +pub(super) fn invalid_data() -> io::Error { + io::Error::new(io::ErrorKind::InvalidData, "invalid analytics data") +} + +fn now_ms() -> u64 { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_millis() + .min(u64::MAX as u128) as u64 +} + +fn fact_digest(route: &Route, fact: &str) -> String { + let mut hash = Sha256::new(); + hash.update(serde_json::to_vec(route).expect("route contains serializable strings")); + hash.update([0]); + hash.update(fact.as_bytes()); + format!("{:x}", hash.finalize()) +} + +pub(super) fn safe_metadata(path: &Path) -> io::Result { + let meta = fs::symlink_metadata(path)?; + if meta.file_type().is_symlink() { + return Err(invalid_data()); + } + #[cfg(windows)] + { + use std::os::windows::fs::MetadataExt; + if meta.file_attributes() & 0x400 != 0 { + return Err(invalid_data()); + } + } + Ok(meta) +} + +fn ensure_directory(path: &Path) -> io::Result<()> { + match fs::create_dir(path) { + Ok(()) => Ok(()), + Err(error) if error.kind() == io::ErrorKind::AlreadyExists => { + if safe_metadata(path)?.is_dir() { + Ok(()) + } else { + Err(invalid_data()) + } + } + Err(error) => Err(error), + } +} + +pub(super) fn read_bounded(path: &Path, limit: usize) -> io::Result> { + let meta = safe_metadata(path)?; + if !meta.is_file() || meta.len() > limit as u64 { + return Err(invalid_data()); + } + let mut bytes = Vec::new(); + File::open(path)? + .take(limit as u64 + 1) + .read_to_end(&mut bytes)?; + if bytes.len() > limit { + return Err(invalid_data()); + } + Ok(bytes) +} + +fn read_batch(path: &Path) -> io::Result { + if !safe_metadata(path)?.is_dir() { + return Err(invalid_data()); + } + let meta: BatchMeta = + serde_json::from_slice(&read_bounded(&path.join("meta.json"), MAX_META_BYTES)?)?; + if meta.schema_version != 1 + || !meta.route.validate() + || meta.event_count == 0 + || meta.event_count > MAX_EVENTS + || meta.event_count != meta.event_ids.len() + || meta.event_count != meta.facts.len() + || path.file_name().and_then(|name| name.to_str()) != Some(meta.batch_id.as_str()) + || path + .parent() + .and_then(Path::parent) + .and_then(Path::file_name) + .and_then(|name| name.to_str()) + != Some(meta.editor_session_id.as_str()) + || uuid::Uuid::parse_str(&meta.batch_id).is_err() + { + return Err(invalid_data()); + } + let bytes = read_bounded(&path.join("events.jsonl"), MAX_BYTES)?; + if bytes.last() != Some(&b'\n') { + return Err(invalid_data()); + } + let mut ids = HashSet::new(); + for (index, line) in bytes[..bytes.len() - 1] + .split(|byte| *byte == b'\n') + .enumerate() + { + let event: Event = serde_json::from_slice(line)?; + if event.validate().is_err() + || event.user_id != meta.route.user_id + || event.editor_session_id != meta.editor_session_id + || meta.event_ids.get(index) != Some(&event.event_id) + || !ids.insert(event.event_id) + { + return Err(invalid_data()); + } + } + if ids.len() != meta.event_count + || meta.facts.iter().any(|(key, id)| { + key.len() != 64 || !key.bytes().all(|c| c.is_ascii_hexdigit()) || !ids.contains(id) + }) + || meta.facts.values().collect::>().len() != ids.len() + { + return Err(invalid_data()); + } + Ok(meta) +} + +fn list_batches(root: &Path) -> io::Result> { + let mut batches = Vec::new(); + let instances = root.join("instances"); + if !safe_metadata(&instances)?.is_dir() { + return Err(invalid_data()); + } + for instance in fs::read_dir(instances)? { + let Ok(instance) = instance else { continue }; + if !safe_metadata(&instance.path()).is_ok_and(|meta| meta.is_dir()) { + continue; + } + let path = instance.path().join("batches"); + if !safe_metadata(&path).is_ok_and(|meta| meta.is_dir()) { + continue; + } + let Ok(entries) = fs::read_dir(path) else { + continue; + }; + for batch in entries { + let Ok(batch) = batch else { continue }; + // 临时、隔离和未知目录不能被当成可上传批次,也不能猜其写入者已退出。 + if uuid::Uuid::parse_str(&batch.file_name().to_string_lossy()).is_err() { + continue; + } + if let Ok(meta) = safe_metadata(&batch.path()) { + if meta.is_dir() { + if batches.len() >= 65536 { + return Err(invalid_data()); + } + batches.push(Batch { + path: batch.path(), + modified: meta.modified()?, + }); + } + } + } + } + Ok(batches) +} + +fn directory_size(path: &Path, depth: usize, counters: &Counters) -> u64 { + if depth > 8 { + counters.corrupt_batches.fetch_add(1, Ordering::Relaxed); + return 0; + } + let meta = match safe_metadata(path) { + Ok(meta) => meta, + Err(_) => { + counters.corrupt_batches.fetch_add(1, Ordering::Relaxed); + // 链接只计链接本身的元数据,不打开或跟随其目标。 + return fs::symlink_metadata(path) + .map(|meta| meta.len()) + .unwrap_or(0); + } + }; + if meta.is_file() { + return meta.len(); + } + if !meta.is_dir() { + return 0; + } + let mut bytes = 0u64; + let Ok(entries) = fs::read_dir(path) else { + counters.io_errors.fetch_add(1, Ordering::Relaxed); + return 0; + }; + for entry in entries { + if let Ok(entry) = entry { + bytes = bytes.saturating_add(directory_size(&entry.path(), depth + 1, counters)); + } else { + counters.io_errors.fetch_add(1, Ordering::Relaxed); + } + } + bytes +} + +fn remove_batch(path: &Path) -> io::Result<()> { + if !safe_metadata(path)?.is_dir() { + return Err(invalid_data()); + } + let files = fs::read_dir(path)?.collect::, _>>()?; + // 删除范围严格停留在已核实的批次普通文件,绝不递归穿过未知目录或链接。 + for file in &files { + if !safe_metadata(&file.path())?.is_file() { + return Err(invalid_data()); + } + } + for file in files { + fs::remove_file(file.path())?; + } + fs::remove_dir(path) +} + +#[cfg(test)] +#[path = "store_tests.rs"] +mod tests; + +fn read_events(path: &Path) -> io::Result> { + let bytes = read_bounded(&path.join("events.jsonl"), MAX_BYTES)?; + bytes + .split(|b| *b == b'\n') + .filter(|line| !line.is_empty()) + .map(|line| serde_json::from_slice(line).map_err(io::Error::from)) + .collect() +} + +fn observe_project(projects: &mut HashMap, route: &Route, event: &Event) { + let Some(project) = &event.project_id else { + return; + }; + let key = fact_digest(route, project); + match event.event_name.as_str() { + "project_open" => { + projects.insert(key, true); + } + "project_create_success" => { + projects.entry(key).or_insert(false); + } + _ => {} + } +} + +/// 已验证的封存批次;路径只来自本地扫描,不接受服务端输入。 +pub(super) struct UploadBatch { + path: PathBuf, + pub request: serde_json::Value, + pub batch_id: String, + pub route: Route, + pub event_count: usize, +} + +pub(super) fn upload_candidates(root: &Path) -> io::Result> { + let mut batches = list_batches(root)?; + batches.sort_by_key(|batch| batch.modified); + Ok(batches.into_iter().map(|batch| batch.path).collect()) +} + +pub(super) fn load_upload_batch(path: PathBuf) -> io::Result { + let meta = read_batch(&path)?; + let events = read_events(&path)?; + // 同一份内存副本再次核对,避免保留清理或外部修改造成两次读取不一致。 + if events.len() != meta.event_count + || events.iter().zip(&meta.event_ids).any(|(event, id)| { + &event.event_id != id + || event.validate().is_err() + || event.user_id != meta.route.user_id + || event.editor_session_id != meta.editor_session_id + }) + { + return Err(invalid_data()); + } + let request = serde_json::json!({ + "schema_version": 1, "batch_id": meta.batch_id, + "destination_origin": meta.route.destination_origin, "user_id": meta.route.user_id, + "events": events, + }); + Ok(UploadBatch { + path, + request, + batch_id: meta.batch_id, + route: meta.route, + event_count: meta.event_count, + }) +} + +impl UploadBatch { + pub(super) fn exists(&self) -> bool { + safe_metadata(&self.path).is_ok_and(|m| m.is_dir()) + } + + pub(super) fn acknowledge(&self) -> io::Result<()> { + match remove_batch(&self.path) { + Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(()), + result => result, + } + } +} diff --git a/apps/ai-game-creator-shell/src-tauri/src/analytics/store_tests.rs b/apps/ai-game-creator-shell/src-tauri/src/analytics/store_tests.rs new file mode 100644 index 000000000..61b830f31 --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/src/analytics/store_tests.rs @@ -0,0 +1,1245 @@ +use super::*; +use serde_json::json; + +/// 由 API 测试启动隔离主站与数据库;本进程走实际封存、上传和确认清理。 +#[tokio::test] +#[ignore = "requires isolated local API and database smoke bridge"] +async fn analytics_live_api_upload_cleans_confirmed_batch() { + #[derive(serde::Deserialize)] + #[serde(rename_all = "camelCase", deny_unknown_fields)] + struct Bridge { + origin: String, + user_id: String, + access_token: String, + result_path: PathBuf, + } + let bridge_path = std::env::var_os("AGC_ANALYTICS_SMOKE_BRIDGE") + .expect("isolated smoke bridge path required"); + let bridge: Bridge = serde_json::from_slice( + &read_bounded(Path::new(&bridge_path), 16 * 1024).expect("read smoke bridge"), + ) + .expect("valid smoke bridge"); + let url = url::Url::parse(&bridge.origin).expect("valid smoke origin"); + assert!( + url.scheme() == "http" + && url.origin().ascii_serialization() == bridge.origin + && url.host_str().is_some_and(|host| { + host == "localhost" + || host + .trim_matches(['[', ']']) + .parse::() + .is_ok_and(|ip| ip.is_loopback()) + }), + "smoke requires a loopback origin" + ); + let dir = tempfile::tempdir().unwrap(); + let mut store = open(dir.path()); + let event = event(&store.session_id, &bridge.user_id); + let event_id = event.event_id.clone(); + store.record( + Route::from_identity(Some(bridge.user_id.clone()), Some(&bridge.origin)), + event, + "live-api-session-start", + ); + store.seal(); + let candidates = upload_candidates(&store.root).unwrap(); + assert_eq!(candidates.len(), 1, "real local batch must be sealed"); + let batch = load_upload_batch(candidates.into_iter().next().unwrap()).unwrap(); + let _identity = crate::platform_session::install_test_platform_session( + &bridge.user_id, + &bridge.access_token, + &bridge.origin, + ); + let client = reqwest::Client::builder() + .no_proxy() + .redirect(reqwest::redirect::Policy::none()) + .timeout(Duration::from_secs(30)) + .build() + .unwrap(); + super::super::upload::cycle(&store.root, &client).await; + assert!( + !batch.exists(), + "only a matching server acknowledgement permits cleanup" + ); + assert!(upload_candidates(&store.root).unwrap().is_empty()); + fs::write( + &bridge.result_path, + serde_json::to_vec(&json!({"eventId": event_id, "batchId": batch.batch_id})).unwrap(), + ) + .expect("write non-secret smoke result"); +} + +#[tokio::test] +async fn upload_keeps_failures_then_deletes_only_acknowledged_batch_without_regranting_fact() { + use std::net::TcpListener; + let dir = tempfile::tempdir().unwrap(); + let mut store = open(dir.path()); + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let origin = format!("http://{}", listener.local_addr().unwrap()); + let route = Route::from_identity(Some("A".into()), Some(&origin)); + store.record(route.clone(), event(&store.session_id, "A"), "single-fact"); + store.seal(); + let batch = load_upload_batch(upload_candidates(&store.root).unwrap().remove(0)).unwrap(); + store.record( + Route::from_identity(Some("B".into()), Some(&origin)), + event(&store.session_id, "B"), + "other-account", + ); + store.seal(); + let id = batch.batch_id.clone(); + let server = std::thread::spawn(move || { + for (status, body) in [ + ( + 200, + json!({"ok": true, "data": {"acknowledged_batch_ids": ["wrong"], "event_count": 1}, "error": null}), + ), + (503, json!({"ok": false})), + ( + 200, + json!({"ok": true, "data": {"acknowledged_batch_ids": [id], "event_count": 1}, "error": null}), + ), + ] { + let (mut stream, _) = listener.accept().unwrap(); + stream + .set_read_timeout(Some(Duration::from_secs(5))) + .unwrap(); + let mut bytes = Vec::new(); + let mut chunk = [0; 4096]; + loop { + let count = stream.read(&mut chunk).unwrap(); + assert!(count > 0); + bytes.extend_from_slice(&chunk[..count]); + if let Some(end) = bytes.windows(4).position(|w| w == b"\r\n\r\n") { + let headers = String::from_utf8_lossy(&bytes[..end]).to_lowercase(); + let length: usize = headers + .lines() + .find_map(|line| line.strip_prefix("content-length: ")) + .unwrap() + .parse() + .unwrap(); + if bytes.len() >= end + 4 + length { + assert!(headers.contains("authorization: bearer test-token")); + assert!(headers.contains("x-genarrative-response-envelope: 1")); + let request: serde_json::Value = + serde_json::from_slice(&bytes[end + 4..]).unwrap(); + assert_eq!(request["user_id"], "A"); + assert_eq!(request["events"].as_array().unwrap().len(), 1); + break; + } + } + } + let body = body.to_string(); + write!(stream, "HTTP/1.1 {status} Test\r\nContent-Length: {}\r\nContent-Type: application/json\r\nConnection: close\r\n\r\n{body}", body.len()).unwrap(); + } + }); + let _identity = + crate::platform_session::install_test_platform_session("A", "test-token", &origin); + let client = reqwest::Client::builder() + .timeout(Duration::from_secs(5)) + .build() + .unwrap(); + for _ in 0..2 { + super::super::upload::cycle(&store.root, &client).await; + assert!(batch.exists()); + } + super::super::upload::cycle(&store.root, &client).await; + assert!(!batch.exists()); + assert_eq!(upload_candidates(&store.root).unwrap().len(), 1); + server.join().unwrap(); + store.prune(0).unwrap(); + store.record(route, event(&store.session_id, "A"), "single-fact"); + assert!(store.events.is_empty()); + assert_eq!(store.counters.duplicate.load(Ordering::Relaxed), 1); +} + +fn route(user: &str) -> Route { + Route { + user_id: Some(user.into()), + destination_origin: Some("https://example.com".into()), + } +} + +fn event(session: &str, user: &str) -> Event { + serde_json::from_value(json!({ + "schema_version": 1, + "event_id": uuid::Uuid::new_v4().to_string(), + "event_name": "editor_session_start", + "event_time": "2026-09-21T00:00:00.000Z", + "user_id": user, + "editor_session_id": session, + "project_id": null, "creative_task_id": null, + "agent_run_id": null, "agent_turn_id": null, + "status": "success", "error_code": null, "source": "editor", "client_version": "1.0.0", + "properties": { "entry_source": "direct_launch", "first_project_id": null } + })) + .unwrap() +} + +fn open(config: &Path) -> Store { + Store::open( + config.to_path_buf(), + uuid::Uuid::new_v4().to_string(), + Arc::new(Counters::default()), + ) + .unwrap() +} + +#[test] +fn buffered_and_published_replay_keep_original_identity() { + let dir = tempfile::tempdir().unwrap(); + let mut store = open(dir.path()); + let first = event(&store.session_id, "A"); + let original_id = first.event_id.clone(); + store.record(route("A"), first, "start-original-session"); + store.record( + route("A"), + event(&store.session_id, "A"), + "start-original-session", + ); + assert_eq!(store.events.len(), 1); + assert!(list_batches(&store.root).unwrap().is_empty()); + store.seal(); + let batches = list_batches(&store.root).unwrap(); + assert_eq!(batches.len(), 1); + assert_eq!( + read_batch(&batches[0].path).unwrap().event_ids, + [original_id.clone()] + ); + let mut restored = open(dir.path()); + restored.record( + route("A"), + event(&restored.session_id, "A"), + "start-original-session", + ); + assert!(restored.events.is_empty()); + assert_eq!(restored.known.values().next(), Some(&original_id)); + assert_eq!(restored.counters.duplicate.load(Ordering::Relaxed), 1); +} + +#[test] +fn account_switch_and_count_limit_publish_complete_separate_batches() { + let dir = tempfile::tempdir().unwrap(); + let mut store = open(dir.path()); + store.record(route("A"), event(&store.session_id, "A"), "A"); + store.record(route("B"), event(&store.session_id, "B"), "B"); + let batches = list_batches(&store.root).unwrap(); + assert_eq!(read_batch(&batches[0].path).unwrap().route, route("A")); + for index in 1..MAX_EVENTS { + store.record( + route("B"), + event(&store.session_id, "B"), + &format!("B-{index}"), + ); + } + assert!(store.events.is_empty()); + let batches = list_batches(&store.root).unwrap(); + assert_eq!(batches.len(), 2); + assert_eq!( + batches + .iter() + .map(|batch| read_batch(&batch.path).unwrap().event_count) + .sum::(), + 501 + ); + assert!(fs::read_dir(&store.batches).unwrap().all(|entry| !entry + .unwrap() + .file_name() + .to_string_lossy() + .starts_with('.'))); +} + +#[test] +fn deadline_and_size_rotate_without_empty_files() { + let dir = tempfile::tempdir().unwrap(); + let mut store = open(dir.path()); + store.seal(); + assert!(list_batches(&store.root).unwrap().is_empty()); + store.record(route("A"), event(&store.session_id, "A"), "first"); + store.started = Some(Instant::now() - SEAL_AFTER); + store.record(route("A"), event(&store.session_id, "A"), "next"); + assert_eq!(list_batches(&store.root).unwrap().len(), 1); + store.bytes = MAX_BYTES; + store.record(route("A"), event(&store.session_id, "A"), "third"); + assert_eq!(list_batches(&store.root).unwrap().len(), 2); + let mut huge = event(&store.session_id, "A"); + huge.client_version = "x".repeat(MAX_BYTES + 1); + store.record(route("A"), huge, "oversized"); + assert_eq!(store.events.len(), 1); + assert_eq!(store.counters.dropped.load(Ordering::Relaxed), 1); +} + +#[test] +fn corrupt_batch_does_not_rewrite_valid_batches_or_other_instance_temporary_files() { + let dir = tempfile::tempdir().unwrap(); + let mut store = open(dir.path()); + store.record(route("A"), event(&store.session_id, "A"), "good"); + store.seal(); + let good = list_batches(&store.root).unwrap().pop().unwrap().path; + let original = fs::read(good.join("events.jsonl")).unwrap(); + store.record(route("A"), event(&store.session_id, "A"), "bad"); + store.seal(); + let bad = list_batches(&store.root) + .unwrap() + .into_iter() + .find(|batch| batch.path != good) + .unwrap() + .path; + fs::write(bad.join("events.jsonl"), b"{truncated").unwrap(); + let temporary = store.batches.join(".tmp-other-writer"); + fs::create_dir(&temporary).unwrap(); + fs::write(temporary.join("events.jsonl"), b"in progress").unwrap(); + let restored = open(dir.path()); + assert_eq!(restored.known.len(), 1); + assert_eq!(restored.counters.corrupt_batches.load(Ordering::Relaxed), 1); + assert_eq!(fs::read(good.join("events.jsonl")).unwrap(), original); + assert!(temporary.exists()); + assert!(bad.exists()); +} + +#[test] +fn retention_counts_corrupt_files_and_removes_expired_sealed_batches() { + let dir = tempfile::tempdir().unwrap(); + let mut store = open(dir.path()); + store.record(route("A"), event(&store.session_id, "A"), "old"); + store.seal(); + let old = list_batches(&store.root).unwrap().pop().unwrap().path; + // 发布目录 mtime 是封存时间;不需要等待一周。 + let old_time = SystemTime::now() - RETENTION - Duration::from_secs(1); + store.trim_live_at(Instant::now() + RETENTION + Duration::from_secs(1)); + #[cfg(not(windows))] + File::open(&old) + .unwrap() + .set_times(fs::FileTimes::new().set_modified(old_time)) + .unwrap(); + #[cfg(windows)] + { + use std::os::windows::fs::OpenOptionsExt; + fs::OpenOptions::new() + .write(true) + .custom_flags(0x02000000) + .open(&old) + .unwrap() + .set_times(fs::FileTimes::new().set_modified(old_time)) + .unwrap(); + } + store.prune(0).unwrap(); + assert!(!old.exists()); + assert!(store.known.is_empty()); + let corrupt = store.batches.join(uuid::Uuid::new_v4().to_string()); + fs::create_dir(&corrupt).unwrap(); + File::create(corrupt.join("events.jsonl")) + .unwrap() + .set_len(MAX_TOTAL_BYTES + 1) + .unwrap(); + store.prune(0).unwrap(); + assert!(!corrupt.exists()); +} + +#[test] +fn full_or_disconnected_channel_never_waits_and_counts_drops() { + let (sender, receiver) = mpsc::sync_channel(1); + let writer = AnalyticsWriter { + sender, + counters: Arc::new(Counters::default()), + }; + let session = uuid::Uuid::new_v4().to_string(); + assert!(writer.try_record(route("A"), event(&session, "A"), "first".into())); + let before = Instant::now(); + assert!(!writer.try_record(route("A"), event(&session, "A"), "full".into())); + assert!(before.elapsed() < Duration::from_secs(1)); + drop(receiver); + assert!(!writer.try_record(route("A"), event(&session, "A"), "closed".into())); + assert_eq!(writer.counters().dropped, 2); +} + +#[test] +fn disk_failure_drops_only_current_batch_without_returning_business_error() { + let dir = tempfile::tempdir().unwrap(); + let mut store = open(dir.path()); + fs::remove_dir(&store.batches).unwrap(); + fs::write(&store.batches, b"not a directory").unwrap(); + store.record(route("A"), event(&store.session_id, "A"), "failure"); + store.seal(); + assert_eq!(store.counters.io_errors.load(Ordering::Relaxed), 1); + assert_eq!(store.counters.dropped.load(Ordering::Relaxed), 1); + assert!(store.events.is_empty()); +} + +#[test] +fn oversized_input_is_rejected_before_channel_and_byte_budget_is_bounded() { + let (sender, receiver) = mpsc::sync_channel(QUEUE_CAPACITY); + let writer = AnalyticsWriter { + sender, + counters: Arc::new(Counters::default()), + }; + let session = uuid::Uuid::new_v4().to_string(); + let mut huge = event(&session, "A"); + huge.client_version = "x".repeat(MAX_BYTES + 1); + assert!(!writer.try_record(route("A"), huge, "huge".into())); + assert!(matches!( + receiver.try_recv(), + Err(mpsc::TryRecvError::Empty) + )); + assert!(!writer.try_record(route("A"), event(&session, "A"), "x".repeat(4097))); + writer + .counters + .queued_bytes + .store(MAX_BYTES as u64, Ordering::Relaxed); + assert!(!writer.try_record(route("A"), event(&session, "A"), "full-bytes".into())); + assert!(matches!( + receiver.try_recv(), + Err(mpsc::TryRecvError::Empty) + )); +} + +#[test] +fn real_background_writer_flushes_when_last_sender_closes() { + let dir = tempfile::tempdir().unwrap(); + let session = uuid::Uuid::new_v4().to_string(); + let writer = AnalyticsWriter::start(dir.path().to_path_buf(), session.clone()); + assert!(writer.try_record(route("A"), event(&session, "A"), "background".into())); + drop(writer); + let until = Instant::now() + Duration::from_secs(5); + loop { + if let Ok(batches) = list_batches(&dir.path().join("analytics")) { + if let Some(batch) = batches.first() { + assert_eq!(read_batch(&batch.path).unwrap().event_count, 1); + break; + } + } + assert!(Instant::now() < until, "background batch was not published"); + std::thread::sleep(Duration::from_millis(10)); + } +} + +#[test] +fn retention_preserves_recent_live_facts_after_another_instance_removed_a_batch() { + let dir = tempfile::tempdir().unwrap(); + let mut store = open(dir.path()); + store.record( + route("A"), + event(&store.session_id, "A"), + "removed-by-another-instance", + ); + store.seal(); + let batch = list_batches(&store.root).unwrap().pop().unwrap(); + remove_batch(&batch.path).unwrap(); + assert_eq!(store.known.len(), 1); + store.prune(0).unwrap(); + assert_eq!(store.known.len(), 1); + assert_eq!(store.known_ids.len(), 1); + store.trim_live_at(Instant::now() + RETENTION); + store.prune(0).unwrap(); + assert!(store.known.is_empty()); + assert!(store.known_ids.is_empty()); +} + +#[test] +fn unexpected_deep_tree_does_not_disable_unrelated_batches() { + let dir = tempfile::tempdir().unwrap(); + let mut store = open(dir.path()); + let mut deep = store.root.join("unrecognized"); + for _ in 0..10 { + deep = deep.join("nested"); + } + fs::create_dir_all(&deep).unwrap(); + fs::write(deep.join("foreign"), b"leave intact").unwrap(); + store.record(route("A"), event(&store.session_id, "A"), "valid"); + store.seal(); + assert_eq!(list_batches(&store.root).unwrap().len(), 1); + assert!(deep.join("foreign").exists()); + assert!(store.counters.corrupt_batches.load(Ordering::Relaxed) > 0); +} + +fn project_event(session: &str, user: &str, name: &str) -> Event { + let mut event = event(session, user); + event.event_name = name.into(); + event.project_id = Some("project-1".into()); + event.creative_task_id = None; + event.properties = if name == "project_open" { + json!({"open_source":"recent","is_first_open":null}) + } else { + json!({"creation_source":"home_game"}) + }; + event +} + +#[test] +fn first_open_is_derived_from_route_scoped_known_facts_and_survives_restart() { + let dir = tempfile::tempdir().unwrap(); + let mut store = open(dir.path()); + store.record( + route("A"), + project_event(&store.session_id, "A", "project_create_success"), + "create", + ); + store.record( + route("A"), + project_event(&store.session_id, "A", "project_open"), + "open1", + ); + assert_eq!( + store.events.last().unwrap().0.properties["is_first_open"], + true + ); + store.record( + route("A"), + project_event(&store.session_id, "A", "project_open"), + "open1", + ); + assert_eq!(store.events.len(), 2); + store.seal(); + let mut restored = open(dir.path()); + restored.record( + route("A"), + project_event(&restored.session_id, "A", "project_open"), + "open2", + ); + assert_eq!( + restored.events.last().unwrap().0.properties["is_first_open"], + false + ); + restored.record( + route("B"), + project_event(&restored.session_id, "B", "project_open"), + "open3", + ); + assert!(restored.events.last().unwrap().0.properties["is_first_open"].is_null()); +} + +fn session_record(session: &str) -> SessionRecord { + SessionRecord { + schema_version: 1, + editor_session_id: session.into(), + route: route("A"), + lifecycle_state: crate::analytics::session::LifecycleState::Active, + focus_interval_id: None, + updated_at: "2026-09-21T00:00:00.000Z".into(), + incomplete_detected_at: None, + } +} + +#[test] +fn session_commands_share_the_event_byte_budget_and_restore_on_send_failure() { + let (sender, receiver) = mpsc::sync_channel(4); + let counters = Arc::new(Counters::default()); + let writer = AnalyticsWriter { + sender, + counters: counters.clone(), + }; + let record = session_record(&uuid::Uuid::new_v4().to_string()); + let bytes = serde_json::to_vec(&record).unwrap().len() as u64; + counters + .queued_bytes + .store(MAX_BYTES as u64 - bytes + 1, Ordering::Relaxed); + assert!(!writer.try_session(record.clone())); + assert_eq!( + counters.queued_bytes.load(Ordering::Relaxed), + MAX_BYTES as u64 - bytes + 1 + ); + counters + .queued_bytes + .store(MAX_BYTES as u64 - bytes, Ordering::Relaxed); + assert!(writer.try_session(record.clone())); + assert_eq!( + counters.queued_bytes.load(Ordering::Relaxed), + MAX_BYTES as u64 + ); + match receiver.recv().unwrap() { + Command::Session(_, charged) => { + assert_eq!(charged, bytes); + counters.queued_bytes.fetch_sub(charged, Ordering::Relaxed); + } + _ => panic!("expected session"), + } + drop(receiver); + let before = counters.queued_bytes.load(Ordering::Relaxed); + assert!(!writer.try_session(record)); + assert_eq!(counters.queued_bytes.load(Ordering::Relaxed), before); +} + +#[test] +fn session_atomic_write_reserves_full_temporary_file_capacity() { + let dir = tempfile::tempdir().unwrap(); + let mut store = open(dir.path()); + let record = session_record(&store.session_id); + let bytes = serde_json::to_vec(&record).unwrap().len() as u64; + store.write_session(&record, bytes).unwrap(); + let path = store.batches.parent().unwrap().join("session.json"); + let original = fs::read(&path).unwrap(); + let padding = File::create(store.root.join("unknown-padding")).unwrap(); + padding.set_len(MAX_TOTAL_BYTES - bytes).unwrap(); + assert!(store.write_session(&record, bytes).is_err()); + assert_eq!(fs::read(&path).unwrap(), original); + assert_eq!( + directory_size(&store.root, 0, &store.counters), + MAX_TOTAL_BYTES + ); +} + +fn goal_project() -> (tempfile::TempDir, PathBuf) { + let dir = tempfile::tempdir().unwrap(); + let root = dir.path().join("project"); + crate::init_local_game_project_at(&root, "goal-project", "目标采集测试").unwrap(); + (dir, root) +} + +fn goal_writer(config: &Path, user: &str) -> (super::super::contract::Context, AnalyticsWriter) { + let context = super::super::contract::Context { + route: route(user), + editor_session_id: uuid::Uuid::new_v4().to_string(), + client_version: "1.0.0".into(), + }; + let writer = AnalyticsWriter::start(config.into(), context.editor_session_id.clone()); + (context, writer) +} + +// 同 FIFO 的真实事件哨兵:哨兵落盘后,前面的命令必已执行,不靠 sleep 猜零事件。 +fn drain_goal_writer( + config: &Path, + context: &super::super::contract::Context, + writer: &AnalyticsWriter, +) -> Vec { + let marker = event( + &context.editor_session_id, + context.route.user_id.as_deref().unwrap(), + ); + let marker_id = marker.event_id.clone(); + assert!(writer.try_record(context.route.clone(), marker, marker_id.clone())); + assert!(writer.flush()); + let deadline = Instant::now() + Duration::from_secs(5); + loop { + let events: Vec<_> = list_batches(&config.join("analytics")) + .unwrap_or_default() + .iter() + .flat_map(|batch| read_events(&batch.path).unwrap_or_default()) + .collect(); + if events.iter().any(|event| event.event_id == marker_id) { + return events; + } + assert!( + Instant::now() < deadline, + "analytics FIFO sentinel timed out" + ); + std::thread::sleep(Duration::from_millis(5)); + } +} + +#[test] +fn project_goal_is_once_across_sources_writers_and_batch_retention_with_frozen_identity() { + use super::super::{contract::Source, goal}; + let (_project_dir, root) = goal_project(); + let config = tempfile::tempdir().unwrap(); + let (a, writer) = goal_writer(config.path(), "A"); + goal::created(Some(&writer), &root, "goal-project"); + goal::accepted( + Some((a.clone(), writer.clone())), + &root, + "goal-project", + Source::DesignAgent, + ); + let mut b = a.clone(); + b.route = route("B"); + goal::accepted( + Some((b, writer.clone())), + &root, + "goal-project", + Source::Direct, + ); + let events = drain_goal_writer(config.path(), &a, &writer); + let submissions: Vec<_> = events + .iter() + .filter(|e| e.event_name == "creative_task_submit") + .collect(); + assert_eq!(submissions.len(), 1); + assert_eq!(submissions[0].user_id.as_deref(), Some("A")); + assert_eq!(submissions[0].source, Source::DesignAgent); + assert_eq!(submissions[0].properties, json!({})); + for batch in list_batches(&config.path().join("analytics")).unwrap() { + remove_batch(&batch.path).unwrap(); + } + let (restarted, next) = goal_writer(config.path(), "B"); + goal::created(Some(&next), &root, "goal-project"); // 不覆盖 consumed + goal::accepted( + Some((restarted.clone(), next.clone())), + &root, + "goal-project", + Source::Direct, + ); + let events = drain_goal_writer(config.path(), &restarted, &next); + assert!(!events + .iter() + .any(|e| e.event_name == "creative_task_submit")); +} + +#[test] +fn goal_unknown_corrupt_backup_and_mismatched_projects_do_not_submit() { + use super::super::{contract::Source, goal}; + let (_project_dir, root) = goal_project(); + let config = tempfile::tempdir().unwrap(); + let (context, writer) = goal_writer(config.path(), "A"); + let accept = |project| { + goal::accepted( + Some((context.clone(), writer.clone())), + &root, + project, + Source::Direct, + ) + }; + accept("goal-project"); + assert!(!drain_goal_writer(config.path(), &context, &writer) + .iter() + .any(|e| e.event_name == "creative_task_submit")); + let marker = root.join(".agent/analytics-goal.json"); + fs::write(&marker, b"broken").unwrap(); + goal::created(Some(&writer), &root, "goal-project"); + accept("goal-project"); + assert!(!drain_goal_writer(config.path(), &context, &writer) + .iter() + .any(|e| e.event_name == "creative_task_submit")); + assert_eq!(fs::read(&marker).unwrap(), b"broken"); + fs::remove_file(&marker).unwrap(); + let backup = crate::agent::agent_runtime_json_sidecar_backup_path(&marker); + fs::write( + &backup, + br#"{"schema_version":1,"project_id":"goal-project","submitted":false}"#, + ) + .unwrap(); + goal::created(Some(&writer), &root, "goal-project"); + accept("goal-project"); + assert!(!drain_goal_writer(config.path(), &context, &writer) + .iter() + .any(|e| e.event_name == "creative_task_submit")); + assert!(!marker.exists()); + fs::remove_file(backup).unwrap(); + goal::created(Some(&writer), &root, "goal-project"); + accept("other-project"); + assert!(!drain_goal_writer(config.path(), &context, &writer) + .iter() + .any(|e| e.event_name == "creative_task_submit")); +} + +#[test] +fn goal_creation_without_analytics_context_recovers_on_later_acceptance() { + use super::super::{ + contract::{CreationSource, Source}, + goal, gui, + }; + let (_project_dir, root) = goal_project(); + gui::created( + None, + &root, + "goal-project".into(), + CreationSource::HomeGame, + None, + ); + assert!(!root.join(".agent/analytics-goal.json").exists()); + let config = tempfile::tempdir().unwrap(); + let (context, writer) = goal_writer(config.path(), "A"); + goal::accepted( + Some((context.clone(), writer.clone())), + &root, + "goal-project", + Source::Direct, + ); + let events = drain_goal_writer(config.path(), &context, &writer); + assert_eq!( + events + .iter() + .filter(|event| event.event_name == "creative_task_submit") + .count(), + 1 + ); + // 已落盘资格之后即使标记丢失,也不能凭旧的进程内待办重新授予。 + let marker = root.join(".agent/analytics-goal.json"); + fs::remove_file(&marker).unwrap(); + let backup = crate::agent::agent_runtime_json_sidecar_backup_path(&marker); + if backup.exists() { + fs::remove_file(backup).unwrap(); + } + goal::accepted( + Some((context.clone(), writer.clone())), + &root, + "goal-project", + Source::Direct, + ); + let events = drain_goal_writer(config.path(), &context, &writer); + assert_eq!( + events + .iter() + .filter(|event| event.event_name == "creative_task_submit") + .count(), + 1 + ); + assert!(!marker.exists()); +} + +#[test] +fn goal_creation_lock_and_io_failures_recover_on_later_acceptance() { + use super::super::{contract::Source, goal}; + for io_failure in [false, true] { + let (_project_dir, root) = goal_project(); + let config = tempfile::tempdir().unwrap(); + let (context, writer) = goal_writer(config.path(), "A"); + let lock_path = root.join(".agent/runtime/locks/analytics-goal.lock"); + let lock = if io_failure { + // 用目录占据埋点锁文件,模拟临时文件系统故障,不改业务 manifest。 + fs::create_dir_all(&lock_path).unwrap(); + None + } else { + Some( + crate::agent::try_acquire_game_creator_agent_runtime_task_lock( + &root, + "analytics-goal", + ) + .unwrap() + .unwrap(), + ) + }; + goal::created(Some(&writer), &root, "goal-project"); + drain_goal_writer(config.path(), &context, &writer); + assert!(!root.join(".agent/analytics-goal.json").exists()); + drop(lock); + if io_failure { + fs::remove_dir(&lock_path).unwrap(); + } + goal::accepted( + Some((context.clone(), writer.clone())), + &root, + "goal-project", + Source::Direct, + ); + let events = drain_goal_writer(config.path(), &context, &writer); + assert_eq!( + events + .iter() + .filter(|event| event.event_name == "creative_task_submit") + .count(), + 1 + ); + } +} + +#[test] +fn goal_queue_capacity_rejection_is_silent_and_does_not_charge_bytes() { + use super::super::goal; + let (sender, receiver) = mpsc::sync_channel(1); + let counters = Arc::new(Counters::default()); + let writer = AnalyticsWriter { + sender, + counters: counters.clone(), + }; + let (_dir, root) = goal_project(); + assert!(writer.flush()); // 占满队列,让创建通知从第一次起就无法投递。 + goal::created(Some(&writer), &root, "goal-project"); + let charged = counters.queued_bytes.load(Ordering::Relaxed); + assert_eq!(charged, 0); + goal::created(Some(&writer), &root, "goal-project"); + assert_eq!(counters.queued_bytes.load(Ordering::Relaxed), charged); + assert_eq!(counters.dropped.load(Ordering::Relaxed), 2); + assert!(!root.join(".agent/analytics-goal.json").exists()); + drop(receiver); + counters + .queued_bytes + .store(MAX_BYTES as u64, Ordering::Relaxed); + goal::created(Some(&writer), &root, "goal-project"); + assert_eq!( + counters.queued_bytes.load(Ordering::Relaxed), + MAX_BYTES as u64 + ); + let config = tempfile::tempdir().unwrap(); + let (context, recovered) = goal_writer(config.path(), "A"); + goal::accepted( + Some((context.clone(), recovered.clone())), + &root, + "goal-project", + super::super::contract::Source::Direct, + ); + let events = drain_goal_writer(config.path(), &context, &recovered); + assert_eq!( + events + .iter() + .filter(|event| event.event_name == "creative_task_submit") + .count(), + 1 + ); +} + +#[test] +fn later_real_acceptance_can_consume_after_lock_contention_and_two_writers_do_not_duplicate() { + use super::super::{contract::Source, goal}; + let (_project_dir, root) = goal_project(); + let config = tempfile::tempdir().unwrap(); + let (a, first) = goal_writer(config.path(), "A"); + let (b, second) = goal_writer(config.path(), "B"); + goal::created(Some(&first), &root, "goal-project"); + drain_goal_writer(config.path(), &a, &first); + let lock = + crate::agent::try_acquire_game_creator_agent_runtime_task_lock(&root, "analytics-goal") + .unwrap() + .unwrap(); + goal::accepted( + Some((a.clone(), first.clone())), + &root, + "goal-project", + Source::DesignAgent, + ); + assert!(!drain_goal_writer(config.path(), &a, &first) + .iter() + .any(|event| event.event_name == "creative_task_submit")); + drop(lock); + // 两个 worker 的独立线程竞争同一资格,只可能其中一个消费成功。 + goal::accepted( + Some((a.clone(), first.clone())), + &root, + "goal-project", + Source::DesignAgent, + ); + goal::accepted( + Some((b.clone(), second.clone())), + &root, + "goal-project", + Source::Direct, + ); + drain_goal_writer(config.path(), &a, &first); + let events = drain_goal_writer(config.path(), &b, &second); + assert_eq!( + events + .iter() + .filter(|event| event.event_name == "creative_task_submit") + .count(), + 1 + ); +} + +fn run_outcome() -> super::super::run::Outcome { + super::super::run::Outcome { + turn_id: None, + end_reason: super::super::contract::RunEndReason::Finished, + error_code: None, + duration_ms: Some(123), + output_change_detected: None, + revision_id: None, + } +} + +#[test] +fn run_retry_counter_is_project_scoped_and_duplicate_acceptance_does_not_reopen_terminal() { + use super::super::{ + contract::{RunSource, Source}, + run, + }; + let (_project_dir, root) = goal_project(); + let config = tempfile::tempdir().unwrap(); + let (context, writer) = goal_writer(config.path(), "A"); + let initial = run::Metadata::new(context.clone(), Source::Direct, RunSource::UserSubmit); + let retry = run::Metadata::new(context.clone(), Source::DesignAgent, RunSource::UserRetry); + let later = run::Metadata::new(context.clone(), Source::Direct, RunSource::UserContinue); + for metadata in [&initial, &retry, &later] { + run::accepted(&writer, &root, "goal-project", metadata); + run::accepted(&writer, &root, "goal-project", metadata); + run::finished( + Some((context.clone(), writer.clone())), + &root, + "goal-project", + metadata, + run_outcome(), + ); + run::accepted(&writer, &root, "goal-project", metadata); + run::finished( + Some((context.clone(), writer.clone())), + &root, + "goal-project", + metadata, + run_outcome(), + ); + } + let events = drain_goal_writer(config.path(), &context, &writer); + for (metadata, ordinal) in [(&initial, 0), (&retry, 1), (&later, 1)] { + let matching: Vec<_> = events + .iter() + .filter(|e| e.agent_run_id.as_deref() == Some(&metadata.run_id)) + .collect(); + assert_eq!(matching.len(), 1); + assert_eq!(matching[0].event_id, metadata.terminal_event_id); + assert_eq!(matching[0].properties["retry_index"], ordinal); + } + let state: serde_json::Value = + serde_json::from_slice(&fs::read(root.join(".agent/analytics-runs.json")).unwrap()) + .unwrap(); + assert_eq!(state["retry_count"], 1); + assert_eq!(state["direct"]["terminal_consumed"], true); + assert!(state.get("context").is_none()); +} + +#[test] +fn recovered_run_uses_original_account_and_current_gui_session_without_recounting() { + use super::super::{ + contract::{RunSource, Source}, + run, + }; + let (_project_dir, root) = goal_project(); + let config = tempfile::tempdir().unwrap(); + let (original, writer) = goal_writer(config.path(), "A"); + let metadata = run::Metadata::new(original.clone(), Source::DesignAgent, RunSource::UserRetry); + run::accepted(&writer, &root, "goal-project", &metadata); + drain_goal_writer(config.path(), &original, &writer); + let persisted: run::Metadata = + serde_json::from_slice(&serde_json::to_vec(&metadata).unwrap()).unwrap(); + let (mut current, recovered) = goal_writer(config.path(), "B"); + current.client_version = "2.0.0".into(); + let mut outcome = run_outcome(); + outcome.duration_ms = None; + run::finished( + Some((current.clone(), recovered.clone())), + &root, + "goal-project", + &persisted, + outcome.clone(), + ); + run::finished( + Some((current.clone(), recovered.clone())), + &root, + "goal-project", + &persisted, + outcome, + ); + let events = drain_goal_writer(config.path(), ¤t, &recovered); + let matching: Vec<_> = events + .iter() + .filter(|event| event.event_id == metadata.terminal_event_id) + .collect(); + assert_eq!(matching.len(), 1); + assert_eq!(matching[0].user_id.as_deref(), Some("A")); + assert_eq!(matching[0].editor_session_id, current.editor_session_id); + assert_eq!(matching[0].client_version, "2.0.0"); + assert_eq!(matching[0].properties["retry_index"], 1); + assert!(matching[0].properties["duration_ms"].is_null()); +} + +#[test] +fn missing_overwritten_or_unwritable_run_slots_do_not_fabricate_terminal_events() { + use super::super::{ + contract::{RunSource, Source}, + run, + }; + let (_project_dir, root) = goal_project(); + let config = tempfile::tempdir().unwrap(); + let (context, writer) = goal_writer(config.path(), "A"); + let first = run::Metadata::new(context.clone(), Source::Direct, RunSource::UserSubmit); + let next = run::Metadata::new(context.clone(), Source::Direct, RunSource::UserContinue); + run::finished( + Some((context.clone(), writer.clone())), + &root, + "goal-project", + &first, + run_outcome(), + ); + run::accepted(&writer, &root, "goal-project", &first); + run::accepted(&writer, &root, "goal-project", &next); + run::finished( + Some((context.clone(), writer.clone())), + &root, + "goal-project", + &first, + run_outcome(), + ); + assert!(!drain_goal_writer(config.path(), &context, &writer) + .iter() + .any(|e| e.agent_run_id.is_some())); + let lock = + crate::agent::try_acquire_game_creator_agent_runtime_task_lock(&root, "analytics-runs") + .unwrap() + .unwrap(); + run::finished( + Some((context.clone(), writer.clone())), + &root, + "goal-project", + &next, + run_outcome(), + ); + assert!(!drain_goal_writer(config.path(), &context, &writer) + .iter() + .any(|e| e.agent_run_id.is_some())); + drop(lock); + // 阻止sidecar完成替换后的备份清理:写入返回失败时不得投递成功事件。 + let path = root.join(".agent/analytics-runs.json"); + let backup = crate::agent::agent_runtime_json_sidecar_backup_path(&path); + fs::create_dir(&backup).unwrap(); + run::finished( + Some((context.clone(), writer.clone())), + &root, + "goal-project", + &next, + run_outcome(), + ); + assert!(!drain_goal_writer(config.path(), &context, &writer) + .iter() + .any(|e| e.agent_run_id.is_some())); + fs::remove_dir(backup).unwrap(); +} + +#[test] +fn direct_terminal_waits_for_exact_attempt_settlement_and_discards_intermediate_failures() { + use super::super::{ + contract::{ErrorCode, RunEndReason, RunSource, Source}, + run, + }; + let (_project_dir, root) = goal_project(); + let config = tempfile::tempdir().unwrap(); + let (context, writer) = goal_writer(config.path(), "A"); + let metadata = run::Metadata::new(context.clone(), Source::Direct, RunSource::UserSubmit); + run::accepted(&writer, &root, "goal-project", &metadata); + let first = uuid::Uuid::new_v4().to_string(); + let final_attempt = uuid::Uuid::new_v4().to_string(); + let capture = || Some((context.clone(), writer.clone())); + let mut failure = run_outcome(); + failure.end_reason = RunEndReason::Failed; + failure.error_code = Some(ErrorCode::ProviderTimeout); + run::direct_finished( + capture(), + &root, + "goal-project", + &metadata, + Some(&first), + failure.clone(), + ); + run::settle(capture(), &uuid::Uuid::new_v4().to_string(), false); + assert!(!drain_goal_writer(config.path(), &context, &writer) + .iter() + .any(|e| e.agent_run_id.is_some())); + // 另一个被取消的尝试不消费槽位;保留第一次失败,验证最终确认不会选错它。 + let cancelled = uuid::Uuid::new_v4().to_string(); + run::direct_finished( + capture(), + &root, + "goal-project", + &metadata, + Some(&cancelled), + failure, + ); + run::settle(capture(), &cancelled, true); + run::settle(capture(), &cancelled, false); + assert!(!drain_goal_writer(config.path(), &context, &writer) + .iter() + .any(|e| e.agent_run_id.is_some())); + run::direct_finished( + capture(), + &root, + "goal-project", + &metadata, + None, + run_outcome(), + ); + run::direct_finished( + capture(), + &root, + "goal-project", + &metadata, + Some(&final_attempt), + run_outcome(), + ); + assert!(!drain_goal_writer(config.path(), &context, &writer) + .iter() + .any(|e| e.agent_run_id.is_some())); + run::settle(capture(), &final_attempt, false); + run::settle(capture(), &final_attempt, false); + let events = drain_goal_writer(config.path(), &context, &writer); + let terminal: Vec<_> = events.iter().filter(|e| e.agent_run_id.is_some()).collect(); + assert_eq!(terminal.len(), 1); + assert_eq!(terminal[0].event_name, "agent_run_completed"); + assert_eq!(terminal[0].event_id, metadata.terminal_event_id); +} + +#[test] +fn direct_pending_capacity_evicts_oldest_without_settlement_fallback() { + use super::super::{ + contract::{RunSource, Source}, + run, + }; + let (_project_dir, root) = goal_project(); + let config = tempfile::tempdir().unwrap(); + let (context, writer) = goal_writer(config.path(), "A"); + let metadata = run::Metadata::new(context.clone(), Source::Direct, RunSource::UserSubmit); + run::accepted(&writer, &root, "goal-project", &metadata); + let ids: Vec<_> = (0..17).map(|_| uuid::Uuid::new_v4().to_string()).collect(); + for id in &ids { + run::direct_finished( + Some((context.clone(), writer.clone())), + &root, + "goal-project", + &metadata, + Some(id), + run_outcome(), + ); + } + run::settle(Some((context.clone(), writer.clone())), &ids[0], false); + assert!(!drain_goal_writer(config.path(), &context, &writer) + .iter() + .any(|e| e.agent_run_id.is_some())); + assert!(writer.counters().dropped >= 1); + run::settle(Some((context.clone(), writer.clone())), &ids[16], false); + assert_eq!( + drain_goal_writer(config.path(), &context, &writer) + .iter() + .filter(|e| e.agent_run_id.is_some()) + .count(), + 1 + ); +} + +#[test] +fn direct_pending_byte_budget_and_session_are_checked_before_consumption() { + use super::super::{ + contract::{Context, RunSource, Source}, + run, + }; + let config = tempfile::tempdir().unwrap(); + let mut store = open(config.path()); + let context = Context { + route: route("A"), + editor_session_id: store.session_id.clone(), + client_version: "1.0.0".into(), + }; + let metadata = run::Metadata::new(context.clone(), Source::Direct, RunSource::UserSubmit); + let mut last = String::new(); + for _ in 0..10 { + last = uuid::Uuid::new_v4().to_string(); + // worker接收到的序列化预算是独立的保守保留量。 + store.run_request( + run::Request::DirectCandidate { + attempt_id: last.clone(), + terminal: Box::new(run::Request::Terminal { + root: config.path().into(), + project_id: "project".into(), + metadata: metadata.clone(), + context: context.clone(), + event_time: "2026-09-21T00:00:00.000Z".into(), + outcome: run_outcome(), + }), + }, + 128 * 1024, + ); + } + assert_eq!(store.pending_runs.len(), 8); + assert_eq!(store.pending_run_bytes, MAX_BYTES as u64); + store.run_request( + run::Request::Settle { + editor_session_id: uuid::Uuid::new_v4().to_string(), + attempt_id: last.clone(), + discard: true, + }, + 128, + ); + assert_eq!(store.pending_runs.len(), 8); + store.run_request( + run::Request::Settle { + editor_session_id: context.editor_session_id, + attempt_id: last, + discard: true, + }, + 128, + ); + assert_eq!(store.pending_runs.len(), 7); + assert_eq!(store.pending_run_bytes, 7 * 128 * 1024); +} diff --git a/apps/ai-game-creator-shell/src-tauri/src/analytics/upload.rs b/apps/ai-game-creator-shell/src-tauri/src/analytics/upload.rs new file mode 100644 index 000000000..8d6bda7b9 --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/src/analytics/upload.rs @@ -0,0 +1,228 @@ +//! 独立后台上传轮次;网络等待不占用 writer 或业务锁。 +use super::{contract::Route, store}; +use crate::platform_session::{current_platform_session, PlatformSessionSnapshot}; +use std::fs::{File, OpenOptions}; +use std::path::{Path, PathBuf}; +use std::sync::atomic::{AtomicU64, Ordering}; +use std::time::{Duration, Instant}; + +const INTERVAL: Duration = Duration::from_secs(15 * 60); +const REQUEST_TIMEOUT: Duration = Duration::from_secs(30); +const CYCLE_BUDGET: Duration = Duration::from_secs(120); +const MAX_BATCHES: usize = 20; +static FAILURES: AtomicU64 = AtomicU64::new(0); + +fn failure() { + let _ = FAILURES.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |n| { + Some(n.saturating_add(1)) + }); +} + +pub(super) fn start(config_dir: PathBuf) { + tauri::async_runtime::spawn(async move { + let Ok(client) = reqwest::Client::builder() + .redirect(reqwest::redirect::Policy::none()) + .timeout(REQUEST_TIMEOUT) + .build() + else { + return; + }; + let root = config_dir.join("analytics"); + let mut next = tokio::time::Instant::now() + INTERVAL; + loop { + tokio::time::sleep_until(next).await; + // 休眠恢复只跑一次,下一轮从当前时间重新计时。 + if advance_schedule(tokio::time::Instant::now(), &mut next) { + cycle(&root, &client).await; + } + } + }); +} + +fn advance_schedule(now: tokio::time::Instant, next: &mut tokio::time::Instant) -> bool { + if now < *next { + return false; + } + *next = now + INTERVAL; + true +} + +fn claim(root: &Path) -> std::io::Result { + if !store::safe_metadata(root)?.is_dir() { + return Err(store::invalid_data()); + } + let path = root.join("upload.lock"); + if path.exists() { + store::safe_metadata(&path)?; + } + let lock = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(false) + .open(path)?; + lock.try_lock().map_err(|_| store::invalid_data())?; + Ok(lock) +} + +fn matches_identity(route: &Route, session: &PlatformSessionSnapshot) -> bool { + route.user_id.is_some() + && route.destination_origin.is_some() + && *route + == Route::from_identity(Some(session.user_id.clone()), Some(&session.api_base_url)) +} + +fn acknowledged(value: &serde_json::Value, batch: &store::UploadBatch) -> bool { + value.get("ok") == Some(&serde_json::Value::Bool(true)) + && value.get("error") == Some(&serde_json::Value::Null) + && value.pointer("/data/acknowledged_batch_ids") + == Some(&serde_json::json!([batch.batch_id])) + && value + .pointer("/data/event_count") + .and_then(serde_json::Value::as_u64) + == Some(batch.event_count as u64) +} + +fn stop_after(status: u16) -> bool { + matches!(status, 401 | 403 | 429 | 500..=599) +} + +pub(super) async fn cycle(root: &Path, client: &reqwest::Client) { + let Ok(_lock) = claim(root) else { return }; + let started = Instant::now(); + let Ok(candidates) = store::upload_candidates(root) else { + failure(); + return; + }; + let mut attempted = 0; + for path in candidates { + if attempted >= MAX_BATCHES || started.elapsed() >= CYCLE_BUDGET { + break; + } + let Ok(batch) = store::load_upload_batch(path) else { + continue; + }; + let Some(session) = current_platform_session() else { + break; + }; + if !matches_identity(&batch.route, &session) || !batch.exists() { + continue; + } + let Some(origin) = &batch.route.destination_origin else { + continue; + }; + attempted += 1; + // 身份只在发起前读取;在途请求保持原凭据,切换账号后仍可清理原批次。 + let response = client + .post(format!("{origin}/api/agc/analytics/batches")) + .bearer_auth(&session.access_token) + .header("x-genarrative-response-envelope", "1") + .timeout(REQUEST_TIMEOUT.min(CYCLE_BUDGET.saturating_sub(started.elapsed()))) + .json(&batch.request) + .send() + .await; + let Ok(mut response) = response else { + failure(); + break; + }; + let status = response.status().as_u16(); + if status != 200 { + failure(); + if stop_after(status) { + break; + } + continue; + } + let mut bytes = Vec::new(); + let mut valid = true; + let mut unavailable = false; + loop { + match response.chunk().await { + Ok(Some(chunk)) if bytes.len() + chunk.len() <= 16 * 1024 => { + bytes.extend_from_slice(&chunk) + } + Ok(None) => break, + Err(_) => { + valid = false; + unavailable = true; + break; + } + _ => { + valid = false; + break; + } + } + } + if valid && serde_json::from_slice(&bytes).is_ok_and(|value| acknowledged(&value, &batch)) { + if batch.acknowledge().is_err() { + failure(); + } + } else { + failure(); + } + if unavailable { + break; + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn first_cycle_waits_fifteen_minutes_and_resume_does_not_catch_up() { + let start = tokio::time::Instant::now(); + let mut next = start + INTERVAL; + assert!(!advance_schedule(start, &mut next)); + assert!(!advance_schedule( + start + INTERVAL - Duration::from_secs(1), + &mut next + )); + assert!(advance_schedule(start + INTERVAL, &mut next)); + let resumed = start + INTERVAL * 8; + assert!(advance_schedule(resumed, &mut next)); + assert!(!advance_schedule(resumed, &mut next)); + assert_eq!(next, resumed + INTERVAL); + } + + #[test] + fn identity_does_not_claim_anonymous_or_other_account_or_platform() { + let session = PlatformSessionSnapshot { + user_id: "A".into(), + access_token: "test".into(), + api_base_url: "https://example.com/api".into(), + identity_generation: 1, + revision: 1, + }; + let route = Route::from_identity(Some("A".into()), Some("https://example.com")); + assert!(matches_identity(&route, &session)); + for route in [ + Route::from_identity(None, Some("https://example.com")), + Route::from_identity(Some("B".into()), Some("https://example.com")), + Route::from_identity(Some("A".into()), Some("https://other.example")), + ] { + assert!(!matches_identity(&route, &session)); + } + } + + #[test] + fn upload_lock_is_nonblocking_and_single_owner() { + let dir = tempfile::tempdir().unwrap(); + let lock = claim(dir.path()).unwrap(); + assert!(claim(dir.path()).is_err()); + drop(lock); + assert!(claim(dir.path()).is_ok()); + } + + #[test] + fn toxic_batch_can_be_skipped_but_auth_and_service_failures_end_cycle() { + for status in [400, 409, 413] { + assert!(!stop_after(status)); + } + for status in [401, 403, 429, 500, 503] { + assert!(stop_after(status)); + } + assert_eq!(INTERVAL, Duration::from_secs(900)); + } +} diff --git a/apps/ai-game-creator-shell/src-tauri/src/commands.rs b/apps/ai-game-creator-shell/src-tauri/src/commands.rs index 96468794f..b5c09bb9d 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/commands.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/commands.rs @@ -590,11 +590,26 @@ pub(crate) fn create_automatic_local_game_project( planning: Option, projects_root: Option, ) -> Result { - create_automatic_local_game_project_at( + let analytics_context = crate::analytics::gui::capture_analytics_context(); + let result = create_automatic_local_game_project_at( &resolve_game_project_creation_root(&app, projects_root.as_deref())?, name.as_deref(), planning.unwrap_or(false), - ) + ); + if let Ok(project) = &result { + crate::analytics::gui::created( + analytics_context, + Path::new(&project.project_path), + project.manifest.project_id.clone(), + if planning.unwrap_or(false) { + crate::analytics::contract::CreationSource::HomeDesign + } else { + crate::analytics::contract::CreationSource::HomeGame + }, + None, + ); + } + result } #[tauri::command] @@ -603,10 +618,24 @@ pub(crate) fn init_local_game_project( project_id: String, name: String, ) -> Result { + let analytics_context = crate::analytics::gui::capture_analytics_context(); let root = Path::new(project_path.trim()); enforce_project_permission_policy(root, "project.create")?; let _lock = acquire_project_write_lock(root, "project.create")?; - init_local_game_project_at(root, project_id.trim(), name.trim()) + let new_project = matches!(fs::symlink_metadata(root.join(".agent/manifest.json")), Err(error) if error.kind() == std::io::ErrorKind::NotFound); + let result = init_local_game_project_at(root, project_id.trim(), name.trim()); + if new_project { + if let Ok(project) = &result { + crate::analytics::gui::created( + analytics_context, + Path::new(&project.project_path), + project.manifest.project_id.clone(), + crate::analytics::contract::CreationSource::SelectedDirectory, + None, + ); + } + } + result } #[derive(Clone, Debug, Eq, PartialEq, Serialize)] @@ -649,13 +678,27 @@ pub(crate) fn import_local_godot_project( project_id: String, name: String, ) -> Result { + let analytics_context = crate::analytics::gui::capture_analytics_context(); let root = Path::new(project_path.trim()); enforce_project_permission_policy(root, "project.create")?; if discover_local_godot_project_root(root)?.is_none() { return Err("所选工作区未在根目录或一层子目录发现 project.godot".to_string()); } let _lock = acquire_project_write_lock(root, "project.create")?; - import_local_godot_project_at(root, project_id.trim(), name.trim()) + let new_project = matches!(fs::symlink_metadata(root.join(".agent/manifest.json")), Err(error) if error.kind() == std::io::ErrorKind::NotFound); + let result = import_local_godot_project_at(root, project_id.trim(), name.trim()); + if new_project { + if let Ok(project) = &result { + crate::analytics::gui::created( + analytics_context, + Path::new(&project.project_path), + project.manifest.project_id.clone(), + crate::analytics::contract::CreationSource::SelectedDirectory, + None, + ); + } + } + result } #[tauri::command] @@ -664,6 +707,7 @@ pub(crate) fn import_local_cocos_project( project_id: String, name: String, ) -> Result { + let analytics_context = crate::analytics::gui::capture_analytics_context(); let root = Path::new(project_path.trim()); enforce_project_permission_policy(root, "project.create")?; if discover_local_cocos_project_root(root)?.is_none() { @@ -673,7 +717,20 @@ pub(crate) fn import_local_cocos_project( ); } let _lock = acquire_project_write_lock(root, "project.create")?; - import_local_cocos_project_at(root, project_id.trim(), name.trim()) + let new_project = matches!(fs::symlink_metadata(root.join(".agent/manifest.json")), Err(error) if error.kind() == std::io::ErrorKind::NotFound); + let result = import_local_cocos_project_at(root, project_id.trim(), name.trim()); + if new_project { + if let Ok(project) = &result { + crate::analytics::gui::created( + analytics_context, + Path::new(&project.project_path), + project.manifest.project_id.clone(), + crate::analytics::contract::CreationSource::SelectedDirectory, + None, + ); + } + } + result } #[tauri::command] @@ -682,13 +739,27 @@ pub(crate) fn import_local_unity_project( project_id: String, name: String, ) -> Result { + let analytics_context = crate::analytics::gui::capture_analytics_context(); let root = Path::new(project_path.trim()); enforce_project_permission_policy(root, "project.create")?; if discover_local_unity_project_root(root)?.is_none() { return Err("所选目录不是有效的 Unity 项目".to_string()); } let _lock = acquire_project_write_lock(root, "project.create")?; - import_local_unity_project_at(root, project_id.trim(), name.trim()) + let new_project = matches!(fs::symlink_metadata(root.join(".agent/manifest.json")), Err(error) if error.kind() == std::io::ErrorKind::NotFound); + let result = import_local_unity_project_at(root, project_id.trim(), name.trim()); + if new_project { + if let Ok(project) = &result { + crate::analytics::gui::created( + analytics_context, + Path::new(&project.project_path), + project.manifest.project_id.clone(), + crate::analytics::contract::CreationSource::SelectedDirectory, + None, + ); + } + } + result } #[tauri::command] @@ -5644,18 +5715,14 @@ pub(crate) fn cancel_local_project_resource_preview_scope( preview_manager.cancel_scope(&scope_id) } -#[tauri::command] -pub(crate) fn write_local_project_file( - project_path: String, - relative_path: String, - content: String, -) -> Result { - let root = Path::new(project_path.trim()); - enforce_project_permission_policy(root, "file.write")?; - let _lock = acquire_project_write_lock(root, "file.write")?; - advance_agent_runtime_project_revision_locked(root)?; - write_local_project_file_at(root, relative_path.trim(), &content) -} +type ManualAnalyticsCapture = Option<( + crate::analytics::contract::Context, + crate::analytics::store::AnalyticsWriter, +)>; + +#[cfg(test)] +#[path = "commands_manual_analytics_tests.rs"] +mod manual_analytics_tests; #[tauri::command] pub(crate) fn read_local_game_memory( @@ -5889,7 +5956,7 @@ pub(crate) async fn read_direct_project_history_slice( return Err( "DirectProject 历史切片只接受一个锚点(beforeItemId / throughItemId)" .to_string(), - ) + ); } (Some(before), None) => DirectProjectHistoryAnchor::Before(before), (None, Some(through)) => DirectProjectHistoryAnchor::Through(through), @@ -5968,21 +6035,65 @@ pub(crate) fn build_local_project_index( pub(crate) fn create_local_project_checkpoint( project_path: String, ) -> Result { + create_local_project_checkpoint_with_capture( + project_path, + crate::analytics::gui::capture_writer_context(), + ) +} + +fn create_local_project_checkpoint_with_capture( + project_path: String, + capture: ManualAnalyticsCapture, +) -> Result { + use crate::analytics::{ + contract::{ProjectSaved, SaveSource, Source}, + project, + }; let root = Path::new(project_path.trim()); enforce_project_permission_policy(root, "project.checkpoint")?; let _lock = acquire_project_write_lock(root, "project.checkpoint")?; - create_local_project_checkpoint_at(root) + let project_id = capture + .as_ref() + .and_then(|_| read_existing_manifest_for_project(root).ok()) + .map(|manifest| manifest.project_id); + let result = create_local_project_checkpoint_at(root)?; + if let Some(project_id) = project_id { + project::saved( + capture, + &project_id, + Source::Manual, + &result.checkpoint_id, + ProjectSaved { + save_source: SaveSource::Checkpoint, + revision_id: None, + }, + None, + ); + } + Ok(result) } +#[cfg(test)] +pub(crate) fn checkpoint_with_capture_for_test( + project_path: String, + capture: ManualAnalyticsCapture, +) -> Result { + create_local_project_checkpoint_with_capture(project_path, capture) +} + +/// 为发布导出试玩包:项目还没有可玩入口时先跑项目自己的 `npm run build`。 +/// +/// 作者只点一次「发布」:已有 `game/index.html` 或 `dist/index.html` 直接打包;只有源码时 +/// 走 `project.verify` 的受控 npm 运行器构建后再打包,失败信息带构建日志尾部。 #[tauri::command] -pub(crate) fn export_local_project_package( +pub(crate) async fn export_local_project_package( project_path: String, ) -> Result { let root = Path::new(project_path.trim()); enforce_project_permission_policy(root, "project.export_package")?; let _lock = acquire_project_write_lock(root, "project.export_package")?; advance_agent_runtime_project_revision_locked(root)?; - export_local_project_package_at(root) + export_local_project_package_for_publish_at(root).await } #[tauri::command] diff --git a/apps/ai-game-creator-shell/src-tauri/src/commands_manual_analytics_tests.rs b/apps/ai-game-creator-shell/src-tauri/src/commands_manual_analytics_tests.rs new file mode 100644 index 000000000..b8bb1a793 --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/src/commands_manual_analytics_tests.rs @@ -0,0 +1,195 @@ +use super::*; + +#[test] +fn ui_gui_save_records_only_saved_revision_with_frozen_identity() { + use crate::ui_editor::persistence::{ + initialize_ui_design_state_at, SaveUiDesignStateInput, SaveUiDesignStateResult, + }; + let temp = tempfile::tempdir().unwrap(); + let root = temp.path().join("project"); + let project_id = "ui-analytics"; + init_local_game_project_at(&root, project_id, "UI 成果采集").unwrap(); + let relative_path = "ui/design.json"; + fs::create_dir_all(root.join("ui")).unwrap(); + fs::write(root.join(relative_path), b"").unwrap(); + let asset = register_local_asset_at( + &root, + relative_path, + GameCreationAppAssetKind::UiDesignDoc, + shared_contracts::game_creation_app::GAME_CREATION_APP_UI_DESIGN_DOC_MEDIA_TYPE, + "test", + GameCreationAppAssetSource { + kind: GameCreationAppAssetSourceKind::Generated, + canvas_project_id: None, + resource_id: Some("ui:test".into()), + asset_object_id: None, + task_id: None, + prompt: None, + model: None, + generation_route: None, + generation_kind: None, + reference_resource_ids: Vec::new(), + }, + ) + .unwrap(); + initialize_ui_design_state_at(&root, project_id, &asset.id).unwrap(); + let config = temp.path().join("config"); + fs::create_dir_all(&config).unwrap(); + let mut current = Context { + route: Route::from_identity(Some("A".into()), Some("https://example.com")), + editor_session_id: uuid::Uuid::new_v4().to_string(), + client_version: "1.0.0".into(), + }; + let writer = AnalyticsWriter::start(config.clone(), current.editor_session_id.clone()); + let capture = Some((current.clone(), writer.clone())); + current.route.user_id = Some("B".into()); + let state = serde_json::from_value(serde_json::json!({ + "ui_trees": [], "ui_design_images": {"page": { + "metadata": {"name":"主界面", "description":"", "role":"Page", "slave_to":null}, + "path":"assets/missing-reference.png", "pixel_size":[1280.0,720.0], "pixels_per_unit":1.0 + }}, "sprite_assets": {}, "font_assets": {} + })).unwrap(); + let mut input = SaveUiDesignStateInput { + project_path: root.to_string_lossy().into_owned(), + expected_project_id: project_id.into(), + asset_id: asset.id, + expected_revision: 0, + state, + }; + let saved = crate::save_ui_design_state_with_capture(input.clone(), capture.clone()).unwrap(); + let SaveUiDesignStateResult::Saved { + revision, + committed_project_revision, + .. + } = saved + else { + panic!("expected real Saved") + }; + assert!(matches!( + crate::save_ui_design_state_with_capture(input.clone(), capture.clone()).unwrap(), + SaveUiDesignStateResult::Conflict { .. } + )); + input.expected_revision = revision; + assert!(matches!( + crate::save_ui_design_state_with_capture(input.clone(), capture.clone()).unwrap(), + SaveUiDesignStateResult::Unchanged { .. } + )); + input.expected_project_id = "wrong-project".into(); + assert!(crate::save_ui_design_state_with_capture(input, capture).is_err()); + let events = drain(&config, ¤t, &writer); + let revisions: Vec<_> = events + .iter() + .filter(|event| event["event_name"] == "project_revision_created") + .collect(); + assert_eq!(revisions.len(), 1); + let event = revisions[0]; + assert_eq!(event["user_id"], "A"); + assert_eq!(event["project_id"], project_id); + assert_eq!(event["source"], "ui_editor"); + assert_eq!(event["properties"]["revision_source"], "ui_editor"); + assert_eq!(event["properties"]["change_kind"], "ui"); + assert_eq!( + event["properties"]["revision_id"], + committed_project_revision.to_string() + ); + assert!(!events + .iter() + .any(|event| event["event_name"] == "project_save")); +} +use crate::analytics::{ + contract::{Context, EntrySource, EventData, Route, SessionStart, Source}, + store::AnalyticsWriter, +}; + +fn drain(config: &Path, context: &Context, writer: &AnalyticsWriter) -> Vec { + let marker = context + .capture( + EventData::EditorSessionStart(SessionStart { + entry_source: EntrySource::DirectLaunch, + first_project_id: None, + }), + None, + Source::Editor, + None, + ) + .unwrap(); + let marker_id = marker.event_id.clone(); + assert!(writer.try_record(context.route.clone(), marker, marker_id.clone())); + assert!(writer.flush()); + let batches = config + .join("analytics/instances") + .join(&context.editor_session_id) + .join("batches"); + let deadline = std::time::Instant::now() + std::time::Duration::from_secs(5); + loop { + let events: Vec = fs::read_dir(&batches) + .into_iter() + .flatten() + .flatten() + .filter(|entry| !entry.file_name().to_string_lossy().starts_with('.')) + .filter_map(|entry| fs::read_to_string(entry.path().join("events.jsonl")).ok()) + .flat_map(|text| { + text.lines() + .filter_map(|line| serde_json::from_str(line).ok()) + .collect::>() + }) + .collect(); + if events.iter().any(|event| event["event_id"] == marker_id) { + return events; + } + assert!( + std::time::Instant::now() < deadline, + "manual analytics FIFO sentinel timed out" + ); + std::thread::sleep(std::time::Duration::from_millis(5)); + } +} + +#[test] +fn manual_checkpoint_records_only_complete_save_with_frozen_identity() { + let temp = tempfile::tempdir().unwrap(); + let root = temp.path().join("project"); + init_local_game_project_at(&root, "manual-analytics", "人工操作采集").unwrap(); + let config = temp.path().join("config"); + fs::create_dir_all(&config).unwrap(); + let mut current = Context { + route: Route::from_identity(Some("A".into()), Some("https://example.com")), + editor_session_id: uuid::Uuid::new_v4().to_string(), + client_version: "1.0.0".into(), + }; + let writer = AnalyticsWriter::start(config.clone(), current.editor_session_id.clone()); + let captured = Some((current.clone(), writer.clone())); + current.route.user_id = Some("B".into()); + let path = root.to_string_lossy().into_owned(); + fs::create_dir_all(root.join("game")).unwrap(); + fs::write(root.join("game/result.js"), "const result = 1;").unwrap(); + let checkpoint = + create_local_project_checkpoint_with_capture(path.clone(), captured.clone()).unwrap(); + assert!(checkpoint.file_count > 0); + let blocked = temp.path().join("blocked-checkpoint"); + init_local_game_project_at(&blocked, "blocked-checkpoint", "checkpoint 失败夹具").unwrap(); + fs::write(blocked.join(".agent/checkpoints"), b"not a directory").unwrap(); + assert!(create_local_project_checkpoint_with_capture( + blocked.to_string_lossy().into_owned(), + captured, + ) + .is_err()); + let events = drain(&config, ¤t, &writer); + let saves: Vec<_> = events + .iter() + .filter(|event| event["event_name"] == "project_save") + .collect(); + assert_eq!(saves.len(), 1, "only the complete checkpoint is saved"); + let checkpoint_event = saves + .iter() + .find(|event| event["properties"]["save_source"] == "checkpoint") + .unwrap(); + assert!(checkpoint_event["properties"].get("revision_id").is_none()); + for event in &saves { + assert_eq!(event["user_id"], "A"); + assert_eq!(event["project_id"], "manual-analytics"); + assert_eq!(event["source"], "manual"); + assert!(event["agent_run_id"].is_null()); + assert!(event["agent_turn_id"].is_null()); + } +} diff --git a/apps/ai-game-creator-shell/src-tauri/src/main.rs b/apps/ai-game-creator-shell/src-tauri/src/main.rs index 263f74d52..9d5f1ae18 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/main.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/main.rs @@ -61,6 +61,7 @@ use tauri_plugin_opener::OpenerExt; /// 更新完成后的进程重启:Windows 由 NSIS 安装程序代为重启,macOS / Linux 由客户端在安装后调用。 #[tauri::command] fn restart_agc_app(app: tauri::AppHandle) { + analytics::gui::mark_restart(); app.restart(); } @@ -110,6 +111,7 @@ include!(concat!(env!("OUT_DIR"), "/agent_runtime_prompt_bundle.rs")); mod agent; mod agent_native_tools; +mod analytics; mod asset_generation_tasks; mod assets; mod browser; @@ -275,9 +277,38 @@ fn load_ui_design_state( fn save_ui_design_state( input: ui_editor::persistence::SaveUiDesignStateInput, ) -> Result { + save_ui_design_state_with_capture(input, analytics::gui::capture_writer_context()) +} + +fn save_ui_design_state_with_capture( + input: ui_editor::persistence::SaveUiDesignStateInput, + capture: Option<( + analytics::contract::Context, + analytics::store::AnalyticsWriter, + )>, +) -> Result { + let project_id = input.expected_project_id.clone(); let root = Path::new(input.project_path.trim()); enforce_project_permission_policy(root, "asset.register")?; - ui_editor::persistence::save_ui_design_state_at(input) + let result = ui_editor::persistence::save_ui_design_state_at(input)?; + if let ui_editor::persistence::SaveUiDesignStateResult::Saved { + committed_project_revision, + .. + } = &result + { + analytics::project::revision( + capture, + &project_id, + analytics::contract::Source::UiEditor, + analytics::contract::RevisionCreated { + revision_id: committed_project_revision.to_string(), + revision_source: analytics::contract::RevisionSource::UiEditor, + change_kind: analytics::contract::ChangeKind::Ui, + files_changed_count: None, + }, + ); + } + Ok(result) } #[tauri::command] @@ -2447,7 +2478,15 @@ fn main() { .plugin(tauri_plugin_clipboard_manager::init()) .plugin(tauri_plugin_updater::Builder::new().build()) .plugin(context_menu::init()) - .on_window_event(|window, event| handle_project_snapshot_window_event(window, event)) + .on_page_load(|webview, payload| { + if matches!(payload.event(), tauri::webview::PageLoadEvent::Started) { + analytics::gui::page_loading(webview.window().label()); + } + }) + .on_window_event(|window, event| { + analytics::gui::window_event(window, event); + handle_project_snapshot_window_event(window, event); + }) .manage(game_creator_preview_registry()) .manage(ProjectResourcePreviewReadManager::default()) .manage(PluginHost::default()) @@ -2572,6 +2611,11 @@ fn main() { Ok(()) }) .invoke_handler(tauri::generate_handler![ + analytics::gui::capture_analytics_context, + analytics::gui::settle_direct_run_analytics, + analytics::gui::record_analytics_project_open, + analytics::gui::record_analytics_project_leave, + analytics::gui::record_analytics_ui_save, start_game_creator_external_mcp, stop_game_creator_external_mcp, create_automatic_local_game_project, @@ -2706,7 +2750,6 @@ fn main() { read_local_project_structured_preview, read_local_project_media_preview, cancel_local_project_resource_preview_scope, - write_local_project_file, read_local_game_memory, read_local_agent_memory, write_local_agent_memory, @@ -2776,7 +2819,21 @@ fn main() { std::process::exit(1); } }; - app.run(move |_app_handle, event| handle_game_creator_gui_run_event(&event)); + app.run(move |app_handle, event| { + if matches!(event, tauri::RunEvent::Ready) { + if let Some(directory) = game_creator_runtime_config_dir() { + analytics::gui::initialize( + app_handle.clone(), + directory, + app_handle.package_info().version.to_string(), + ); + } + } + if matches!(event, tauri::RunEvent::Exit) { + analytics::gui::exit(); + } + handle_game_creator_gui_run_event(&event); + }); } #[cfg(test)] diff --git a/apps/ai-game-creator-shell/src-tauri/src/platform_session.rs b/apps/ai-game-creator-shell/src-tauri/src/platform_session.rs index 41fe89783..a58d9eebf 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/platform_session.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/platform_session.rs @@ -289,6 +289,46 @@ struct PlatformSessionState { static PLATFORM_SESSION: OnceLock> = OnceLock::new(); +// 仅用于同进程埋点通知排序,不替代认证的 revision/身份代次,不持久化凭据。 +static ANALYTICS_IDENTITY_SEQUENCE: std::sync::atomic::AtomicU64 = + std::sync::atomic::AtomicU64::new(0); + +fn analytics_route(current: &PlatformSessionState) -> crate::analytics::contract::Route { + crate::analytics::contract::Route::from_identity( + current.snapshot.as_ref().map(|s| s.user_id.clone()), + current.snapshot.as_ref().map(|s| s.api_base_url.as_str()), + ) +} + +fn analytics_identity_notice( + current: &PlatformSessionState, +) -> (crate::analytics::contract::Route, u64) { + let sequence = + ANALYTICS_IDENTITY_SEQUENCE.fetch_add(1, std::sync::atomic::Ordering::Relaxed) + 1; + (analytics_route(current), sequence) +} + +pub(crate) fn analytics_identity_snapshot() -> Option<(crate::analytics::contract::Route, u64)> { + let current = platform_session().try_lock().ok()?; + Some(( + analytics_route(¤t), + ANALYTICS_IDENTITY_SEQUENCE.load(std::sync::atomic::Ordering::Relaxed), + )) +} + +// 仅供后台初始化使用:持锁发布 GUI 身份,避免快照与通知之间出现空窗。 +// 回调只允许更新内存或非阻塞投递,不能访问磁盘或重新取得认证锁。 +pub(crate) fn initialize_analytics_identity( + initialize: impl FnOnce(crate::analytics::contract::Route, u64), +) { + if let Ok(current) = platform_session().lock() { + initialize( + analytics_route(¤t), + ANALYTICS_IDENTITY_SEQUENCE.load(std::sync::atomic::Ordering::Relaxed), + ); + } +} + fn platform_session() -> &'static Mutex { PLATFORM_SESSION.get_or_init(|| Mutex::new(PlatformSessionState::default())) } @@ -380,6 +420,9 @@ pub(crate) fn install_platform_session( snapshot.identity_generation, snapshot.revision, ); + let (route, sequence) = analytics_identity_notice(¤t); + drop(current); + crate::analytics::gui::identity_changed(route, sequence); Ok(()) } @@ -453,6 +496,9 @@ pub(crate) fn replace_platform_session_for_gui_owner( current.revision = snapshot.revision; current.identity_generation = snapshot.identity_generation; current.snapshot = Some(snapshot); + let (route, sequence) = analytics_identity_notice(¤t); + drop(current); + crate::analytics::gui::identity_changed(route, sequence); Ok(()) } @@ -481,7 +527,11 @@ pub(crate) fn install_platform_session_checked( snapshot.identity_generation, snapshot.revision, ); - if current.snapshot.as_ref() == Some(&snapshot) { + let accepted = current.snapshot.as_ref() == Some(&snapshot); + let (route, sequence) = analytics_identity_notice(¤t); + drop(current); + crate::analytics::gui::identity_changed(route, sequence); + if accepted { Ok(()) } else { Err("authentication-required: 平台登录态写入已过期或主体冲突".to_string()) @@ -519,6 +569,9 @@ pub(crate) fn clear_platform_session(identity_generation: u64, revision: u64) { .lock() .unwrap_or_else(|poisoned| poisoned.into_inner()); clear_platform_session_in(&mut current, identity_generation, revision); + let (route, sequence) = analytics_identity_notice(¤t); + drop(current); + crate::analytics::gui::identity_changed(route, sequence); } pub(crate) fn clear_platform_session_for_gui_owner(identity_generation: u64, revision: u64) { @@ -529,6 +582,9 @@ pub(crate) fn clear_platform_session_for_gui_owner(identity_generation: u64, rev current.revision = revision; current.identity_generation = identity_generation; current.snapshot = None; + let (route, sequence) = analytics_identity_notice(¤t); + drop(current); + crate::analytics::gui::identity_changed(route, sequence); } pub(crate) fn clear_platform_session_checked( @@ -539,10 +595,13 @@ pub(crate) fn clear_platform_session_checked( .lock() .unwrap_or_else(|poisoned| poisoned.into_inner()); clear_platform_session_in(&mut current, identity_generation, revision); - if current.revision >= revision + let accepted = current.revision >= revision && current.identity_generation >= identity_generation - && current.snapshot.is_none() - { + && current.snapshot.is_none(); + let (route, sequence) = analytics_identity_notice(¤t); + drop(current); + crate::analytics::gui::identity_changed(route, sequence); + if accepted { Ok(()) } else { Err("authentication-required: 平台登出写入已过期".to_string()) diff --git a/apps/ai-game-creator-shell/src-tauri/src/preview.rs b/apps/ai-game-creator-shell/src-tauri/src/preview.rs index e678d6438..6a6520abe 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/preview.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/preview.rs @@ -8,6 +8,7 @@ pub(crate) struct PreviewRegistry { struct PreviewServer { preview: LocalPreviewResult, stop: mpsc::Sender<()>, + _analytics_lease: Option, } impl PreviewRegistry { @@ -15,6 +16,15 @@ impl PreviewRegistry { &self, preview: LocalPreviewResult, stop: mpsc::Sender<()>, + ) -> (LocalPreviewResult, Option) { + self.set_running_with_lease(preview, stop, None) + } + + fn set_running_with_lease( + &self, + preview: LocalPreviewResult, + stop: mpsc::Sender<()>, + analytics_lease: Option, ) -> (LocalPreviewResult, Option) { let mut current = self.current.lock().expect("preview registry lock"); let previous_preview = if let Some(previous) = current.take() { @@ -27,6 +37,7 @@ impl PreviewRegistry { *current = Some(PreviewServer { preview: preview.clone(), stop, + _analytics_lease: analytics_lease, }); (preview, previous_preview) } @@ -713,10 +724,14 @@ pub(crate) fn filter_preview_status_for_project( pub(crate) fn start_local_game_preview( project_path: String, expected_revision: Option, + preview_source: Option, registry: tauri::State<'_, PreviewRegistry>, ) -> Result { let root = Path::new(project_path.trim()); - start_local_game_preview_at_revision(root, expected_revision, ®istry) + let capture = (preview_source == Some(crate::analytics::contract::PreviewSource::User)) + .then(crate::analytics::gui::capture_writer_context) + .flatten(); + start_local_game_preview_with_capture(root, expected_revision, ®istry, capture) } pub(crate) fn start_local_game_preview_at( @@ -730,6 +745,18 @@ pub(crate) fn start_local_game_preview_at_revision( root: &Path, expected_revision: Option, registry: &PreviewRegistry, +) -> Result { + start_local_game_preview_with_capture(root, expected_revision, registry, None) +} + +fn start_local_game_preview_with_capture( + root: &Path, + expected_revision: Option, + registry: &PreviewRegistry, + capture: Option<( + crate::analytics::contract::Context, + crate::analytics::store::AnalyticsWriter, + )>, ) -> Result { enforce_project_permission_policy(root, "preview.start")?; let _lock = acquire_project_write_lock(root, "preview.start")?; @@ -741,6 +768,16 @@ pub(crate) fn start_local_game_preview_at_revision( )); } } + let observation = crate::analytics::preview::prepare( + root, + capture, + crate::analytics::contract::Source::Editor, + crate::analytics::contract::PreviewSource::User, + ); + let (analytics_lease, observation) = match observation { + Some((lease, observation)) => (Some(lease), Some(observation)), + None => (None, None), + }; let (preview, stop) = start_local_game_preview_for_project(root)?; if let Err(error) = record_preview_state( root, @@ -756,7 +793,8 @@ pub(crate) fn start_local_game_preview_at_revision( let _ = record_preview_state(root, GameCreationAppPreviewStatus::Stopped, None, None); return Err(error); } - let (preview, previous_preview) = registry.set_running(preview, stop); + let (preview, previous_preview) = + registry.set_running_with_lease(preview, stop, analytics_lease); if let Some(previous_preview) = previous_preview.as_ref() { // 同一个项目重启预览(换监听线程、换端口)时,旧的 registry 身份与新预览共享 // 同一份落盘记录:上面刚写进去的是 running,这里若再用旧预览收尾,就会把它覆盖 @@ -772,9 +810,16 @@ pub(crate) fn start_local_game_preview_at_revision( let _ = record_preview_state(root, GameCreationAppPreviewStatus::Stopped, None, None); return Err(error); } + if let Some(observation) = observation { + observation.schedule(preview.port); + } Ok(preview) } +#[cfg(test)] +#[path = "preview_analytics_tests.rs"] +mod analytics_tests; + #[tauri::command] pub(crate) fn stop_local_game_preview( project_path: Option, diff --git a/apps/ai-game-creator-shell/src-tauri/src/preview_analytics_tests.rs b/apps/ai-game-creator-shell/src-tauri/src/preview_analytics_tests.rs new file mode 100644 index 000000000..99caee428 --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/src/preview_analytics_tests.rs @@ -0,0 +1,297 @@ +use super::*; +use crate::analytics::{ + contract::{Context, EntrySource, EventData, PreviewSource, Route, SessionStart, Source}, + preview::{prepare, Lease, Observation}, + store::AnalyticsWriter, +}; + +struct Fixture { + _temp: tempfile::TempDir, + root: PathBuf, + config: PathBuf, + context: Context, + writer: AnalyticsWriter, +} + +impl Fixture { + fn new() -> Self { + let temp = tempfile::tempdir().unwrap(); + let root = temp.path().join("project"); + init_local_game_project_at(&root, "preview-analytics", "预览埋点").unwrap(); + fs::create_dir_all(project_game_root(&root)).unwrap(); + fs::write( + project_game_root(&root).join("index.html"), + "游戏入口", + ) + .unwrap(); + let config = temp.path().join("config"); + fs::create_dir_all(&config).unwrap(); + let context = Context { + route: Route::from_identity(Some("A".into()), Some("https://example.com")), + editor_session_id: uuid::Uuid::new_v4().to_string(), + client_version: "1.0.0".into(), + }; + let writer = AnalyticsWriter::start(config.clone(), context.editor_session_id.clone()); + Self { + _temp: temp, + root, + config, + context, + writer, + } + } + + fn capture(&self) -> Option<(Context, AnalyticsWriter)> { + Some((self.context.clone(), self.writer.clone())) + } + + fn observation(&self, source: Source, preview_source: PreviewSource) -> (Lease, Observation) { + prepare(&self.root, self.capture(), source, preview_source).unwrap() + } + + fn events(&self) -> Vec { + let batches = self + .config + .join("analytics/instances") + .join(&self.context.editor_session_id) + .join("batches"); + fs::read_dir(batches) + .into_iter() + .flatten() + .flatten() + .filter(|entry| !entry.file_name().to_string_lossy().starts_with('.')) + .filter_map(|entry| fs::read_to_string(entry.path().join("events.jsonl")).ok()) + .flat_map(|text| { + text.lines() + .filter_map(|line| serde_json::from_str(line).ok()) + .collect::>() + }) + .collect() + } + + async fn drained(&self) -> Vec { + let marker = self + .context + .capture( + EventData::EditorSessionStart(SessionStart { + entry_source: EntrySource::DirectLaunch, + first_project_id: None, + }), + None, + Source::Editor, + None, + ) + .unwrap(); + let marker_id = marker.event_id.clone(); + assert!(self + .writer + .try_record(self.context.route.clone(), marker, marker_id.clone())); + assert!(self.writer.flush()); + let deadline = std::time::Instant::now() + Duration::from_secs(5); + loop { + let events = self.events(); + if events.iter().any(|event| event["event_id"] == marker_id) { + return events; + } + assert!( + std::time::Instant::now() < deadline, + "preview writer FIFO timeout" + ); + tokio::time::sleep(Duration::from_millis(5)).await; + } + } +} + +fn ready(events: &[serde_json::Value]) -> Vec<&serde_json::Value> { + events + .iter() + .filter(|event| event["event_name"] == "preview_ready") + .collect() +} + +#[tokio::test] +async fn preview_analytics_real_entry_and_reopen_have_distinct_instances_and_original_identity() { + let fixture = Fixture::new(); + let version = read_game_creator_agent_runtime_project_revision(&fixture.root) + .unwrap() + .revision; + let mut current = fixture.context.clone(); + for source in [PreviewSource::User, PreviewSource::Agent] { + let event_source = if source == PreviewSource::User { + Source::Editor + } else { + Source::Direct + }; + let (_lease, observation) = fixture.observation(event_source, source); + current.route.user_id = Some("B".into()); + let (preview, stop) = start_local_game_preview_for_project(&fixture.root).unwrap(); + observation.observe(preview.port).await; + let _ = stop.send(()); + } + assert_eq!(current.route.user_id.as_deref(), Some("B")); + let events = fixture.drained().await; + let events = ready(&events); + assert_eq!(events.len(), 2); + assert_ne!(events[0]["event_id"], events[1]["event_id"]); + for event in &events { + assert_eq!(event["user_id"], "A"); + assert_eq!(event["project_id"], "preview-analytics"); + assert_eq!(event["creative_task_id"], "preview-analytics"); + assert_eq!(event["properties"]["preview_version"], version.to_string()); + assert!(event["agent_run_id"].is_null()); + assert!(event["agent_turn_id"].is_null()); + assert!(!event.to_string().contains("127.0.0.1")); + } + assert!(events.iter().any( + |event| event["source"] == "editor" && event["properties"]["preview_source"] == "user" + )); + assert!(events.iter().any( + |event| event["source"] == "direct" && event["properties"]["preview_source"] == "agent" + )); +} + +#[tokio::test] +async fn preview_analytics_missing_empty_stopped_or_changed_entry_is_not_ready() { + let fixture = Fixture::new(); + let entry = project_game_root(&fixture.root).join("index.html"); + let (preview, stop) = start_local_game_preview_for_project(&fixture.root).unwrap(); + let (lease, observation) = fixture.observation(Source::Direct, PreviewSource::Agent); + drop(lease); + observation.observe(preview.port).await; + let (_lease, observation) = fixture.observation(Source::Editor, PreviewSource::User); + fs::write(&entry, b"").unwrap(); + observation.observe(preview.port).await; + assert!(prepare( + &fixture.root, + fixture.capture(), + Source::Editor, + PreviewSource::User + ) + .is_none()); + fs::write(&entry, b"entry").unwrap(); + let (_lease, observation) = fixture.observation(Source::Editor, PreviewSource::User); + fs::remove_file(&entry).unwrap(); + observation.observe(preview.port).await; + fs::write(&entry, b"entry").unwrap(); + let (_lease, observation) = fixture.observation(Source::Editor, PreviewSource::User); + { + let _lock = acquire_project_write_lock(&fixture.root, "file.write").unwrap(); + advance_agent_runtime_project_revision_locked(&fixture.root).unwrap(); + } + observation.observe(preview.port).await; + let _ = stop.send(()); + assert!(ready(&fixture.drained().await).is_empty()); +} + +#[tokio::test] +async fn preview_analytics_checks_version_again_after_the_actual_request() { + let fixture = Fixture::new(); + let (_lease, observation) = fixture.observation(Source::Editor, PreviewSource::User); + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let port = listener.local_addr().unwrap().port(); + let (requested, request_received) = tokio::sync::oneshot::channel(); + let (allow_response, response_allowed) = mpsc::channel(); + let server = thread::spawn(move || { + let (mut stream, _) = listener.accept().unwrap(); + assert!(read_preview_request_line(&mut stream).unwrap().is_some()); + requested.send(()).unwrap(); + response_allowed + .recv_timeout(Duration::from_secs(3)) + .unwrap(); + stream + .write_all(b"HTTP/1.1 200 OK\r\nContent-Length: 5\r\nConnection: close\r\n\r\nready") + .unwrap(); + }); + let probe = tokio::spawn(observation.observe(port)); + tokio::time::timeout(Duration::from_secs(3), request_received) + .await + .unwrap() + .unwrap(); + { + let _lock = acquire_project_write_lock(&fixture.root, "file.write").unwrap(); + advance_agent_runtime_project_revision_locked(&fixture.root).unwrap(); + } + allow_response.send(()).unwrap(); + probe.await.unwrap(); + server.join().unwrap(); + assert!(ready(&fixture.drained().await).is_empty()); +} + +#[tokio::test] +async fn preview_analytics_http_failure_or_empty_response_is_not_ready() { + let fixture = Fixture::new(); + for response in [ + "HTTP/1.1 404 Not Found\r\nContent-Length: 3\r\nConnection: close\r\n\r\nbad", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\nConnection: close\r\n\r\n", + ] { + let (_lease, observation) = fixture.observation(Source::Editor, PreviewSource::User); + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let port = listener.local_addr().unwrap().port(); + let server = thread::spawn(move || { + let (mut stream, _) = listener.accept().unwrap(); + assert!(read_preview_request_line(&mut stream).unwrap().is_some()); + stream.write_all(response.as_bytes()).unwrap(); + }); + observation.observe(port).await; + server.join().unwrap(); + } + assert!(ready(&fixture.drained().await).is_empty()); +} + +#[tokio::test] +async fn preview_analytics_gui_start_schedules_without_waiting_and_registry_invalidates_old_instance( +) { + let fixture = Fixture::new(); + let registry = PreviewRegistry::default(); + let started = + start_local_game_preview_with_capture(&fixture.root, None, ®istry, fixture.capture()) + .unwrap(); + assert_eq!(registry.status().port, Some(started.port)); + let deadline = std::time::Instant::now() + Duration::from_secs(5); + loop { + if !ready(&fixture.drained().await).is_empty() { + break; + } + assert!( + std::time::Instant::now() < deadline, + "GUI scheduled ready timeout" + ); + tokio::time::sleep(Duration::from_millis(10)).await; + } + registry.stop(); + let (lease, old_observation) = fixture.observation(Source::Editor, PreviewSource::User); + let (old_preview, old_stop) = start_local_game_preview_for_project(&fixture.root).unwrap(); + registry.set_running_with_lease(old_preview.clone(), old_stop, Some(lease)); + let (lease, stopped_observation) = fixture.observation(Source::Editor, PreviewSource::User); + let (new_preview, new_stop) = start_local_game_preview_for_project(&fixture.root).unwrap(); + registry.set_running_with_lease(new_preview.clone(), new_stop, Some(lease)); + old_observation.observe(old_preview.port).await; + registry.stop(); + stopped_observation.observe(new_preview.port).await; + assert_eq!(ready(&fixture.drained().await).len(), 1); + + // 空入口仍遵循原有启动行为,采集跳过不能变成业务启动失败。 + fs::write(project_game_root(&fixture.root).join("index.html"), b"").unwrap(); + assert!(start_local_game_preview_with_capture( + &fixture.root, + None, + ®istry, + fixture.capture() + ) + .is_ok()); + registry.stop(); + assert_eq!(ready(&fixture.drained().await).len(), 1); +} + +#[tokio::test] +async fn preview_analytics_cancelled_direct_scope_does_not_publish_ready() { + let fixture = Fixture::new(); + let (_lease, observation) = fixture.observation(Source::Direct, PreviewSource::Agent); + let cancelled = Arc::new(std::sync::atomic::AtomicBool::new(false)); + let observation = observation.with_cancellation(Some(cancelled.clone())); + let (preview, stop) = start_local_game_preview_for_project(&fixture.root).unwrap(); + cancelled.store(true, std::sync::atomic::Ordering::Release); + observation.observe(preview.port).await; + let _ = stop.send(()); + assert!(ready(&fixture.drained().await).is_empty()); +} diff --git a/apps/ai-game-creator-shell/src-tauri/src/project/export.rs b/apps/ai-game-creator-shell/src-tauri/src/project/export.rs index cb8fc948c..214b3f16d 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/project/export.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/project/export.rs @@ -136,6 +136,159 @@ pub(crate) fn export_local_project_package_at( /// /// The caller receives the package bytes and a deterministic file manifest, but /// never receives a filesystem path that it could accidentally send to the API. +/// 发布前构建的超时上限:与 `project.verify` 的上限保持一致(构建属于常规步骤, +/// 给足时间但必须有界),避免发布路径越过校验器允许的区间。 +pub(crate) const PUBLISH_BUILD_TIMEOUT_SECONDS: u64 = 300; + +/// 找到声明了 `scripts.build` 的 npm 工作目录(项目根或 `game/` 子工程)。 +/// +/// 只读 `package.json`,不执行任何东西;真正的执行交给 `project.verify` 的受控 +/// npm 运行器(脚本白名单含 `build`、禁止项目级 `.npmrc` 改写语义、沙箱与超时都在那里)。 +pub(crate) fn resolve_publish_build_cwd(root: &Path) -> Result, String> { + for cwd in [".", "game"] { + let package_root = if cwd == "." { + root.to_path_buf() + } else { + resolve_local_project_path(root, cwd)? + }; + let package_path = package_root.join("package.json"); + let metadata = match fs::symlink_metadata(&package_path) { + Ok(metadata) => metadata, + Err(_) => continue, + }; + if metadata.file_type().is_symlink() || !metadata.is_file() { + continue; + } + let Ok(content) = fs::read_to_string(&package_path) else { + continue; + }; + let Ok(package) = serde_json::from_str::(&content) else { + continue; + }; + let declared = package + .get("scripts") + .and_then(|scripts| scripts.get("build")) + .and_then(serde_json::Value::as_str) + .map(str::trim) + .filter(|value| !value.is_empty()); + if declared.is_some() { + return Ok(Some(cwd)); + } + } + Ok(None) +} + +/// 读取声明的 build 脚本原文:`project.verify` 用它做 expectedCommand 反漂移校验。 +pub(crate) fn read_publish_build_command( + root: &Path, + cwd_relative: &str, +) -> Result { + let package_root = if cwd_relative == "." { + root.to_path_buf() + } else { + resolve_local_project_path(root, cwd_relative)? + }; + let package_path = package_root.join("package.json"); + let content = fs::read_to_string(&package_path).map_err(|error| { + format!( + "读取 package.json 失败:{}: {error}", + package_path.display() + ) + })?; + let package: serde_json::Value = serde_json::from_str(&content) + .map_err(|error| format!("解析 package.json 失败:{error}"))?; + package + .get("scripts") + .and_then(|scripts| scripts.get("build")) + .and_then(serde_json::Value::as_str) + .map(|value| value.trim().to_string()) + .filter(|value| !value.is_empty()) + .ok_or_else(|| "package.json 未定义 build 脚本".to_string()) +} + +/// 构建失败的日志尾部:命令输出有界,直接回传最后一段给作者判断。 +fn publish_build_failure_tail(output: &str) -> String { + const MAX_CHARS: usize = 2_000; + let trimmed = output.trim(); + let chars = trimmed.chars().count(); + if chars <= MAX_CHARS { + return trimmed.to_string(); + } + let tail = trimmed.chars().skip(chars - MAX_CHARS).collect::(); + format!("…{tail}") +} + +/// 发布前构建计划:在哪个目录构建、构建脚本原文、以及是否需要先装依赖。 +#[derive(Clone, Debug, Eq, PartialEq)] +pub(crate) struct PublishBuildPlan { + pub(crate) cwd_relative: &'static str, + pub(crate) command: String, + /// `game/` 子工程缺 `node_modules` 时为 true:构建前必须先跑 `project.bootstrap`。 + pub(crate) needs_dependency_install: bool, +} + +/// 解析发布前构建计划;项目没有任何可构建的 npm 工程时返回可操作错误。 +pub(crate) fn resolve_publish_build_plan(root: &Path) -> Result { + let Some(cwd_relative) = resolve_publish_build_cwd(root)? else { + return Err( + "项目还没有可玩入口,且项目根 / game 目录的 package.json 都没有 build 脚本:请让 Agent 生成可玩产物,或补上 build 脚本后重试" + .to_string(), + ); + }; + let command = read_publish_build_command(root, cwd_relative)?; + let needs_dependency_install = + cwd_relative == "game" && !root.join("game").join("node_modules").is_dir(); + Ok(PublishBuildPlan { + cwd_relative, + command, + needs_dependency_install, + }) +} + +/// 为发布导出试玩包:项目还没有可玩入口时,先跑项目自己的 `npm run build`。 +/// +/// 作者只需要点一次「发布」:已有可玩产物(`game/index.html` 或 `dist/index.html`)直接打包; +/// 只有源码时用 `project.verify` 的受控 npm 运行器执行 build,再校验入口并打包。构建失败 +/// 返回带日志尾部的可操作错误,不回传本地路径。 +pub(crate) async fn export_local_project_package_for_publish_at( + root: &Path, +) -> Result { + if validate_project_game_entry(root).is_ok() { + return export_local_project_package_at(root); + } + let plan = resolve_publish_build_plan(root)?; + // `game/` 子工程构建前必须先有依赖:缺 node_modules 时由发布流程自己补一次安装, + // 否则作者要点两次(先 bootstrap 再发布)。 + if plan.needs_dependency_install { + let bootstrap = + crate::project::run_project_bootstrap_at(root, PUBLISH_BUILD_TIMEOUT_SECONDS).await?; + if bootstrap.status != "completed" { + return Err(format!( + "安装 game 依赖失败(npm install 未通过):\n{}", + publish_build_failure_tail(&bootstrap.output) + )); + } + } + let built = crate::project::verification::run_project_verification_with_commit_at( + root, + "build", + &plan.command, + PUBLISH_BUILD_TIMEOUT_SECONDS, + plan.cwd_relative, + || Ok(()), + ) + .await?; + if built.status != "completed" { + return Err(format!( + "构建可玩版本失败(npm run build 未通过):\n{}", + publish_build_failure_tail(&built.output) + )); + } + validate_project_game_entry(root) + .map_err(|error| format!("构建完成但项目仍没有可玩入口:{error}"))?; + export_local_project_package_at(root) +} + pub(crate) fn read_local_project_export_package_at( root: &Path, package_relative_path: &str, diff --git a/apps/ai-game-creator-shell/src-tauri/src/template_library.rs b/apps/ai-game-creator-shell/src-tauri/src/template_library.rs index fbf8fbc10..45f9b0330 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/template_library.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/template_library.rs @@ -1032,6 +1032,7 @@ pub(crate) async fn create_automatic_local_game_project_from_template( planning: Option, projects_root: Option, ) -> Result { + let analytics_context = crate::analytics::gui::capture_analytics_context(); let identity = require_template_library_access().await?; let projects_root = crate::resolve_game_project_creation_root(&app, projects_root.as_deref())?; let cache_root = template_cache_root(&app)?; @@ -1043,14 +1044,24 @@ pub(crate) async fn create_automatic_local_game_project_from_template( &identity, ) .await?; - with_validated_platform_session_identity(&identity, || { + let result = with_validated_platform_session_identity(&identity, || { create_project_from_installed_template_at( &projects_root, Path::new(&record.project_dir), name.as_deref(), planning.unwrap_or(false), ) - }) + }); + if let Ok(project) = &result { + crate::analytics::gui::created( + analytics_context, + Path::new(&project.project_path), + project.manifest.project_id.clone(), + crate::analytics::contract::CreationSource::Template, + Some(template_id), + ); + } + result } #[cfg(test)] diff --git a/apps/ai-game-creator-shell/src-tauri/src/tests/project.rs b/apps/ai-game-creator-shell/src-tauri/src/tests/project.rs index a67c171f5..9b0f1a480 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/tests/project.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/tests/project.rs @@ -3935,6 +3935,165 @@ fn local_project_export_package_uses_runtime_whitelist_and_records() { fs::remove_dir_all(root).ok(); } +#[test] +fn publish_build_plan_prefers_game_subproject_and_requires_dependencies() { + let root = unique_project_path(); + init_local_game_project_at(&root, "project-plan-game", "Phaser 工程").expect("project init"); + + // 脚手架是 game/ + vite build(Phaser 4 工程):缺依赖时必须先 install。 + let plan = resolve_publish_build_plan(&root).expect("解析构建计划"); + assert_eq!(plan.cwd_relative, "game"); + assert_eq!(plan.command, "vite build"); + assert!( + plan.needs_dependency_install, + "缺少 game/node_modules 时应先装依赖" + ); + + fs::create_dir_all(root.join("game/node_modules")).expect("create node_modules"); + let installed = resolve_publish_build_plan(&root).expect("解析构建计划"); + assert!( + !installed.needs_dependency_install, + "已有依赖时不应重复 install" + ); + + fs::remove_dir_all(root).ok(); +} + +#[test] +fn publish_build_plan_falls_back_to_root_npm_build() { + let root = unique_project_path(); + init_local_game_project_at(&root, "project-plan-root", "根工程构建").expect("project init"); + // 去掉 game 子工程的 build,改用项目根 npm 工程构建。 + fs::write( + root.join("game/package.json"), + serde_json::to_string_pretty(&serde_json::json!({ + "name": "plan-root-game", + "private": true, + "scripts": { "check": "node -e \"process.exit(0)\"" } + })) + .expect("serialize game package json"), + ) + .expect("write game package json"); + fs::write( + root.join("package.json"), + serde_json::to_string_pretty(&serde_json::json!({ + "name": "plan-root-fixture", + "private": true, + "scripts": { "build": "node build-root.mjs" } + })) + .expect("serialize root package json"), + ) + .expect("write root package json"); + + let plan = resolve_publish_build_plan(&root).expect("解析构建计划"); + assert_eq!(plan.cwd_relative, "."); + assert_eq!(plan.command, "node build-root.mjs"); + assert!(!plan.needs_dependency_install); + + fs::remove_dir_all(root).ok(); +} + +#[tokio::test] +async fn publish_export_runs_project_build_before_packaging() { + let root = unique_project_path(); + init_local_game_project_at(&root, "project-auto-build", "自动构建发布项目") + .expect("project init"); + // 只有源码:package.json 声明 build,构建脚本产出 dist/ 可玩产物。 + fs::write( + root.join("package.json"), + serde_json::to_string_pretty(&serde_json::json!({ + "name": "publish-auto-build-fixture", + "private": true, + "scripts": { "build": "node build-publish.mjs" } + })) + .expect("serialize package json"), + ) + .expect("write package json"); + fs::write( + root.join("build-publish.mjs"), + r#"import { mkdirSync, writeFileSync } from 'node:fs'; +mkdirSync('dist/assets', { recursive: true }); +writeFileSync('dist/index.html', 'Auto Build

AUTO-BUILD

'); +writeFileSync('dist/assets/app.js', 'document.documentElement.dataset.autoBuild = "1";'); +"#, + ) + .expect("write build script"); + write_local_project_file_at(&root, "exports/README.md", "publish notes").expect("write readme"); + + let result = export_local_project_package_for_publish_at(&root) + .await + .expect("发布前构建并导出"); + + assert!(root.join("dist/index.html").is_file()); + assert!(root.join("dist/assets/app.js").is_file()); + assert!(result + .package_relative_path + .starts_with("exports/playtest-package-")); + let log = fs::read_to_string(root.join(".agent/logs/command.log")).unwrap_or_default(); + assert!( + log.contains("project.verify build"), + "发布前应记录一次 project.verify build:{log}" + ); + + fs::remove_dir_all(root).ok(); +} + +#[tokio::test] +async fn publish_export_skips_build_when_playable_entry_exists() { + let root = unique_project_path(); + init_existing_html_project_at(&root, "project-publish-skip", "已构建发布项目") + .expect("project init"); + write_local_project_file_at(&root, "game/index.html", &fake_llm_game_draft().game_html) + .expect("write playable html"); + write_local_project_file_at(&root, "exports/README.md", "publish notes").expect("write readme"); + + let result = export_local_project_package_for_publish_at(&root) + .await + .expect("已有可玩入口时直接导出"); + + assert!(result.package_relative_path.ends_with(".zip")); + let log = fs::read_to_string(root.join(".agent/logs/command.log")).unwrap_or_default(); + assert!( + !log.contains("project.verify build"), + "已有可玩入口时不应触发构建:{log}" + ); + + fs::remove_dir_all(root).ok(); +} + +#[tokio::test] +async fn publish_export_reports_actionable_error_without_entry_or_build_script() { + let root = unique_project_path(); + init_local_game_project_at(&root, "project-no-entry", "缺少可玩入口项目") + .expect("project init"); + // 脚手架默认带 build 脚本;这里改成只有 check 脚本,模拟“没有可玩产物且没有构建脚本”。 + fs::write( + root.join("game/package.json"), + serde_json::to_string_pretty(&serde_json::json!({ + "name": "publish-no-entry-fixture", + "private": true, + "scripts": { "check": "node -e \"process.exit(0)\"" } + })) + .expect("serialize package json"), + ) + .expect("write package json"); + + let error = export_local_project_package_for_publish_at(&root) + .await + .expect_err("缺少入口且没有 build 脚本时必须失败关闭"); + + assert!( + error.contains("还没有可玩入口"), + "错误应说明缺少可玩入口:{error}" + ); + assert!( + error.contains("build 脚本"), + "错误应指向 build 脚本:{error}" + ); + + fs::remove_dir_all(root).ok(); +} + #[test] fn local_project_export_package_publish_payload_contains_bytes_and_file_digests() { let root = unique_project_path(); diff --git a/apps/ai-game-creator-shell/src-tauri/src/tests/sessions.rs b/apps/ai-game-creator-shell/src-tauri/src/tests/sessions.rs index af671e1c2..64426bcb8 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/tests/sessions.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/tests/sessions.rs @@ -2777,17 +2777,11 @@ fn agent_run_history_prunes_to_latest_hundred_traces() { } #[test] -fn developer_project_file_and_memory_writes_advance_project_revision() { +fn developer_memory_writes_advance_project_revision() { let root = unique_project_path(); init_local_game_project_at(&root, "project-1", "开发面板 revision").expect("project init"); let project_path = root.to_string_lossy().into_owned(); - write_local_project_file( - project_path.clone(), - "game/revision.txt".to_string(), - "v1".to_string(), - ) - .expect("write project file through command"); write_local_agent_memory( project_path.clone(), "design-director".to_string(), @@ -2804,7 +2798,7 @@ fn developer_project_file_and_memory_writes_advance_project_revision() { read_game_creator_agent_runtime_project_revision(&root) .expect("read developer mutation revision") .revision, - 3 + 2 ); fs::remove_dir_all(root).ok(); } diff --git a/apps/ai-game-creator-shell/src/App.tsx b/apps/ai-game-creator-shell/src/App.tsx index 493f3ba80..30427f1be 100644 --- a/apps/ai-game-creator-shell/src/App.tsx +++ b/apps/ai-game-creator-shell/src/App.tsx @@ -1206,16 +1206,27 @@ export function App({ * 权限口径沿用本地命令:`project.export_package` 需要确认时先入队,确认后再导出; * 导出结果只留在壳里,发布面板关闭即丢弃,不写入项目。 */ + /** + * 发布相关提示同时写工作台状态与 DirectProject 对话。 + * + * 普通项目走 `DirectProjectChatView` 时并不渲染工作台状态行,只写 workspaceStatus + * 会让「点了发布没反应」;这里统一通过聊天容器的 announce 出口回话。 + */ + function announcePublishMessage(message: string) { + setWorkspaceStatus(message); + directProjectChatRef.current?.announce(message); + } + async function requestGamePublish() { const invoke = resolveTauriInvoke(); if (!invoke) { - setWorkspaceStatus('需要在 Tauri App 内发布'); + announcePublishMessage('需要在 Tauri App 内发布'); return; } const nextProjectPath = resolveChatProjectPath(localProject) ?? projectPath.trim(); if (!nextProjectPath) { - setWorkspaceStatus('先打开一个项目再发布'); + announcePublishMessage('先打开一个项目再发布'); return; } const runExport = async () => { @@ -1224,7 +1235,9 @@ export function App({ 'export_local_project_package', { projectPath: nextProjectPath }, ); - setWorkspaceStatus(`已导出本地试玩包:${result.packageRelativePath}`); + announcePublishMessage( + `已构建并打包试玩包:${result.packageRelativePath}`, + ); setPublishPackageResult(result); setPublishPanelOpen(true); appendLocalPermissionLog( @@ -1233,7 +1246,7 @@ export function App({ 'project.export_package', ); } catch (error) { - setWorkspaceStatus( + announcePublishMessage( error instanceof Error ? error.message : String(error), ); } @@ -1852,7 +1865,7 @@ export function App({ } const previewResult = await invoke( 'start_local_game_preview', - { projectPath: nextProjectPath }, + { projectPath: nextProjectPath, previewSource: 'user' }, ); updateClientPreview(previewResult); void refreshManifest(nextProjectPath); diff --git a/apps/ai-game-creator-shell/src/components/ChatMarkdownMessage/index.tsx b/apps/ai-game-creator-shell/src/components/ChatMarkdownMessage/index.tsx index d8acce153..543351e25 100644 --- a/apps/ai-game-creator-shell/src/components/ChatMarkdownMessage/index.tsx +++ b/apps/ai-game-creator-shell/src/components/ChatMarkdownMessage/index.tsx @@ -6,6 +6,7 @@ import { Component, createContext, isValidElement, + memo, useContext, } from 'react'; import ReactMarkdown, { type Components } from 'react-markdown'; @@ -302,7 +303,15 @@ const streamingMarkdownComponents: Components = { p: StreamingMarkdownParagraph, }; -export function ChatMarkdownMessage({ +/** + * 解析器的输入只有 `text` / `role` / `streaming` / `preserveBlankLines` 这几个标量,所以 + * 内容没变的旧消息在父级重渲染时可以直接跳过:Markdown 解析与语法高亮是这个组件里最贵的 + * 两件事(`react-markdown` 每次渲染都会重建 `unified()` 处理器并重跑全部插件),而旧消息 + * 的文本永远不会再改。 + */ +export const ChatMarkdownMessage = memo(ChatMarkdownMessageImpl); + +function ChatMarkdownMessageImpl({ text, role, streaming = false, @@ -317,8 +326,13 @@ export function ChatMarkdownMessage({ MAX_HIGHLIGHT_CHARACTERS + ? [] + : [rehypeHighlight] } components={ streaming ? streamingMarkdownComponents : markdownComponents diff --git a/apps/ai-game-creator-shell/src/features/app-shell/WorkspaceLauncher.tsx b/apps/ai-game-creator-shell/src/features/app-shell/WorkspaceLauncher.tsx index 296b1d776..440107a2d 100644 --- a/apps/ai-game-creator-shell/src/features/app-shell/WorkspaceLauncher.tsx +++ b/apps/ai-game-creator-shell/src/features/app-shell/WorkspaceLauncher.tsx @@ -101,8 +101,12 @@ export function WorkspaceLauncherShell({ }); const templateLibrary = useTemplateLibrary({ userId: currentUser.id, - onProjectCreated: async (result, isCurrent) => { - await homeProject.enterCreatedTemplateProject(result, isCurrent); + onProjectCreated: async (result, isCurrent, analytics) => { + await homeProject.enterCreatedTemplateProject( + result, + isCurrent, + analytics, + ); }, }); useEffect(() => { @@ -608,6 +612,17 @@ export function WorkspaceLauncherShell({ ); }, []); + function navigateLauncher(view: LauncherView) { + if ( + launcherView === 'project-development' && + view !== launcherView && + currentProjectContext + ) { + homeProject.leaveProjectAnalytics(); + } + setLauncherView(view); + } + const handleRunNotice = useCallback((notice: ProjectRunNotice) => { setRunNotice((current) => ({ id: (current?.id ?? 0) + 1, ...notice })); }, []); @@ -680,6 +695,7 @@ export function WorkspaceLauncherShell({ templateLibraryEnabled={templateLibrary.enabled} currentUser={currentUser} onLogout={() => { + homeProject.leaveProjectAnalytics(); resetLauncherHomeDraft(); accountWallet.resetWalletBalance(); onLogout(); @@ -687,7 +703,7 @@ export function WorkspaceLauncherShell({ onNoticeRequest={showLauncherNotice} onRechargeRequest={accountWallet.openRecharge} onRuntimeConfigOpen={() => setRuntimeConfigOpen(true)} - onViewChange={setLauncherView} + onViewChange={navigateLauncher} />
setLauncherView('projects')} + onProjectsOpen={() => navigateLauncher('projects')} onProjectOpen={(path) => { setProjectPath(path); void openProject(path, 'open'); @@ -839,8 +855,8 @@ export function WorkspaceLauncherShell({ } onNotice={handleRunNotice} onManifestChange={syncActiveProjectManifest} - onHomeOpen={() => setLauncherView('home')} - onProjectsOpen={() => setLauncherView('projects')} + onHomeOpen={() => navigateLauncher('home')} + onProjectsOpen={() => navigateLauncher('projects')} chat={ (null); + const leaveProjectAnalytics = useCallback(() => { + const path = analyticsProjectPathRef.current; + analyticsProjectPathRef.current = null; + const invoke = resolveTauriInvoke(); + if (path && invoke) recordAnalyticsProjectLeave(invoke, path); + }, []); + useLayoutEffect(() => { + const lifecycle = lifecycleRef.current; + lifecycle.mounted = true; + const onPageHide = () => { + lifecycle.mounted = false; + lifecycle.generation += 1; + leaveProjectAnalytics(); + }; + window.addEventListener('pagehide', onPageHide); + return () => { + lifecycle.mounted = false; + lifecycle.generation += 1; + window.removeEventListener('pagehide', onPageHide); + // StrictMode 的同步 setup 重放不是用户离开;真实卸载才清理宿主登记。 + queueMicrotask(() => { + if (!lifecycle.mounted) leaveProjectAnalytics(); + }); + }; + }, [leaveProjectAnalytics]); const [projectPath, setProjectPathState] = useState(''); const [projectAction, setProjectAction] = useState< 'opening' | 'creating' | null @@ -241,7 +274,10 @@ export function useHomeProjectCreation({ async function enterProjectDevelopment( context: LauncherProjectContext, isCurrent: () => boolean = () => true, + analytics: ProjectOpenAnalytics = null, ) { + if (!lifecycleRef.current.mounted) return; + const generation = lifecycleRef.current.generation; const entryToken = (projectEntryTokenRef.current += 1); /** * 会话预览只认"内存 registry 里真的还在跑"的那一个(见 @@ -254,7 +290,12 @@ export function useHomeProjectCreation({ projectPath: context.projectPath, recordedPreview: context.manifest.preview ?? null, }); - if (entryToken !== projectEntryTokenRef.current || !isCurrent()) { + if ( + !lifecycleRef.current.mounted || + generation !== lifecycleRef.current.generation || + entryToken !== projectEntryTokenRef.current || + !isCurrent() + ) { // 更晚的一次进项目已经接管工作区:这一次的结果(预览与项目上下文)全部丢弃, // 否则慢请求后到会把新项目覆盖回旧项目。 return; @@ -276,6 +317,8 @@ export function useHomeProjectCreation({ setProjectPath(context.projectPath); setLauncherView('project-development'); rememberRecentWorkspace(context.projectPath); + analyticsProjectPathRef.current = context.projectPath; + analytics?.record(context.projectPath); } async function readCurrentProjectRevision( @@ -314,6 +357,7 @@ export function useHomeProjectCreation({ prompt: string, attachments: HomeAttachmentDraft[], startMode: ProjectStartMode, + analytics: ProjectOpenAnalytics, ) { if (startMode === 'planning') { await invoke('set_design_agent_runtime_mode', { @@ -333,29 +377,33 @@ export function useHomeProjectCreation({ startMode === 'planning' ? [] : await importHomeAttachments(invoke, result.projectPath, attachments); - await enterProjectDevelopment({ - projectPath: result.projectPath, - projectName: - result.manifest.name || projectNameFromPath(result.projectPath), - projectKind: 'web', - manifest: result.manifest, - projectRevision: await readCurrentProjectRevision( - invoke, - result.projectPath, - ), - creationType, - startMode, - initialPrompt: - prompt.trim() || - (attachments.length > 0 && startMode !== 'planning' - ? '用户上传了参考附件,等待后续补充需求。' - : ''), - attachments: importedAttachments, - fileImportNotice, - recentRunStatus: null, - recentRunStopReason: null, - createdAt: Date.now(), - }); + await enterProjectDevelopment( + { + projectPath: result.projectPath, + projectName: + result.manifest.name || projectNameFromPath(result.projectPath), + projectKind: 'web', + manifest: result.manifest, + projectRevision: await readCurrentProjectRevision( + invoke, + result.projectPath, + ), + creationType, + startMode, + initialPrompt: + prompt.trim() || + (attachments.length > 0 && startMode !== 'planning' + ? '用户上传了参考附件,等待后续补充需求。' + : ''), + attachments: importedAttachments, + fileImportNotice, + recentRunStatus: null, + recentRunStopReason: null, + createdAt: Date.now(), + }, + undefined, + analytics, + ); resetLauncherHomeDraft(); } @@ -366,6 +414,7 @@ export function useHomeProjectCreation({ attachments: HomeAttachmentDraft[], startMode: ProjectStartMode, skipNonEmptyCheck = false, + analytics?: ProjectOpenAnalytics, ) { const trimmedProjectPath = validateProjectPath(nextProjectPath); if (!trimmedProjectPath) { @@ -376,6 +425,10 @@ export function useHomeProjectCreation({ setStatus('需要在 Tauri App 内运行'); return '需要在 Tauri App 内运行'; } + analytics = + analytics === undefined + ? beginProjectOpenAnalytics(invoke, 'create') + : analytics; setStatus('正在创建项目'); try { if (!skipNonEmptyCheck) { @@ -416,6 +469,7 @@ export function useHomeProjectCreation({ prompt, attachments, startMode, + analytics, ); setStatus('已创建项目,正在开始智能创作'); } catch (error) { @@ -439,6 +493,7 @@ export function useHomeProjectCreation({ // 首页输入框里已经写好的要求:打开已有项目时不能再丢掉(此前写死空串, // 用户写的内容既不发首轮也不进对话历史)。 initialPrompt = '', + analytics?: ProjectOpenAnalytics, ) { if (projectActionRef.current) { return; @@ -454,6 +509,10 @@ export function useHomeProjectCreation({ } projectActionRef.current = 'creating'; setProjectAction('creating'); + analytics = + analytics === undefined + ? beginProjectOpenAnalytics(invoke, 'create') + : analytics; setStatus('正在创建项目'); try { if (!skipNonEmptyCheck) { @@ -479,24 +538,28 @@ export function useHomeProjectCreation({ }, ); setStatus('已创建项目'); - await enterProjectDevelopment({ - projectPath: result.projectPath, - projectName: - result.manifest.name || projectNameFromPath(result.projectPath), - projectKind: 'web', - manifest: result.manifest, - projectRevision: await readCurrentProjectRevision( - invoke, - result.projectPath, - ), - creationType: null, - startMode: null, - initialPrompt, - attachments: [], - recentRunStatus: null, - recentRunStopReason: null, - createdAt: Date.now(), - }); + await enterProjectDevelopment( + { + projectPath: result.projectPath, + projectName: + result.manifest.name || projectNameFromPath(result.projectPath), + projectKind: 'web', + manifest: result.manifest, + projectRevision: await readCurrentProjectRevision( + invoke, + result.projectPath, + ), + creationType: null, + startMode: null, + initialPrompt, + attachments: [], + recentRunStatus: null, + recentRunStopReason: null, + createdAt: Date.now(), + }, + undefined, + analytics, + ); } catch (error) { setStatus(error instanceof Error ? error.message : String(error)); } finally { @@ -514,6 +577,7 @@ export function useHomeProjectCreation({ async function enterCreatedTemplateProject( result: InitLocalProjectResult, isCurrent: () => boolean = () => true, + analytics: ProjectOpenAnalytics = null, ) { const invoke = resolveTauriInvoke(); if (!invoke) { @@ -541,10 +605,15 @@ export function useHomeProjectCreation({ createdAt: Date.now(), }, isCurrent, + analytics, ); } - async function openProject(nextProjectPath: string, mode: 'open' | 'create') { + async function openProject( + nextProjectPath: string, + mode: 'open' | 'create', + analytics?: ProjectOpenAnalytics, + ) { if (mode === 'create') { await createProjectFromProjectPage(nextProjectPath); return; @@ -563,6 +632,10 @@ export function useHomeProjectCreation({ } projectActionRef.current = 'opening'; setProjectAction('opening'); + analytics = + analytics === undefined + ? beginProjectOpenAnalytics(invoke, 'recent') + : analytics; setStatus('正在打开'); try { const directoryStatus = await invoke( @@ -626,32 +699,37 @@ export function useHomeProjectCreation({ projectPath: trimmedProjectPath, }); setStatus('已打开项目'); - await enterProjectDevelopment({ - projectPath: trimmedProjectPath, - projectName: - directoryStatus.projectName || - projectNameFromPath(trimmedProjectPath), - projectKind: directoryStatus.isUnityProject - ? 'unity' - : directoryStatus.isCocosProject - ? 'cocos' - : directoryStatus.godotProjectRoot !== null && - directoryStatus.godotProjectRoot !== undefined - ? 'godot' - : 'web', - manifest: projectManifest, - projectRevision: await readCurrentProjectRevision( - invoke, - trimmedProjectPath, - ), - creationType: null, - startMode: runtimeMode?.activeRuntime === 'design' ? 'planning' : null, - initialPrompt: homeDraftPromptText(), - attachments: [], - recentRunStatus: directoryStatus.recentRunStatus, - recentRunStopReason: directoryStatus.recentRunStopReason, - createdAt: Date.now(), - }); + await enterProjectDevelopment( + { + projectPath: trimmedProjectPath, + projectName: + directoryStatus.projectName || + projectNameFromPath(trimmedProjectPath), + projectKind: directoryStatus.isUnityProject + ? 'unity' + : directoryStatus.isCocosProject + ? 'cocos' + : directoryStatus.godotProjectRoot !== null && + directoryStatus.godotProjectRoot !== undefined + ? 'godot' + : 'web', + manifest: projectManifest, + projectRevision: await readCurrentProjectRevision( + invoke, + trimmedProjectPath, + ), + creationType: null, + startMode: + runtimeMode?.activeRuntime === 'design' ? 'planning' : null, + initialPrompt: homeDraftPromptText(), + attachments: [], + recentRunStatus: directoryStatus.recentRunStatus, + recentRunStopReason: directoryStatus.recentRunStopReason, + createdAt: Date.now(), + }, + undefined, + analytics, + ); } catch (error) { setStatus(error instanceof Error ? error.message : String(error)); } finally { @@ -704,6 +782,7 @@ export function useHomeProjectCreation({ if (!invoke) { throw new Error('需要在 Tauri App 内运行'); } + const analytics = beginProjectOpenAnalytics(invoke, 'create'); const selectedPath = await invoke( 'pick_local_project_directory', projectPath.trim() ? { initialPath: projectPath.trim() } : undefined, @@ -717,6 +796,8 @@ export function useHomeProjectCreation({ draft.prompt, draft.attachments, startMode, + false, + analytics, ); } @@ -748,6 +829,7 @@ export function useHomeProjectCreation({ if (!invoke) { throw new Error('需要在陶泥儿客户端内运行'); } + const analytics = beginProjectOpenAnalytics(invoke, 'create'); const attempt = (homeCreationAttemptRef.current += 1); const isCurrentAttempt = () => homeCreationAttemptRef.current === attempt; const operation = createClientOperation( @@ -849,6 +931,7 @@ export function useHomeProjectCreation({ draft.prompt, draft.attachments, startMode, + analytics, ); setHomeCreationOperation( transitionClientOperation(operation, 'success', { @@ -910,6 +993,7 @@ export function useHomeProjectCreation({ } projectActionRef.current = 'opening'; setProjectAction('opening'); + const analytics = beginProjectOpenAnalytics(invoke, 'picker'); setStatus('正在选择项目'); try { const selectedPath = await invoke( @@ -923,7 +1007,7 @@ export function useHomeProjectCreation({ setProjectPath(selectedPath); projectActionRef.current = null; setProjectAction(null); - await openProject(selectedPath, 'open'); + await openProject(selectedPath, 'open', analytics); } catch (error) { setStatus(error instanceof Error ? error.message : String(error)); } finally { @@ -945,6 +1029,7 @@ export function useHomeProjectCreation({ } projectActionRef.current = 'creating'; setProjectAction('creating'); + const analytics = beginProjectOpenAnalytics(invoke, 'create'); setStatus('正在选择新项目文件夹'); try { const selectedPath = await invoke( @@ -962,6 +1047,7 @@ export function useHomeProjectCreation({ selectedPath, false, homeDraftPromptText(), + analytics, ); } catch (error) { setStatus(error instanceof Error ? error.message : String(error)); @@ -999,6 +1085,7 @@ export function useHomeProjectCreation({ } return { + leaveProjectAnalytics, projectPath, setProjectPath, currentProjectContext, diff --git a/apps/ai-game-creator-shell/src/features/template-library/useTemplateLibrary.ts b/apps/ai-game-creator-shell/src/features/template-library/useTemplateLibrary.ts index f2f835f09..2d38e27f9 100644 --- a/apps/ai-game-creator-shell/src/features/template-library/useTemplateLibrary.ts +++ b/apps/ai-game-creator-shell/src/features/template-library/useTemplateLibrary.ts @@ -10,6 +10,10 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { resolveTauriInvoke } from '../../app/tauri'; import type { InitLocalProjectResult } from '../../app/types'; +import { + beginProjectOpenAnalytics, + type ProjectOpenAnalytics, +} from '../../services/clientAnalytics'; import { currentPlatformSessionGeneration, subscribePlatformSessionGeneration, @@ -38,6 +42,7 @@ type UseTemplateLibraryOptions = { onProjectCreated: ( result: InitLocalProjectResult, isCurrent: () => boolean, + analytics: ProjectOpenAnalytics, ) => Promise | void; }; @@ -247,6 +252,7 @@ export function useTemplateLibrary({ if (!invoke) { throw new Error('需要在陶泥儿客户端内运行'); } + const analytics = beginProjectOpenAnalytics(invoke, 'create'); try { if (needsTemplateDownload(template)) { await downloadTemplate(template); @@ -268,7 +274,7 @@ export function useTemplateLibrary({ }, ); if (!isCurrent()) throw new Error('登录态已变化,模板操作已停止'); - await onProjectCreated(result, isCurrent); + await onProjectCreated(result, isCurrent, analytics); if (isCurrent()) setNotice(`已用模板「${template.title}」创建项目`); return result; } catch (nextError) { diff --git a/apps/ai-game-creator-shell/src/services/clientAnalytics.ts b/apps/ai-game-creator-shell/src/services/clientAnalytics.ts new file mode 100644 index 000000000..7e5c928c6 --- /dev/null +++ b/apps/ai-game-creator-shell/src/services/clientAnalytics.ts @@ -0,0 +1,134 @@ +import type { TauriInvoke } from '../app/types'; + +// 一个 run 可因自动认证刷新调用多次 native,只确认最后一次尝试。 +export function beginDirectRunAnalytics( + invoke: TauriInvoke, + currentGeneration: () => number, +) { + const generation = currentGeneration(); + let attemptId: string | undefined; + let settled = false; + return { + nextAttempt() { + attemptId = undefined; + try { + attemptId = crypto.randomUUID(); + } catch { + // 最后一次 UUID 失败不能留下前一次失败候选的标识。 + } + return attemptId; + }, + settle() { + if (settled) return; + settled = true; + if (!attemptId) return; + try { + void invoke('settle_direct_run_analytics', { + attemptId, + discard: currentGeneration() !== generation, + }).catch(() => undefined); + } catch { + // 不等待埋点,不改变调用链的成功、失败和取消结果。 + } + }, + }; +} + +// 宿主签发的无凭据上下文:前端只传回原值,不从当前登录态补身份。 +type AnalyticsContext = { + route: { user_id: string | null; destination_origin: string | null }; + editor_session_id: string; + client_version: string; +}; + +export type ProjectOpenAnalytics = ReturnType; + +export function beginProjectOpenAnalytics( + invoke: TauriInvoke, + openSource: 'create' | 'picker' | 'recent', +) { + try { + const operationId = crypto.randomUUID(); + const context = invoke( + 'capture_analytics_context', + ).catch(() => null); + let recorded = false; + return { + record(projectPath: string) { + if (recorded) return; + recorded = true; + const eventTime = new Date().toISOString(); + void context + .then((captured) => { + if (!captured) return; + return invoke('record_analytics_project_open', { + context: captured, + projectPath, + operationId, + openSource, + eventTime, + }); + }) + .catch(() => undefined); + }, + }; + } catch { + // UUID、桥接与写入失败都不能改变业务操作结果。 + return null; + } +} + +export function recordAnalyticsProjectLeave( + invoke: TauriInvoke, + projectPath: string, +) { + try { + void invoke('record_analytics_project_leave', { projectPath }).catch( + () => undefined, + ); + } catch { + // 离开项目不能等待或依赖埋点。 + } +} + +// 保存开始冻结身份,完成时冻结时间;观察器不能影响保存结果。 +export function beginUiSaveAnalytics( + invoke: TauriInvoke, + projectPath: string, + saveSource: 'manual' | 'auto', +) { + try { + const operationId = crypto.randomUUID(); + const context = invoke( + 'capture_analytics_context', + ).catch(() => null); + let recorded = false; + return { + record(changed: boolean) { + if (recorded) return; + recorded = true; + if (saveSource === 'auto' && !changed) return; + try { + const eventTime = new Date().toISOString(); + void context + .then((captured) => { + if (!captured) return; + return invoke('record_analytics_ui_save', { + context: captured, + projectPath, + operationId, + saveSource, + changed, + eventTime, + }); + }) + .catch(() => undefined); + } catch { + // 时间或桥接失败仅丢弃本条埋点。 + } + }, + }; + } catch { + return null; + } +} diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/components/AgentReasoning/AgentReasoning.tsx b/apps/ai-game-creator-shell/src/view/project-development/chat/components/AgentReasoning/AgentReasoning.tsx index f2d836663..c3d7da397 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/components/AgentReasoning/AgentReasoning.tsx +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/components/AgentReasoning/AgentReasoning.tsx @@ -1,5 +1,5 @@ import { ChevronDown, Lightbulb } from 'lucide-react'; -import { useState } from 'react'; +import { memo, useMemo, useState } from 'react'; import { AgentMessageContent } from '../../../../../../../../packages/shared/src/components/AgentMessageContent'; import { AgentProcessSummary } from '../../../../../../../../packages/shared/src/components/AgentProcessSummary'; @@ -12,7 +12,9 @@ import { agentProcessPreview } from '../../../../../features/project-workspace/a * 折叠态是单行纯文本预览(Markdown 只取可见文字,符号不进预览);展开态复用助手正文的 * 安全 Markdown 链路。这里只有表现与展开态,思考内容本身由两条产品路径各自的事实源提供。 */ -export function AgentReasoning({ +export const AgentReasoning = memo(AgentReasoningImpl); + +function AgentReasoningImpl({ text, label = '思考过程', testId, @@ -22,7 +24,12 @@ export function AgentReasoning({ testId?: string; }) { const [expanded, setExpanded] = useState(false); - const preview = agentProcessPreview(text); + /* + 折叠态那一行预览是**完整 Markdown AST 解析**(`remark-parse` + `unified`),和展开态 + `react-markdown` 那次解析是两笔开销;上面那层 `memo` 让内容没变的思考块整个跳过, + 这里的 `useMemo` 再兜一层,避免同一文本在真正重渲染时被重算。 + */ + const preview = useMemo(() => agentProcessPreview(text), [text]); return ( - invoke('chat_with_game_creator_direct_codex', { - projectPath: nextProjectPath, - clientTurnId: input.clientTurnId, - userItem: input.userItem, - ...(input.creationType ? { creationType: input.creationType } : {}), - }), + const runAnalytics = beginDirectRunAnalytics( + invoke, + currentPlatformSessionGeneration, ); + try { + await withDirectCodexSessionRefresh(() => + invoke('chat_with_game_creator_direct_codex', { + projectPath: nextProjectPath, + clientTurnId: input.clientTurnId, + userItem: input.userItem, + analyticsAttemptId: runAnalytics.nextAttempt(), + ...(input.creationType ? { creationType: input.creationType } : {}), + }), + ); + } finally { + runAnalytics.settle(); + } // 清单刷新统一交给 startTurn 的 finally:成功与报错路径都覆盖,且只读一次。 } catch (error) { if ( diff --git a/apps/ai-game-creator-shell/src/view/ui-editor/useUiEditorPage.ts b/apps/ai-game-creator-shell/src/view/ui-editor/useUiEditorPage.ts index 2d2ccd165..6a2d84664 100644 --- a/apps/ai-game-creator-shell/src/view/ui-editor/useUiEditorPage.ts +++ b/apps/ai-game-creator-shell/src/view/ui-editor/useUiEditorPage.ts @@ -50,6 +50,7 @@ import { type NodeTransformOptions, useUiEditorState, } from '../../features/ui-editor/useUiEditorState'; +import { beginUiSaveAnalytics } from '../../services/clientAnalytics'; import { cancelLocalProjectResourcePreviewScope, createProjectResourcePreviewRequestId, @@ -1216,7 +1217,7 @@ export function useUiEditorSession( if (separationResult === null) throw new Error('自动切分素材没有返回结果'); const completedResult = separationResult as SeparationDTO; - if (!(await save({ allowDuringSeparation: true }))) { + if (!(await save({ allowDuringSeparation: true, saveSource: 'auto' }))) { throw new Error( '自动切分素材结果已写入编辑器,但 State 保存失败;sidecar 已保留,可继续恢复。', ); @@ -1375,7 +1376,10 @@ export function useUiEditorSession( } } - async function save(options?: { allowDuringSeparation?: boolean }) { + async function save(options?: { + allowDuringSeparation?: boolean; + saveSource?: 'manual' | 'auto'; + }) { const allowDuringSeparation = options?.allowDuringSeparation === true; if ( !resourceId || @@ -1389,6 +1393,11 @@ export function useUiEditorSession( ) { return false; } + const analytics = beginUiSaveAnalytics( + invoke, + projectPath, + options?.saveSource ?? 'manual', + ); setSaveError(null); setGenerateError(null); setIsSaving(true); @@ -1406,6 +1415,7 @@ export function useUiEditorSession( } setPersistedRevision(result.revision); setSavedStateSignature(snapshotSignature); + analytics?.record(result.status === 'saved'); return true; }); } catch { @@ -1457,6 +1467,7 @@ export function useUiEditorSession( ) { return null; } + const analytics = beginUiSaveAnalytics(invoke, projectPath, 'manual'); setSaveError(null); setGenerateError(null); setIsSaving(true); @@ -1475,7 +1486,9 @@ export function useUiEditorSession( } setPersistedRevision(saved.revision); setSavedStateSignature(snapshotSignature); - return await stateStore.generateCode(resourceId); + const generated = await stateStore.generateCode(resourceId); + analytics?.record(saved.status === 'saved'); + return generated; }); } catch (cause) { setGenerateError(cause instanceof Error ? cause.message : String(cause)); diff --git a/apps/ai-game-creator-shell/tests/appSurface/chat-composer.suite.ts b/apps/ai-game-creator-shell/tests/appSurface/chat-composer.suite.ts index 8d4889fa6..205bd0fca 100644 --- a/apps/ai-game-creator-shell/tests/appSurface/chat-composer.suite.ts +++ b/apps/ai-game-creator-shell/tests/appSurface/chat-composer.suite.ts @@ -1,4 +1,5 @@ import { directCodexUserItemFromContent } from '../../src/features/project-workspace/resourceReferences'; +import * as platformSession from '../../src/services/platformSession'; import { chatQueueFullNotice, createQueuedChatTurn, @@ -31,6 +32,7 @@ import { renderLauncherProjectsAt, screen, setComposerText, + testAuthUser, vi, waitFor, within, @@ -395,6 +397,55 @@ export function registerChatComposerControlTests() { expect(speechRecognitionErrorMessage('no-speech')).toContain('重试'); }); + it('settles only the final analytics attempt after a DirectProject authentication retry', async () => { + const { invoke, surface } = await openDirectCodexSurface({ + chat_with_game_creator_direct_codex: (() => { + let attempts = 0; + return () => { + if (++attempts === 1) throw new Error('authentication-required'); + return '完成'; + }; + })(), + }); + const refresh = vi + .spyOn(platformSession, 'requestPlatformSessionRefresh') + .mockResolvedValue({ + status: 'refreshed', + user: testAuthUser, + generation: platformSession.currentPlatformSessionGeneration(), + }); + try { + const composer = within(surface).getByLabelText('陶泥儿对话内容'); + await submitDirectTurn(surface, composer, '继续制作'); + await waitFor(() => { + expect( + invoke.mock.calls.filter( + ([command]) => command === 'settle_direct_run_analytics', + ), + ).toHaveLength(1); + }); + const attempts = invoke.mock.calls + .filter( + ([command]) => command === 'chat_with_game_creator_direct_codex', + ) + .map(([, args]) => args); + expect(attempts).toHaveLength(2); + expect(attempts[0]?.clientTurnId).toBe(attempts[1]?.clientTurnId); + expect(attempts[0]?.analyticsAttemptId).toEqual(expect.any(String)); + expect(attempts[1]?.analyticsAttemptId).toEqual(expect.any(String)); + expect(attempts[0]?.analyticsAttemptId).not.toBe( + attempts[1]?.analyticsAttemptId, + ); + expect(invoke).toHaveBeenCalledWith('settle_direct_run_analytics', { + attemptId: attempts[1]?.analyticsAttemptId, + discard: false, + }); + expect(refresh).toHaveBeenCalledTimes(1); + } finally { + refresh.mockRestore(); + } + }); + it('queues messages sent while a turn runs, cancels one chip, and sends the rest in order', async () => { const pending: Array<{ resolve: (value: string) => void; diff --git a/apps/ai-game-creator-shell/tests/appSurface/home.suite.ts b/apps/ai-game-creator-shell/tests/appSurface/home.suite.ts index 339508627..e4607c0d0 100644 --- a/apps/ai-game-creator-shell/tests/appSurface/home.suite.ts +++ b/apps/ai-game-creator-shell/tests/appSurface/home.suite.ts @@ -1461,6 +1461,7 @@ export function registerHomeProjectCreationTests() { projectPath: automaticProjectPath, creationType: 'game', clientTurnId: expect.any(String), + analyticsAttemptId: expect.any(String), userItem: { id: expect.stringMatching(/^direct-codex:[A-Za-z0-9-]+:user$/), type: 'message', @@ -1583,6 +1584,7 @@ export function registerHomeProjectCreationTests() { projectPath: automaticProjectPath, creationType: 'game', clientTurnId: expect.any(String), + analyticsAttemptId: expect.any(String), userItem: { id: expect.stringMatching(/^direct-codex:[A-Za-z0-9-]+:user$/), type: 'message', @@ -1622,6 +1624,7 @@ export function registerHomeProjectCreationTests() { expect(invoke).toHaveBeenCalledWith('chat_with_game_creator_direct_codex', { projectPath: automaticProjectPath, clientTurnId: expect.any(String), + analyticsAttemptId: expect.any(String), userItem: { id: expect.stringMatching(/^direct-codex:[A-Za-z0-9-]+:user$/), type: 'message', @@ -2374,6 +2377,7 @@ export function registerHomeProjectCreationTests() { { projectPath, clientTurnId: expect.any(String), + analyticsAttemptId: expect.any(String), userItem: { id: expect.stringMatching(/^direct-codex:[A-Za-z0-9-]+:user$/), type: 'message', @@ -2428,6 +2432,7 @@ export function registerHomeProjectCreationTests() { expect(args).toEqual({ projectPath, clientTurnId: expect.any(String), + analyticsAttemptId: expect.any(String), userItem: { id: `direct-codex:${clientTurnId}:user`, type: 'message', diff --git a/apps/ai-game-creator-shell/tests/clientAnalytics.test.tsx b/apps/ai-game-creator-shell/tests/clientAnalytics.test.tsx new file mode 100644 index 000000000..043f7ec8d --- /dev/null +++ b/apps/ai-game-creator-shell/tests/clientAnalytics.test.tsx @@ -0,0 +1,332 @@ +// @vitest-environment jsdom +import { act, cleanup, renderHook } from '@testing-library/react'; +import { StrictMode } from 'react'; +import { afterEach, expect, it, vi } from 'vitest'; + +import { createGameCreationAppManifest } from '../../../packages/shared/src/contracts/gameCreationApp'; +import type { TauriInvoke } from '../src/app/types'; +import { useHomeProjectCreation } from '../src/features/app-shell/useHomeProjectCreation'; +import { + beginProjectOpenAnalytics, + beginUiSaveAnalytics, +} from '../src/services/clientAnalytics'; + +const context = { + route: { user_id: 'user-a', destination_origin: 'https://a.example' }, + editor_session_id: 'session-a', + client_version: '1', +}; +function deferred() { + let resolve!: (value: T) => void; + return { + promise: new Promise((done) => { + resolve = done; + }), + resolve: (value: T) => resolve(value), + }; +} +afterEach(() => { + cleanup(); + delete window.__TAURI__; + vi.restoreAllMocks(); +}); + +function mount( + capture: () => Promise = async () => context, + preview: (path: string) => Promise = async () => null, +) { + vi.spyOn(crypto, 'randomUUID').mockReturnValue( + '12345678-1234-4234-8234-123456789012', + ); + const manifest = createGameCreationAppManifest('project', '项目'); + const invoke = vi.fn( + async (command: string, args?: Record) => { + if (command === 'capture_analytics_context') return capture(); + if (command === 'get_local_game_preview_status') + return preview(String(args?.projectPath)); + if (command === 'inspect_local_project_directory') + return { exists: true, isDirectory: true, isGameCreatorProject: true }; + if (command === 'get_local_game_manifest') return manifest; + if (command === 'pick_local_project_directory') return 'C:/picker'; + if (command === 'init_local_game_project') + return { projectPath: args?.projectPath, manifest }; + if (command === 'get_local_game_project_revision') return { revision: 1 }; + return null; + }, + ); + window.__TAURI__ = { core: { invoke } } as unknown as typeof window.__TAURI__; + const hook = renderHook( + () => + useHomeProjectCreation({ + setStatus: vi.fn(), + setLauncherView: vi.fn(), + rememberRecentWorkspace: vi.fn(), + }), + { wrapper: StrictMode }, + ); + return { + ...hook, + invoke, + manifest, + records: () => + invoke.mock.calls.filter( + ([command]) => command === 'record_analytics_project_open', + ), + }; +} + +it.each(['recent', 'picker', 'create'] as const)( + '成功进入项目记录真实 %s 来源', + async (source) => { + const { result, records } = mount(); + await act(async () => { + if (source === 'picker') await result.current.pickAndOpenProject(); + else + await result.current.openProject( + 'C:/project', + source === 'create' ? 'create' : 'open', + ); + }); + expect(records()).toHaveLength(1); + expect(records()[0][1]).toMatchObject({ context, openSource: source }); + }, +); + +it('身份抓取挂起不阻塞打开,成功时间在抓取完成前冻结', async () => { + const captured = deferred(); + const { result, records } = mount(() => captured.promise); + await act(async () => { + await result.current.openProject('C:/project', 'open'); + }); + expect(result.current.currentProjectContext?.projectPath).toBe('C:/project'); + const latestSuccessTime = Date.now(); + expect(records()).toHaveLength(0); + await act(async () => { + captured.resolve(context); + }); + expect(records()).toHaveLength(1); + expect(Date.parse(String(records()[0][1]?.eventTime))).toBeLessThanOrEqual( + latestSuccessTime, + ); +}); + +it('预览核验挂起时卸载,不记录从未进入的工作区', async () => { + const preview = deferred(); + const { result, unmount, records, invoke } = mount( + undefined, + () => preview.promise, + ); + let pending!: Promise; + await act(async () => { + pending = result.current.openProject('C:/old', 'open'); + }); + unmount(); + await act(async () => { + preview.resolve(null); + await pending; + }); + expect(records()).toHaveLength(0); + expect( + invoke.mock.calls.filter( + ([command]) => command === 'record_analytics_project_leave', + ), + ).toHaveLength(0); +}); + +it('StrictMode 重放不产生离开,真正卸载清除已进入的项目', async () => { + const { result, unmount, invoke } = mount(); + await act(async () => { + await result.current.openProject('C:/project', 'open'); + }); + const leaves = () => + invoke.mock.calls.filter( + ([command]) => command === 'record_analytics_project_leave', + ); + expect(leaves()).toHaveLength(0); + unmount(); + await act(async () => {}); + expect(leaves()).toEqual([ + ['record_analytics_project_leave', { projectPath: 'C:/project' }], + ]); +}); + +it('页面关闭通知尽力清理,随后卸载不会重复通知', async () => { + const { result, unmount, invoke } = mount(); + await act(async () => { + await result.current.openProject('C:/project', 'open'); + }); + window.dispatchEvent(new Event('pagehide')); + unmount(); + await act(async () => {}); + expect( + invoke.mock.calls.filter( + ([command]) => command === 'record_analytics_project_leave', + ), + ).toHaveLength(1); +}); + +it('同项目再次显式打开是新操作,重渲染不会产生额外打开', async () => { + const { result, rerender, records } = mount(); + vi.mocked(crypto.randomUUID) + .mockReturnValueOnce('12345678-1234-4234-8234-123456789011') + .mockReturnValueOnce('12345678-1234-4234-8234-123456789012'); + await act(async () => { + await result.current.openProject('C:/project', 'open'); + }); + rerender(); + expect(records()).toHaveLength(1); + await act(async () => { + await result.current.openProject('C:/project', 'open'); + }); + expect(records()).toHaveLength(2); + expect(records()[0][1]?.operationId).not.toBe(records()[1][1]?.operationId); +}); + +it('身份抓取和记录写入失败静默,不改变成功打开', async () => { + const { result, records, invoke } = mount(async () => { + throw new Error('offline'); + }); + await act(async () => { + await result.current.openProject('C:/project', 'open'); + }); + expect(result.current.currentProjectContext?.projectPath).toBe('C:/project'); + expect(records()).toHaveLength(0); + const failing = vi.fn(async (command: string) => { + if (command === 'capture_analytics_context') return context; + throw new Error('write'); + }); + beginProjectOpenAnalytics(failing as TauriInvoke, 'recent')?.record( + 'C:/project', + ); + await act(async () => {}); + expect(failing).toHaveBeenCalledWith( + 'record_analytics_project_open', + expect.anything(), + ); + expect(invoke).toHaveBeenCalledWith('capture_analytics_context'); +}); + +it('较晚的导航获采纳,旧预览核验迟到不记录打开', async () => { + const oldPreview = deferred(); + const { result, invoke, manifest, records } = mount( + undefined, + async (path) => (path === 'C:/old' ? oldPreview.promise : null), + ); + let old!: Promise; + await act(async () => { + old = result.current.enterCreatedTemplateProject( + { projectPath: 'C:/old', manifestPath: '', manifest }, + () => true, + beginProjectOpenAnalytics(invoke as TauriInvoke, 'create'), + ); + }); + await act(async () => { + await result.current.enterCreatedTemplateProject( + { projectPath: 'C:/new', manifestPath: '', manifest }, + () => true, + beginProjectOpenAnalytics(invoke as TauriInvoke, 'create'), + ); + oldPreview.resolve(null); + await old; + }); + expect(result.current.currentProjectContext?.projectPath).toBe('C:/new'); + expect(records().map(([, args]) => args?.projectPath)).toEqual(['C:/new']); +}); + +it('模板权限失效后不记录被舍弃的导航,同次成功通知只记一次', async () => { + const pending = deferred(); + const { result, invoke, manifest, records } = mount( + undefined, + () => pending.promise, + ); + let current = true; + let entry!: Promise; + const action = beginProjectOpenAnalytics(invoke as TauriInvoke, 'create'); + await act(async () => { + entry = result.current.enterCreatedTemplateProject( + { projectPath: 'C:/old', manifestPath: '', manifest }, + () => current, + action, + ); + }); + await act(async () => { + current = false; + pending.resolve(null); + await entry; + }); + expect(records()).toHaveLength(0); + action?.record('C:/accepted'); + action?.record('C:/accepted'); + await act(async () => {}); + expect(records()).toHaveLength(1); +}); + +it('freezes UI save identity and completion time while context delivery is delayed', async () => { + const captured = deferred(); + const invoke = vi.fn(async (command: string) => + command === 'capture_analytics_context' ? captured.promise : undefined, + ); + const now = vi + .spyOn(Date.prototype, 'toISOString') + .mockReturnValue('2026-09-21T01:00:00.000Z'); + const analytics = beginUiSaveAnalytics( + invoke as TauriInvoke, + 'C:/project', + 'manual', + ); + analytics?.record(false); + now.mockReturnValue('2026-09-21T02:00:00.000Z'); + analytics?.record(true); + captured.resolve(context); + await act(async () => { + await captured.promise; + }); + const calls = invoke.mock.calls.filter( + ([command]) => command === 'record_analytics_ui_save', + ); + expect(calls).toHaveLength(1); + expect(invoke).toHaveBeenCalledWith( + 'record_analytics_ui_save', + expect.objectContaining({ + context, + changed: false, + eventTime: '2026-09-21T01:00:00.000Z', + }), + ); +}); + +it('isolates UI save analytics UUID and sync/async bridge failures', async () => { + const throwing = vi.fn(() => { + throw new Error('bridge unavailable'); + }); + expect(() => + beginUiSaveAnalytics( + throwing as TauriInvoke, + 'C:/project', + 'manual', + )?.record(true), + ).not.toThrow(); + const rejected = vi.fn().mockRejectedValue(new Error('bridge rejected')); + beginUiSaveAnalytics(rejected as TauriInvoke, 'C:/project', 'manual')?.record( + true, + ); + const recordFailure = vi.fn((command: string) => { + if (command === 'capture_analytics_context') + return Promise.resolve(context); + throw new Error('record failed'); + }); + beginUiSaveAnalytics( + recordFailure as TauriInvoke, + 'C:/project', + 'manual', + )?.record(true); + vi.spyOn(crypto, 'randomUUID').mockImplementation(() => { + throw new Error('no UUID'); + }); + expect( + beginUiSaveAnalytics(rejected as TauriInvoke, 'C:/project', 'manual'), + ).toBeNull(); + await act(async () => { + await Promise.resolve(); + }); +}); diff --git a/apps/ai-game-creator-shell/tests/directRunAnalytics.test.ts b/apps/ai-game-creator-shell/tests/directRunAnalytics.test.ts new file mode 100644 index 000000000..245e2ebe8 --- /dev/null +++ b/apps/ai-game-creator-shell/tests/directRunAnalytics.test.ts @@ -0,0 +1,91 @@ +// @vitest-environment jsdom +import { afterEach, expect, it, vi } from 'vitest'; + +import type { TauriInvoke } from '../src/app/types'; +import { beginDirectRunAnalytics } from '../src/services/clientAnalytics'; + +afterEach(() => vi.restoreAllMocks()); + +it('自动重试保持业务回合,只确认最后一次尝试且确认不等待桥接', async () => { + const first = '11111111-1111-4111-8111-111111111111'; + const last = '22222222-2222-4222-8222-222222222222'; + vi.spyOn(crypto, 'randomUUID') + .mockReturnValueOnce(first) + .mockReturnValueOnce(last); + const invoke = vi.fn(() => new Promise(() => {})); + const analytics = beginDirectRunAnalytics(invoke as TauriInvoke, () => 1); + const attempts: string[] = []; + const operation = async () => { + attempts.push(analytics.nextAttempt()!); + if (attempts.length === 1) throw new Error('authentication-required'); + return '完成'; + }; + let result: string; + try { + result = await operation().catch(() => operation()); + expect(invoke).not.toHaveBeenCalled(); + } finally { + analytics.settle(); + } + expect(result).toBe('完成'); + expect(attempts).toEqual([first, last]); + expect(invoke).toHaveBeenCalledTimes(1); + expect(invoke).toHaveBeenCalledWith('settle_direct_run_analytics', { + attemptId: last, + discard: false, + }); + analytics.settle(); + expect(invoke).toHaveBeenCalledTimes(1); +}); + +it('最终 UUID 失败不能回退确认第一次失败', () => { + vi.spyOn(crypto, 'randomUUID') + .mockReturnValueOnce('11111111-1111-4111-8111-111111111111') + .mockImplementationOnce(() => { + throw new Error('UUID unavailable'); + }); + const invoke = vi.fn(); + const analytics = beginDirectRunAnalytics(invoke as TauriInvoke, () => 1); + expect(analytics.nextAttempt()).toBeDefined(); + expect(analytics.nextAttempt()).toBeUndefined(); + analytics.settle(); + expect(invoke).not.toHaveBeenCalled(); +}); + +it('账号代次变化只丢弃候选,不提交成功失败结论', () => { + let generation = 1; + const invoke = vi.fn(async () => undefined); + const analytics = beginDirectRunAnalytics( + invoke as TauriInvoke, + () => generation, + ); + const attemptId = analytics.nextAttempt(); + generation = 2; + analytics.settle(); + expect(invoke).toHaveBeenCalledWith('settle_direct_run_analytics', { + attemptId, + discard: true, + }); +}); + +it.each(['sync', 'async'])( + '确认桥接 %s 失败不会覆盖最终业务错误', + async (mode) => { + const invoke = vi.fn(() => { + if (mode === 'sync') throw new Error('bridge'); + return Promise.reject(new Error('bridge')); + }); + const analytics = beginDirectRunAnalytics(invoke as TauriInvoke, () => 1); + const failure = new Error('最终执行失败'); + const operation = async () => { + try { + analytics.nextAttempt(); + throw failure; + } finally { + analytics.settle(); + } + }; + await expect(operation()).rejects.toBe(failure); + expect(invoke).toHaveBeenCalledTimes(1); + }, +); diff --git a/apps/ai-game-creator-shell/tests/homeWebPreflight.test.tsx b/apps/ai-game-creator-shell/tests/homeWebPreflight.test.tsx index 44b64ae0a..1bee3d950 100644 --- a/apps/ai-game-creator-shell/tests/homeWebPreflight.test.tsx +++ b/apps/ai-game-creator-shell/tests/homeWebPreflight.test.tsx @@ -14,7 +14,7 @@ afterEach(() => { function mount(preflight: () => Promise) { const calls: string[] = []; const invoke = vi.fn(async (command: string) => { - calls.push(command); + if (command !== 'capture_analytics_context') calls.push(command); if (command === 'preflight_web_game_creation') return preflight(); if (command === 'suggest_automatic_project_name') return '预检项目'; if (command === 'create_automatic_local_game_project') diff --git a/apps/ai-game-creator-shell/tests/runVersionSwitchEventSubscription.test.tsx b/apps/ai-game-creator-shell/tests/runVersionSwitchEventSubscription.test.tsx index 866a2b039..bd748bc1c 100644 --- a/apps/ai-game-creator-shell/tests/runVersionSwitchEventSubscription.test.tsx +++ b/apps/ai-game-creator-shell/tests/runVersionSwitchEventSubscription.test.tsx @@ -142,6 +142,7 @@ describe('运行模块切换版本时的事件订阅', () => { await waitFor(() => expect(invoke).toHaveBeenCalledWith('start_local_game_preview', { projectPath: PROJECT_PATH, + previewSource: 'user', }), ); await openRunModuleAndPickVersion(/智能体修订/); diff --git a/apps/ai-game-creator-shell/tests/sessionPreview.test.ts b/apps/ai-game-creator-shell/tests/sessionPreview.test.ts index 872fb48d1..90f8e6750 100644 --- a/apps/ai-game-creator-shell/tests/sessionPreview.test.ts +++ b/apps/ai-game-creator-shell/tests/sessionPreview.test.ts @@ -195,7 +195,7 @@ describe('本地预览记录的生命周期(Rust 侧结构性守卫)', () => // record_replaced_preview_stop 只允许在旧预览属于别的项目时调用:同项目重启时它会把 // 刚写进去的 running 覆盖成 stopped。 const replaceBranch = - /let \(preview, previous_preview\) = registry\.set_running\(preview, stop\);([\s\S]*?)\n {4}\}/u.exec( + /let \(preview, previous_preview\) =\s*registry\.set_running_with_lease\(preview, stop, analytics_lease\);([\s\S]*?)\n {4}\}/u.exec( previewSource, )?.[1] ?? ''; expect(replaceBranch).toContain('ensure_preview_belongs_to_project'); diff --git a/apps/ai-game-creator-shell/tests/uiEditorPage.test.ts b/apps/ai-game-creator-shell/tests/uiEditorPage.test.ts index d631c5051..503d02003 100644 --- a/apps/ai-game-creator-shell/tests/uiEditorPage.test.ts +++ b/apps/ai-game-creator-shell/tests/uiEditorPage.test.ts @@ -747,4 +747,129 @@ describe('UiEditorPage', () => { '资源已在别处更新;请重新加载后再保存。', ); }); + it.each([ + ['manual', 'saved', 1], + ['manual', 'unchanged', 1], + ['auto', 'saved', 1], + ['auto', 'unchanged', 0], + ['manual', 'conflict', 0], + ['manual', 'failure', 0], + ] as const)( + 'records the real %s save outcome %s', + async (saveSource, status, count) => { + vi.mocked(invoke).mockImplementation(async (command) => + command === 'capture_analytics_context' + ? { + route: { + user_id: 'A', + destination_origin: 'https://example.com', + }, + editor_session_id: 'session', + client_version: '1', + } + : undefined, + ); + const stateStore: IUiDesignStateStore = { + load: vi.fn().mockResolvedValue(structuredClone(EMPTY_SNAPSHOT)), + save: + status === 'failure' + ? vi.fn().mockRejectedValue(new Error('write failed')) + : vi.fn().mockResolvedValue({ + status, + revision: 1, + state: EMPTY_SNAPSHOT.state, + committedProjectRevision: 3, + }), + generateCode: vi.fn(), + }; + const hook = renderHook(() => + useUiEditorSession('/tmp/ui-editor', 'ui-resource', stateStore), + ); + await waitFor(() => + expect(hook.result.current.save.isLoading).toBe(false), + ); + await act(async () => { + await hook.result.current.save.save({ saveSource }); + }); + const calls = vi + .mocked(invoke) + .mock.calls.filter( + ([command]) => command === 'record_analytics_ui_save', + ); + expect(calls).toHaveLength(count); + if (count) + expect(calls[0][1]).toMatchObject({ + projectPath: '/tmp/ui-editor', + saveSource, + changed: status === 'saved', + }); + }, + ); + + it.each([true, false])( + 'records combined save only after successful code generation: %s', + async (success) => { + vi.mocked(invoke).mockImplementation(async (command) => + command === 'capture_analytics_context' + ? { + route: { user_id: 'A', destination_origin: null }, + editor_session_id: 'session', + client_version: '1', + } + : undefined, + ); + let complete!: () => void; + const generation = new Promise((resolve) => { + complete = resolve; + }); + const stateStore: IUiDesignStateStore = { + load: vi.fn().mockResolvedValue(structuredClone(EMPTY_SNAPSHOT)), + save: vi.fn().mockResolvedValue({ + status: 'saved', + revision: 1, + state: EMPTY_SNAPSHOT.state, + committedProjectRevision: 3, + }), + generateCode: vi.fn(async () => { + await generation; + if (!success) throw new Error('generation failed'); + return { + relativePath: 'ui/generated.js', + treeExports: [], + treeCount: 0, + nodeCount: 0, + }; + }), + }; + const hook = renderHook(() => + useUiEditorSession('/tmp/ui-editor', 'ui-resource', stateStore), + ); + await waitFor(() => + expect(hook.result.current.save.isLoading).toBe(false), + ); + let operation!: Promise; + await act(async () => { + operation = hook.result.current.save.saveAndGenerateCode(); + await Promise.resolve(); + }); + expect( + vi + .mocked(invoke) + .mock.calls.filter( + ([command]) => command === 'record_analytics_ui_save', + ), + ).toHaveLength(0); + await act(async () => { + complete(); + await operation; + }); + expect( + vi + .mocked(invoke) + .mock.calls.filter( + ([command]) => command === 'record_analytics_ui_save', + ), + ).toHaveLength(success ? 1 : 0); + }, + ); }); diff --git a/deploy/container/README.md b/deploy/container/README.md index e03b4dddf..7efe511d9 100644 --- a/deploy/container/README.md +++ b/deploy/container/README.md @@ -79,7 +79,22 @@ bash scripts/gitea-ci-job-image.sh export /仓库外受控路径/genarrative-git bash scripts/gitea-ci-job-image.sh load-runner ``` -默认构建 tag 为 `genarrative/gitea-project-ci:20260920.2`。脚本通过 NUL 分隔白名单 tar 流只发送 Dockerfile、checkout 脚本、根 workspace 的唯一 npm lock 与全部 workspace manifest,以及 server-rs、桌面壳和 AI 游戏创作壳的 Cargo manifests/lock,外加 AI 游戏创作壳本地路径依赖的三个编辑器 bridge crate 源树;不会把业务源码、素材或本地私密文件发送给 Docker daemon。新镜像显式安装并精确校验 `npm 10.9.7`,不依赖 Node 发行包隐含的 npm 版本;除固定工具链外,还按一份 npm workspace lock 与三份 Cargo lock 预热下载缓存。npm 只执行一次忽略 lifecycle scripts 的 workspace `npm ci`(最多 5 次整命令级有界重试,处理 registry ECONNRESET),三个 `cargo fetch --locked` 最多执行 5 次整命令级有界重试,再分别以断网 `cargo fetch --locked` 验证缓存闭合,镜像不包含 `node_modules` 或 Cargo `target`。`build` 完成后会自动运行环境校验,`load-runner` 还会比对宿主和 runner 内层的完整 Image ID,并在内层执行 bwrap 与 Chrome headless canary。workspace lock 或 manifest 变化落地后必须按下述顺序重建并装载镜像;过渡期旧固定镜像缺少 `GENARRATIVE_GITEA_CI_NPM_VERSION` 时,校验只输出 `npm_version=partial` 和 Actions warning,继续由当前 job 的根 `npm ci` 验证唯一 lock,不能据此宣称 npm 版本或新依赖缓存已经闭合。执行这些命令不要求必须使用 root,但执行账号必须有权访问宿主 Docker API 并管理 runner 容器;没有该权限时交给 runner 运维人员执行。 +默认构建 tag 为 `genarrative/gitea-project-ci:20260920.2`。脚本通过 NUL 分隔白名单 tar 流只发送 Dockerfile、构建配置与缓存导出脚本、checkout 脚本、根 workspace 的唯一 npm lock 与全部 workspace manifest,以及 server-rs、桌面壳和 AI 游戏创作壳的 Cargo manifests/lock。AGC 的 `vendor/*/Cargo.toml` 和三个编辑器 bridge crate 的 manifest 同样参与,避免漏掉本地 path 依赖;不发送业务源码、素材或本地私密文件。新镜像显式安装并精确校验 `npm 10.9.7`,不依赖 Node 发行包隐含的 npm 版本;除固定工具链外,还按一份 npm workspace lock 与三份 Cargo lock 预热下载缓存。npm 只执行一次忽略 lifecycle scripts 的 workspace `npm ci`(最多 5 次整命令级有界重试,处理 registry ECONNRESET),三个 `cargo fetch --locked` 最多执行 5 次整命令级有界重试,再分别以断网 `cargo fetch --locked` 验证缓存闭合,镜像不包含 `node_modules` 或 Cargo `target`。`build` 完成后会自动运行环境校验,`load-runner` 还会比对宿主和 runner 内层的完整 Image ID,并在内层执行 bwrap 与 Chrome headless canary。workspace lock 或 manifest 变化落地后必须按下述顺序重建并装载镜像;过渡期旧固定镜像缺少 `GENARRATIVE_GITEA_CI_NPM_VERSION` 时,校验只输出 `npm_version=partial` 和 Actions warning,继续由当前 job 的根 `npm ci` 验证唯一 lock,不能据此宣称 npm 版本或新依赖缓存已经闭合。执行这些命令不要求必须使用 root,但执行账号必须有权访问宿主 Docker API 并管理 runner 容器;没有该权限时交给 runner 运维人员执行。 + +基础镜像构建需要 Docker Buildx 插件,固定使用独立的 `genarrative-ci-images` docker-container builder(BuildKit `v0.23.2`),不改变默认 builder、Docker daemon 配置或其它构建。脚本按 `gitea-ci-buildkitd.toml` 首次创建 builder;配置的 24 GB 为 GC 空间目标、4 GB 为保留量、宿主保留 10 GB 空闲,均不是活动构建的硬磁盘配额。BuildKit 自动回收可释放的旧记录,正在使用的记录受保护;不运行全局 prune。已有 builder 的配置变更须另择空闲窗口应用,脚本不会为修改 GC 配置而重启它。 + +Cargo registry 的压缩包与索引、npm `_cacache` 使用稳定命名、`sharing=locked` 的持久 cache mount,不随 commit 或 lock 哈希更名。它们仅供受信任宿主的镜像构建使用,不挂给 PR job;未缓存的新版本仍按当前锁文件下载并校验。cache mount 本身不进入输出镜像,因此构建显式物化下载快照:Cargo 只导出本次实际解包的 crate 归档及索引;npm 按当前 lock 的 integrity 筛选已下载条目并校验内容,不把历史包版本、凭据或可写 target 一并复制。最终 CI 镜像仍提供独立的下载缓存目录,普通 job 在自身容器内使用。 + +首次启用前可从现有可信 CI 镜像导入下载缓存,避免从空缓存重新下载;后续正常构建不必重复导入。维护服务以 root 运行时,下述命令也以 root 执行,确保使用同一套 Buildx 配置。Ubuntu 发行版 Docker 的插件包名为 `docker-buildx`(Docker 官方发行源则为 `docker-buildx-plugin`);只安装匹配当前 Docker 来源的插件包,无需重启 runner。 + +```bash +sudo apt-get install docker-buildx +# Buildx 0.30.1 的 inspect 不支持 --format;脚本读取普通输出的 Driver 字段。 +# 替换为运维已验证的完整 Image ID;只提取 registry/cache、registry/index 和 npm/_cacache。 +sudo bash scripts/gitea-ci-job-image.sh seed-downloads 'sha256:<可信镜像的64位摘要>' +``` + +seed 临时目录与容器在结束时删除,既有镜像只读提取、不运行其入口;新基础镜像继续从固定工具链与 runner base 构建,不继承旧对象快照层。未执行 seed 或下载缓存被 GC 回收只影响速度,不影响正确性。升级维护器需同步安装新版 `maintain-gitea-rust-cache.py` 才会获得 journal 阶段日志;基础镜像构建脚本与 Dockerfile 来自所选 master run 的提交,不把 PR 分支代码直接用于线上维护。 runner 配置保留原 `ubuntu-latest` 映射,`genarrative-ci` 继续映射到经 `build / verify / load-runner` 验证并写入配置的完整 Image ID。内层 Docker 数据必须持久化,`force_pull` 保持 `false`;该精确 Image ID 在内层不存在时 job 应直接失败,不回退到浮动 tag 或现场拉取。各个 job 使用镜像内 `genarrative-gitea-checkout` 直接从当前 Gitea 拉取事件 commit,带 5 次有界重试,不再运行时下载 GitHub checkout action;随后以 `GENARRATIVE_GITEA_CI_CHECK_RUNTIME=1` 执行 `scripts/check-gitea-ci-job-image.sh`,同时校验工具链、一份 npm workspace 缓存锁、三份 Cargo 缓存锁、bwrap 和 Chrome headless。锁不匹配时校验会输出 `partial` 和醒目的 Actions warning,提示在可信分支落地后刷新镜像。各 job 仍各自运行一次干净的根 `npm ci`,以唯一 workspace lock 校验全部 App/package/tool 依赖并隔离 PR 依赖;统一通过 `scripts/ci-npm-ci-with-retry.sh` 最多执行 3 次整命令级有界重试,并使用镜像内 npm cache 和 `prefer-offline`。锁文件新增依赖时允许经受控网络补齐,本阶段不启用共享 Actions cache。 @@ -97,8 +112,16 @@ runner 配置保留原 `ubuntu-latest` 映射,`genarrative-ci` 继续映射到 ### Rust 测试组编译对象快照 +宿主下载每份 artifact 时核对 Gitea `size_in_bytes`、响应 `Content-Length`(若提供)和实际字节数,并在下载完成后立即检查 ZIP 格式与 CRC。截断、损坏归档或临时传输故障最多尝试 3 次,每次重新获取签名下载地址;不向签名地址转发 API Token。重试仍失败则删除临时下载并保留现役镜像,不能把 EOF 当作完整下载成功。 + +同一 sccache key 的完整对象 SHA 不同时,不直接视为编译结果不同:sccache 对象 ZIP 的成员写入顺序可能不同。仅对不同 job 新增对象之间的冲突,按成员名核对内容 SHA-256、权限及 ZIP 元数据,全部一致才保留一份原始对象并更新使用时间;真实内容差异、异常 ZIP 和继承对象冲突仍拒绝。此比较不改写缓存 key 或对象,不依赖 CRC 代替内容校验。 + 自动维护由宿主 systemd timer 调用 `scripts/maintain-gitea-rust-cache.py`,只管理 Gitea CI 测试镜像,不修改 Jenkins、生产发布、本地开发或客户端发行构建。六个 Rust job 仅在 master push 中导出本次 CI 新增的 sccache 对象;已命中的继承对象只上传新近使用时间,通过 Gitea 原生 V4 artifact 接口上传;PR 不发布。维护器选择已结束且六组产物完整的最新 master run,校验提交、任务尝试、工具链与来源镜像,与六组实际使用的同一镜像快照合并去重,并按新近使用时间限制快照总容量为 4 GiB,然后从无对象缓存基础镜像组装新镜像,**不重复执行 Cargo 预热编译,也不要求源 run 事先全绿**。缺组、取消或校验失败时保留现役版,不混合不同 run 的对象来假装完整快照。 +维护 journal 分阶段记录来源 run、基础镜像重建或复用、artifact 下载、对象合并、镜像组装校验、导出、载入及空闲等待;长操作记录开始和结束耗时,失败输出对应私有 `artifacts//build.log` 路径。构建的详细下载与 Docker 输出仍只写该日志,不回显 Token、命令环境或认证配置。 + +快照组装使用宿主 `default` Docker builder,读取已载入宿主的无对象缓存基础镜像;不能使用无法直接读取宿主镜像的独立 docker-container builder。BuildKit 的 `FROM` 不接受裸 `sha256:`,因此维护器在持锁期间将确定的基础 Image ID 绑定到专用临时 `assembly-base` tag,并在组装成功或失败后去除该 tag;来源元数据及 runner 配置仍使用完整 Image ID。临时别名不登记为受管基础镜像,不改变历史镜像的清理归属;进程被强杀时最多残留这一个别名,下次组装会重新绑定并清除。 + 切换先通过专属入口阻断新的 FetchTask,确认已转发的领取请求全部收到完整上游响应,并检查入口持久化跟踪的已领取任务全部结束、内层 Docker 没有活动容器。任务终态必须依据 Runner 的执行结束及最终上报协议,不能由容器暂时为空、API 已取消或请求超时推断。有任务即恢复领取并延后,不停止任务;状态未知拒绝切换。维护器只需普通账号的 `write:repository` Token(包括查询、下载及定向删除 artifact),不访问全局 Runner 管理 API。切换后等待使用该 Image ID 的完整真实 master push CI 通过,才允许下一次升级及旧镜像清理;不会自动重跑失败用例或为了验收额外触发整轮 CI。首次接管的历史镜像默认不归自动清理管理。 维护状态、凭据、归档和配置备份保存在仓库外。当前版、回滚版、待验证候选、它们的基础镜像及容器引用的镜像均受保护。清理只针对维护器登记的专属 tag、完整 Image ID 和专用目录中的归档;禁止全局 prune。API、构建、验证或空闲检查失败时保留现役镜像与回滚资料,不以失败重跑制造全绿结果。 diff --git a/deploy/container/api-server.env.example b/deploy/container/api-server.env.example index b4e0286b1..55f051ba0 100644 --- a/deploy/container/api-server.env.example +++ b/deploy/container/api-server.env.example @@ -5,6 +5,11 @@ GENARRATIVE_ENV=container GENARRATIVE_API_HOST=0.0.0.0 GENARRATIVE_API_PORT=8082 +# 客户端埋点接收绑定的公开 origin,由 API Server 运行时读取;修改后重启服务。 +# 必须与客户端登录地址一致,不带 /api、路径或尾部斜杠;未配置/非法时上传接口返回 503。 +# 以下为 compose 默认宿主机入口;更改映射端口或接入域名时同步修改,不填容器内部地址。 +# dev 使用 https://dev.genarrative.world;release 使用 https://www.genarrative.world。 +GENARRATIVE_AGC_ANALYTICS_ORIGIN=http://127.0.0.1:18080 GENARRATIVE_API_LOG=info,tower_http=info GENARRATIVE_API_LISTEN_BACKLOG=1024 GENARRATIVE_API_WORKER_THREADS=4 diff --git a/deploy/container/gitea-ci-buildkitd.toml b/deploy/container/gitea-ci-buildkitd.toml new file mode 100644 index 000000000..5da73da8d --- /dev/null +++ b/deploy/container/gitea-ci-buildkitd.toml @@ -0,0 +1,18 @@ +# 专用于 Gitea CI 基础镜像;不调整宿主 Docker 或其它 builder 的 GC。 +[worker.oci] + gc = true + reservedSpace = "4GB" + maxUsedSpace = "24GB" + minFreeSpace = "10GB" + + # 覆盖默认的 48 小时 / 488 MiB 临时缓存回收规则,周末后仍可命中下载包。 + [[worker.oci.gcpolicy]] + filters = ["type==exec.cachemount"] + keepDuration = "168h" + maxUsedSpace = "8GB" + + [[worker.oci.gcpolicy]] + all = true + reservedSpace = "4GB" + maxUsedSpace = "24GB" + minFreeSpace = "10GB" diff --git a/deploy/container/gitea-ci-job.Dockerfile b/deploy/container/gitea-ci-job.Dockerfile index ec94382f6..cc5433557 100644 --- a/deploy/container/gitea-ci-job.Dockerfile +++ b/deploy/container/gitea-ci-job.Dockerfile @@ -8,6 +8,16 @@ RUN rustup component add rustfmt \ && cargo --version \ && rustfmt --version +# 显式的一次性迁移入口:只导入下载缓存,不继承旧 CI 镜像层。 +FROM rust-toolchain AS download-cache-seed +RUN --mount=type=bind,from=download-seed,target=/seed \ + --mount=type=cache,id=genarrative-ci-cargo-cache-v1,target=/downloads/cargo-cache,sharing=locked \ + --mount=type=cache,id=genarrative-ci-cargo-index-v1,target=/downloads/cargo-index,sharing=locked \ + --mount=type=cache,id=genarrative-ci-npm-v1,target=/downloads/npm,sharing=locked \ + cp -a /seed/cargo-cache/. /downloads/cargo-cache/ \ + && cp -a /seed/cargo-index/. /downloads/cargo-index/ \ + && cp -a /seed/npm/. /downloads/npm/ + FROM rust-toolchain AS rust-dependency-cache ENV CARGO_HTTP_MULTIPLEXING=false \ @@ -20,7 +30,9 @@ COPY plugins/agc-cocos-editor/native/cocos-editor-bridge /tmp/genarrative-cargo- COPY plugins/agc-unity-editor/native/unity-editor-bridge /tmp/genarrative-cargo-cache/plugins/agc-unity-editor/native/unity-editor-bridge COPY plugins/agc-godot-editor/native/godot-editor-bridge /tmp/genarrative-cargo-cache/plugins/agc-godot-editor/native/godot-editor-bridge -RUN find /tmp/genarrative-cargo-cache -name Cargo.toml -exec dirname {} \; \ +RUN --mount=type=cache,id=genarrative-ci-cargo-cache-v1,target=/usr/local/cargo/registry/cache,sharing=locked \ + --mount=type=cache,id=genarrative-ci-cargo-index-v1,target=/usr/local/cargo/registry/index,sharing=locked \ + find /tmp/genarrative-cargo-cache -name Cargo.toml -exec dirname {} \; \ | while IFS= read -r crate_dir; do \ mkdir -p "${crate_dir}/src"; \ : > "${crate_dir}/src/lib.rs"; \ @@ -53,6 +65,16 @@ RUN find /tmp/genarrative-cargo-cache -name Cargo.toml -exec dirname {} \; \ && CARGO_NET_OFFLINE=true cargo fetch --locked \ --target x86_64-unknown-linux-gnu \ --manifest-path /tmp/genarrative-cargo-cache/apps/ai-game-creator-shell/src-tauri/Cargo.toml \ + && mkdir -p /opt/ci-downloads/registry/cache \ + && cp -a /usr/local/cargo/registry/index /opt/ci-downloads/registry/ \ + && for source in /usr/local/cargo/registry/src/*/*; do \ + [ -d "${source}" ] || continue; \ + registry="$(basename "$(dirname "${source}")")"; \ + package="$(basename "${source}")"; \ + mkdir -p "/opt/ci-downloads/registry/cache/${registry}"; \ + cp "/usr/local/cargo/registry/cache/${registry}/${package}.crate" \ + "/opt/ci-downloads/registry/cache/${registry}/" || exit 1; \ + done \ && rm -rf /tmp/genarrative-cargo-cache FROM ${RUNNER_IMAGE} @@ -127,6 +149,7 @@ RUN node_archive="node-v${NODE_VERSION}-linux-x64.tar.xz" \ && ln -sfn /usr/local/lib/genarrative-node/bin/corepack /usr/local/bin/corepack COPY --from=rust-dependency-cache /usr/local/cargo /usr/local/cargo +COPY --from=rust-dependency-cache /opt/ci-downloads/registry /usr/local/cargo/registry COPY --from=rust-dependency-cache /usr/local/rustup /usr/local/rustup ARG NPM_LOCK_SHA256 @@ -148,10 +171,12 @@ COPY server-rs/Cargo.lock /usr/local/share/genarrative-ci/locks/server-rs.Cargo. COPY apps/desktop-shell/src-tauri/Cargo.lock /usr/local/share/genarrative-ci/locks/desktop-shell.Cargo.lock COPY apps/ai-game-creator-shell/src-tauri/Cargo.lock /usr/local/share/genarrative-ci/locks/ai-game-creator-shell.Cargo.lock COPY deploy/container/gitea-ci-checkout.sh /usr/local/bin/genarrative-gitea-checkout +COPY scripts/export-ci-npm-download-cache.mjs /usr/local/share/genarrative-ci/export-npm-cache.mjs # npm registry 偶发 ECONNRESET,镜像预热也需要整命令级有界重试; # 失败重试复用同一 npm cache,不会重复下载已完成的包。 -RUN test -n "${NPM_LOCK_SHA256}" \ +RUN --mount=type=cache,id=genarrative-ci-npm-v1,target=/var/cache/genarrative-ci-npm,sharing=locked \ + test -n "${NPM_LOCK_SHA256}" \ && test -n "${SERVER_RUST_LOCK_SHA256}" \ && test -n "${DESKTOP_RUST_LOCK_SHA256}" \ && test -n "${AGC_RUST_LOCK_SHA256}" \ @@ -175,6 +200,7 @@ RUN test -n "${NPM_LOCK_SHA256}" \ && npm_ci_with_retry() { \ for attempt in 1 2 3 4 5; do \ if npm ci \ + --cache /var/cache/genarrative-ci-npm \ --ignore-scripts \ --no-audit \ --no-fund \ @@ -194,6 +220,12 @@ RUN test -n "${NPM_LOCK_SHA256}" \ /usr/local/share/genarrative-ci/npm/apps/*/node_modules \ /usr/local/share/genarrative-ci/npm/packages/*/node_modules \ /usr/local/share/genarrative-ci/npm/tools/*/node_modules \ + && rm -rf /root/.npm/_cacache \ + && mkdir -p /root/.npm/_cacache \ + && node /usr/local/share/genarrative-ci/export-npm-cache.mjs \ + /usr/local/lib/genarrative-node/lib/node_modules/npm \ + /usr/local/share/genarrative-ci/npm/package-lock.json \ + /var/cache/genarrative-ci-npm/_cacache /root/.npm/_cacache \ && npm cache verify # 依赖预热会在 workspace 内解析出 Node 发行包自带的 npm(例如 10.9.8), diff --git a/deploy/container/gitea-ci-job.Dockerfile.dockerignore b/deploy/container/gitea-ci-job.Dockerfile.dockerignore index 43bc93a4c..edcf31154 100644 --- a/deploy/container/gitea-ci-job.Dockerfile.dockerignore +++ b/deploy/container/gitea-ci-job.Dockerfile.dockerignore @@ -3,6 +3,9 @@ !deploy/container/ !deploy/container/gitea-ci-job.Dockerfile !deploy/container/gitea-ci-checkout.sh +!deploy/container/gitea-ci-buildkitd.toml +!scripts/ +!scripts/export-ci-npm-download-cache.mjs !package.json !package-lock.json !server-rs/ @@ -19,6 +22,9 @@ !apps/ai-game-creator-shell/src-tauri/ !apps/ai-game-creator-shell/src-tauri/Cargo.toml !apps/ai-game-creator-shell/src-tauri/Cargo.lock +!apps/ai-game-creator-shell/src-tauri/vendor/ +!apps/ai-game-creator-shell/src-tauri/vendor/*/ +!apps/ai-game-creator-shell/src-tauri/vendor/*/Cargo.toml !apps/desktop-shell/ !apps/desktop-shell/package.json !apps/desktop-shell/src-tauri/ @@ -48,4 +54,4 @@ !plugins/agc-godot-editor/ !plugins/agc-godot-editor/native/ !plugins/agc-godot-editor/native/godot-editor-bridge/ -!plugins/agc-*-editor/native/*-editor-bridge/** +!plugins/agc-*-editor/native/*-editor-bridge/Cargo.toml diff --git a/deploy/env/api-server.env.example b/deploy/env/api-server.env.example index c97ad913c..3cd99970f 100644 --- a/deploy/env/api-server.env.example +++ b/deploy/env/api-server.env.example @@ -4,6 +4,10 @@ GENARRATIVE_ENV=production GENARRATIVE_API_HOST=127.0.0.1 GENARRATIVE_API_PORT=8082 +# 客户端埋点接收绑定的公开 origin,由 API Server 运行时读取;修改后重启服务。 +# 必须与客户端登录地址一致,不带 /api、路径或尾部斜杠;未配置/非法时上传接口返回 503。 +# 以下为 release;dev 部署改为 https://dev.genarrative.world。 +GENARRATIVE_AGC_ANALYTICS_ORIGIN=https://www.genarrative.world GENARRATIVE_API_LOG=info,tower_http=info GENARRATIVE_API_LISTEN_BACKLOG=1024 GENARRATIVE_API_WORKER_THREADS=4 diff --git a/docs/README.md b/docs/README.md index 9bcef1589..b1eea2e71 100644 --- a/docs/README.md +++ b/docs/README.md @@ -25,6 +25,8 @@ ## AI 游戏创作与 Agent Runtime +- [客户端本地埋点与主站入库契约](./technical/【技术方案】客户端本地埋点与主站入库契约-2026-09-21.md):本地 12 类事件采集、每 15 分钟上传、私有事件表、确认后清理与后台明细查询已完成隔离环境验收;不扩充采集范围、不做加密,未部署生产。配置要求及验证边界见第 13 节。 + - [AGC 资源 kind 枚举化契约](./technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md#2026-09-15-gamecreationapp-资源-kind-枚举化当前权威口径):GameCreationApp 资源 kind 的 Rust enum、ts-rs 绑定、Unknown 可观测性和 shell 内重构边界。 - [策划 Agent 生产迁移与工作区浏览](./technical/【技术方案】策划Agent生产迁移与工作区浏览-2026-09-10.md):已完成;当前策划入口统一使用 Design Agent,采用阶段审批与用户工作区文件浏览。旧 V1/V2 会话、命令、专用展示和测试不再作为兼容目标。 diff --git a/docs/project-memory/plans/【实施计划】游戏分发阶段A领域合同-2026-09-19.md b/docs/project-memory/plans/【实施计划】游戏分发阶段A领域合同-2026-09-19.md index c5b4f61eb..0620f55c5 100644 --- a/docs/project-memory/plans/【实施计划】游戏分发阶段A领域合同-2026-09-19.md +++ b/docs/project-memory/plans/【实施计划】游戏分发阶段A领域合同-2026-09-19.md @@ -116,6 +116,11 @@ - 发布入口灰度下发:`GET /api/runtime/frontend-config` 新增 `gameDistributionPublishEnabled`,复用既有 `is_game_distribution_publish_enabled_for_user`(未配置 `game-distribution:publish` 或 `enabled=false` 时对已登录作者默认开放,显式收紧后只放行白名单/灰度命中,匿名恒为 false),避免前端入口与写入口出现两套判据。网页端 `PlatformEntryActiveFlowShell` 据此隐藏「发布游戏 / 发布新版本」入口,`/games/publish` 直接访问时渲染「发布功能正在灰度中」并提供重新检查;AGC 端 `readGamePublishAvailability` 同样读该字段,只有命中才把发布回调交给 DirectProject 聊天头。 - 灰度验证:`cargo test -p api-server frontend_runtime_config`(6 passed,含新增的 `frontend_runtime_config_game_distribution_publish_is_scoped_to_authenticated_gate`:无 gate 行 → 登录作者 true/匿名 false;`enabled=true` 无白名单 → false;白名单命中 → true;`deny_user_ids` → false;`enabled=false` → true;`rolloutPercent=100` → true)、网页发布页 15 用例(含灰度未命中隐藏表单与「重新检查」放行)、平台壳 18 用例(含广场入口按灰度隐藏/显示)、AGC 发布服务 6 用例(含字段缺失与读取失败按不开放处理)。 +- Phaser 一键发布闭环(作者不构建、不打 ZIP):`export_local_project_package` 改为发布前构建——已有可玩入口直接打包,否则解析 `game/` 或项目根的 npm `build` 脚本(`resolve_publish_build_plan`),缺 `game/node_modules` 时先跑 `project.bootstrap`,再走 `project.verify` 的受控 npm 运行器执行 build,最后校验入口并打包;构建或安装失败返回带日志尾部的可操作错误。真实 Phaser 4.2.1 + Vite 7 工程验证:构建产物使用相对引用(`./assets/...`),ZIP 370,969 B 经真实素材直传 + 创建游戏/版本/上传/送审/审核通过后,发行网关 `index.html` 200(323 B)与 `assets/index-DZGg_tPs.js` 200(1,388,719 B),网页播放页在 `allow-scripts` 沙箱 iframe 内渲染出 `PHASER-PUBLISH-OK` 与可点击按钮。 +- 发行网关根路径:`GET /api/game-distribution/releases/{gameId}` 与带尾斜杠的同一路径等价于 `index.html`(生产由每游戏 origin 映射根路径,本地直连网关或入口直接填网关地址时同样可玩);路由级用例覆盖 Cookie 拒绝门与根路径。 + +- 发布灰度改为**默认关闭**并修掉客户端“看得到点不动”:`is_game_distribution_publish_enabled_for_user` 现在要求 gate 行存在且 `enabled=true`(未登录、无行、`enabled=false` 一律 false),因此没配灰度时 `gameDistributionPublishEnabled=false`,AGC 不再渲染「发布到游戏广场」按钮、网页入口也不出现;AGC 侧新增 `announcePublishMessage`,把「已构建并打包试玩包」「先打开一个项目再发布」等提示通过 DirectProject 聊天容器的 `announce` 出口回话(普通项目不渲染工作台状态行,之前只写 workspaceStatus 才会表现为点击无反应)。后台「灰度发布配置」新增「可配置开关」列表:预设开关在未创建行时也可见并可一键配置(不再需要先猜 gate key)。 + ## 尚未完成 - 真实独立发行域名、通配 TLS 与 CDN 仍属部署侧:边缘模板与门禁已就绪,本地已用真实 nginx 验证按主机映射、Cookie 403 与命名空间隔离,但仍需在真实域名/证书下跑一次“审核通过 → 游玩 → 换版 → 下架”并确认 CDN TTL 不超过 60 秒窗口。 diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index ffed66ba5..85f5b4e34 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -22,6 +22,54 @@ - 未纳入本次:斜杠命令 `/` 解析、拖拽文本(drop)、附件 / 运行画面区域 / 文件路径 / URL / 剪贴板图片、复制侧 `text/plain` 形态调整、扩展安装卸载后的目录即时失效。 - 验证方式:`buildContentFromPastedText` 规则矩阵单测(含「显示文本再粘贴回来得到同一份 content」这条逆运算)、provider 的 `fuzzyLookup` / `lookup` 用例、输入区集成用例(真 Lexical `paste` 事件 → 芯片、未命中等价于默认粘贴、Skill 冷启动保持字面且敲过 `$` 后可解析);另跑 `npm run typecheck`、`npm run check:encoding`、`npm run check:doc-index`、`git diff --check`。 +## 2026-09-22 Direct 埋点与业务持久化锁隔离 + +- Direct 采集身份和最新成果编号改由独立纯内存状态保存,初始化时从最终执行账本冻结项目与原 run 身份;成果采集、预览采集上下文和终态成果读取不再争用业务落盘锁。 +- 内存锁释放后才投递事件,不等待文件 I/O、后台队列或网络,不新增用户报错。缺少 run 元数据不套用当前用户身份,恢复不补造历史成果;退出仍尽力封存,不增加退出等待。 +- 修正后台埋点查询 DTO 的分页注释:按 `(event_time, event_id)` 倒序,入库时间仅限制快照;接口和查询行为不变。 + +## 2026-09-22 新项目埋点资格支持有限恢复 + +- 真实创建成功先登记有界进程内待办,不依赖埋点服务或身份快照;后台服务就绪及后续真实受理可重试初始化资格。资格文件格式、每项目最多一次首次提交和上传合同不变。 +- 业务线程仅更新内存和非阻塞投递;资格文件读写和独立锁操作仍在后台,不向用户报错或要求介入。队列满、暂时 I/O 失败和锁竞争保留待办;已有标记、备份或项目身份不符不重新授予资格。 +- 内存最多 1024 项、路径与 ID 合计 1 MiB;超限或持久化前退出仍允许漏记,不补旧项目历史,不承诺零丢失。细节与验证见客户端埋点主规范。 + +## 2026-09-22 清理无调用方的 GUI 文件写入命令 + +- 确认 `write_local_project_file` 无现役前端或业务调用方后,删除命令、Tauri 注册及命令检查豁免;移除对应测试片段,保留 checkpoint、UI 保存和记忆写入的既有测试。 +- Agent 使用的底层 `write_local_project_file_at` 保留。GUI 人工文件写入不再列为采集入口;不扩充其他文件操作埋点,不修改已有事件数据合同。 + +## 2026-09-22 客户端埋点后台按发生时间排序 + +- 按技术负责人要求,列表改为 `(event_time, event_id)` 倒序,历史补传按发生时间归位。入库时间仍用于固定分页快照,翻页期间新入库的事件在刷新后显示。 +- 分页游标改存发生时间;旧游标刷新后重新取得,不迁移持久表、不新增索引、不改变采集与上传行为。 + +## 2026-09-22 埋点分支同步发布入口与工作台更新 + +- 合并 master `079466b29`,同时保留项目离开埋点与工作台运行通知、后台埋点查询与游戏发布审核入口;不扩大采集范围。 +- 本次冲突位于工作台相邻回调、后台 API 测试导入及本文件新增记录,均保留双方现役内容;Direct 聊天的认证重试埋点与 master 回合状态调整继续共存。 + +## 2026-09-22 埋点分支合并 DirectProject 聊天重构 + +- 保留 master 的独立 DirectProject 聊天控制器及 canonical `userItem` 合同;旧 Supervisor、独立 prompt/attachments IPC 参数和已退役删除命令不恢复。 +- 原有 Direct run 埋点从 App 聊天链迁至 `useDirectProjectChatController.runTurn`,认证重试仍逐次生成 attempt ID,并仅确认最后一次;账号代次变化时丢弃确认。项目进入/离开及用户预览的原有接线继续保留,不扩大采集范围。 +- 过期测试按现役聊天入口调整,新增实际 UI→controller 认证重试用例验证最终尝试确认。上传、数据库和后台合同不变。 +- 合并验证:Rust analytics 56 项通过(真实服务桥接用例维持 ignored),App 界面 203 项通过 / 13 项既有跳过;预览激活、版本切换、工作台清单及客户端埋点辅助测试通过,客户端 TypeScript、原生契约、编码、文档索引和 diff 检查通过。本次未重跑上传真实服务 smoke 或完整 GUI/Provider 创作。 + +## 2026-09-21 客户端埋点方案进入团队共享文档 + +- 本期验收完成:原始需求与已确认口径的 12 类事件入口已核对,同一 writer/session/project/goal 的宿主组件链路通过真实文件、HTTP、checkpoint 与 JSONL 关联验证;最终 51 项 Rust、46 项前端测试和类型/格式/文档检查通过。仅测试辅助模拟创建投递、run 结果和构建产物,不宣称完整 GUI/Provider 端到端验证;未提交或发布。禁止把全部资源操作逐项接线重新当作本期必做范围。 +- 最新口径:共 12 类启用事件;策划审批通过后实际进入下一阶段并成功持久化,复用 project_revision_created,revision_id=design::、source=design_agent、revision_source=agent、change_kind=design_document。同会话同目标阶段幂等;不严格校验文档版本/差异,阶段内文件修改不逐次采集,重开不补历史。不新增独立策划进度事件或审批、澄清状态字段。Direct 文件/补丁、UI 成果、预览与保存已有定向验收,基础事件入口已核对,同一宿主组件链路验收已通过。 +- 两类 Agent run 元数据随真实受理保存,后台维护项目累计观测重试与双 Agent 当前终态槽位;重放不新建,恢复保留原身份且耗时未知,取消/不确定不伪造失败。Direct 自动认证刷新只确认最后一次原生尝试的有界内存候选,账号代次变化丢弃;缺失不回退旧失败,不为观测增加业务写盘等待。运行结果已通过独立验收,真实付费 Provider/完整 GUI run 尚未 smoke,现有 Direct 合同中断恢复行为未改变。 +- Direct 宿主文件写入/正式补丁仅在已知成果内容变化且原事务 revision 成功提交后记成果,原 run 用户归属不变,末尾 projection 不重复记。当前 session 内存关联最新可信成果到 run;缺证据为 null,不据全局 fingerprint 推断作者。真实 writer、bundled patch 执行器和定向测试已通过。 +- GUI 人工文件写入命令已于 2026-09-22 清理,不再作为采集入口;完整项目 checkpoint 按真实 checkpoint_id 记保存。UI State 仅 Saved 记成果;手动 Saved/Unchanged 可记保存,自动保存仅 Saved,保存并生成需全操作成功。起点冻结身份,埋点失败不影响业务。63 项 Rust、41 项前端测试及独立验收通过;无完整 GUI 跨层保存 smoke。旧 Runtime 开发/CLI 文件及 UI workflow 不因存在代码就纳入正式 GUI 必需采集。 +- 正式 Web preview_ready 由 GUI 用户持续预览和 Direct 临时浏览器预览接入,冻结原身份、版本与实例;异步2秒loopback GET禁代理/重定向,原入口及响应非空、版本/实例仍匹配才记录。实例停止/替换、验证结束或取消后丢弃迟到结果;可访问不等于JS/游戏验证成功。合并后78项Rust、104项前端测试及独立验收通过,未调用真实Provider或跑完整Chrome双端验证。资源操作全面接线计划已撤销;现有采集只表示已观测变化,不代表全部资源操作或项目全部修订。 +- 首次提交按本地观测口径每个新项目最多一条:真实受理候选在后台持久消费 `.agent/analytics-goal.json` 资格后投递。资格跨批次清理保留,旧项目不初始化;此前候选丢失时允许后续真实受理消费,使用后者自己的用户与时间,不宣称绝对首次。消费后事件丢失可零条,重放与恢复不补历史;不得为埋点扫描双 Agent 完整历史或阻塞业务写盘。 + +- 当前合同唯一维护入口为[客户端本地埋点与主站入库契约](../../technical/【技术方案】客户端本地埋点与主站入库契约-2026-09-21.md),原始需求作为仓库内历史来源保存;后续里程碑规范与实施计划放在 `docs/project-memory/plans/`。 +- 本地采集阶段已验收明文 JSONL 持久化;当前仍不做加密。一个项目对应一个目标,事件按业务节点采集,5 分钟封存,7 天或 20 MiB 清理;上传失败也受保留上限约束。 +- 当前上传实现已完成隔离环境验收,证据见同一主规范第 13 节:每 15 分钟上传匹配当前账号与平台的封存批次,新增一张客户端事件私有表、批次原子入库与幂等确认、成功清理及独立后台明细栏目;失败静默留待下周期重试。真实客户端文件、HTTP、数据库与后台查询已关联同一事件验证,浏览器列表/筛选/详情通过;未部署生产。保持原 12 类事件和原采集边界。上线须配置 `GENARRATIVE_AGC_ANALYTICS_ORIGIN`,按数据库、API/后台、客户端顺序发布。 +- 已按技术负责人授权开始实施:合同与本地队列、会话窗口与项目接入、策划阶段成果、首次提交及两类 Agent run 已实现并经独立审查;定向测试、生产编译和前序 GUI 启停证据统一见主规范第 12 节。不得宣称完整产品采集已上线。 ## 2026-09-22 引用输入区改为宿主注入引用 provider,选择器面板与输入区分离 - 背景:`ResourceReferenceInput`(`apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx`)同时承担「拿数据」与「编辑数据」:素材以未过滤 manifest 传入后由组件自己派生候选、显示名与「当前版本素材」scope,Skill 候选由组件自己 invoke `list_agc_skill_catalog` 与 `list_client_extensions`(只在用户敲出 `$` 时触发),素材选择面板与缩略图预览 invoke 也住在组件内部。后果是 5 个宿主(DirectProject 聊天、策划输入盒、画布生成面板、资源卡快速编辑、测试夹具)无差别获得 `$` Skill 候选,而只有 DirectProject 回合会把 `agc_skill_reference` 解析成真 Skill(Rust `direct_codex_user_item_to_codex_turn_input`,`apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/wire.rs`),其余宿主只把它退化成字面文本,形成误导入口。 @@ -819,6 +867,15 @@ Godot 编辑器操控复用既有 AGC 插件宿主、EditorAdapter、Runner 和 - 验证方式:运行评论弹层恢复竞态回归、完整 `appSurface.test.ts`,并执行类型、编码和 diff 检查。 - 关联文档:`docs/technical/【技术方案】立项策划Agent(Fast GDD)-2026-08-10.md`、`apps/ai-game-creator-shell/src/features/project-workspace/GddApprovalCard.tsx`。 +## 2026-09-22 旧创作模板历史表从 schema 与生成绑定中删除 + +- 背景:旧创作模板的 63 张历史玩法表已经完成业务代码退役;release 在 2026-09-22 apply 前仍有 26 张表、5922 行历史数据。维护窗口内先完成可恢复备份,再执行固定清单清空,继续保留 table 定义、迁移白名单、旧行兼容分支和生成绑定会让当前 schema、客户端类型和迁移合同长期停留在退役状态。 +- 决策:从 `spacetime-module` 可达源码删除旧 gameplay、自定义世界、Puzzle / Puzzle Clear、Bark Battle、Match3D、Jump Hop、Wooden Fish、Square Hole、Visual Novel 与 Big Fish 的 63 张表定义及专属类型;同步删除只服务这些表的 `clear_retired_database_tables` procedure、固定清单、migration 导入导出项和旧行归一化分支,并重新生成 `spacetime-client` bindings。`runtime_setting`、`runtime_snapshot`、`user_browse_history`、`creation_entry_config` 等现役表和通用迁移能力保持不变。 +- 门禁处理:SpacetimeDB schema guard 只对本轮 63 个已确认 accessor 的从基线删除放行,其他表删除/改名以及字段级破坏性变更仍失败;该一次性白名单在删除结果进入后续主线基线后移除。生产发布仍必须单独完成冷备份、客户端兼容性和运行态确认,禁止用 SQL `DROP TABLE`、`--delete-data=always` 或系统表写入代替受控发布。 +- 影响范围:`server-rs/crates/spacetime-module/src/{active.rs,migration.rs}`、旧表专属 module/legacy schema 文件、`server-rs/crates/spacetime-client/src/module_bindings*`、schema guard 及后端数据契约。 +- 生产数据与发布闭环:`genarrative-prod` 在维护态、API/controller/worker 已停止时,以已授权 migration operator 执行 `clear_retired_database_tables`;apply 返回 63 张表且每张 `cleared_row_count == row_count_before`,共清空 5922 行。apply 前后两次 `dry_run=true` 均为 63/63 全零,第二次在 10 分钟观察窗口结束后执行。清空前完成 files-minimal OSS 备份、latest/catalog 验真和 restore dry-run;随后将 release 从 `2.7.0` 直接切换到本地锁定并有 commit 校验的 `2.8.3 / 8e410d…` 二进制,再用 source commit `05a5ea4d8534b3f96d4d462c6cfda9b0775073df` 的 wasm 发布。发布后 schema 为 84 张表、旧表为 0、`clear_retired_database_tables` 为 0;API/controller/worker 已恢复,维护退出,`genarrative.world` 与 `www.genarrative.world` 返回 200。 +- 验证方式:`npm run spacetime:generate` 生成 766 个 binding 文件;`cargo check -p spacetime-client -p api-server`、`cargo test -p spacetime-module migration`(21 passed)、`npm run check:server-rs-ddd`、`npm run check:spacetime-schema`(84 tables)、`npm run check:spacetime-runtime-access`、schema guard 单测(9 passed)、`npm run check:encoding`、`npm run check:doc-index` 与 `git diff --check` 通过。 + ## 2026-09-02 旧玩法表采用两阶段退役清理 - 背景:旧创作模板的业务代码已退出现役编译链,但 SpacetimeDB 中的历史表仍需先完成数据清理;直接删除表定义会扩大 schema 迁移和客户端兼容风险。 diff --git a/docs/project-memory/shared-memory/development-workflow.md b/docs/project-memory/shared-memory/development-workflow.md index 6aaee50b9..71fbddf88 100644 --- a/docs/project-memory/shared-memory/development-workflow.md +++ b/docs/project-memory/shared-memory/development-workflow.md @@ -96,6 +96,14 @@ SpacetimeDB 任务统一先读取 `.codex/skills/genarrative-spacetimedb/SKILL.m ## Gitea CI 依赖闭合 +缓存维护下载必须核对 artifact 元数据大小与实际响应,并立即检查 ZIP 完整性;有长度上限不等于能检测短读。网络或归档损坏最多重试 3 次且重新取签名链接。sccache 同 key 的不同 ZIP 成员排列会改变整个对象 SHA;新增对象去重仅在成员内容 SHA、权限和 ZIP 元数据均一致时接受排列差异,真实内容及继承对象冲突仍拒绝。禁止通过任取一份冲突对象绕过完整性契约。 + +Buildx 0.30.1 的 `inspect` 不支持 `--format`,builder 驱动校验读取普通输出的 `Driver:` 字段。相关命令须在宿主真实插件上验证;测试替身应拒绝不支持的参数,避免把模拟命令成功误当兼容性证据。 + +BuildKit 会把 Dockerfile 中的裸 `FROM sha256:` 当作远程镜像名;快照组装须在维护锁内把可信基础 Image ID 绑定到专用临时 tag,并显式使用能读取宿主镜像的 `default` Docker builder。成功或失败后去 tag,元数据和 runner 仍固定完整 Image ID;不要复用受管 `base_tag` 给历史基础镜像打别名,以免改变自动清理归属。 + +Gitea 基础镜像通过专用 `genarrative-ci-images` Buildx builder 持久复用 Cargo/npm 下载缓存;稳定 cache mount 与 commit、lock 哈希无关,以 `sharing=locked` 隔离并发写入,仅供可信宿主构建、不开放给 PR。最终镜像显式物化当前依赖下载快照,仍不包含 node_modules/target 或上一版 sccache 层。首次可用 `seed-downloads` 从可信完整 Image ID 提取包缓存,操作账号须与维护服务一致;部署要求及 builder GC 空间目标见 `deploy/container/README.md`。构建上下文必须覆盖 AGC vendor 与编辑器 bridge 的全部本地 path manifest,普通源码变化不应使依赖层失效。维护 journal 提供阶段耗时和失败 build.log 定位。 + Gitea Rust 缓存自动维护由宿主 `genarrative-ci-cache.timer` 收集同一 master push run 六个 Rust job 的原生 V4 缓存产物,不重复执行 Cargo 预热。只传本轮新 key,命中对象只传使用时间;宿主与真实来源镜像对象合并、去重、按新近使用时间裁剪到 4 GiB,从无对象缓存基础镜像重新组装。源 run 不要求全绿,但取消、缺组、旧 attempt、未完成上传或混用来源镜像不得采用。网关暂停新 FetchTask、在途领取结束、持久化任务账本清空且内层活动容器为空才切换,不打断运行中的 CI。首次接入/升级网关需空闲窗口;Token 只需普通仓库 `write:repository`,不查管理员 API。候选装载后清理已收集 artifact,遗留项保留 7 天;真实 master CI 验证后才清理旧镜像,保留当前、一个回滚版、基础镜像及容器引用。部署入口见 `deploy/container/README.md`,合并代码不等于服务启用。 修改 Gitea workflow 的 job 显示名称、ID 或缓存导出组时,必须同步维护器的 `JOBS` / `RUST_JOB_IDS`;`test_gitea_cache_maintenance.py` 直接对照实际 workflow 检查全集和导出映射,避免自动刷新或镜像验收因名单漂移长期等待。维护器 `Api.request` 的 `method` 是必填关键字参数,GET 也必须显式指定,不根据 body 推断请求方法。 diff --git a/docs/project-memory/shared-memory/pitfalls.md b/docs/project-memory/shared-memory/pitfalls.md index 7e2d98345..7e6bb8215 100644 --- a/docs/project-memory/shared-memory/pitfalls.md +++ b/docs/project-memory/shared-memory/pitfalls.md @@ -49,6 +49,8 @@ 按上游 [#5555](https://github.com/clockworklabs/SpacetimeDB/pull/5555) 的 retention 语义,只有最近 `retain-snapshots`(默认 2)份 snapshot 与覆盖它之后的 commitlog 段是重启所需,其余历史可丢;因此备份改为 `files + full + --minimal --retain-snapshots 2`(release 实测 40G → 3.6G,热备不停服),不再做增量差异计算,也不需要 44.7G 冷备空间。 +2026-09-22 的 release 清表窗口再次验证:41.2GiB 数据目录执行 `archive` 会因根盘不足失败;尝试非 minimal 的 `files + full + --stop-service` 虽通过空间预检,但在扫描 43GiB 后于 catalog 序列化阶段报 `RangeError: Invalid string length`。生产中等数据目录继续使用可验真的 `files + full + --minimal` 备份,并在 apply 前执行 `restore-files-state --dry-run`;非 minimal files 大库备份需要先修复 catalog 序列化上限,不能把失败备份当作通过。 + ## copyArtifacts 报「Unable to find project for artifact copy」的用户触发构建差异 Copy Artifact 插件在**非 SYSTEM 认证**下按「认证用户」判权:只有当被复制 Job 的 `CopyArtifactPermissionProperty`(仓库里由 Declarative 的 `copyArtifactPermission(...)` 维护)显式列出当前消费者,或者该 Job 对认证用户开放 Item.Read 时才放行;`ACL.SYSTEM2` 的定时构建会短路通过。因此会出现「定时调度一路成功、手动发布必挂」的现象(2026-09-21 手动发布 #6/#7 与同期的用户触发探测全部命中,定时调度 #104+ 正常)。`Genarrative-Agc-Global-Version-Issue` 生产权限模式的授权名单必须同时包含 `Genarrative-Scheduled-Revision-Trigger` 与 `Genarrative-Manual-Build-And-Deploy`;改完 `copyArtifactPermission` 后要先跑一次发号 Job 把 Job property 写回 Jenkins,只改仓库文件不生效。 @@ -1121,7 +1123,7 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/` - 现象:画板生成按钮显示 `N泥点`,后端也能按模型配置计算出价格,但用户点击后钱包余额不变。 - 原因:前端展示价和后端价格计算只证明价格能被展示 / 解析;如果 handler 没有包进 `execute_billable_asset_operation_with_cost`,或异步音频发布目标没有携带本次模型价格,外部 provider 仍会被调用但不会真实扣费。 - 处理:新增或改造编辑器外部生成入口时,确认前端请求不携带 `priceMudPoints`,后端按运行时模型定价重新计算价格,并用该价格进入资产扣费 wrapper。音频提交 / 发布分离时,把后端计算出的价格写入 `AudioAssetBindingTarget.billing_points_cost`。 -- 验证:结构性测试覆盖对应 handler 包含 `execute_billable_asset_operation_with_cost` 和价格变量;音频测试覆盖 `resolve_creation_audio_points_cost` 优先读取 editor target 的 `billing_points_cost`。 +- 验证:结构性测试覆盖对应 handler 包含 `execute_billable_asset_operation_with_cost` 和价格变量;`worker_billing_context_freezes_charge_and_preserves_job_metadata` 与 `logged_in_background_music_queue_preparation_uses_canonical_prompt_and_frozen_price` 覆盖现役队列冻结价格,原子计费测试覆盖提交失败与结果未知时的退款边界。 - 关联:`server-rs/crates/api-server/src/editor_project.rs`、`server-rs/crates/api-server/src/character_animation_assets.rs`、`server-rs/crates/api-server/src/vector_engine_audio_generation/`、`src/components/image-editor/ImageCanvasGenerationSubmissionModel.ts`。 ## 本地 dev 启动日志先看成功锚点,不要把非阻断 warning 当失败 diff --git a/docs/technical/【后端架构】编辑器生成结果原子提交与幂等重放方案-2026-08-06.md b/docs/technical/【后端架构】编辑器生成结果原子提交与幂等重放方案-2026-08-06.md index 8e76aa04d..1cb113101 100644 --- a/docs/technical/【后端架构】编辑器生成结果原子提交与幂等重放方案-2026-08-06.md +++ b/docs/technical/【后端架构】编辑器生成结果原子提交与幂等重放方案-2026-08-06.md @@ -77,6 +77,7 @@ EditorGenerationResultPersistInput { ## api-server 接入 +- 旧分段持久化、worker 独立完成及其重复结果序列化实现,在失去现役调用方后直接删除;不保留只供旧测试调用的生产副本。废弃实现的专属测试随实现删除,不因清理而将旧用例改接到现役函数;现有现役行为测试保持原有覆盖。手动拆分、上传等现役路径使用的底层 helper 继续保留,HTTP / DTO、inline 模式和历史任务解析兼容不受清理影响。 - 通用持久化改为 `prepare -> build canvas candidate -> atomic commit`。prepare 阶段只生成稳定 ID、上传/验证对象和构造候选 DTO,不创建 resource/asset。 - api-server 继续复用现有画布 completion / replacement 逻辑计算候选 `layers_json` 和 `expected_revision`;统一 procedure 在最终事务内重新执行既有 layout 校验和 CAS。 - CAS 冲突只刷新当前 project、重新计算 layout 并重试 prepared commit;相同 operation、slot、对象和记录候选保持不变,禁止重跑 Provider。 diff --git a/docs/technical/【技术方案】客户端本地埋点与主站入库契约-2026-09-21.md b/docs/technical/【技术方案】客户端本地埋点与主站入库契约-2026-09-21.md new file mode 100644 index 000000000..411158929 --- /dev/null +++ b/docs/technical/【技术方案】客户端本地埋点与主站入库契约-2026-09-21.md @@ -0,0 +1,736 @@ +# 客户端本地埋点与主站入库契约 + +Version: 0.31 +Status: 本地采集及上传、入库、成功清理、后台查询已实现并完成本地隔离环境验收;未部署生产 +Date: 2026-09-21 +需求来源:[Game Agent 埋点设计原始方案](./【需求来源】GameAgent埋点设计原始方案-2026-09-05.md);原始方案与后续已确认决策有差异时,以本文为准。 + +## 1. 交付目标与范围 + +2026-09-22 CI 检查适配:Tauri 命令清单解析仅提取模块路径末尾的函数名,避免将 `analytics::gui` 误判为命令;预览生命周期结构性测试匹配当前 `set_running_with_lease` 调用,继续检查同项目重启不覆盖新预览记录的保护逻辑。此修正不改变运行行为或采集范围。 + +阅读说明:第 1 至 12 节记录本地采集合同及其已完成的验收证据;当前上传、入库、清理与后台查询的实施合同统一见第 13 节。第 13 节细化第 8 节,不改变现有 12 类事件和采集触发点。当前整体仍在实施验收中,不表示已经上线。 + +交付结果:在 Game Agent 与现役 Design Agent 客户端的真实业务节点产生有明确语义的产品事件,以明文 JSONL 批次持久化在应用级目录;当前实施增加主站入库、确认后清理与后台明细查询,验收要求见第 13 节。 + +本地采集阶段的既有验收以本地记录为准:字段来源可追溯、事件不会冒充业务成功、正常重放不重复、跨账号不串归属、埋点故障不影响正常操作。这些证据不替代当前上传成功、服务端去重与后台查询的验收。 + +优先级: + +- 必须项:字段合同、身份与因果关联、原方案 13 类事件逐项对照(采集其中 12 类,暂不采集 session_timeout)、策划阶段推进复用成果事件、本地未闭合会话标记、本地 JSONL 持久化、静默失败、定向验证。本版合计启用 12 类事件。 +- 风险项:项目目标身份稳定性、跨账号在途操作、多窗口前台时间、崩溃未闭合区间、revision 与保存事实、重复回调。 +- 可选项:无;本阶段不扩充分析维度或细粒度点击事件。 + +当前实施包括上传定时器、HTTP 接口、一张私有事件表与后台明细栏目;不实现文件加密、服务端聚合或统计看板。不读取或批量转换已有对话历史为埋点,不改变现有 Agent 产物与恢复账本的职责。 + +2026-09-21 存储范围确认:用户决定本阶段先不做加密,直接保存明文事件批次;无公钥配置、密钥生成或轮换前置要求。以后若启用加密,另行定义文件格式与接收兼容合同。 + +2026-09-21 产品口径确认:一个项目就是一个创作目标。项目内全部创作请求、澄清、审批、重试及跨会话继续均属于同一目标;不再根据消息内容划分新目标。 + +2026-09-21 异常会话口径确认:下次启动时,确认旧实例已退出且旧会话没有正常结束标记,再将本地会话标为 incomplete(不完整)。不设置周期心跳或检查点定时器、不等待超时阈值、不补记 session_timeout,不补造退出时间或未闭合前台时长。 + +2026-09-21 执行终态口径确认:等待澄清或审批算本次 run 正常完成,通过 end_reason 区分;用户取消和进程崩溃不计入 agent_run_failed,不进入已知成功/失败终态的分母。 + +2026-09-21 本地保留策略确认:埋点队列及相关索引最多保留 7 天、总量上限 20 MiB。任一条件达到即按第 7.3 节清理,未上传的数据也适用;不影响项目、Agent 对话或创作成果。上传失败的数据同样不会无限保留。 + +2026-09-21 本地封存时间确认:从当前批次第一条事件进入开始,5 分钟到期后封存落盘;没有事件不生成空批次。该时间与后续每 15 分钟上传的周期独立,本轮实施评审采用 500 条及 1 MiB 的提前封存上限,作为内部常量。 + +2026-09-21 策划成果采集确认:审批通过后实际进入下一阶段,且该阶段变化成功持久化,视为一次 project_revision_created;不严格校验文档版本或文件差异,不为埋点新增文件 revision 机制。阶段内随意修改文件不逐次采集,打开、重开或关闭项目不补历史阶段事件。同策划会话同目标阶段幂等;不独立采集策划进度事件或审批、澄清状态字段。5 分钟是封存落盘周期,后续 15 分钟是上传周期,均不是采集周期。 + +用户已确定并授权实施的上传要求:上传至主站数据库;客户端每 15 分钟上传一次;绑定真实用户与业务标识;成功后删除对应待上传副本;失败无弹窗、不阻塞正常进程。当前实现采用失败保留至下一个周期重试,不做立即重试,仍受本地保留上限约束;整体完成情况以第 13 节验收为准。 + +本文是团队共享的埋点技术方案唯一维护入口,原始需求副本仅用于追溯。正式编码前,按仓库规范驱动工作流在 `docs/project-memory/plans/` 补齐里程碑规范及当前里程碑实施计划,并完成对应评审;本文的建议项不因迁入仓库而自动视为已确认。本次按技术负责人授权推进实施,里程碑仍按规范逐项评审和验收。 + +## 2. 已核实的现有记录与复用边界 + +| 现有记录 | 当前事实 | 本阶段复用方式 | +| --- | --- | --- | +| `.agent/conversations/project.jsonl` | Game Agent 正式对话历史,包含正文 | 复用正式受理、终态的业务入口;不复制正文到埋点 | +| `.agent/runtime/direct-codex/turns/.jsonl` | 回合工具审计,条目有上限,写入可失败 | 参考执行事实;不能把其条数作为完整产品事件数量 | +| `.agent/agent.db` | 逐行 JSON 本地索引与审计,非 SQLite | 保持原用途,不作为待上传队列 | +| `.agent/design-agent/session.json` | 策划会话、对话、工具结果、阶段、审批、当前回合与恢复状态 | 审批通过且实际推进阶段成功持久化后记录成果事件;不上传完整会话文件 | +| `design_artifacts/` | 正式策划成果 | 保持原文件保存行为,本版不为统计新增 revision;文件内容不进入事件 | +| 应用级 `direct-executions/`、`direct-delivery/` | 执行控制与交付状态 | 关联正式执行生命周期;不额外复制一套业务状态机 | +| `.agent/analytics-goal.json` | 新增的项目目标采集资格:格式版本、项目 ID、已消费状态 | 仅后台初始化和消费;跨批次清理保留,不包含用户、对话或执行内容,不参与业务放行 | + +旧 Planning V1/V2 与 Fast GDD 不作为新埋点接线目标。主站已有 HTTP tracking 也不等于本方案事件已经被接收或保存。 + +## 3. 总体链路与非阻塞原则 + +```text +真实业务节点产生不可变事件候选(冻结身份、时间与业务引用) + → 有界内存队列,非阻塞投递 + → 单个后台写入器校验,在有界内存中组成 JSON 批次 + → 序列化为明文 JSONL,写入事件文件与最小控制元数据 + → 应用级本地待上传目录,批次不可变 + → 后续阶段:15 分钟上传 JSON 事件批次、主站入库、整批确认后删除 +``` + +- 业务线程不等待磁盘写入、文件清理或网络。队列满时丢弃本次埋点并增加本地计数,不拖慢业务。 +- 写入失败、权限异常、格式错误、磁盘满:埋点失败静默处理,不向业务调用返回错误、不显示弹窗、不回滚已经成功的操作。 +- 字段缺失不能通过伪造值满足校验。整条事件不合规时不写入正式事件文件,在内部记录事件名、原因码及丢弃数量,不记录正文或凭据。 +- 捕获时生成 event_id 与 event_time,后台排队延迟不得改变事件发生时间。 +- 正常退出仅尽力排空已经在队列中的事件,不新增等待上传或等待写盘的退出门禁。 +- 这一取舍允许“业务已成功,但埋点尚未持久化就进程退出”的丢数窗口。不能同时宣称完全不等待与绝对零丢数;本方案优先满足用户要求的不阻塞。 + +## 4. 公共事件合同 + +### 4.1 序列化规则 + +- UTF-8、无 BOM;字段名统一 snake_case。本地使用 JSONL,每行一个完整公共事件对象,按第 7 节组织批次文件。 +- 新写入事件固定 `schema_version: 1`;语义或类型发生不兼容变化时升版本,不能悄悄改变旧字段含义。 +- 顶层字段全部显式出现;不适用的可空字段为 null,不使用空串、0、`unknown` 或设备 ID 冒充真实业务身份。 +- properties 是按 event_name 定义的封闭对象,只允许本方案列出的字段;必填字段不可缺少,可选字段不可得时省略。 +- 公共字段不在 properties 中重复。所有 ID 为字符串,不将数据库整数 ID 转为可能丢精度的 JavaScript number。 +- 时间为 UTC ISO 8601,毫秒精度;时长和计数为非负整数,限制在 JavaScript 安全整数范围。时间倒退、跨重启无法可靠计算时写 null 或省略,不写负数或猜测值。 + +### 4.2 字段定义 + +| 字段 | JSON 类型 | 来源与约束 | +| --- | --- | --- | +| schema_version | integer | 固定 1;本文新增,供本地读取与后续服务端识别版本 | +| event_id | string | 客户端 UUID v4,单条事件唯一;重试、复制批次与恢复重放沿用原值 | +| event_name | string | 仅允许第 6 节本版启用的 12 个英文事件名;session_timeout 不在本版写入白名单中 | +| event_time | string | 业务事实发生时捕获的 UTC 时间;不能以重启检测时间冒充旧会话的退出时间 | +| user_id | string/null | 由已确认的平台登录会话取得;匿名明确 null,不从邮箱、设备或项目所有者猜测 | +| editor_session_id | string | 埋点专用 UUID;不复用 Runtime sessionId、threadId 或 clientTurnId | +| project_id | string/null | 项目 manifest 的稳定 ID;第 6 节规定项目事件必须非空 | +| creative_task_id | string/null | 项目对应的唯一创作目标 ID;有任务关联时直接等于该事件的 project_id,规则见第 5 节;不另造随机任务身份 | +| agent_run_id | string/null | 一次受理的 Agent 执行 ID;仅 run 终态事件填写 | +| agent_turn_id | string/null | 真实底层技术回合标识,可选;禁止把 run ID 复制进来凑字段 | +| status | string/null | 按本版事件固定映射为 success、failed 或 null;不能任意填写;本地会话 incomplete 不属于本字段 | +| error_code | string/null | 仅 agent_run_failed 非空,来自稳定错误类别映射;其余为 null | +| source | string | 仅 editor、direct、design_agent、asset_canvas、resource_editor、ui_editor、manual、system;表示事实产生模块 | +| client_version | string | 从实际运行的应用版本元数据读取,不使用示例值或空串 | +| properties | object | 对应事件的专属字段,允许空对象 | + +source 新增 design_agent 以表达现役策划实现;不使用旧 supervisor 标签代替。尚未接线的来源不能因枚举存在而被认为已覆盖。 + +### 4.3 用户归属与主站目标 + +- 用户与平台地址一并在事件发生时冻结。队列的本地路由元数据保存 `destination_origin`(经规范化的平台协议、主机、端口,无路径、查询串与凭据)和 user_id;它不是额外的产品指标。 +- 同一批文件只包含同一个 destination_origin 和 user_id 的事件。使用不含用户标识的随机批次文件名;路由元数据不保存 Token、Cookie 或 API Key。文件内容与路由元数据均为明文,其采集边界见第 7.4 节。 +- 账号 A 的在途任务结束事件继续归属发起执行时的 A;不得在后台写入时读取当前 B 账号并替换。 +- 账号切换、登录与注销:闭合旧身份下的 focus 区间,原子切换埋点身份后按实际窗口状态开启新区间。编辑器会话可保持不变,按用户统计时必须按事件归属拆分,不能将整个会话时长归给最后登录者。 +- 匿名事件保持 user_id=null;不因之后登录自动回填。缺乏可解析的平台目标时可以以 destination_origin=null 本地保存,后续禁止默认发给当前任意服务器,待上传阶段明确处理策略。 +- 后续上传必须验证凭据主体与批次所属账号、平台一致。无法认证 A 时保留 A 的数据,不使用 B 的凭据代传;匿名接收规则在上传阶段明确。 +- 本地 user_id 只是待验证声明,后续服务端不能不核验鉴权就信任客户端填报的用户身份。 + +## 5. ID、因果关系与执行语义 + +### 5.1 编辑器会话与多窗口 + +一个 GUI 应用实例对应一个 editor_session_id,从可用初始化到该实例实际退出。新进程新 ID;WebView 重载不重建会话。Runner 继续在后台运行不等于编辑器仍有前台会话。 + +同实例多个可交互编辑器窗口的前台区间取并集,不累加重叠时长。以宿主查询的窗口总体状态为准,聚合窗口切换;不同应用实例独立记会话。后台 Runner 自己不产生 editor_session_start。 + +现役生产界面由 WorkspaceLauncher 进入项目工作区,内嵌 App 的 hydration 不是第二次打开。打开采集以 Launcher 成功采纳的显式导航操作为准。当前没有已验证的文件关联或上次工作区自动恢复入口,不为填满枚举而伪造 app_restore/project_association。当前原生回调可观察普通焦点和最小化;尚未接入独立锁屏/休眠系统通知,可能存在前台时长误差,不宣称完整覆盖系统休眠。 + +身份变化、真实工作区卸载和 WebView 开始重载时清除当前项目归属;卸载后迟到的异步导航不能记录为成功打开。已经成功的旧身份操作允许延迟记入历史,但不能恢复当前项目。生命周期状态在只含内存操作与非阻塞投递的短临界区串行更新,身份通知不能因竞争而永久丢失;启动身份快照与服务发布同步,等待认证状态在后台进行,不阻塞 GUI。 + +异常会话以每个 analytics 实例持有的独立文件锁证明存活;写 active 标记前先取得锁,恢复旧会话时取得对应锁并持有到修改完成。锁缺失、格式未知或无法判断所有权时保留原状,不用 Runner 共享参与锁代替。 + +### 5.2 项目与创作目标一一对应 + +- 用户已确认:一个项目就是一个目标。同项目内修改需求、改变方向、普通追加、澄清、审批和用户重试都不产生新目标;只有不同项目才对应不同目标。 +- 建议采用最简单的字段映射:creative_task_id 直接复用 manifest 的 project_id 值,保留两个字段的契约名称但不维护第二份随机 ID 或映射表。该等值映射是本文实现方案,不表示 clientTurnId、agent_run_id 也可复用项目 ID。 +- 项目改名、移动目录、重开、客户端重启、换账号以及从 Design Agent 转到 Game Agent 均不重建目标 ID。另存为新项目时应使用业务实际生成的新 project_id;复制目录但仍保留相同 project_id 的情况按同一项目身份处理,埋点不自行修正项目身份。 +- creative_task_submit 每个目标只记录一次本地成功采集到的真实受理;仅创建或打开项目不算提交。之后的执行用多个 run 表达,不把消息条数算成目标数。首次是本地观测口径,不保证绝对首次操作:较早受理的埋点丢失时,后续真实受理可以成为首条记录,仍使用后者自己的发生时间与身份,不补原历史。 +- 首次提交事实随项目已有受理记录或最小标记持久保存,不能只存在 React 状态或会过期的上传索引中。上传后清理批次不清除目标已提交事实,避免重开项目重复首次提交。 +- 现有项目的目标 ID 可由真实 project_id 直接确定,但不补发历史事件。无法证明是首次创作请求时,不将首次启用埋点或第一次遇见旧项目冒充首次提交;后续 run、revision 等仍可记录并关联项目目标。 +- 不新增“新目标/继续目标”选择器,不使用模型、关键词、消息间隔或最近任务推断目标归属。所有任务相关事件校验 creative_task_id == project_id。 + +### 5.3 Agent 执行 + +- 一次用户指令或明确继续动作被 Runtime 受理后生成 agent_run_id,执行至正常返回、最终失败、取消或中断。一次任务可以包含多个 run。 +- 同一执行内部的 Provider 重试不创建新 run;相同受理请求重放复用原 run ID。 +- 用户主动重试形成新的 run,沿用任务 ID。retry_index 为该项目启用采集后、后台成功处理的累计显式用户重试次数:初始观测为 0,主动重试递增;普通提交、澄清/审批不递增。它不表示 Provider 的请求重试次数,也不能证明启用前的完整历史;受理候选丢失可能少计。现役 Direct 没有明确用户重试入口,普通再次发送仍为 user_submit,不按文本或上次失败猜测 user_retry。 +- 正常等待澄清或审批结束本次 run,以 completed + end_reason 区分;用户答复后新建 run。completed 表示本次执行正常收束,不代表整个任务完成或用户满意。 +- 用户取消、崩溃、结果不确定不伪造 completed 或 failed。原方案未覆盖这些 run 终态,本版不新增对应终态事件,明确它们不进入成功/失败分母。 +- duration_ms 用单调时钟测量本次执行,含内部等待与自动重试,不含等用户答复的间隔;跨进程恢复无法可靠累加时为 null。 +- run UUID、终态事件 UUID、原身份与来源随已有业务受理记录保存,不新增业务线程的埋点写盘。旧执行无元数据时恢复不补事件。新请求重放不再登记受理;同一次自动恢复沿用原 run。 +- 后台项目记录仅维护重试计数及每类 Agent 一个当前 run 槽位,原子分配序号并幂等消费终态;不保存全部历史。新受理可覆盖同类旧槽位,迟到旧终态因而可能漏记;缺失、损坏或锁竞争均静默丢弃,不猜序号。消费成功但事件落盘前退出可能丢数,不重置终态资格。 +- 跨进程恢复的终态继续使用受理时的用户、平台与 run ID,editor_session_id、client_version 使用实际观察终态的当前 GUI 实例,duration_ms=null;不使用恢复时的新账号替换原身份。没有 GUI 埋点 writer 的执行不制造编辑器会话。 +- Direct 以宿主账本和整体执行结果共同判定:Interrupted 或取消/结果不确定不记终态;Exhausted 记 runtime_failed;明确错误记 failed;正常 Completed 或无交付合同的普通对话正常返回记 completed。需要交付合同但仍未完成时不猜 completed。判定在执行 guard 释放前完成,不改变 UI 返回结果。 + +### 5.4 下游因果关联 + +project_revision_created、preview_ready、project_save 已知所属项目,因此 creative_task_id 填同一 project_id,包括人工编辑与保存。这个关联只表示项目目标归属,不表示修改由 Agent 造成;实际来源由 source 与 revision_source/save_source 表达。其 agent_run_id 与 agent_turn_id 按原需求保持 null,不将“当前运行的 Agent”作为推定因果。 + +执行上下文冻结 project_id、creative_task_id、agent_run_id、用户与平台身份;后续不能从当前选中项目重新取值。run 的 output_change_detected 必须根据本次执行可归因的有效修改判定,不能只比较全局 revision 前后值,因为其他窗口也可能改动项目。 + +Direct 的自动登录刷新重试仍属同一个 run。原生单次调用结束只生成终态候选,外层自动重试链结束后才确认最后一次调用的候选;中间鉴权错误不提前消费 run 终态。每次原生调用使用独立的临时尝试标识,确认必须匹配最后一次尝试,避免取消、不确定结果或队列丢弃后误用旧失败。账号代次变化则丢弃候选;同账号凭据续期不改变代次。候选仅有界保存在内存,不写历史、不增加网络或业务等待;窗口关闭、崩溃、候选丢失或最后一次前置拒绝可漏记,不回退确认先前尝试。前端只确认调用链结束,不提供成功或失败结论。恢复或跨原生调用无法证明连续耗时时,duration_ms 为 null。 + +## 6. 事件合同(原方案启用 12 类) + +本节 properties 中“可选”字段在不可得时省略;未标可选的字段必须存在。公共 status、ID 与 source 的赋值同时受第 4、5 节约束。 + +### 6.1 editor_session_start + +- 触发:GUI 完成可用初始化,宿主首次确认会话开始;不是每次组件挂载。 +- 公共字段:status=success;project_id 仅在已成功打开项目时填写;任务/run/turn ID 均为 null;source=editor。 +- properties:entry_source 为 direct_launch / project_association / app_restore;first_project_id 为已确认首次项目 ID 或 null。之后打开项目不回写本事件。 +- 去重事实键:editor_session_id + event_name。 + +### 6.2 editor_session_end + +- 触发:应用实际正常退出,先尝试闭合前台区间;关闭项目窗口但应用仍运行、退出被取消时不记。 +- 公共字段:status=success;project_id 为最后成功活动项目或 null;任务/run/turn ID 均 null;source=editor。 +- properties:end_reason=user_exit / app_restart;session_duration_ms 为可靠时长或 null;last_project_id 为稳定 ID 或 null。 +- 去重事实键:editor_session_id + event_name。正常退出事件也可能因不等待后台写盘而丢失,不能据此声称进程必然崩溃。 + +### 6.3 session_timeout(本版暂不采集) + +- 按用户确认,本版不产生该事件,也不新增其他异常退出产品事件替代它。后续若需要服务端异常会话统计,另行定义接收合同。 +- 下次启动在后台检查本地旧会话:仅当缺少正常结束标记,且能够确认所属旧实例已退出时,将旧会话标为 incomplete。 +- 旧实例仍在运行则不处理;无法确认进程归属或存活状态时保持原记录,不猜测退出。实例确认需防止 PID 被复用,复用宿主实例锁或 PID 与进程启动身份的组合,不仅检查 PID 数字。 +- 发现即可标记,不要求等待 30 分钟,不维护 60 秒检查点定时器,也不添加启动等待门禁。 +- incomplete 只表达记录不完整,不认定原因是崩溃。标记保持旧会话及原用户归属,不改成当前登录用户;重复启动处理保持幂等。 +- 不补记 editor_session_end、editor_focus_end、session_timeout,不改写已封存的历史事件。未闭合 focus 区间不计入完整前台时长,已正确配对的历史区间仍可计入。 +- 用户不再启动时,旧记录保持未闭合;主站后续只可将缺结束或缺配对记录视为不完整,不能从上传缺席推出确定退出时间。当前本地 incomplete 标记不随事件批次上传。 + +### 6.4 editor_focus_start + +- 触发:实例的可交互窗口总体状态从无前台变为有前台;启动时已获得焦点也需要记录。 +- 公共字段:status=null;project_id 为开始时实际活动项目或 null;source=editor;任务/run/turn ID 均 null。 +- properties:focus_interval_id(UUID);focus_reason=initial_focus / window_focus / restore / account_change;active_project_id(可为 null)。 +- focus_interval_id 是本文新增的事件专属关联 ID,确保存在丢数与乱序时仍能准确配对;不新增顶层业务 ID。 +- 项目切换不拆分区间,因此不能用 active_project_id 把整个区间归为某个项目的编辑时长。 +- 去重事实键:focus_interval_id + event_name。 + +### 6.5 editor_focus_end + +- 触发:总体前台状态关闭、最小化、可观测的锁屏/休眠或正常退出。锁屏/休眠监听能力必须实际验证,无法观察的情况标为统计限制。 +- 公共字段:status=null;source=editor;project_id 为结束时活动项目;任务/run/turn ID 均 null。 +- properties:原 focus_interval_id;blur_reason=window_blur / minimized / app_exit / system_suspend / account_change;focus_duration_ms 为单调时钟时长或 null;active_project_id(可为 null)。 +- 重复 blur 不重复结束。缺 start 的 end 或缺 end 的 start 都不组成有效配对,不凭空补齐另一端。 +- 去重事实键:focus_interval_id + event_name。 + +### 6.6 project_create_success + +- 触发:新项目初始化完成,manifest 已持久化且稳定 project_id 已确认;覆盖自动创建与用户选目录创建。 +- 公共字段:status=success;project_id 必填;source=editor;任务/run/turn ID 均 null。 +- properties:creation_source=home_game / home_design / template / selected_directory;project_template_id 可选,仅填真实模板稳定 ID。 +- 打开已有项目、幂等初始化不记创建;文件夹刚建立但后续失败不记成功。 +- 去重事实键:project_id + 本次创建操作 ID + event_name,沿用业务操作身份,不读取路径当项目 ID。 +- 只有成功事件,不能计算创建成功率;创建尝试数不在本版范围。 + +### 6.7 project_open + +- 触发:一次显式导航或启动恢复成功加载项目并进入工作区;后台读取与同页面刷新不记。 +- 公共字段:status=success;project_id 必填;source=editor;任务/run/turn ID 均 null。 +- properties:open_source=create / picker / recent / app_restore / project_association;is_first_open 为 boolean 或 null。 +- is_first_open 口径为“当前账号在本安装可观察范围内首次成功打开此项目”,不是全平台首次。使用本地有界索引保存该事实;无历史覆盖证据、旧项目首次遇到或索引清理后填 null,不将未查到当 true。新创建并首次进入可确认为 true。 +- 去重事实键:本次工作区打开操作 ID + event_name;之后真正重新打开必须有新的操作 ID。 + +### 6.8 creative_task_submit + +- 触发:本版实际新建项目的创作请求通过基本校验并被业务受理,且后台成功消费尚未提交的项目资格;不是创建项目、点击按钮、未提交草稿或请求重放。每项目最多采集一次。 +- 项目资格只在真实创建成功后初始化,记录格式版本、project_id 与已提交状态,随项目保留,不进入 7 天批次清理。创建成功先登记进程内待初始化资格,不依赖埋点服务或身份快照就绪;登记仅包含项目目录与 project_id,最多 1024 项且路径/ID 合计最多 1 MiB,超限静默放弃新增,不影响创建。后台互斥消费后才投递事件;此前候选丢弃而资格尚未消费时,后续真实受理可记录。 +- 埋点服务就绪后尝试投递待办;创建通知和后续真实受理均可在现有后台写入器中重试初始化。不增加定时器或项目扫描,不在业务线程执行资格文件 I/O,也不等待队列、磁盘或网络;失败不弹窗、不返回业务错误、不要求用户介入。队列拒绝、独立锁竞争与暂时 I/O 失败保留待办;只有明确观察到本进程创建、主标记和恢复副本均不存在时才允许初始化。初始化成功、发现任意已有标记/恢复副本或 manifest 项目身份不符后移除待办,不重置已消费状态,不修复损坏标记。 +- 没有待办依据的旧项目缺失资格仍为未知,不补历史。待办未持久化前进程退出或超出内存限额时允许漏记;资格已消费但事件未落盘时同样允许漏记,不反向重建资格。此恢复不承诺零丢失。 +- 并发候选以成功持久消费资格的顺序决定保留哪次受理,不保证业务最早请求或最早 event_time;最终事件可能为零条。项目标记属于持久的观测状态,不保存用户身份、正文或路径,也不作为业务执行门禁。 +- 公共字段:status=success;project_id、creative_task_id 必填;source=direct / design_agent;run/turn ID 均 null。 +- properties:空对象。公共字段不重复,不增加 Prompt、长度、附件或任务分类。 +- 去重事实键:creative_task_id + event_name;已成功消费资格后,同项目澄清、审批、追加和重试不再发本事件。项目级首次提交标记跨应用会话及批次清理保留。 +- creative_task_id 必须等于 project_id;同一项目先策划再开发也不再记第二次目标首次提交。 + +### 6.9 agent_run_completed + +- 触发:本次执行达到确定正常终态;现役 Direct 与 Design 在各自正式生命周期接线,不以“返回一个字符串”或 HTTP 200 代替业务成功。 +- 公共字段:status=success;project_id、creative_task_id、agent_run_id 必填;agent_turn_id 可空;source=direct / design_agent。 +- properties:agent_type=game_agent / design_agent;run_source=user_submit / user_continue / clarification / approval / user_retry;duration_ms(integer/null);retry_index(integer);output_change_detected(boolean/null);revision_id 可选;end_reason=finished / waiting_for_user / waiting_for_approval。 +- output_change_detected=true 必须有本次归属的有效变更证据;false 必须完成检测且确认无变化;无可靠证据填 null。revision_id 仅填本次归属的最新已提交 revision。 +- 对 Design,本次受理操作中已成功持久化的阶段推进即可作为变化依据,output_change_detected=true 并关联该阶段 revision,不额外要求文档版本或文件差异检测。没有阶段推进时仍可能改了文件,若没有其他变化依据则填 null、省略 revision_id,不能因阶段没变而填 false。 +- 去重事实键:agent_run_id + terminal;同一个 run 最多一个正常终态,不因 GUI 与 Rust 双写而重复。 + +### 6.10 agent_run_failed + +- 触发:业务已经判定本次执行最终失败;内部重试尚在继续时不记。 +- 公共字段:status=failed;同 completed 的 ID 要求;error_code 必填。 +- properties:同 completed 的公共执行属性;end_reason=failed。失败前可能已产生有效修改,因此 output_change_detected 可以为 true。 +- error_code v1 白名单:provider_auth_failed、provider_rate_limited、provider_unavailable、provider_timeout、provider_invalid_response、local_io_failed、runtime_failed、runtime_error_unclassified。 +- 错误码由结构化错误种类映射;无法分类才使用 runtime_error_unclassified。不能通过异常正文猜分类,不保存错误正文、文件路径或堆栈。普通工具失败被 Agent 修复后完成不记 run_failed。 +- 去重事实键:agent_run_id + terminal。取消与异常中断不冒充 failed;本版 run 完成率仅比较已观察到的 success/failed。 + +### 6.11 project_revision_created + +- 触发:Game Agent、代码、资源、UI 等已有 revision 路径要求成果确实发生有效变化,且现有业务修改与正式 revision 都成功提交;策划阶段推进采用下述独立口径。存储损坏或不确定提交不记成功。 +- 公共字段:status=success;project_id 必填;creative_task_id 与 project_id 相同;run/turn ID 为 null;source 使用实际修改模块。 +- properties:revision_id(已有正式 revision 转为字符串;策划阶段推进使用下述稳定事实标识,不使用 event_id);revision_source=agent / asset_canvas / resource_editor / ui_editor / manual_edit / system_projection;change_kind=code / asset / ui / design_document / mixed;files_changed_count 可选。 +- 只更新聊天历史、访问时间或运行状态不属于有效变化。system_projection 仅在投影真实业务成果时允许,纯修复缓存/同步元数据不进入有效变化率。 +- 当前 Direct 的 outputs_changed 与 manifest_requires_sync 要区分;不能给 revision 递增函数加一个无条件事件后就宣称满足语义。 +- Direct 的宿主 file.write 与正式补丁事务使用持锁目标内容比较和本次已提交项目 revision,成功且内容确实变化时记 source=direct、revision_source=agent。运行期间的全局 fingerprint 和写许可本身不证明本 run 改了文件;末尾投影登记不再重复统计工具已经提交的成果,也不将纯登记修复计为新成果。未经过可观察宿主提交的外部/命令行写入不推断事件。 +- Direct run 的 output_change_detected=true 与 revision_id 来自本 run 已确认的宿主成果提交;保存当前内存中最后一个真实成果 revision,不为埋点新增业务文件版本或同步写盘。没有观察到成果、恢复后缺少该证据时为 null,不能推断 false。后续 run 失败不撤销已提交成果事件。 +- Direct 的采集身份与最新成果编号使用独立的纯内存状态,项目 ID 和原 run 身份在执行会话创建时从最终账本冻结;采集不争用业务持久化锁,不因业务写入或 tick 占锁而漏记。内存锁只保护采集状态读写,事件投递在释放锁后进行,不等待磁盘、网络或队列,不向用户报错。恢复仍使用原 run 身份,但不补造此前未保留的成果编号;旧账本缺少 run 元数据时不套用当前用户身份。 +- 宿主文件通道仅对已识别成果类型采集:策划成果目录、UI 目录以及支持的代码/媒体扩展名;私有控制面、隐藏记录、构建缓存和类型未知的文件不据此统计。该口径不承诺观察全部磁盘文件;恢复后的未知成果证据不补填。 +- Design Agent:仅审批通过后实际进入下一阶段且成功持久化时记录;不严格检查文档版本或文件差异,不增加业务文件 revision。revision_id=design::,使用真实策划会话 ID 和本次实际进入的目标阶段;source=design_agent,revision_source=agent,change_kind=design_document,files_changed_count 省略。该标识只表示阶段推进事实,不代表文件版本。 +- 策划同会话同目标阶段只记一次;同阶段内文件写入、普通对话、工具执行、提交审批、审批拒绝、等待澄清、没有实际阶段变化的批准,以及持久化失败均不产生该成果事件。项目重开、会话恢复或读取现有阶段不补历史。 +- 策划阶段事件的 event_time 取本次阶段变更成功持久化时间,用户和平台取审批操作开始时捕获的身份,不能归入异步完成时的新账号。 +- 去重事实键:project_id + revision_id + event_name。一个原子 revision 只记一次;多来源合并提交按真实提交范围填写,禁止任选最后一个来源。 +- 外部编辑器的修改仅在宿主已有变化确认与 revision 提交时覆盖;本版不新建全盘监听,不宣称能看到所有磁盘改动。 +- 采集覆盖边界:第一阶段记录基础创作链路中的项目变化,不要求逐项覆盖所有资源操作。资源上传、删除、重命名、派生、图片正规化、音频/画布生成、版本资源替换与批量导入,不因已有业务 revision 就自动成为本期必须接入的埋点入口。撤销此前为这些入口新增的全面接线计划,不新增资源账本采集字段。已接入的 Direct 文件/补丁与 UI 成果按上述真实变化规则记录;统计结果仅表示已观测变化,不能宣称是全量资源操作或项目全部修订次数。 + +### 6.12 preview_ready + +- 触发:宿主对本次预览实例的实际入口执行访问检查成功,且确认检查期间项目版本仍匹配;Web 以真实入口成功响应且内容存在为最低可访问判据,其他引擎需各自真实 ready 信号。 +- 公共字段:status=success;project_id 必填;creative_task_id 与 project_id 相同;run/turn ID 为 null;source 为实际发起模块。 +- properties:preview_source=user / agent / auto_restore;preview_version 为该实例实际服务的项目 revision 字符串;ready_duration_ms 可选。 +- 只启动监听、写 Running、返回 URL 不能直接产生本事件。探测失败或版本漂移不产生 ready;不记录本地 URL、端口或绝对路径。 +- 去重事实键:项目 + 预览实例 ID + preview_version + event_name;轮询与重复回调不重复。同版本真正重开预览可产生新事件,漏斗按任务去重。 +- ready 只证明可访问,不证明 JS 无异常、游戏通关或用户满意。仅策划文档项目不强行产生游戏预览事件。 +- 正式入口覆盖 GUI 用户启动的持续 Web 预览(editor/user),以及 Direct 宿主浏览器验证的临时 Web 预览(direct/agent)。Direct 复用原 run 捕获身份;无新实例的缓存验证不补事件。外部任意 URL、环境自检项目和旧开发/CLI 入口不据 URL 推断本事件;当前无正式 auto_restore 新建实例入口,不伪造来源。 +- 每次实例使用独立内存 ID 和存活标记;GUI 停止/替换、Direct 临时验证结束或取消时失效。异步有界 loopback GET 探测不得延迟或改变预览/验证返回;仅对宿主端口的根入口请求,禁代理与重定向。失败不重试、不弹窗;只记录第一次可信 ready,不等待 JS 或整个浏览器验证成功。 +- 探测前后确认真实入口文件非空,避免空 HTML 被辅助脚本注入后误判;前后项目 revision 和实例须与启动捕获值一致。探测只读已有版本,不推进版本、不持有跨网络请求的项目锁;读取未知则跳过。原始响应、路径、端口不进入事件。 + +### 6.13 project_save + +- 触发:一次面向用户成果的逻辑保存操作已全部成功落盘,包括手动保存、业务自动保存或完整 checkpoint;多文件保存按一次操作记,不按底层 write 次数记。 +- 公共字段:status=success;project_id 必填;creative_task_id 与 project_id 相同;run/turn ID 为 null;source 为实际保存模块。 +- properties:save_source=manual / auto / checkpoint;revision_id 可选,取本次保存结果对应的真实 revision。 +- Agent 会话检查点、审计记录、埋点写入、配置保存、云快照同步不算项目保存。独立素材导出也不自动等于项目保存。 +- 无变化的自动保存不记;用户显式保存成功可记,但不能同时伪造 revision。失败或部分写入不记成功。 +- 无现役调用方的 `write_local_project_file` GUI 命令及其人工文件写入埋点已删除;Agent 仍使用底层文件写入函数。当前 GUI 保存采集来自项目 checkpoint 与 UI 编辑器,不将已删除命令计为采集入口。旧 `delete_local_project_file` 命令已随主分支退役,不恢复这两个入口或扩充其他文件操作采集。 +- GUI 手动项目 checkpoint 完整成功后记 source=manual、save_source=checkpoint,复用真实 checkpoint_id 作为操作身份,revision 不确定时省略;不同于 Agent 会话 checkpoint。其他工具调用该底层函数不自动归为人工。 +- UI 编辑器普通保存与保存并生成是两个逻辑操作。State 的 Saved 结果可记 ui_editor 成果,Unchanged/Conflict 不记成果;普通手动保存 Saved/Unchanged 均可记一次保存,自动保存仅 Saved 记。保存并生成必须等代码生成也成功后才记一次保存,不能在中间 State 成功时提前记;其保存事件省略没有整体提交依据的 revision_id。原生 State 成功事件即使后续生成失败也保留。 +- UI 逻辑保存起点捕获宿主身份和操作 UUID,收尾异步非等待回传;原生校验本 GUI 会话、字段和真实项目再投递。身份捕获、桥接或采集失败不改变业务结果。不增加 UI 业务状态机或保存专用持久化。 +- 去重事实键:项目 + 保存操作 ID + event_name。自动保存不表示用户认可;看板必须按 save_source 区分。 + +## 7. 本地存储、恢复与去重 + +### 7.1 位置与文件格式 + +使用客户端已解析的应用级配置目录下 `analytics/`;正式 Windows 默认基于 `%APPDATA%/world.genarrative.ai-game-creator/`,显式 config-dir 覆盖时随之变化。不放在项目目录或 `.debug` 中。 + +```text +analytics/ + instances// + session.json 本地生命周期标记和恢复所需关联 + batches// + meta.json 最小路由、幂等与清理元数据 + events.jsonl 每行一条事件的明文批次,封存后不可变 +``` + +batch_id 为随机 UUID;每个实例由单个后台写入器负责。批次在内存中组装,在同文件系统的临时批次目录写 meta.json 与 events.jsonl,写入完成后原子发布整个目录。未来上传只处理已发布批次,不读取在写临时目录。账号或目标平台变化时切新批次。 + +已确认时间条件:从当前批次第一条事件进入开始计时,5 分钟到期后由后台写入器封存落盘;后续事件进入新批次,没有事件时不产生空批次。批次达到 500 条或 1 MiB 序列化事件大小时提前封存;该内部上限已在本轮实施评审中采用。单事件超过批次字节上限时静默拒绝,不生成超限批次。正常退出尽力封存,不新增阻塞退出的等待。 + +这些是本地写入参数,与未来 15 分钟上传周期独立。封存前原始事件只存在有界内存,强杀或断电可能损失最近约 5 分钟尚未封存的数据;后台调度或写盘延迟可能扩大窗口,不承诺严格的最大丢数时长。实现时作为内部常量,不增加用户设置界面。 + +session.json 保存会话 owner(含可验证的实例身份)、原用户/平台归属、lifecycle_state(active / closed / incomplete)、未闭合 focus 及必要的幂等事实关联;原子替换。生命周期状态与会话开始、身份/focus 变化、正常退出等实际节点一起由后台写入,不设周期检查点。 + +下次启动识别旧实例退出后,只将符合第 6.3 节条件的 active 会话改为 incomplete;closed 和 incomplete 保持不变。可以保存本地 incomplete_detected_at 表示发现时间,它不是退出时间,不进入公共事件字段。记录缺失或损坏时不猜测重建完整会话。正常退出标记和事件均为尽力持久化,缺失可能来自写盘失败,不能据此确定为崩溃。 + +session.json 是本地恢复元数据,不是待上传事件;事件文件不能代替其中的实例存活身份和生命周期标记。用户下次启动前没有机会作出的标记,不视为已经完成。 + +### 7.2 去重与重放 + +- 第 6 节的事实键是本地逻辑幂等依据,不新增到公共 envelope。首次接收事实时分配 event_id;队列、批次及恢复保留同一身份。 +- 普通重放从已有业务操作/任务记录取得关联 ID,不按相同正文去重;相同文本可能是两次合法操作。 +- 幂等关联持久化与写入器串行执行。meta.json 保存批次的 event_id 清单和事实键摘要到 event_id 的映射,不复制事件正文。恢复从已发布批次元数据重建索引;批次成功发布但索引尚未更新时,不能重新生成 UUID 追加同一事实。 +- 无法证明原事件身份时不补造历史事件,保留丢数限制;不为每条埋点给业务事务增加同步磁盘门禁。 +- 重启保留完整已发布批次,清理未发布临时批次。读取时逐行解析并校验事件及元数据一致性;截断、坏行或身份冲突导致的损坏批次隔离并计数,不清空其他批次,也不自动改写事件或重新生成 event_id。 +- meta.json 记录格式版本、批次身份、路由、创建时间、事件数量及幂等关联。事件白名单校验不等于防篡改认证;后续服务端仍须独立鉴权和校验。 +- 正常退出标记缺失只是“未闭合”,不能证明具体退出原因;后续 incomplete 标记也不得被解释为已确定的 crash。 + +### 7.3 容量与生命周期 + +已确认:本地埋点队列及相关索引整体最多 20 MiB、最多保留 7 天。超过 7 天的批次按期清理;总量超过 20 MiB 时,从最旧封存批次开始清理及其专属索引,直到回到上限内。任一条件达到即执行,未上传批次也适用。清理记录丢弃条数;写入器轮转当前批次后仍无法满足上限则丢弃新事件。损坏文件同样计入限额,不无限隔离积压。 + +清理只作用于埋点队列及相关索引,不删除项目、Agent 对话、业务恢复记录或创作成果。清理由后台执行,失败静默,不阻塞正常客户端操作。 + +实例生命周期标记、打开历史索引与批次幂等映射均需有界清理;索引过期后不承诺识别无限久远的重放或首次打开。不可因此将未知 is_first_open 填 true。项目级首次创作提交标记跟随项目业务记录,不随埋点批次保留期清理。 + +容量/保留期清理与上传成功清理独立:前者不表示已入库,后者必须收到主站匹配的整批确认,详见第 13.7 节。任何批次均不保证无限保留至上传成功。 + +### 7.4 数据最小化与文件边界 + +- 本地 events.jsonl 为可直接读取的明文,不承诺文件保密或防用户修改。本阶段不引入加密库、密钥配置或文件加密开关。 +- 事件只包含本方案白名单字段;session.json 与 meta.json 只保存路由、实例身份、生命周期、幂等和清理所需元数据。 +- 不采集 Prompt、对话正文、工具参数/结果、代码、文件正文、Token、Cookie、API Key 或异常堆栈;不因取消加密扩大采集范围。 +- 正式事件写入 analytics 队列,不在普通应用日志、诊断包中重复输出完整事件正文。目录沿用现有应用私有目录权限。 +- 网络传输使用 HTTPS,本地开发仅允许显式配置的 loopback HTTP;由主站验证用户身份与字段。文件不加密不等于取消传输安全或服务端校验,上传实现见第 13 节。 + +## 8. 主站入库的事件与传输合同 + +### 8.1 保持事件与传输分离 + +本地事件 envelope 保持第 4 至 6 节合同,不添加 uploaded、retry_count、last_upload_error 等会随传输变化的业务字段。批次目标、发送进度与确认信息留在传输元数据。 + +批量请求固定包含 schema_version(整数 1)、batch_id(批次 UUID)、destination_origin(规范平台 origin)、user_id(真实用户 ID 字符串)、events(从 JSONL 解析得到的事件对象数组)。本地匿名事件仍可保留 null,但本次上传不接收匿名批次。全批事件用户必须一致;本地路由只作发送提示,不能作为服务端归属的唯一证据。 + +客户端通过 HTTPS 上传 JSON 批次,传输体类型为 application/json;保持各事件的原 ID、时间和字段值。具体接口、物理表与本地开发例外以第 13.3 至 13.4 节为准。 + +保持整批确认语义:服务端只有在全批事件已可靠保存,或按 event_id 去重确认内容相同时,才返回 `acknowledged_batch_ids`。客户端核对预期主站、成功 envelope、批次 ID 与事件数均匹配本次请求后,删除对应整个批次目录。 + +本次使用单批原子事务,任一事件冲突导致整批回滚且不确认;客户端保留原批次并在下个周期重发,由服务端按 event_id 去重。相同 event_id 不同内容为冲突,不能覆盖原记录或谎报确认。 + +本版不实现逐事件确认后的部分文件重写。永久无效批次的拒收/过期清理不得记为上传成功,也不能因为 HTTP 200、收到字节或仅解析成功就删除本地数据。 + +### 8.2 主站接收的最低语义 + +- 按 schema_version + event_name 校验字段类型、必填项、枚举、事件与 status 的组合;properties 不作为任意 JSON 垃圾桶。 +- 任务相关事件要求 creative_task_id == project_id;项目目标首次提交只能按已确认的项目首次提交事实记录,不能在接收端把每个新用户的第一次消息再算成新目标。 +- 限制请求体积与事件数量,校验 JSON 格式、批次身份和字段版本;解析或校验失败不确认该批次。请求鉴权和 HTTPS 独立于本地文件存储格式。 +- user_id 与鉴权主体必须一致;项目 ID 是客户端本地项目的关联标识,不因此赋予主站项目权限。 +- event_id 是全局唯一去重键。导入时保留原 ID、发生时间、关联字段和客户端版本,不重生成事件身份。 +- 服务端单独生成 received_at,用于观察延迟;不覆盖 event_time。 +- 不要求会话、任务、run 与 revision 按顺序到达,不因父事件丢失或批次乱序拒绝所有子事件;关联不完整需可识别。 +- 查询维度支持 user_id、project_id、creative_task_id、agent_run_id、event_name、event_time 和 client_version。主站独立事件表、索引与后台查询以第 13 节为准,不进入现有主站 tracking 聚合链路。 +- 本地匿名事件、未知平台、未知 schema 版本不能静默改写归属或格式后入库。 +- 每 15 分钟触发后台上传、同一应用数据目录同时最多一个上传轮次;成功清理、失败静默、不阻塞退出。重试策略、请求上限和超时以第 13.6 节为准。 + +### 8.3 可用指标的限制 + +- 匿名事件不纳入按用户的留存;稳定用户也要等主站接收链路验证后才能出正式留存。 +- 创作目标数就是项目目标数,不是消息数或执行次数;目标提交漏斗按有 creative_task_submit 的项目去重。旧项目缺失首次提交事件时不回填,应明确其不在该漏斗 cohort 中。新项目首条记录表示首次成功采集的真实受理,不能声称其时间和用户一定等于绝对首次操作;此前丢失的候选可能来自更早时间或其他用户。 +- 同目标可能跨天、跨会话、跨账号并经历许多 run。回访创作可由后续 run、revision、project_open 观察,不能只用首次 creative_task_submit 判断用户是否继续创作;每会话目标首次提交数不再代表每会话交互次数。 +- 人工修改、预览和保存归入相同项目目标,但不能据此宣传为 Agent 导致的成果;run 的 output_change_detected 仍需要本次执行的真实变化证据。 +- Game Agent 与 Design Agent 的预览适用性不同;不能把所有策划任务算入“游戏预览失败”的分母。 +- 策划成果按成功持久化的阶段推进记录为 project_revision_created,可作为策划成果次数统计;它不证明文档内容改变,也不等于某次 run 产生文件变化。按 source=design_agent 与其他成果来源区分解释,不能混称代码或文件有效变化率。 +- 没有独立策划进度、审批或澄清状态字段;阶段推进记录不能推导完整审批次数或精确阶段耗时,重开旧项目不补历史成果。 +- 自动保存、checkpoint 与手动保存分开解释;focus 仅为前台时长。 +- 只采集创建成功事件无法计算创建成功率;不采 task_type 就不能按任务类型分组;不能拿 agent_type 冒充 task_type。 +- 取消、崩溃与未闭合 run 未纳入失败事件,本版完成率是已知终态样本的完成率,不是所有提交的完成率。 + +## 9. 合规事件示例 + +以下是字段形状示例,ID、版本和时间均为示例值,生产必须从对应事实取得。 + +```json +{ + "schema_version": 1, + "event_id": "708cc064-e1ad-46d1-a26d-181432eef8aa", + "event_name": "agent_run_completed", + "event_time": "2026-09-21T10:30:00.000Z", + "user_id": "123", + "editor_session_id": "a5d5e098-e515-4b28-a27a-6018d47b55dd", + "project_id": "gameagent-example-project", + "creative_task_id": "gameagent-example-project", + "agent_run_id": "36c70186-93c7-4e2d-ad07-80d6b91a1371", + "agent_turn_id": null, + "status": "success", + "error_code": null, + "source": "design_agent", + "client_version": "0.1.0", + "properties": { + "agent_type": "design_agent", + "run_source": "user_submit", + "duration_ms": 32000, + "retry_index": 0, + "output_change_detected": null, + "end_reason": "waiting_for_user" + } +} +``` + +该例表示:本次策划执行正常停在等待用户澄清,没有已记录的阶段推进且文件变化未知;不表示整个任务完成,不记录 revision_id。 + +## 10. 实施拆分与验收依据 + +技术负责人已授权按计划落地;以下为实施里程碑边界。合同与本地队列、会话窗口与项目接入、策划阶段推进成果事件、首次提交、两类 Agent run、Direct 宿主文件/补丁成果、checkpoint 与 UI 保存,以及正式 Web 预览 ready 均已定向验收,并完成下述同一宿主组件链路的关联验证。全部资源操作的逐项接入不是本期完成条件。 + +| 里程碑 | 范围 | 退出判据 | +| --- | --- | --- | +| A 数据合同与本地队列 | 强类型事件、捕获身份、JSONL 批次、有界异步写入与恢复、静默失败 | 字段校验、JSONL 读取、跨账号、不阻塞、损坏隔离、容量与幂等测试通过 | +| B 会话、窗口与项目 | start/end/focus/create/open,以及下次启动的本地 incomplete 标记 | 多窗口、重载、最小化、正常退出、旧实例存活识别、异常未闭合、项目重复打开测试与桌面 smoke | +| C 两类 Agent 与成果链路 | submit/run、策划阶段推进成果、已有真实 revision、preview/save | 成功失败与等待、阶段实际推进且持久化成功与幂等、重试关联、无变化、版本漂移、真实访问与保存边界全部可核对;不新建策划文件 revision 机制 | +| 当前上传阶段 | 上传主站、确认后清理与后台查询 | 按第 13 节及配套里程碑实施,尚待完成整体验收 | + +实施前为选定里程碑生成单独实现计划,前一个里程碑评审/验收后再推进下一项。 + +最小验收矩阵: + +| 场景 | 必须成立的结果 | +| --- | --- | +| 正常完整创作 | 读取本地 JSONL 批次得到原方案完整链路;事件 ID 各自唯一,关联 ID 同语义一致 | +| 策划澄清/审批/继续 | 同一 task、多次 run;等待不误报失败,不重复 task_submit | +| 策划审批通过并推进阶段 | 目标阶段成功持久化后产生一条 revision;ID 为 design::,来源与 change_kind 按第 6.11 节固定 | +| 策划项目 5 分钟内打开又关闭 | 不补历史阶段成果;期间新产生的阶段推进进入应用队列,不随项目关闭消失 | +| 策划阶段重复回调与阶段内修改 | 同策划会话同目标阶段幂等;阶段内任意文件修改、审批拒绝、无阶段变化均不单独生成成果事件 | +| 策划阶段持久化失败或跨账号完成 | 保存失败不记成果;异步结果保留操作开始时项目与用户身份,不绑定到当前其他项目或其他用户 | +| 项目重开、改名、移动、切账号及策划转开发 | project_id 不变时 creative_task_id 恒定且等于 project_id;首次提交不因批次删除再产生 | +| 不同项目与旧项目首次观测 | 不同 project_id 对应不同目标;旧项目不补造历史首次提交,后续事件仍可关联目标 | +| 自动请求重试/用户重试 | 前者原 run,后者新 run;retry_index 口径一致 | +| 同请求重放/双回调 | 同事实不重复;故意重复相同文本的新操作不被误去重 | +| 纯聊天/相同内容保存 | 不生成有效 revision;output_change_detected 不误填 true | +| 失败前已有文件变化 | 可同时有 revision 和 run_failed,不因失败隐藏真实变更 | +| URL 返回但入口失败 | 没有 preview_ready | +| 保存失败/部分提交 | 没有 project_save success | +| A 发起后切 B | A 在途结果不归 B,B 的新操作归 B;平台分区不串 | +| 匿名后登录 | 历史匿名事件不回填用户;focus 归属正确切段 | +| 多窗口/最小化/重载 | 同实例不重复 session_start,前台并集不重计 | +| 强杀与下次启动 | 确认旧实例退出且旧会话未闭合后标记 incomplete;不伪造结束时间、run 失败、完整前台时长或 timeout 事件 | +| 旧实例仍运行、身份不确定或 PID 复用 | 不误标存活或归属不明的旧会话;再次启动不重复改变已确定的 incomplete 状态 | +| 队列满/只读目录/磁盘失败 | 正常创建、对话、保存仍继续,无弹窗;内部可观察丢弃计数 | +| 批次发布中断与重启 | 保留完整已发布事件批次,未发布临时目录可清理;不重新生成已发布事件 ID | +| JSONL 截断、坏行或身份冲突 | 损坏批次隔离并计数,不改写事实、不清空其他批次、不阻塞业务 | +| 数据最小化 | 正式事件和元数据符合白名单,日志不重复完整事件;无 Prompt、凭据或工具正文等禁止字段 | +| 本阶段运行 | 不发起埋点上传或外部 HTTP;预览仅允许第 6.12 节的宿主 loopback 可访问性检查。不创建 15 分钟上传定时器或周期会话检查点,不补发 timeout,不删除“假确认”数据;本地批次封存定时不受影响 | + +主要代码核查入口(相对仓库根目录): + +- 生命周期与配置:`apps/ai-game-creator-shell/src-tauri/src/main.rs`、`config.rs`、`platform_session.rs`。 +- 项目创建与打开:`apps/ai-game-creator-shell/src-tauri/src/commands.rs`、`src/features/app-shell/useHomeProjectCreation.ts`;离开登记由 `WorkspaceLauncher.tsx` 保持。 +- Direct 前端尝试与终态确认:`apps/ai-game-creator-shell/src/view/project-development/chat/controller/useDirectProjectChatController.ts`;沿用 `services/clientAnalytics.ts` 冻结账号代次、每次原生重试生成 attempt ID、只确认最后一次尝试。不在已退役的 App 聊天状态链恢复接线。 +- Direct 执行与审计:`apps/ai-game-creator-shell/src-tauri/src/agent/direct_runtime/user_input.rs`、`agent/direct_runtime/mod.rs`、`agent/direct_codex_audit.rs`。 +- Design 执行与持久化:`apps/ai-game-creator-shell/src-tauri/src/agent/design_runtime.rs`、`agent/runtime_protocol/design_session.rs`、`agent/design_tools.rs`。 +- revision:`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/project_gates.rs`,结合各实际写入调用方。 +- 预览与保存:`apps/ai-game-creator-shell/src-tauri/src/preview.rs`、`ui_editor/persistence.rs`、`project/checkpoint.rs`。 + +上述为定位线索,不表示这些函数已经完成埋点接入;正式实现必须再次核对当时源码。 + +## 11. 需要评审的口径与原需求差异 + +| 项目 | 本草案建议 | 未确认时的限制 | +| --- | --- | --- | +| 目标边界(已确认) | 用户已确认一个项目就是一个目标;方案据此令 creative_task_id=project_id | 不再需要消息意图分类或新增目标选择交互 | +| creative_task_submit 次数(实施采用) | 新建项目每个目标首次成功采集的真实受理一次,之后通过 run 表达继续执行 | 属于本地观测口径;不能证明绝对首次时间或用户,旧项目不得补历史提交 | +| 异常会话处理(已确认) | 下次启动确认旧实例已退出且未正常结束,标记本地 incomplete;本版不采集 session_timeout | 无周期检查点、无超时阈值、无补造退出/前台时长;未再次启动则保持未闭合 | +| 等待用户(已确认) | completed + end_reason,后续继续为新 run | run 完成不是任务完成 | +| 取消与崩溃 run(已确认) | 本版不映射到失败事件 | 成功率仅覆盖已知正常/失败终态 | +| is_first_open | 本安装当前账号可观察范围,未知为 null | 不能声称全平台首次打开 | +| output_change_detected / duration_ms | 证据不足允许 null | 原方案未明确可空性,不能用 false/0 伪造确定值 | +| 策划阶段成果(已确认) | 审批通过并实际进入下一阶段,成功持久化后复用 project_revision_created;同会话同目标阶段幂等 | 不采独立进度与审批字段;不严格校验文档版本/差异;阶段内修改不逐次采集,重开不补历史 | +| revision | Game Agent 与其他已有正式 revision 路径按真实变化采集;策划使用 design:: 阶段事实标识 | 策划标识不是文件版本,不据此伪造 run 文件变化;其他来源剔除纯元数据同步 | +| 本地保留(已确认) | 最多 7 天或总量 20 MiB,任一条件达到即清理;超量先清最旧批次 | 未上传数据也会清理,不保证保留至上传成功;不删除项目及 Agent 业务数据 | +| 本地封存时间(已确认) | 当前批次首条事件进入后 5 分钟封存;无事件不生成空批次 | 与 15 分钟上传独立;强退可能丢失尚未落盘的一批事件 | +| 本地批量上限(实施采用) | 达到 500 条或 1 MiB 序列化事件大小提前封存;超大单事件静默拒绝 | 内部常量,与 5 分钟条件并行;不新增用户设置 | +| 字段补充 | schema_version、focus_interval_id、run end_reason;incomplete 仅是本地生命周期状态 | 需与后续接收端按同版合同实现,不任意扩展 properties,不将本地状态冒充产品事件 | +| 本地格式(已确认) | 本阶段不加密,使用明文 JSONL 批次 | 无密钥前置要求;原字段白名单与数据最小化要求不变 | +| 未来确认删除 | 整批确认、整批删除,失败重发原事件批次 | 服务端仍需逐事件去重;暂不增加逐事件部分重写机制 | + +## 12. 实施与验证状态 + +2026-09-22 Direct 采集锁隔离验证:原生 `analytics` 定向测试 60 项通过、1 项既有跳过,`agent::direct_execution::tests` 24 项全部通过(两组有 1 项重叠)。新增线程用例持续占用业务锁,验证采集身份设置、成果记录、上下文与最新成果读取在释放业务锁前完成,并实际读回原用户的成果事件;另验证恢复不补造历史成果编号、旧账本缺少元数据不套用当前用户。独立代码复核及格式、编码、文档索引、diff 检查通过。分页 DTO 仅修正注释,查询行为不变;退出机制未改,未运行完整 GUI/Provider 联调。 + +2026-09-22 新项目资格有限恢复验证:原生 `analytics` 定向测试 59 项通过、1 项既有跳过;覆盖创建时无埋点上下文、创建通知队列拒绝、独立锁竞争和临时文件系统故障后的真实受理恢复,以及资格成功落盘后不重授、进程内待办容量限制。既有损坏/备份/身份不符、跨 writer 去重测试继续通过。命令配置、Rust 格式、编码、文档索引与 diff 检查通过;独立代码复核确认业务线程不执行资格文件 I/O,内存锁不覆盖后台 I/O。未执行完整 GUI/Provider 联调或生产发布。 + +已做:原产品方案逐项对照;核对现役 Direct/Design 持久化、项目创建、revision、预览、UI 保存与 checkpoint 的源码入口。本文新增合同和参数均以草案标识,不作为已经上线的事实。 + +合同与本地队列、会话窗口与项目接入、策划阶段推进成果事件、首次提交、两类 Agent run、Direct 宿主文件/补丁成果、checkpoint 与 UI 保存,以及正式 Web 预览 ready 已完成实现、独立审查和定向验收。最终按原始需求和已确认口径核对全部 12 类事件入口,并补齐同一 writer、会话、项目和目标的宿主组件集成链路验证,本期本地采集验收通过。资源操作全面接线计划因超出原始需求撤销,未进入资源实现,不作为必做待办保留。本期无主站 API 或数据库行为;验收不表示已经提交、发布或上线。 + +入口核查以正式 Direct/Design GUI 可达链路为准。`src/main.tsx` 的旧 agent-chat/supervisor-chat 入口受 DEV 限制,正式 Direct 项目跳过旧 Runtime 恢复;旧 Runtime 的 file_ops/project_ops/ui.workflow 仍由开发入口和 CLI 使用,但不因这些函数存在就扩张本期正式 GUI 采集范围。通用画布导入/同步也需核实正式面板可达性,不能仅凭 App 内保留命令分支认定已经接入或必须接入。 + +| 已实现合同 | 验证证据 | 结果与边界 | +| --- | --- | --- | +| 基础创作链路的同一身份与关联 ID | 增强既有 `analytics_real_file_write_preserves_original_identity_and_failed_run_revision`;最终 `cargo +stable test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell analytics -- --test-threads=1` | 51 项全部通过,独立审查通过。同一 writer 串联会话/前台、创建/打开、首次受理、真实 Direct 文件事务、失败 run 保留成果、真实宿主 HTTP ready、checkpoint 保存和退出;核对事件唯一、必需 ID 非空且一致、run 成果版本、预览实际版本、focus 配对与真实 checkpoint 事实键。创建投递使用测试辅助入口,run 结果和构建产物由夹具提供;不等同于完整 GUI、Provider 或构建器端到端验证 | +| 最终前端与静态检查 | `clientAnalytics.test.tsx`、`directRunAnalytics.test.ts`、`uiEditorPage.test.ts`;shell `tsc --noEmit`、Rust fmt、编码/索引/diff | 前端 46 项全部通过,其余检查通过。最终收尾只增强测试和 `cfg(test)` 辅助,无产品逻辑变更,生产编译沿用下述合并后成功证据 | +| 12 类事件合同、必填 nullable、身份/来源/状态组合与安全整数 | `analytics::contract::tests` 的 5 项测试 | 通过;已删除未发布的独立策划快照合同和专属测试 | +| 路由切批、恢复去重、JSONL 原子发布、数量/大小/时间阈值、保留清理及项目目标资格 | `analytics::store::tests` 的 18 项测试 | 通过,使用真实临时目录;包括首次打开三态、跨实例索引回收、损坏项隔离、会话队列与写盘空间预留,以及新增的目标资格四项验证 | +| 非阻塞投递、内存条数与字节上限、真实线程封存 | 公开 writer 入队拒绝和最后 sender 关闭后的文件读回测试 | 通过;不等待业务退出,不保证强退零丢数 | +| 正式客户端模块集成 | `cargo +stable test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell analytics:: -- --test-threads=1` | 32 passed,0 failed;非独立替身 harness | +| 会话一次启动、实际退出、窗口并集、身份切分、迟到打开与重复回执 | `analytics::gui::tests` 的 4 项状态测试及原生接线独立复查 | 通过;纯内存临界区串行更新,启动身份发布与通知同步 | +| 未闭合会话恢复、活动实例保护、损坏/临时元数据回收 | `analytics::session::tests` 的 5 项真实文件锁与目录测试 | 通过;只对已取得旧 owner 锁的实例操作,未知所有权保持原样 | +| 创建成功、已有项目不误计、实际打开来源与卸载保护 | 前端 clientAnalytics/homeWebPreflight/useTemplateLibrary 共 27 项测试与 shell TypeScript 检查;同一 Rust 测试可执行文件的自动创建 3 项、初始化 2 项及认证会话 11 项回归 | 全部通过;内部 hydration 不计第二次打开,未宣称覆盖不存在的恢复/文件关联入口 | +| 生产 Tauri 入口编译与真实生命周期 | `cargo +stable build --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell`;临时配置目录启动真实客户端后正常关闭并读回 | 构建通过;start/end 各一条,end_reason=user_exit,单调时长 32297 ms,session.json 为 closed,未遗留该配置的子进程 | +| 格式与文档 | `cargo +stable fmt --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --all -- --check`,文档索引、编码、差异检查 | 通过 | +| 策划阶段成果、审批幂等及失败边界 | 正式测试可执行文件 `agent::design_runtime::tests::` 19 项;`design_session` 筛选 3 项(其中 1 项重叠) | 全部通过;五阶段业务流程配合模拟 Provider,真实文件及 writer 读回 5 条阶段事件。后续模型失败仍保留一条;跨用户重放仍一条;拒绝与 checkpoint 失败零条。否定断言在同队列哨兵落盘后检查 | +| 策划审批生产入口 | `cargo +stable check --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell`;独立代码及验收审查 | 通过;Tauri 入口在资源加载前冻结身份。未调用外部付费模型;run 的阶段成果关联已由下述最新运行时测试覆盖 | +| 新项目首次观测提交、跨来源与批次清理不重复 | 新增四项真实 writer/项目测试,包含在上述 32 项中 | 通过;独立锁竞争后允许后续真实受理消费剩余资格。跨账号和双 writer 最多一条,未知/损坏/备用文件不重建,队列条数与字节拒绝不执行项目 I/O | +| 策划受理与失败、重放、审批拒绝和 checkpoint 失败 | 同一正式测试可执行文件 `agent::design_runtime::tests::` 22 项 | 通过;模拟 Provider 走真实运行时和文件队列。模型失败仍计已受理提交;旧命令重放不消费新出现资格,无效输入不消费后续用户资格 | +| Direct 新受理、账本重放与旧预算迁移 | 同一测试可执行文件 `agent::direct_execution::tests::` 21 项,生产入口独立代码审查及 `cargo +stable check` | 通过;新增的纯内存新受理标志不改变账本格式,恢复/迁移为 false,真实持久受理后才投递。未调用外部 Direct Provider 做完整创作 smoke | +| 六类创建入口与现有建项行为 | 自动创建 3 项、初始化 2 项、模板创建/缺失拒绝 2 项、Godot manifest/import 17 项;生产 check、格式检查 | 24 项通过;六个创建调用传实际项目目录,已有 manifest 不重授资格。当前仓库模板正文无 `.agent`;复制时保留同一 project_id 的项目仍按同一目标处理 | +| 两类 Agent 的运行身份、重试序号、恢复与终态去重 | 最新正式测试可执行文件 analytics 38 项、Design Runtime 24 项、Direct execution 23 项、Direct 终态分类 2 项 | 共 87 项通过;真实 writer/项目文件与模拟 Provider 验证。Design 等待正常完成、结构化失败、显式重试和阶段成果关联;恢复保留原身份、耗时未知;Direct 未完合同和取消不误记成功 | +| Direct 自动认证刷新后的最终尝试确认 | 上述 analytics 中 3 项候选测试;前端 directRunAnalytics 5 项及 clientAnalytics 11 项;shell `tsc --noEmit` | 通过;首次失败与最终成功同时暂存时只确认最终成功;未知尝试、discard、重复确认、16 项/1 MiB 上限和会话校验覆盖。前端 UUID 失败不回退、代次变化丢弃、桥接失败不阻塞或覆盖业务结果。独立代码审查通过 | +| Agent 运行结果生产入口与验收 | 最新 `cargo +stable check --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell`;fmt、编码、索引、差异检查;独立条款验收 | 全部通过;生产 check 有既存告警,无编译错误。未新增上传、加密、网络请求或业务埋点 I/O 等待;运行结果临时计划已融合删除 | +| Direct 宿主文件与补丁成果、原身份及 run 成果关联 | `cargo +stable test ... analytics -- --test-threads=1` 43 项;同正式测试可执行文件 `agent::direct_patch::tests::` 6 项、`bridge_write_file` 4 项、`queued_write_rechecks_the_original_lease_after_project_lock_release` 1 项、`agent::direct_execution::tests::` 23 项 | 去重 76 项全部通过。真实写许可/文件/JSONL验证新内容记成果、同内容不记、原用户 A 归属;真实 bundled patch 两文件成功仅一条/count=2,随后部分失败不覆盖成果。失败 run 的关联为 writer 集成测试加生产接线审查,未宣称完整 Provider 失败流程;两个成功版本取最新经代码审查 | +| Direct 成果生产编译、故障隔离及条款验收 | 最新生产 `cargo +stable check`、fmt/编码/索引/diff及独立代码与条款审查 | 全部通过;读取未知/队列拒绝不改变工具结果,不新增业务版本或同步埋点写盘。测试夹具已补真实合同与 config 父目录;Windows patch smoke 将既有 `target/debug/coding-agent` 完整复制至测试 exe 相邻的 `target/debug/deps/coding-agent`,使用校验通过的 0.155.1 执行器,未放宽版本校验或更改全局 Codex。成果采集临时计划已融合删除 | +| checkpoint 与原生 UI 成果 | 最新 `cargo +stable test ... analytics -- --test-threads=1` 45 项;同正式测试二进制 UI persistence 14 项、bridge_write_file 4 项 | 此前合计 63 项通过;其中已退役的 GUI 文件写入/删除测试不再作为现役入口证据。当前保留完整及失败 checkpoint、UI Saved/Unchanged/Conflict/错误和原用户归属验证。checkpoint 失败夹具使用真实项目中被普通文件占用的检查点目录,不把业务允许初始化的缺失目录当作失败 | +| UI 逻辑保存及故障隔离 | 前端 clientAnalytics/uiEditorPage 两文件 41 项、shell `tsc --noEmit`,生产 `cargo +stable check`、fmt/编码/索引/diff,独立代码审查及条款验收 | 全部通过;普通手动保存、自动保存、组合生成成功/失败、重复回调、桥接失败与冻结身份已验证。保存不等待埋点;没有更改业务 DTO 或上传/加密。临时计划已融合删除;未执行 GUI 交互或前端到原生 UI 保存命令的完整跨层 smoke | +| 正式 Web 预览实际 ready、实例寿命与身份 | 最新正式测试二进制 analytics 51 项(含新增六项真实 loopback/JSONL 测试)、既有本地预览及 registry/lifecycle 21 项、Direct validation 6 项 | 合计 78 项通过。覆盖真实 GUI helper 自动探测、user/agent 来源、同版本新实例、原用户、空/缺失入口、HTTP失败/空响应、请求期间版本漂移、停止/替换/取消。一个旧 Runtime 模拟模型测试在并发编译时触发原有 2 秒等待超时,编译结束后单独 exact 复跑通过,未修改断言 | +| 预览前端来源、生产编译及条款验收 | 合并 master 后 `appSurface.test.ts --threads=false -t 'preview\|预览\|play request\|run local\|local game'` 104 项、shell tsc、生产 `cargo +stable check`、fmt/编码/索引/diff及独立验收 | 全部通过;旧草稿自动预览不传 user,不据任意外部 URL 推断项目成果。Direct 原 run capture 与临时 guard 经独立接线审查;实测 host HTTP 可访问性不等价于完整 Chrome 双端验证。无上传、外部探测或新增业务版本;临时计划已融合删除 | + +环境限制:本机固定 1.98.1 工具链缺可用 cargo,实际显式使用 stable(1.96.0)完成编译测试,未更改仓库固定版本。真实 GUI smoke 使用隐藏窗口,只证明启动与正常退出,不证明实际焦点操作;窗口并集、最小化和重复通知以状态测试验证,锁屏/休眠为已知观测限制。真实付费 Provider 和完整 GUI run smoke 未执行,Runtime 模拟 Provider 与前端 helper 测试不等价于真实模型验证。Direct 未完成交付合同的 guard 释放可能将账本中断,本版不改变其业务恢复行为,不承诺所有认证刷新都能继续生成;埋点不会将此类中断报告记为成功。人工和 UI 保存已有真实业务函数/文件/JSONL及前端 hook 验证,尚无完整 GUI 跨层操作 smoke;预览已有真实宿主 HTTP 和 JSONL 验证,未运行完整 Chrome 双端验证。 + +## 13. 上传、入库、成功清理与后台查询工程方案 + +### 13.1 交付目标与边界 + +状态:implemented / verified;技术负责人已授权开工,本地隔离环境验收完成,证据与限制见 §13.11,未核验或变更线上 schema。客户端定期上传已有封存批次,主站可靠保存并确认后清理对应本地副本,管理员能够查询真实入库的事件明细。 + +- 必须项:一张私有持久表、批量接收 API、后台上传器、确认后删除、一个后台明细栏目、身份和幂等验证。 +- 风险项:服务端已提交但响应丢失、跨账号/平台串传、保留清理与上传并发、删除导致观测资格重置、查询截断冒充最新数据。 +- 可选项:本版无。暂不做加密、匿名接收、聚合表、统计看板、Excel 导出、后台编辑/删除、立即重试或新增采集事件。 +- 采集仍为现有 12 类事件;不上传对话、提示词、文件内容、策划快照、本地路径、Token、项目资格账本或会话 incomplete 元数据。 +- 5 分钟 / 500 条 / 1 MiB 封存和 7 天 / 20 MiB 本地保留合同继续生效。上传成功清理与保留上限清理是两种独立原因,不能把后者统计为上传成功。 + +### 13.2 现状与接入边界 + +现有 `tracking_event` 保存主站的 event_key、scope、用户及 metadata_json,`tracking_daily_stat` 保存每日聚合;后台已有 `#tracking` 和 `#tables`。本方案新增 `agc_tracking_event`,不改主站埋点表、不进入个人任务奖励或主站每日统计链路。 + +正式路径为:客户端 Rust 上传器 → api-server 用户鉴权与 DTO 校验 → module-* 中的事件规则 → spacetime-client typed facade → spacetime-module 原子事务。后台通过管理端鉴权 BFF 和同一 facade 读取私有表,浏览器不直连数据库。 + +主站接受的是客户端观测数据,不因此确认项目所有权、成果真实性或奖励资格。允许父事件缺失、乱序、迟到,不给本地项目 ID 添加主站项目外键约束。 + +### 13.3 数据表与字段映射 + +新增普通私有持久表 `agc_tracking_event`,不是仅供实时订阅的 SpacetimeDB event table。一条事件一行。 + +| 字段 | 数据库类型 | 来源与约束 | +| --- | --- | --- | +| event_id | String,主键 | 原事件 UUID;唯一去重键 | +| schema_version | u32 | 原事件版本,首版只接收 1 | +| event_name | String | 原事件名,现有 12 类白名单 | +| event_time | Timestamp | 原 UTC 毫秒时间,无损转换,不用接收时间替代 | +| user_id | String | 本版只接收非匿名用户;与鉴权主体及批次 user_id 相同 | +| editor_session_id | String | 原编辑器会话 ID | +| project_id | Option | 原值,保留 null | +| creative_task_id | Option | 原值,按事件合同与 project_id 一致 | +| agent_run_id | Option | 原值,保留 null | +| agent_turn_id | Option | 原值,保留 null | +| status | Option | 原枚举 success / failed 或 null | +| error_code | Option | 原错误码白名单或 null | +| source | String | 原来源枚举 | +| client_version | String | 原客户端版本 | +| properties_json | String | 按事件类型验证后的专属属性 JSON;不接受任意字段 | +| batch_id | String | 首次接收入库时的批次 UUID;重复事件不改写 | +| received_at | Timestamp | 首次插入事务的 ctx.timestamp;重传不刷新 | + +字段和 nullable 语义以第 4 至 6 节为准,不能用空串或零替代未知。传输 origin 不作为事件新增采集字段或表内分析维度;部署环境由服务端配置及批次 origin 校验隔离。 + +索引:received_at、(user_id, received_at)、(event_name, received_at)。主键承担去重。SpacetimeDB 2.8.3 的索引过滤不支持 Option 项目字段(已由编译核验),项目条件使用上述时间索引候选进行精确筛选,不增加空串哨兵或重复项目字段。其余关联字段先作为受限查询条件,不为了预想报表遍建索引。 + +本版只新增表,同步 migration 注册、架构表目录、生成绑定和 schema 检查;不迁移旧主站埋点,不改动已有表字段。服务端暂不设置自动到期删除;本地 7 天 / 20 MiB 不适用于数据库。数据库容量与后续留存另行评估,不在本次加入自动清库。 + +### 13.4 上传接口与确认合同 + +新增 `POST /api/agc/analytics/batches`,使用现有用户 Bearer 认证与平台会话能力,HTTPS、`Content-Type: application/json`。本地开发仅复用既有显式配置的开发服务地址。该路径不是 external v1,不引入开发者 API Key。 + +请求保持第 8 节合同,snake_case: + +| 字段 | 类型与来源 | +| --- | --- | +| schema_version | 整数 1,上传协议版本 | +| batch_id | 原批次 UUID 字符串 | +| destination_origin | 批次原目标平台 origin | +| user_id | 批次原真实用户 ID 字符串 | +| events | 从原 JSONL 解析的事件对象数组,完整对象示例见第 9 节 | + +- 一次请求只发一个已封存批次,1 至 500 条。事件数据沿用 1 MiB 上限,JSON 请求体上限 2 MiB,容纳数组及 envelope 开销;服务端不依赖 Content-Length 自报大小。 +- 批次与所有事件的 user_id 必须相同且等于鉴权主体;匿名、未知 origin 批次不上传,不补认领到后来登录的账号。 +- destination_origin 必须匹配当前服务部署的可信公开 origin 配置,不使用未经信任的 Host 头作为判据。 +- 接收端配置 `GENARRATIVE_AGC_ANALYTICS_ORIGIN` 为规范 origin(无路径和尾部斜杠):正式站 `https://www.genarrative.world`,测试站 `https://dev.genarrative.world`,本地联调填写客户端实际连接的 loopback origin。未配置/非法配置时接口返回 503,不猜测默认站点;允许 HTTPS 和本地 loopback HTTP。 +- 该变量在 API Server 运行时注入,修改后重启服务;客户端与管理后台无需新增埋点构建变量。配置示例见根目录 `.env.example`(本地默认 `http://127.0.0.1:8082`)、`deploy/env/api-server.env.example`(release,并注明 dev 值)与 `deploy/container/api-server.env.example`(compose 默认宿主机入口 `http://127.0.0.1:18080`)。实际端口、映射或域名变化时同步修改,始终与客户端登录地址一致。 +- 复用现有事件版本、枚举、字段长度与必填 nullable 校验;批内重复 event_id、未知字段或非法事件整批拒绝。 +- 本接口不进入普通成功路由 tracking 映射,不为每次上传另生成主站产品事件。 + +成功响应使用现有 API 成功 envelope,其 payload 为: + +```json +{ + "acknowledged_batch_ids": ["<本次请求的 batch_id>"], + "event_count": 12 +} +``` + +`event_count` 是本次确认的事件总数,包含内容一致的已有事件,不是新增行数。客户端只在成功 envelope、批次 ID 和本次事件数均匹配时删除。HTTP 200 本身不足以证明入库。 + +| 返回 | 意义 | 客户端处理 | +| --- | --- | --- | +| 200 且确认匹配 | 整批已提交或已存在且内容相同 | 删除该批次待上传副本 | +| 400 | 格式、事件合同或 schema 不支持 | 本轮跳过,保留至后续周期或保留清理 | +| 401 / 403 | 凭据失效、用户或 origin 不匹配 | 本轮停止该身份上传,不弹登录窗口、不替换归属 | +| 409 | event_id 已存在但内容不同 | 不覆盖、不确认,保留原批次 | +| 413 | 请求超限 | 不拆分或改写原批次,保留 | +| 429 / 5xx / 网络超时 | 本轮不可确认 | 保留,下周期重试,不立即循环重试 | +| 响应缺字段、ID/数量不符 | 确认无效 | 保留 | + +沿用现有错误 envelope;响应不回显事件正文、凭据或其他用户数据。 + +### 13.5 原子入库与幂等 + +首版单批最多 500 条 / 1 MiB,采用一个原子事务完成,不新增批次回执表或服务端任务队列。 + +1. API 先鉴权并校验完整请求,再通过受信任服务身份调用数据库写路径;普通客户端身份不能直接写表。 +2. 事务核验全批事件。event_id 不存在则插入;已存在时比较原事件全部业务字段,properties 按解析后的结构比较,JSON 对象键顺序不影响等价。 +3. 相同事件视为已接收,保留第一次的 batch_id 和 received_at;事件 ID 相同但用户或任意事件内容不同则冲突,整批回滚。 +4. 只在确认数据库事务已提交后响应。Reducer 如被采用,facade 必须等待其已提交结果,不能将“已发送调用”当作完成。 +5. 服务端已提交但响应丢失、客户端确认后崩溃或本地删除失败,均可用原批次重发;不增加事件行数。 + +batch_id 是传输关联标识,event_id 是持久幂等依据。一张表不提供独立批次审计、批次内容哈希登记或永久批次状态机;本版不承诺这些能力。 + +### 13.6 客户端调度与身份 + +- 从客户端后台上传器启动时计时,每 15 分钟触发一次;首次不立即上传。休眠恢复最多执行一次到期轮次,不补跑错过的全部轮次。运行不足 15 分钟的数据留待后续启动并达到上传周期;退出不强制联网。 +- 每轮串行处理当时已封存且身份匹配的批次,优先旧批次;轮次开始后新封存的批次留待下一轮。 +- 同一应用数据目录通过一个非阻塞上传锁只允许一个实例执行上传轮次;竞争者本轮跳过。不使用长时间文件锁包住正常采集或网络等待。 +- 单请求总超时 30 秒;每轮最多处理 20 批、最多 2 分钟,不重叠执行。下一轮重新扫描;以上均为内部常量,不新增设置界面。 +- 仅使用与批次 user_id、destination_origin 完全一致的当前认证会话。账号或平台切换后不发起旧身份的新请求;已经发出的请求仍绑定原身份,收到有效确认可以清理原批次。 +- Token 只在内存请求中使用,不写入批次、表或日志。复用现有凭据获取能力,不新增埋点专属登录、刷新循环或登录提示。 +- 未登录、匿名、未知平台数据保留到原有保留策略清理;不主动登录所有历史账号来上传。 +- 400/409/413 等单批错误跳过该批继续本轮剩余候选,避免毒批次独占队列;认证错误或暂时服务故障结束本轮。下一周期仍按相同有界规则处理,不无限立即重试。 + +### 13.7 本地成功清理与现有状态边界 + +上传只读取已发布批次的 meta.json 和 events.jsonl,使用现有安全路径、大小、事件清单及一致性校验;不扫描项目内容。不得根据服务端返回字符串直接拼出待删路径,删除目标只能是本次本地选中的批次目录。 + +上传器持有一个有界批次内存副本再执行网络请求,不在网络等待期间占用 writer。保留清理可能先删原目录:发送前已缺失就跳过;发送后已缺失则确认清理视为无事可做。允许既有保留策略丢弃未上传数据,不建立第二套 durable outbox。 + +有效确认后调用本地存储层的批次删除入口,只删除对应目录,并同步/失效化有关批次缓存。删除失败保留,下一轮允许重传。上传异常只增加有界诊断计数,不弹窗、不阻塞 Agent、项目操作或退出。 + +不能删除项目 `.agent/analytics-goal.json`、`.agent/analytics-runs.json`、正式会话、对话或成果。保留会话恢复所需的控制元数据,空实例目录交给既有保留清理。 + +现有 store 的去重索引会随批次清理重建。上传更早删除批次不能重授首次提交资格或重置 run 身份:项目资格/run 账本保持原生命周期。当前实例另保留有界内存中的近期事实及项目观测,分别最多 16,384 项、最多 7 天,超限淘汰最旧项而非停止后续采集,避免最近已确认批次的重复回调重新生成 ID。内存缓存不承诺无限历史去重,不新增永久历史索引,也不从服务器或完整对话回填历史。 + +### 13.8 后台“客户端埋点”栏目 + +新增路由 `#agc-tracking`,显示名“客户端埋点”,与现有主站“埋点数据”并列;复用后台布局、筛选表单、用户引用组件及详情弹窗。owner 按现有规则可访问,member 必须具备新增页签权限 `agc-tracking`,接口同时执行权限校验。 + +新增 `GET /admin/api/agc/tracking-events`,管理端 DTO 沿用 camelCase: + +- 筛选参数:`userId`、`projectId`、`creativeTaskId`、`agentRunId`、`eventName`、`clientVersion`、`startTime`、`endTime`、`cursor`、`limit`。 +- UI 首版展示发生时间范围、用户、项目和事件类型;其他关联筛选可通过详情入口携带,均使用精确匹配,不引入全文搜索。 +- 时间范围按 event_time,起点包含、终点不包含;时间格式为带时区 RFC3339。默认不设时间过滤,默认每页 50 条,最大 200 条。 +- 返回 payload:`entries`、`nextCursor`。条目包括表内字段的 camelCase 映射,`properties` 返回解析后的 JSON 对象;时间转为 UTC 字符串,Option 转 null,不向 UI 暴露 SATS 原始值。 +- 列表按发生时间 event_time 倒序,同时间按 event_id 倒序稳定排序;明确列标题为“入库时间”和“发生时间”,补传的历史事件按实际发生时间归位。 +- cursor 固定入库时间快照上界、最后一行的 (event_time, event_id) 和筛选摘要;切换筛选重置游标,非法游标返回 400。新增数据点击刷新后出现,分页不依赖会随插入漂移的 offset。旧排序游标失效,刷新列表重新查询;不改变存储表及索引。 +- 由数据库查询路径按索引及条件确定排序候选与页边界;若当前 SQL 不支持排序,通过受限 typed procedure 完成。不能任取 LIMIT N 行后排序并宣称为全表最新;实现计划须在现役 2.8.3 上验证此点,不照搬旧页面的截断查询方式。 + +列表列:入库时间、发生时间、用户、事件中文名、项目、来源、结果、客户端版本。空值显示“—”。详情展示全部既有字段与格式化 properties,包括会话/run/批次 ID;不新增编辑或删除按钮。空结果、加载失败、无权限沿用后台现有反馈,移动端表格支持横向滚动。 + +### 13.9 兼容、上线与回退 + +- 本地事件 schema_version 继续为 1,不改写已封存批次;升级后只处理仍在保留范围内且身份匹配的数据,不恢复已过期数据。 +- 发布顺序:新增数据库表/事务 → API 与后台 → 带上传器的客户端。旧客户端继续只写本地,旧批次无须迁移。 +- API 未部署或服务不可用时客户端静默保留并按周期重试;现有本地保留上限仍有效。 +- 回退客户端上传器或接收路由时保留已入库表,不删除正式数据;本地清理只对真实确认发生。没有新增远程开关或复杂灰度框架。 +- 新增事件版本必须显式扩展接收合同,不能靠忽略未知字段兼容。首次接收字段校验必须与客户端合同做对应测试。 + +### 13.10 实施边界与验收 + +技术负责人已授权按本方案开工;里程碑验收证据已融合至 §13.11,完成的临时里程碑规范与实施计划已删除。实现可在正确配置的部署环境使用,不代表已发布上线。 + +实现涉及 analytics 存储/上传器与平台会话、shared-contracts、现有 module-* 领域、spacetime-module 表/事务/migration、spacetime-client facade/绑定、api-server 用户及后台路由、admin-web 页面/权限。不更改 Game/Design Agent 埋点触发逻辑。 + +| 验收项 | 必须取得的证据 | +| --- | --- | +| 正常闭环 | 真实本地批次 → 测试主站数据库 → 确认 → 本地删除 → 后台可查相同 event_id | +| 原子与去重 | 首传、原批重传不增行;任一冲突导致本次新行全部不落库;确认丢失后重传成功 | +| 身份 | A 批次不能用 B 凭据或另一平台发送;匿名不认领;后台未授权读被拒绝 | +| 静默失败 | 断网、超时、非成功/无效确认时保留;业务调用和退出不等待上传;下一周期可恢复 | +| 清理边界 | 删除失败可重传;保留清理并发不误删其他批次;首次提交资格/run 身份保持;现有 7 天/20 MiB 不变 | +| 调度 | 15 分钟、单目录互斥、有界轮次、休眠不积压补跑、毒批次不阻塞本轮其他数据 | +| 后台查询 | 筛选、null/时间/属性显示、跨页稳定顺序及新数据刷新;数据量超过一页,不用截断结果冒充全量 | +| 回归 | 现有事件合同、store/goal/run 定向测试及主站 tracking 不受影响 | +| 工程检查 | schema 生成/检查、相关 Rust 测试与编译、后台类型检查、文档索引、编码和 diff 检查 | + +运行时 smoke 必须包含真实 SpacetimeDB 提交及后台页面;mock 请求成功不算完成入库验收。不需要为本轮重新调用付费模型或扩大 Agent 创作测试。 + +本版实施口径为:只接收已登录用户、一张事件表、原子整批提交、首轮等待 15 分钟、30 秒请求超时、20 批/2 分钟轮次预算、失败下周期重试、后台按发生时间倒序分页、服务端暂不自动过期。已确认的采集范围、上传周期、静默非阻塞和成功删除原则不变。 + +### 13.11 实现与验证记录(2026-09-21) + +实现沿用既有 12 类事件和采集入口。新增 `analytics/upload.rs`、`agc_tracking_event` 私有持久表、批量接收与后台查询接口,以及后台“客户端埋点”页;未部署生产。 + +| 验证 | 结果与边界 | +| --- | --- | +| 客户端 | `cargo +stable test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell analytics -- --test-threads=1`:56 项通过,真实服务联调用例默认 ignored;普通客户端程序同时编译通过。覆盖调度、锁、身份匹配、错误确认/503 保留、成功清理、近期事实去重和既有 store/goal/run 回归 | +| 领域与 API | module-runtime `agc_analytics` 4 项、api-server `agc_analytics` 3 项和后台权限 2 项通过;覆盖 12 类事件合同、非法字段、身份/origin、请求大小和后台权限 | +| 真实数据库 | `scripts/agc-analytics-smoke.mjs` 在独立临时 SpacetimeDB 2.8.3 上使用最终源码 WASM 通过首传、重传、属性键序等价、冲突整批回滚、保留首次入库值、用户筛选、稳定分页、分页期间插入与刷新、UTC/null 和服务身份限制 | +| 同一事件完整链路 | 手工执行 ignored `app::tests::agc_analytics_real_database_http_roundtrip`:真实客户端 Store 封存 JSONL → 生产上传器 → Axum HTTP → 真实数据库事务 → 确认后删除 → 后台接口查到相同 event_id/batch_id;同一事件重传只保留一行。用户认证使用测试夹具,未通过完整客户端 GUI 登录 | +| 后台静态验证 | 28 项定向测试、admin-web 类型检查与作用域 ESLint 通过 | +| 后台运行时 | 已编译 API 以临时 test 配置连接同一隔离数据库,`/healthz` 返回 200;真实浏览器登录、进入客户端埋点页、查看上传器生成记录、用户筛选及详情成功,时间、null 与 properties 显示正常。分页及刷新由真实数据库多页测试和页面定向测试验证 | +| 数据契约 | migration 注册、表目录与生成绑定已同步;schema 检查通过 145 张表,DDD 边界检查通过;未改变既有表字段 | + +编码、文档索引、作用域 Rust 格式与 diff 检查通过。`npm run dev:api-server` 编译通过,但本机启动脚本以既有短信配置覆盖测试环境变量,因缺少阿里云短信凭据而退出;页面 smoke 改为直接启动同一已编译 API,使用进程级 mock 认证/test 配置,未改本地配置文件。未验证完整客户端 GUI 登录、15 分钟墙钟等待、操作系统休眠及生产部署;调度周期与恢复通过定向状态测试验证。本轮不调用付费 Provider,不扩大 Agent 创作验收。 diff --git a/docs/technical/【需求来源】GameAgent埋点设计原始方案-2026-09-05.md b/docs/technical/【需求来源】GameAgent埋点设计原始方案-2026-09-05.md new file mode 100644 index 000000000..135e64bbc --- /dev/null +++ b/docs/technical/【需求来源】GameAgent埋点设计原始方案-2026-09-05.md @@ -0,0 +1,431 @@ +> 文档状态:`historical`(原始需求存档,仅用于来源追溯,不作为当前实施依据) + +归档日期:2026-09-21。下方保留原始正文;其中目标边界、异常会话、上传阶段等口径已由后续决策调整。当前合同见[客户端本地埋点与主站入库契约](./【技术方案】客户端本地埋点与主站入库契约-2026-09-21.md)。 + +# Game Agent 埋点设计方案|早期地基版 v1.0 + +状态:正式方案;待技术负责人拆解实施 +日期:2026-09-05 +适用产品:当前 Game Agent 桌面端编辑器 / 项目工作台 + +## 1. 方案目的 + +第一阶段不建设完整数据平台,也不一次性覆盖所有细粒度编辑动作。本方案只解决三个问题: + +1. 能不能知道用户进入了编辑器、创建或打开了哪个项目。 +2. 能不能把一次创作任务和 Agent 执行、项目变化、预览结果串起来。 +3. 能不能判断用户是否回到同一个项目继续创作。 + +本版本新增**编辑器前台时长**。它表示编辑器窗口处于前台/获得焦点的累计时间,不等于用户持续操作,也不等于真实编辑时长。本版本仍不统计编辑器活跃编辑时长和单个项目完整创作时长。 + +核心分析对象从旧版的“浏览/消费行为”切换为当前产品的“持续创作行为”。 + +## 2. 当前用户路径 + +```text +进入编辑器 + → 创建项目 / 打开已有项目 + → 提交一次创作任务 + → Agent 执行 + → 用户澄清、确认或追加指令 + → 文件、代码或资源发生有效变化 + → 项目产生 revision + → 预览就绪 + → 用户试玩或继续修改 + → 保存并退出 + → 之后重新打开同一项目继续创作 +``` + +第一阶段不要求把 Asset Canvas、Resource Editor、UI Editor 的每一个点击都拆成独立事件;先通过项目、任务、运行、revision 和前台时长关系判断用户是否真的在使用创作工作台。 + +## 3. 第一阶段事件清单 + +| 事件 | 所在环节 | 触发条件 | 可回答的问题 | +|---|---|---|---| +| `editor_session_start` | 进入编辑器 | 编辑器启动并完成可用初始化 | 有多少编辑器会话、用户从哪里开始 | +| `editor_session_end` | 离开编辑器 | 正常退出或明确关闭编辑器 | 正常结束的会话数;粗略会话时长 | +| `session_timeout` | 异常离开 | 超过约定时间没有心跳或前台状态 | 哪些会话可能异常中断;不可替代真实退出 | +| `editor_focus_start` | 进入前台 | 编辑器窗口获得焦点并处于可交互前台 | 用户把多少时间留在编辑器前台 | +| `editor_focus_end` | 离开前台 | 编辑器失去焦点、最小化或退出 | 前台时长区间和累计前台时长 | +| `project_create_success` | 创建项目 | 项目创建成功且拿到稳定 `project_id` | 创建项目人数、创建成功率 | +| `project_open` | 打开项目 | 项目被成功加载并进入工作区 | 回访项目数、项目复访率 | +| `creative_task_submit` | 发起创作 | 用户提交一次可执行的创作请求 | 用户发起了多少次真实创作任务 | +| `agent_run_completed` | Agent 执行结束 | 一次 Agent run 正常完成 | Agent 任务完成率、耗时、重试情况 | +| `agent_run_failed` | Agent 执行结束 | 一次 Agent run 明确失败 | 失败率、错误类型、失败后的修复行为 | +| `project_revision_created` | 产生有效变化 | 项目产生可识别的新 revision | Agent 或人工操作是否真正改变了项目 | +| `preview_ready` | 预览 | 当前项目预览达到可打开/可运行状态 | 有多少项目走到可预览;从任务到预览的转化 | +| `project_save` | 保存 | 用户或系统完成一次项目保存 | 用户是否保存成果;保存与继续创作关系 | + +说明:`project_revision_created` 是项目变化事件,不等于用户满意;`preview_ready` 是技术/产品中间成功,不等于用户完成试玩或认可结果。 + +## 4. 公共事件字段 + +每条正式产品事件使用统一 envelope。`properties` 只放该事件特有字段,不重复创造新的顶层 ID。 + +| 字段 | 类型 | 是否必填 | 字段说明 | +|---|---|---:|---| +| `event_id` | string | 是 | 单条事件唯一 ID,用于去重;建议 UUID | +| `event_name` | string | 是 | 事件英文名,如 `creative_task_submit` | +| `event_time` | datetime | 是 | 事件发生时间,统一 ISO 8601;不要只记录上传时间 | +| `user_id` | string/null | 条件必填 | 稳定用户标识;没有登录用户时明确为空,不用设备 ID 冒充 | +| `editor_session_id` | string | 是 | 一次编辑器打开到结束/超时的会话 ID | +| `project_id` | string/null | 条件必填 | 当前项目的稳定 ID;编辑器入口事件可以为空 | +| `creative_task_id` | string/null | 条件必填 | 一次用户创作任务的 ID;任务相关事件必须携带 | +| `agent_run_id` | string/null | 条件必填 | 一次 Agent 执行的 ID;仅 Agent run 相关事件填写 | +| `agent_turn_id` | string/null | 否 | Direct 的底层 turn 技术记录 ID;不能替代 `agent_run_id` | +| `status` | string/null | 条件必填 | `success`、`failed`、`timeout`、`cancelled` 等有限枚举 | +| `error_code` | string/null | 失败时必填 | 稳定错误码;不要把整段异常堆栈当作分析字段 | +| `source` | string | 是 | 事件来源,如 `editor`、`supervisor`、`direct`、`asset_canvas`、`ui_editor`、`manual`、`system` | +| `client_version` | string | 是 | 客户端/编辑器版本,用于按版本比较问题 | +| `properties` | object | 是 | 事件专属属性;允许为空对象 | + +### 4.1 ID 语义规则 + +- `editor_session_id`:编辑器会话,不能使用 Runtime 的 `sessionId`。 +- `creative_task_id`:用户的一次创作意图,可能包含多次 Agent run 和多轮追加指令。 +- `agent_run_id`:一次可独立判断成功/失败的 Agent 执行。Direct 需要单独生成,不能把 `clientTurnId` 直接当作 run ID。 +- `agent_turn_id`:底层技术 turn 记录,用于排错和技术审计,不直接作为产品任务口径。 +- `project_id`:项目身份,优先使用 manifest 中稳定的项目 ID,不使用路径作为长期主键。 + +## 5. 各事件最小字段 + +### 5.1 编辑器会话 + +`editor_session_start`: + +```text +entry_source +first_project_id +client_version +``` + +`editor_session_end` / `session_timeout`: + +```text +end_reason +session_duration_ms(若可可靠计算) +last_project_id +``` + +`editor_focus_start`: + +```text +focus_reason +active_project_id +``` + +`editor_focus_end`: + +```text +blur_reason +focus_duration_ms(若可可靠计算) +active_project_id +``` + +前台时长计算规则:同一 `editor_session_id` 下,将成对的 `editor_focus_start` 与 `editor_focus_end` 区间相加。正常退出时补齐最后一个区间;崩溃、断电或强制结束造成的未闭合区间必须标记为不完整,不估算为完整前台时长。 + +### 5.2 项目 + +`project_create_success`: + +```text +project_template_id(如有) +creation_source +``` + +`project_open`: + +```text +open_source +is_first_open +``` + +`project_revision_created`: + +```text +revision_id +revision_source +change_kind +files_changed_count(如可得) +``` + +`project_save`: + +```text +save_source +revision_id(如有) +``` + +`revision_source` 建议至少使用:`agent`、`asset_canvas`、`resource_editor`、`ui_editor`、`manual_edit`、`system_projection`。 + +### 5.3 创作任务与 Agent + +`creative_task_submit`: + +第一阶段只要求带上: + +```text +creative_task_id +project_id +source +``` + +不记录完整自然语言 prompt,也不要求第一阶段记录任务类型、输入方式、指令长度或附件信息。上述属性属于后续需要分析任务结构时再增加的可选字段。 + +`agent_run_completed` / `agent_run_failed`: + +```text +agent_type +run_source +duration_ms +retry_index +output_change_detected +revision_id(如已产生) +``` + +这里的 `agent_run_id` 只是一次 Agent 执行的技术关联 ID,不代表要记录每次执行的提示词内容。完成事件只能说明执行状态。`output_change_detected` 和后续 `project_revision_created` 用于区分“跑完了但没改变项目”。 + +### 5.4 预览 + +`preview_ready`: + +```text +preview_source +preview_version +ready_duration_ms(从触发构建到就绪,如可得) +``` + +第一阶段的 `preview_ready` 必须有明确技术触发条件,例如预览服务确认可访问或本地运行状态确认 ready;不能用“返回了 URL”直接代替。 + +## 6. 可以看的数据 + +### 6.1 创作漏斗 + +```text +编辑器进入 +→ 创建/打开项目 +→ 提交创作任务 +→ Agent 完成 +→ 项目产生 revision +→ 预览就绪 +→ 保存 +→ 后续重新打开项目 +``` + +可计算: + +- 编辑器到项目创建/打开转化率。 +- 项目到首次创作任务转化率。 +- 创作任务提交率:有项目用户中发生 `creative_task_submit` 的用户数 / 有项目用户数。 +- Agent 完成率:`agent_run_completed` /(`agent_run_completed` + `agent_run_failed`)。 +- 有效变化率:产生 `project_revision_created` 的任务数 / 创作任务数。 +- 预览到达率:产生 `preview_ready` 的任务数 / 创作任务数。 +- 保存率:产生 `project_save` 的项目用户数 / 产生 revision 的项目用户数。 + +### 6.2 创作行为 + +第一阶段可以看: + +- 用户每次会话提交多少创作任务。 +- 一个项目累计发生多少次任务、run 和 revision。 +- Agent 完成后是否真的产生项目变化。 +- 失败后是否重试、追加指令或重新打开项目。 +- 用户是一次性尝试,还是回到同一个项目继续创作。 +- 不同来源、版本、任务类型的成功率差异。 + +第一阶段暂时不能可靠看: + +- 编辑器活跃时长。 +- 完整项目创作总时长。 +- 用户是否满意或接受 Agent 结果。 +- 可靠的试玩成功率。 +- 仅凭这些事件直接得到 D1/D3/D7 留存,除非先确认 `user_id` 稳定且会话事件可靠落库。 + +## 7. 留存、LTV 与 ARPU 的当前口径 + +### 7.1 留存 + +当前先定义“创作者回访留存”,不定义泛产品活跃留存: + +```text +某 cohort 用户在 D0 发生 project_create_success 或 creative_task_submit +在 D1/D3/D7 再次发生 project_open、creative_task_submit 或 project_revision_created +``` + +公式: + +```text +Dk 创作者留存率 = D0 cohort 中在第 k 天至少发生一次创作相关事件的用户数 / D0 cohort 用户数 +``` + +前提是 `user_id` 稳定、事件可靠落库、日期按统一时区计算。当前代码审计结论是这些条件尚未全部确认,因此先把公式写入方案,不把结果宣称为已可用。 + +### 7.2 LTV 与单用户 ARPU + +埋点本身不能产生 LTV 或 ARPU。需要另外存在可靠的订单/扣费/退款事实表,并用 `user_id` 关联。 + +```text +ARPU = 统计周期内总收入 / 统计周期内活跃用户数 +``` + +如果看创作者商业价值,可另算: + +```text +创作者 ARPU = 统计周期内创作者收入 / 统计周期内发生创作行为的去重用户数 +``` + +```text +LTV = 用户在定义生命周期内的累计净收入 / cohort 用户数 +``` + +其中净收入应扣除退款、赠送额度和必要的渠道/支付成本,具体财务口径需要业务和财务确认。当前早期地基埋点只负责提供用户行为侧的 cohort 和创作分群,不负责替代收入系统。 + +## 8. 第一阶段建议看板 + +只建议做四组: + +1. **基础使用**:编辑器会话数、创建项目用户数、打开项目用户数、项目复访数。 +2. **创作漏斗**:任务提交、Agent 成功/失败、revision、preview ready、保存。 +3. **失败与恢复**:失败错误码、失败后重试率、失败后产生 revision 的比例。 +4. **回访创作**:D1/D3/D7 创作者回访,按任务类型、客户端版本、入口来源分组。 + +不要在第一阶段做几十个按钮点击看板,也不要把技术 JSONL、Runtime 状态和正式产品事件混成一张业务报表。 + +## 8.1 编辑时长的边界 + +本版本已经纳入前台时长事件,并区分三种时长: + +- **会话时长**:`editor_session_start` 到 `editor_session_end`,包含用户离开电脑或切到其他窗口的时间,不等于编辑时长。 +- **前台时长**:`editor_focus_start` 到 `editor_focus_end` 的累计时间。 +- **活跃编辑时长**:前台期间发生有效编辑、任务提交、预览、保存等行为的累计时间。 + +本版本只承诺会话时长和前台时长两个粗粒度指标;即使记录了 `focus_duration_ms`,也不能把它解释成编辑器活跃时长。 + +前台时长的解释限制: + +- 编辑器在前台但用户没有操作,仍会被计入。 +- 多窗口、系统锁屏、远程桌面或窗口状态异常时,可能出现边界误差。 +- 前台时长适合看停留和使用深度,不适合直接作为生产效率指标。 + +## 8.2 数据可靠性原则 + +已确认采用: + +- 事件先写本地短暂 outbox。 +- 网络恢复后自动重试上传。 +- 服务端或接收端使用 `event_id` 去重。 +- 关闭、断网、崩溃导致的可能丢数需要在技术验收中明确记录。 + +## 9. 当前已收口的产品口径 + +根据当前讨论,本版本采用以下口径: + +1. “创作成功”采用分层口径:`agent_run_completed` 表示执行完成,`project_revision_created` 表示项目发生有效变化,`preview_ready` 表示达到可预览状态;第一阶段不加入用户满意/接受结果事件。 +2. `creative_task_id` 表示用户一次创作意图;第一阶段不记录完整 Prompt,也不拆分 Prompt 内容。 +3. 第一阶段不加入 `task_type`、`input_mode`、指令长度和附件属性,避免早期方案过重。 +4. 事件允许先写本地短暂 outbox;网络恢复后自动重试;接收端按 `event_id` 去重。 +5. 创作者 D1/D3/D7 暂按 `project_open`、`creative_task_submit`、`project_revision_created` 作为回访事件,但只有在 `user_id` 和数据落库可靠后才正式出数。 +6. 编辑器前台时长纳入本版本;编辑器活跃编辑时长留到后续阶段。 + +## 9.1 仍需你确认的一项产品边界 + +只剩一个可能影响报表口径的问题:用户对同一个创作目标进行澄清或追加指令时,是否始终沿用同一个 `creative_task_id`。本方案默认沿用同一个任务 ID,只有用户明确开始新的创作目标时才生成新的任务 ID。 + +如果你没有特别异议,后续按这个默认口径执行即可;其余未收口项属于技术实现确认,不需要你继续定义。 + +## 10. 需要 master 开发对话回答的技术问题 + +开发对话只回答代码事实和实现成本: + +- 是否已有服务端 analytics 接收接口和正式数据落点。 +- 若没有,第一阶段事件落本地 outbox、现有服务端 tracking,还是其他已有入口。 +- Tauri/Rust 是否能统一生成 `event_id`、`event_time`、`project_id`、`client_version`。 +- 当前能否稳定取得 `user_id`。 +- Direct 是否需要新增独立 `agent_run_id`。 +- `editor_session_id`、`creative_task_id` 是否能在现有生命周期生成。 +- `project_revision_created` 和 `preview_ready` 的可靠触发点在哪里。 +- 是否需要本地缓存、重试和去重;哪些异常场景会丢数。 +- 每个第一阶段事件对应的代码文件、触发函数、测试方式和估算成本。 + +前台时长还需要确认: + +- Tauri 当前是否能可靠监听窗口 focus、blur、minimize、restore 和退出事件。 +- 窗口失焦后是否立即落一条 `editor_focus_end`,还是由统一会话管理器补齐。 +- 锁屏、系统休眠、崩溃和强制结束时,如何标记未闭合前台区间。 +- 多窗口场景是否存在;如存在,`editor_session_id` 是按应用实例还是按窗口生成。 + +## 11. 第一阶段验收标准 + +技术实现完成后,至少能够用一条测试链路证明: + +```text +editor_session_start +→ editor_focus_start +→ project_create_success +→ creative_task_submit +→ agent_run_completed 或 agent_run_failed +→ project_revision_created(如果确实发生变化) +→ preview_ready(如果确实达到 ready) +→ project_save +→ editor_focus_end +→ editor_session_end +``` + +并满足: + +- 同一次链路中的 ID 能串联。 +- 重复上传不会制造重复事件。 +- Agent 失败不会被记成成功。 +- Agent 完成但没有项目变化时,不能伪造 `project_revision_created`。 +- 预览 URL 返回但不可访问时,不能伪造 `preview_ready`。 +- 关闭、断网、崩溃等场景的丢数风险已明确记录。 +- 能按 `user_id`、`project_id`、`creative_task_id`、`client_version` 做基本筛选。 +- 正常切换到其他窗口时,能闭合前台区间并计算 `focus_duration_ms`。 +- 最小化、恢复、正常退出至少有明确的 focus 结束/重新开始行为。 +- 崩溃或强制结束不会伪造一条完整的前台时长;未闭合区间必须可识别。 + +## 12. 对抗性自检审查 + +### 12.1 是否把技术完成误当创作成功 + +没有。方案明确区分 Agent 执行完成、项目产生 revision、预览就绪。三者分别是执行层、项目变化层和可预览层,不代表用户满意。 + +### 12.2 是否把前台时长误当编辑时长 + +没有。事件名、字段名和看板解释统一使用“前台时长”;用户没有操作但窗口保持前台的时间会被计入,并在文档中标明限制。 + +### 12.3 是否记录得过细、造成第一阶段过重 + +当前 P0 不记录完整 Prompt、任务类型、输入方式、指令长度和附件属性。保留的是会话、项目、任务、Agent 状态、revision、预览、保存和前台区间,属于基础漏斗与创作回访所需的最小集合。 + +### 12.4 前台事件是否会制造大量噪音 + +会比核心业务事件多,但仍是成对的窗口状态事件,不是按键或鼠标级事件。前台事件只用于时长聚合,不作为单独的产品成功指标。 + +### 12.5 断网、退出和崩溃是否会导致数据不可信 + +不能完全消除,但通过本地 outbox、重试和 `event_id` 去重降低风险。未闭合的 focus 区间必须标记不完整,不把估算时间写成事实。 + +### 12.6 是否能直接计算 D1/D3/D7、LTV、ARPU + +不能直接保证。留存依赖稳定 `user_id` 和可靠落库;LTV/ARPU 还依赖订单、扣费、退款和净收入事实表。当前方案只提供行为 cohort 和创作者分群基础。 + +### 12.7 是否仍有未收口问题 + +有,但已经集中到技术实现确认,不影响产品方案定稿: + +- 当前服务端 analytics 接口和正式落点是否存在。 +- Direct 是否能在现有生命周期生成独立 `agent_run_id`。 +- `project_revision_created` 和 `preview_ready` 的实际可靠触发点。 +- Tauri focus/blur 等窗口事件在当前多窗口、锁屏、休眠和崩溃场景下的行为。 +- `user_id` 是否稳定,以及匿名用户后续是否需要身份合并。 + +这些不是继续扩展事件的理由,而是技术负责人需要逐项确认的实现事实。 + +## 13. 当前结论 + +这套早期地基版埋点足以回答:用户有没有进入编辑器、在前台停留了多久、有没有创建项目、有没有发起创作、Agent 是否完成、项目是否真的变化、是否走到预览、是否回到同一项目继续创作。 + +它暂时不能回答:用户是否喜欢结果、是否完成试玩、编辑器真正活跃了多久、完整 LTV/ARPU,以及在用户身份和数据落库尚未确认前的可靠 D1/D3/D7 留存。 + +因此本方案的产品层已经基本收口。下一步是把第 10 节交给最新 master 开发对话核实,再由技术负责人拆成最小实现任务;如果技术核实发现 focus/blur 触发不稳定,只需要调整前台时长实现方式或降级为会话时长,不需要推翻整个埋点方案。 diff --git a/docs/【协作规范】文档生命周期与现状索引-2026-09-12.md b/docs/【协作规范】文档生命周期与现状索引-2026-09-12.md index ec52ae65f..62302d25d 100644 --- a/docs/【协作规范】文档生命周期与现状索引-2026-09-12.md +++ b/docs/【协作规范】文档生命周期与现状索引-2026-09-12.md @@ -51,6 +51,8 @@ 以下文档明确是历史记录、实施记录、专利材料或问题记录: +- `docs/technical/【需求来源】GameAgent埋点设计原始方案-2026-09-05.md` + - `docs/【实施记录】SFX生成优化V2.0T6测试与发布门禁-2026-08-07.md` - `docs/【专利交底】一种极低成本快速生成高质量2D小游戏高一致性美术素材的解决方案-2026-05-25.md` - `docs/technical/【问题记录】DirectProject客户端Skill自然语言触发能力缺口-2026-09-01.md` diff --git a/docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md b/docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md index bb19b661e..adb2590e5 100644 --- a/docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md +++ b/docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md @@ -147,7 +147,7 @@ npm run check:server-rs-ddd 拼图 `api-server` 内部拆分: - `server-rs/crates/api-server/src/modules/puzzle.rs` 只负责路由装配、鉴权层和参考图 body limit;对外继续引用同一批 handler 名称。 -- `server-rs/crates/api-server/src/state.rs` 中的 `PuzzleApiState` 是拼图 HTTP/BFF 的 Feature State,集中暴露 `SpacetimeClient`、`PuzzleGalleryCache`、OSS client、作者查询所需认证服务、拼图 LLM client 和少量 VectorEngine / Agent 配置快照。拼图 handler 只提取 `State`,不得重新改回 `State`。 +- `server-rs/crates/api-server/src/state.rs` 中的 `PuzzleApiState` 是拼图 HTTP/BFF 的 Feature State,集中暴露 `SpacetimeClient`、OSS client、作者查询所需认证服务、拼图 LLM client 和少量 VectorEngine / Agent 配置快照。拼图 handler 只提取 `State`,不得重新改回 `State`。 - `server-rs/crates/api-server/src/puzzle.rs` 只作为聚合入口,保留共享 import / 常量、内部模块声明和 handler re-export,不继续承载大段实现。 - `server-rs/crates/api-server/src/puzzle/handlers.rs` 承接 Axum handler,负责 extract、鉴权上下文、调用 SpacetimeDB facade / 编排 helper,并返回 HTTP/SSE 响应。 - `server-rs/crates/api-server/src/puzzle/draft.rs` 承接表单草稿保存、草稿编译、首关命名、UI 背景 prompt 和初始资产就绪校验。 @@ -158,7 +158,7 @@ npm run check:server-rs-ddd 拼图发布 / 待发布门槛必须同时要求首图、关卡画面、UI spritesheet 与关卡背景资产包完整;`module-puzzle::validate_publish_requirements` 与 `api-server::puzzle::tags::is_puzzle_session_snapshot_publish_ready` 使用同一资产语言,不得只凭 cover、标题、描述和标签把半成品标为 `publishReady` 或 `ready_to_publish`。 -该拆分只改变 `api-server` 文件组织,不改变 `/api/runtime/puzzle/*` route、DTO、error envelope、SpacetimeDB schema、公开 gallery cache 语义或计费语义;后续继续细分时也必须先保持行为不变,再单独讨论领域规则下沉。 +该拆分只改变 `api-server` 文件组织,不改变 `/api/runtime/puzzle/*` route、DTO、error envelope、SpacetimeDB schema 或计费语义;后续继续细分时也必须先保持行为不变,再单独讨论领域规则下沉。 `/api/runtime/puzzle/runs*` 当前接受 `RuntimePrincipal`,可同时识别登录用户 Bearer 和 runtime guest token。推荐页嵌入运行态的正式开局、交换、拖拽、下一关、暂停、道具与排行榜请求,应由前端在登录态下继续携带账号 access token;匿名游客仅在确认为未登录时走 runtime guest token。不要再把拼图 runtime 当成只认普通 Bearer 的纯账号接口。 @@ -176,7 +176,7 @@ npm run check:server-rs-ddd - `server-rs/crates/api-server/src/match3d/vector_engine_gemini.rs` 仅保留历史 VectorEngine Gemini 物品 sheet helper;当前草稿物品 spritesheet 以关卡整图为参考走 `gpt-image-2` 编辑链路,提示词、绿幕透明化和 OSS 持久化由 `item_assets.rs` / `works.rs` 约束。 - `server-rs/crates/api-server/src/match3d/runtime.rs` 保留运行态轻量归一 helper;`mappers.rs` / `tags.rs` / `tests.rs` 分别承接 DTO 映射、标签 / 通用错误 helper 和原有单测。 -该拆分只改变 `api-server` 文件组织,不改变 `/api/creation/match3d/*`、`/api/runtime/match3d/*` route、DTO、error envelope、SpacetimeDB schema、公开 gallery cache 语义、VectorEngine / OSS 副作用边界或计费语义;后续继续细分时也必须先保持行为不变,再单独讨论领域规则下沉到 `module-match3d`。 +该拆分只改变 `api-server` 文件组织,不改变 `/api/creation/match3d/*`、`/api/runtime/match3d/*` route、DTO、error envelope、SpacetimeDB schema、VectorEngine / OSS 副作用边界或计费语义;后续继续细分时也必须先保持行为不变,再单独讨论领域规则下沉到 `module-match3d`。 生成资产 Adapter 规则: @@ -198,11 +198,11 @@ npm run check:server-rs-ddd 4. 删除字段、改名、重排字段、改类型或修改字段属性前,必须先询问用户并确认迁移计划。 5. Vec 字段不要直接写无法 const 求值的 default;需要默认空集合时优先使用 `Option>` 加 `#[default(None::>)]`,业务层归一为空数组。 6. 运行态读表必须按已声明索引访问。只要 table 上存在覆盖查询前缀的 `#[index(...)]` 或主键 / unique accessor,列表、详情、快照组装和计数都先用对应 accessor `.filter(...)` / `.find(...)`,再在内存中处理索引无法覆盖的残余条件;不得用 `.iter().filter(...)` 扫整表替代现成索引。 -7. 面向公开列表的只读投影优先做成 public view / public 读模型表,并由 `api-server` 的 `spacetime-client` 长期订阅后读本地 cache。跨玩法公开作品统一主读模型是 `public_work_gallery_entry` 和 `public_work_detail_entry`;公开作品资产读取授权投影是 `public_work_asset_read_grant`;各玩法既有 `*_gallery_card_view` / `*_gallery_view` / `custom_world_gallery_entry` 保留为 source view 和兼容路径。短期不把作品列表整体交给浏览器前端直接订阅;不要让 HTTP 列表接口每次请求都调用 procedure 重新组装全量列表。需要请求时间窗口的轻量统计可订阅 `public_work_play_daily_stat` 后在 `api-server` 本地聚合,需要写入副作用的详情、点赞、游玩记录仍走玩法 procedure / reducer。前端不得直接订阅 `puzzle_work_profile`、`custom_world_profile` 等领域源表,也不得自己做 join、聚合或权限逻辑。首屏、排序、字段归一、权限降级和 HTTP fallback 由 `api-server` BFF 维持。 +7. 面向公开列表的只读投影必须先用独立 public view / read model 固化数据契约,再由 `spacetime-client` 通过明确 procedure / query 边界读取;当前连接池不维护公开作品长期订阅缓存。旧创作模板的逐玩法 gallery view、`public_work_gallery_entry` / `public_work_detail_entry` / `public_work_asset_read_grant` 及其兼容路径均已随公开作品基础设施退役,不得作为现役 read model 或 fallback 恢复。需要请求时间窗口的轻量统计可读取 `public_work_play_daily_stat`,需要写入副作用的详情、点赞、游玩记录仍走现役 procedure / reducer。前端不得直接订阅领域源表,也不得自己做 join、聚合或权限逻辑。排序、字段归一、权限降级和 HTTP fallback 由 `api-server` BFF 用当前正式契约处理。 8. 多列索引按 SpacetimeDB 绑定生成的元组参数直接传入,例如 `.filter((source_type, profile_id, played_day))`;前缀查询只传前缀元组,例如 `.filter((scope_kind, scope_id.as_str()))`。不要为了绕过类型问题退回整表遍历。 9. procedure result 必须返回 typed snapshot / typed value。`spacetime-client` mapper 不得再通过 `row_json/session_json/work_json/items_json/run_json/event_json/feedback_json: Option` 做跨层 JSON 字符串传输,也不得在 mapper 里反序列化旧 `*JsonRecord` 兼容结构。业务内部持久化字段如 `profile_payload_json`、`levels_json` 等不属于 procedure result 载荷例外,仍按各自表契约处理。 10. procedure 需要按调用者 identity 鉴权时,必须先从外层 `ProcedureContext::sender()` 捕获 caller,再把 caller 显式传入 `try_with_tx` 闭包内的事务函数。当前 workspace 锁定 SpacetimeDB `2.8.3`;鉴权边界不得依赖事务上下文的隐式 sender 语义,即使 SDK 升级也继续保持显式 caller 参数。 -11. 旧创作模板历史表采用两阶段退役:阶段一只允许 migration operator 调用固定范围的 `clear_retired_database_tables` procedure 清空 63 张旧玩法表,输入仅有 `dry_run`;`dry_run=true` 只返回逐表行数统计,`dry_run=false` 在单一事务内逐表删除全部行,任一失败整体回滚。清单必须在 `spacetime-module/src/migration.rs` 中静态维护,不接受调用方传入任意表名;`runtime_setting`、`runtime_snapshot`、`user_browse_history`、`creation_entry_config` 等现役表不属于清理范围。阶段一保留所有旧表定义、`legacy_schema/**`、migration 导入导出白名单和生成 bindings,不执行 `DROP TABLE`、`--delete-data=always` 或系统表写入。阶段二待备份、客户端兼容性和运行态确认完成后,另行评估从 module 定义与 migration 白名单移除空表,并同步 schema / bindings;当前在固定清单旁保留 TODO,不提前改动表定义。 +11. 旧创作模板的 63 张历史玩法表已从 SpacetimeDB module、migration 导入导出白名单和生成 bindings 中退役,当前 schema 不再包含 `player_progression`、`custom_world_*`、Puzzle / Puzzle Clear、Bark Battle、Match3D、Jump Hop、Wooden Fish、Square Hole、Visual Novel 与 Big Fish 的历史表。清理后不得保留 `clear_retired_database_tables` 这类只服务于空表的数据操作入口,也不得以 SQL `DROP TABLE`、`--delete-data=always` 或系统表写入替代受控 schema 发布。`runtime_setting`、`runtime_snapshot`、`user_browse_history`、`creation_entry_config` 等现役表继续保留并参与迁移。生产发布前仍必须完成数据库冷备份、客户端兼容性和运行态确认,确认后按 SpacetimeDB schema 发布门禁整体更新 module、migration 与 bindings。 12. 修改后运行: ```bash @@ -250,8 +250,6 @@ npm run check:server-rs-ddd 4. 资产操作的预扣费必须 fail-closed:钱包或 SpacetimeDB 预扣费不可达、超时或返回业务错误时,`api-server` 直接返回错误,不允许继续调用图片、音频、GLB 等外部生成 provider。 5. 需要支持 HTTP retry 的计费 ledger id 必须包含当前请求的 `request_id`;前端 `fetchWithApiAuth` 同一次业务请求的静默刷新重试复用同一个 `x-request-id`,后端不得再使用 prompt 指纹或随机 asset id 作为扣费幂等键。 6. 外部生成已预扣费但后续失败时,失败/任务状态变更事务必须在 SpacetimeDB 内按 refund ledger id 幂等写入 `profile_wallet_refund_outbox` pending 行;跨节点 worker 从库内 pending 行批量处理并在库内事务执行退款,成功后删除 outbox 行,失败按 `available_at` 和 `attempts` 重试。当前 attempt 若 consume 尚不可见,事务仍必须先写 `asset_operation_wallet_settlement` 取消 intent,阻止迟到扣费。普通 inline 资产失败也先调用同一 DB outbox procedure;只有 SpacetimeDB 完全不可达时才写 `wallet-refund-outbox` 本机 emergency spool。默认启用,配置项为 `GENARRATIVE_WALLET_REFUND_OUTBOX_ENABLED`、`GENARRATIVE_WALLET_REFUND_OUTBOX_DIR`、`GENARRATIVE_WALLET_REFUND_OUTBOX_BATCH_SIZE`、`GENARRATIVE_WALLET_REFUND_OUTBOX_FLUSH_INTERVAL_MS` 和 `GENARRATIVE_WALLET_REFUND_OUTBOX_MAX_BYTES`。本机文件按 refund ledger id 幂等落盘;成功重放后删除,坏文件隔离为 `corrupt-*`,不能替代库内 outbox。外部生成任务触发的扣费和退款必须在 `profile_wallet_ledger.metadata_json` 与两类 outbox 中保留 `externalGenerationJobId` 和 `externalGenerationClaimAttempt`,便于从退款记录追溯到具体 attempt。 -7. 拼图首图后台生成的跨实例互斥锁必须落在 SpacetimeDB `puzzle_background_compile_task` 表,claim id 由 `task_id + request_id` 构成,释放时必须校验 claim id,避免旧后台任务释放新请求抢到的租约。 - ## 用户钱包与编辑器生成扣费契约 1. `profile_wallet_config` 是账号初始泥点和每日免费泥点基础发放量的统一真相源;后台通过 `/admin/api/profile/wallet-config` 一次读写 `initialMudPoints` 和 `dailyFreePointsPerDay`。新用户账号完成注册并成功同步正式认证表后,注册赠送金额读取 `initial_mud_points`;未写入配置时默认为 `100`。每日免费基础发放量未写入时默认为 `20`。注册赠送流水原因仍使用 `new_user_registration_reward`,流水 ID 继续保持幂等,重复发放请求不得叠加余额。 @@ -419,11 +417,11 @@ Responses 的终态载荷既是工具调用的恢复源,也是正文的恢复 - 说明:对象 metadata 以 bucket / key 标识正式对象及其 owner、访问策略。确认接口的 owner 必须来自登录会话、后台管理员会话或 External API Key 绑定的认证主体,不接受请求体指定 owner;同 bucket / key 首次登记后,重复 confirm 不得改变 owner。已登记对象默认并继续保持 `private`。API 通过 `get_asset_object_by_location_and_return` / `get_asset_object_by_id_and_return` 在服务端索引上权威查询 private table;资产读取 ACL 使用 `get_asset_read_access_by_location_and_return` 在同一事务快照内同时返回位置查询、现役 `editor_showcase_asset` 精选素材派生授权和当前已启用 `editor_showcase_campaign_config` 的活动卡专用目录 exact-key 派生授权,procedure 只允许 runtime service identity 调用。旧创作模板作品授权 view 和逐玩法资产采集器已经退出 module;`spacetime-client` 不订阅全量 `asset_object`,也不把连接级 cache 当成安全判断。位置查询发现重复 bucket / key 时失败关闭,不能任选一条继续授权。普通对象只有权威位置查询返回不存在且显式使用 curated `legacyPublicPath` 时才能进入白名单兼容;历史活动卡上传缺少 metadata 时,可由“`global` 配置已启用 + `image_object_key` 精确匹配 + key 位于 `generated-character-drafts/editor/showcase-campaign/`”这一窄授权继续换签,禁用或替换活动卡后旧 key 立即失效。新上传活动卡仍必须完成 `asset_object` confirm,不能把该历史兼容当作跳过正式登记的常规路径。 - 编辑器生成结果例外不允许先单独 confirm 再分段创建业务记录:OSS `PUT / HEAD` 仍在事务外,但 `AssetObjectUpsertInput` 必须交由统一结果 procedure 在同一事务内与 resource、asset、binding、canvas、job 和 receipt 原子写入。候选省略 object 时,procedure 必须在同一事务快照中验证已登记 object 的 owner、位置和媒体身份;`HEAD` 成功不能代替正式登记。 -### SpacetimeDB view:`public_work_asset_read_grant` +### 退役记录:SpacetimeDB view `public_work_asset_read_grant` - 状态:已退役,不再注册到 `spacetime-module`,也不再生成客户端绑定。 - 历史源码:`server-rs/crates/spacetime-module/src/public_asset_access.rs`,仅供追溯,不参与现役 crate 根。 -- 现役替代:资产读取 procedure 只计算 `editor_showcase_asset` 精选素材的精确授权;历史作品表继续作为数据壳保留,但不再导出公开作品资产授权。 +- 现役替代:资产读取 procedure 只计算 `editor_showcase_asset` 精选素材的精确授权。历史作品表与对应 view 已从 module、migration 和 bindings 删除,不再保留 schema 数据壳;不得用订阅 cache 或历史源码恢复公开作品资产授权。 ### `auth_identity` @@ -446,27 +444,6 @@ Responses 的终态载荷既是工具调用的恢复源,也是正文的恢复 短期状态的并发保护:发短信前先从正式投影刷新工作集,再写入不可消费的占位验证码并通过 `sync_auth_store_projection` 的基线 CAS 占用手机号 / 场景冷却窗口;只有占用成功后才调用外部短信 provider,provider 成功后再同步真实验证码哈希。微信 OAuth state 在 `module-auth` 工作集内限制活动数量,超过上限直接拒绝创建,避免单行 JSON 投影无界增长;过期 state 仍由投影导出时清理。 -### `bark_battle_draft_config` - -- Rust 结构体:`BarkBattleDraftConfigRow` -- 源码:`server-rs/crates/spacetime-module/src/bark_battle/tables.rs` - -### `bark_battle_leaderboard_entry` - -- Rust 结构体:`BarkBattleLeaderboardEntryRow` -- 源码:`server-rs/crates/spacetime-module/src/bark_battle/tables.rs` - -### `bark_battle_personal_best_projection` - -- Rust 结构体:`BarkBattlePersonalBestProjectionRow` -- 源码:`server-rs/crates/spacetime-module/src/bark_battle/tables.rs` - -### `bark_battle_published_config` - -- Rust 结构体:`BarkBattlePublishedConfigRow` -- 源码:`server-rs/crates/spacetime-module/src/bark_battle/tables.rs` -- 字段变更:`visible` 控制是否进入公开列表 / 详情,新作品默认 `false`;旧迁移数据由 `migration.rs` 按历史公开默认补 `true`。 - ## 编辑器角色动作素材持久化契约(2026-07-28) - `asset_kind` 是资源 / 素材可选的权威语义类别,不新增或返回并列的 `media_type` / `mediaType`。普通静态图片的 `asset_kind` 为空;角色动作预览 MP4 使用 `asset_kind = video`,最终透明帧集使用 `asset_kind = character-animation`;前端据此派生具体渲染器。 @@ -513,65 +490,6 @@ Responses 的终态载荷既是工具调用的恢复源,也是正文的恢复 - 只是新增分类或 renderer 且现有媒体字段足够时,不改 schema。只有必须跨刷新、复用、审核或公开保留的数据才新增类别专属字段。 - legacy 数据必须先通过有界、可审计、带 dry-run/hash/apply 门禁的数据库迁移收口;迁移后的 api-server、mapper、主站、后台和画布只读取正式字段,不保留运行时 fallback。 -### `bark_battle_runtime_run` - -- Rust 结构体:`BarkBattleRuntimeRunRow` -- 源码:`server-rs/crates/spacetime-module/src/bark_battle/tables.rs` - -### `bark_battle_score_record` - -- Rust 结构体:`BarkBattleScoreRecordRow` -- 源码:`server-rs/crates/spacetime-module/src/bark_battle/tables.rs` - -### `bark_battle_work_stats_projection` - -- Rust 结构体:`BarkBattleWorkStatsProjectionRow` -- 源码:`server-rs/crates/spacetime-module/src/bark_battle/tables.rs` - -### `battle_state` - -- Rust 结构体:`BattleState` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/gameplay.rs` - -### `big_fish_agent_message` - -- Rust 结构体:`BigFishAgentMessage` -- 源码:`server-rs/crates/spacetime-module/src/big_fish/tables.rs` - -### `big_fish_asset_slot` - -- Rust 结构体:`BigFishAssetSlot` -- 源码:`server-rs/crates/spacetime-module/src/big_fish/tables.rs` - -### `big_fish_creation_session` - -- Rust 结构体:`BigFishCreationSession` -- 源码:`server-rs/crates/spacetime-module/src/big_fish/tables.rs` -- 索引:`by_big_fish_session_owner_user_id`、`by_big_fish_session_stage`。公开广场 view 使用 `by_big_fish_session_stage` 读取已发布会话,避免扫整表。 -- 字段变更:`visible` 控制是否进入公开列表 / 详情,新作品默认 `false`;旧迁移数据由 `migration.rs` 按历史公开默认补 `true`。 - -### `big_fish_event` - -- Rust 结构体:`BigFishEvent` -- 源码:`server-rs/crates/spacetime-module/src/big_fish/events.rs` - -### `big_fish_runtime_run` - -- Rust 结构体:`BigFishRuntimeRun` -- 源码:`server-rs/crates/spacetime-module/src/big_fish/tables.rs` - -### SpacetimeDB view:`big_fish_gallery_view` - -- Rust view:`big_fish_gallery_view` -- 返回类型:`Vec` -- 源码:`server-rs/crates/spacetime-module/src/big_fish/session.rs` -- 说明:大鱼吃小鱼公开 source 投影,只从 `Published` creation session 组装公开卡片字段;统一公开列表 / 详情主路径通过 `public_work_gallery_entry` / `public_work_detail_entry` 消费该 view 并映射成跨玩法契约。玩法旧 gallery 路径保留兼容 shape;个人作品列表、详情、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理。 - -### `chapter_progression` - -- Rust 结构体:`ChapterProgression` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/gameplay.rs` - ### `creation_entry_config` - Rust 结构体:`CreationEntryConfig` @@ -594,46 +512,6 @@ Responses 的终态载荷既是工具调用的恢复源,也是正文的恢复 - 用途:通用功能灰度事实源。当前创作入口使用 `creation-entry:` 约定关联入口 ID;`api-server` 按当前可选登录用户、用户标签和稳定百分比判定后,只把过滤后的入口配置返回普通前端,不下发灰度规则或用户标签。 - 迁移兼容:新增表不改已有入口表字段;未配置 gate 或 `enabled=false` 时不限制功能,黑名单用户 ID 优先于白名单和百分比命中。 -### `custom_world_agent_message` - -- Rust 结构体:`CustomWorldAgentMessage` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/custom_world.rs` - -### `custom_world_agent_operation` - -- Rust 结构体:`CustomWorldAgentOperation` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/custom_world.rs` - -### `custom_world_agent_session` - -- Rust 结构体:`CustomWorldAgentSession` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/custom_world.rs` -- 发布约束:`publish_world` 的 action payload 不要求携带 `settingText`;`spacetime-module` 调用 `module-custom-world::resolve_custom_world_publish_setting_text(...)`,优先从当前 `draft_profile_json` 草稿真相派生正式 `setting_text`,避免旧会话 `seed_text` 为空时在最终 compile / publish 阶段触发 `custom_world.setting_text 不能为空`。 - -### `custom_world_draft_card` - -- Rust 结构体:`CustomWorldDraftCard` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/custom_world.rs` - -### `custom_world_gallery_entry` - -- Rust 结构体:`CustomWorldGalleryEntry` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/custom_world.rs` -- 作用:自定义世界公开 source 读模型。统一公开列表 / 详情主路径通过 `public_work_gallery_entry` / `public_work_detail_entry` 消费该投影并映射成跨玩法契约;`/api/runtime/custom-world-gallery` 保留旧 HTTP shape,并从统一 public cache 映射回旧 DTO。旧 procedure 只用于兼容旧库缺少 gallery 读模型行时的一次性同步兜底。 -- 字段变更:`visible` 控制是否进入公开列表 / 详情,新作品默认 `false`;旧迁移数据由 `migration.rs` 按历史公开默认补 `true`。 - -### `custom_world_profile` - -- Rust 结构体:`CustomWorldProfile` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/custom_world.rs` -- 字段变更:`visible` 控制是否进入公开列表 / 详情,新作品默认 `false`;旧迁移数据由 `migration.rs` 按历史公开默认补 `true`。 -- 兼容约束:历史公开 RPG / 自定义世界 profile 可能存在 `publication_status=Published` 但 `published_at=None`。公开详情、点赞、游玩、Remix 和 `custom_world_gallery_entry` 同步都以 `Published + deleted_at=None + visible=true` 判断作品可公开互动;展示和 gallery 同步时间在 `published_at` 缺失时回退 `updated_at`,不得仅因 `published_at` 为空返回“已发布作品不存在”。 - -### `custom_world_session` - -- Rust 结构体:`CustomWorldSession` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/custom_world.rs` - ### `database_migration_import_chunk` - Rust 结构体:`DatabaseMigrationImportChunk` @@ -663,7 +541,7 @@ Responses 的终态载荷既是工具调用的恢复源,也是正文的恢复 - Rust 结构体:`GameDistributionGame` - 源码:`server-rs/crates/spacetime-module/src/game_distribution.rs` - 用途:游戏分发稳定身份与公开版本指针。保存 owner、标题/简介/分类资料、设备与输入声明、`publication_revision`、当前 `active_version_id`、可见性和游玩计数;标签与输入模式按版本化 JSON 保存,展示资料由 `api-server` 通过 `spacetime-client` 归一后返回。 -- 公开素材:游戏行末尾追加可空 `cover_object_key` 与 `screenshots_json`(截图 `{assetId, objectKey}` 数组);创建游戏时 `api-server` 就复核封面/截图素材存在且属于当前作者(不存在 400、他人素材 403),创建版本时按同一口径再次复核并派生对象键。 发布写入受灰度配置键 `game-distribution:publish` 约束:未配置或 `enabled=false` 默认开放,显式收紧后写入口(创建游戏/版本、确认包、送审、审核通过激活)返回 503 `GAME_DISTRIBUTION_PUBLISH_DISABLED`,读取与安全下架保持可用;同一判据在 `GET /api/runtime/frontend-config` 以 `gameDistributionPublishEnabled` 下发给前端入口,匿名恒为 `false`。只有可见性为 `published` 且存在有效 `active_version_id` 的游戏,其封面/截图素材才在 `/api/assets/read-url` 上获得匿名读授权。 +- 公开素材:游戏行末尾追加可空 `cover_object_key` 与 `screenshots_json`(截图 `{assetId, objectKey}` 数组);创建游戏时 `api-server` 就复核封面/截图素材存在且属于当前作者(不存在 400、他人素材 403),创建版本时按同一口径再次复核并派生对象键。 发布写入受灰度配置键 `game-distribution:publish` 约束:**灰度默认关闭**,未配置或 `enabled=false` 时写入口(创建游戏/版本、确认包、送审、审核通过激活)返回 503 `GAME_DISTRIBUTION_PUBLISH_DISABLED`,`enabled=true` 且白名单/比例/标签命中才放行,读取与安全下架保持可用;同一判据在 `GET /api/runtime/frontend-config` 以 `gameDistributionPublishEnabled` 下发给前端入口,匿名恒为 `false`。只有可见性为 `published` 且存在有效 `active_version_id` 的游戏,其封面/截图素材才在 `/api/assets/read-url` 上获得匿名读授权。 - 复用规则:末尾可空列 `local_project_id` 保存发布方本地项目标识(AGC 的 `manifest.projectId`)。同一 `owner_user_id` 再次以相同 `local_project_id` 创建游戏时复用既有 `game_id` 并只新增版本,避免“更新”被实现成新建游戏;该字段只是复用提示,不构成所有权或路径凭证,也不能用于跨账号匹配。 - 索引:`by_game_distribution_game_owner_user_id` 用于作者私有游戏列表;`game_id` 为主键。公开目录只返回 `visibility = published` 且存在有效 `active_version_id` 的投影。 @@ -863,131 +741,6 @@ Responses 的终态载荷既是工具调用的恢复源,也是正文的恢复 - 说明:模型生成运行时服务 identity 显式轮换审计表。只有已授权迁移操作员可调用 `rotate_editor_generation_runtime_service_identity_and_return`,且新 writer 不能等于当前 writer,也不能是任一已登记 migration operator。每次记录旧 writer、新 writer、迁移操作员 identity、操作人、原因和服务端时间;轮换只修改 writer,不覆盖已有模型价格。生产人工入口为 `scripts/deploy/production-runtime-writer-identity-rotate.mjs`,CLI 会核对当前登录 operator identity 并要求双录新 identity。 - 索引:自增主键 `rotation_id`。 -### `inventory_slot` - -- Rust 结构体:`InventorySlot` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/gameplay.rs` - -### `jump_hop_agent_session` - -- Rust 结构体:`JumpHopAgentSessionRow` -- 源码:`server-rs/crates/spacetime-module/src/jump_hop/tables.rs` - -### `jump_hop_event` - -- Rust 结构体:`JumpHopEventRow` -- 源码:`server-rs/crates/spacetime-module/src/jump_hop/tables.rs` - -### `jump_hop_leaderboard_entry` - -- Rust 结构体:`JumpHopLeaderboardEntryRow` -- 源码:`server-rs/crates/spacetime-module/src/jump_hop/tables.rs` -- 说明:跳一跳作品维度排行榜 read model,每个 `profile_id + player_id` 只保留 1 条最佳记录;排序口径为成功跳跃次数降序、游戏时长升序、更新时间升序,草稿试玩不作为公开排行榜语义。 -- 展示契约:`player_id` 只作为后端去重和 `viewerBest` 匹配身份键,不得直接进入 HTTP/UI 展示字段;`/api/runtime/jump-hop/works/{profile_id}/leaderboard` 必须补齐 `displayName`,已登录玩家读取账号显示名,匿名游客展示“游客玩家”,失效账号展示“失效玩家”。 - -### `jump_hop_runtime_run` - -- Rust 结构体:`JumpHopRuntimeRunRow` -- 源码:`server-rs/crates/spacetime-module/src/jump_hop/tables.rs` -- 说明:运行记录持久化 `runtime_mode`,取值为 `draft` / `published`;草稿试玩只允许作品所有者启动,不累计公开游玩次数,也不写入公开排行榜。 - -### `jump_hop_work_profile` - -- Rust 结构体:`JumpHopWorkProfileRow` -- 源码:`server-rs/crates/spacetime-module/src/jump_hop/tables.rs` -- 说明:作品投影持久化独立 `theme_text`,用于生成主题和公开卡片主题展示;历史行为空时按 `work_title` 兜底。`back_button_asset_json` 保存 image2 单独生成并去绿后的 1:1 左上角返回按钮资产快照;旧迁移数据按 `None` 兼容,运行态缺失该字段时使用同尺寸 CSS 主题按钮兜底。 - -### SpacetimeDB view:`jump_hop_gallery_card_view` - -- Rust view:`jump_hop_gallery_card_view` -- 返回类型:`Vec` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/jump_hop.rs` -- 说明:跳一跳公开列表 source 投影,只暴露 `publication_status = Published` 的作品卡片字段;统一公开列表主路径通过 `public_work_gallery_entry` 消费该 view 并映射成跨玩法契约。个人作品列表、详情、发布和运行态仍按 procedure 路径处理。 - -### SpacetimeDB view:`jump_hop_gallery_view` - -- Rust view:`jump_hop_gallery_view` -- 返回类型:`Vec` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/jump_hop.rs` -- 说明:跳一跳公开详情兼容投影,包含作品、路径和素材字段;统一公开详情主路径通过 `public_work_detail_entry` 消费该 view,只保留平台详情页展示摘要。 -- 字段变更:`visible` 控制是否进入公开列表 / 详情,新作品默认 `false`;旧迁移数据由 `migration.rs` 按历史公开默认补 `true`。 - -### `wooden_fish_agent_session` - -- Rust 结构体:`WoodenFishAgentSessionRow` -- 源码:`server-rs/crates/spacetime-module/src/wooden_fish/tables.rs` - -### `wooden_fish_event` - -- Rust 结构体:`WoodenFishEventRow` -- 源码:`server-rs/crates/spacetime-module/src/wooden_fish/tables.rs` - -### `wooden_fish_runtime_run` - -- Rust 结构体:`WoodenFishRuntimeRunRow` -- 源码:`server-rs/crates/spacetime-module/src/wooden_fish/tables.rs` - -### `wooden_fish_work_profile` - -- Rust 结构体:`WoodenFishWorkProfileRow` -- 源码:`server-rs/crates/spacetime-module/src/wooden_fish/tables.rs` -- 说明:敲木鱼作品 profile 真相,包含敲击物图案、背景环境图、主题返回按钮图、敲击音效、飘字配置、发布状态和公开计数;`background_asset_json` 保存 image2 生成的 9:16 背景环境图资产快照,`back_button_asset_json` 保存 image2 生成并去绿后的 1:1 返回按钮图资产快照,旧迁移数据按 `None` 兼容。 - -### SpacetimeDB view:`wooden_fish_gallery_card_view` - -- Rust view:`wooden_fish_gallery_card_view` -- 返回类型:`Vec` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/wooden_fish.rs` -- 说明:敲木鱼公开列表 source 投影,只暴露 `publication_status = published` 的作品卡片字段;统一公开列表主路径通过 `public_work_gallery_entry` 消费该 view 并映射成跨玩法契约。个人作品列表、详情、发布和运行态仍按 procedure 路径处理。 - -### SpacetimeDB view:`wooden_fish_gallery_view` - -- Rust view:`wooden_fish_gallery_view` -- 返回类型:`Vec` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/wooden_fish.rs` -- 说明:敲木鱼公开详情兼容投影,包含敲击物图案、背景环境图、主题返回按钮图、敲击音效和飘字配置;统一公开详情主路径通过 `public_work_detail_entry` 消费该 view,只保留平台详情页展示摘要。 -- 字段变更:`visible` 控制是否进入公开列表 / 详情,新作品默认 `false`;旧迁移数据由 `migration.rs` 按历史公开默认补 `true`。 - -### `match3d_agent_message` - -- Rust 结构体:`Match3DAgentMessageRow` -- 源码:`server-rs/crates/spacetime-module/src/match3d/tables.rs` - -### `match3d_agent_session` - -- Rust 结构体:`Match3DAgentSessionRow` -- 源码:`server-rs/crates/spacetime-module/src/match3d/tables.rs` - -### `match3d_runtime_run` - -- Rust 结构体:`Match3DRuntimeRunRow` -- 源码:`server-rs/crates/spacetime-module/src/match3d/tables.rs` - -### `match_3_d_work_profile` - -- Rust 结构体:`Match3DWorkProfileRow` -- Rust accessor:`match_3_d_work_profile` -- 源码:`server-rs/crates/spacetime-module/src/match3d/tables.rs` -- 兼容说明:dev 现有 SpacetimeDB 元数据中的真实表名 / 索引名为 `match_3_d_work_profile` 与 `match_3_d_work_profile_*_idx_btree`。module 内部 accessor 必须与该 canonical name 对齐,避免 Rust SDK 在 `index_id_from_name` 初始化二级索引时查找 `match3d_work_profile_*` 并触发 `No such index` panic。`migration.rs` 仍兼容旧迁移包中的 `match3d_work_profile` 表名补默认字段。 - -### SpacetimeDB view:`match_3_d_gallery_view` - -- Rust view:`match3d_gallery_view` -- 返回类型:`Vec` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/match3d.rs` -- 说明:抓大鹅公开 source 投影,只暴露 `publication_status = published` 的作品卡片字段;统一公开列表 / 详情主路径通过 `public_work_gallery_entry` / `public_work_detail_entry` 消费该 view 并映射成跨玩法契约。个人作品列表、详情、发布、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理。 -- 字段变更:`visible` 控制是否进入公开列表 / 详情,新作品默认 `false`;旧迁移数据由 `migration.rs` 按历史公开默认补 `true`。 - -### `npc_state` - -- Rust 结构体:`NpcState` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/gameplay.rs` - -### `player_progression` - -- Rust 结构体:`PlayerProgression` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/gameplay.rs` - ### `profile_dashboard_state` - Rust 结构体:`ProfileDashboardState` @@ -1172,111 +925,13 @@ Responses 的终态载荷既是工具调用的恢复源,也是正文的恢复 - Rust 结构体:`PublicWorkPlayDailyStat` - 源码:`server-rs/crates/spacetime-module/src/runtime/profile.rs` -### `puzzle_agent_message` - -- Rust 结构体:`PuzzleAgentMessageRow` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/puzzle.rs` - -### `puzzle_agent_session` - -- Rust 结构体:`PuzzleAgentSessionRow` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/puzzle.rs` - -### `puzzle_background_compile_task` - -- Rust 结构体:`PuzzleBackgroundCompileTaskRow` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/puzzle.rs` -- 说明:拼图首图后台生成的跨 api-server 实例互斥 claim 表,只保存活动任务租约,不表达最终生成结果;`task_id` 为主键,`claim_id` 用于释放时防止误删新租约,租约超时时间为 30 分钟。 - -### `puzzle_event` - -- Rust 结构体:`PuzzleEvent` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/puzzle.rs` - -### `puzzle_leaderboard_entry` - -- Rust 结构体:`PuzzleLeaderboardEntryRow` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/puzzle.rs` - -### `puzzle_runtime_run` - -- Rust 结构体:`PuzzleRuntimeRunRow` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/puzzle.rs` - -### `puzzle_work_profile` - -- Rust 结构体:`PuzzleWorkProfileRow` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/puzzle.rs` -- 说明:拼图作品 profile 表,保存草稿 / 已发布作品的标题、作者、关卡、封面、发布状态、可见性、基础游玩数、点赞数、改造数和积分激励领取状态。 -- 字段变更:`visible` 控制是否进入公开列表 / 详情、通关后的推荐下一作品候选、公开点赞 / Remix 和正式公开 runtime;新作品默认 `false`,旧迁移数据按历史公开默认补 `true`。后台隐藏后作品可保留 `publication_status = Published`,但公开消费路径必须按 `Published + visible=true` 判断。 - -### `puzzle_clear_agent_session` - -- Rust 结构体:`PuzzleClearAgentSessionRow` -- 源码:`server-rs/crates/spacetime-module/src/puzzle_clear/tables.rs` -- 说明:拼消消创作会话表,保存轻表单草稿、生成状态、已发布 profile 关联和更新时间;只由拼消消 procedure 读写。 - -### `puzzle_clear_work_profile` - -- Rust 结构体:`PuzzleClearWorkProfileRow` -- 源码:`server-rs/crates/spacetime-module/src/puzzle_clear/tables.rs` -- 说明:拼消消作品 profile 表,保存中央底图资产、4 张素材工作表切片后合成的最终 atlas、35 个复合图案组、95 个 1x1 卡牌切片、卡背占位图、发布状态、可见性和基础 play count;公开列表 / 详情只通过 read model 消费,不让前端直接订阅源表。 -- 字段变更:`visible` 控制是否进入公开列表 / 详情,新作品默认 `false`;旧迁移数据由 `migration.rs` 按历史公开默认补 `true`。 - -### `puzzle_clear_runtime_run` - -- Rust 结构体:`PuzzleClearRuntimeRunRow` -- 源码:`server-rs/crates/spacetime-module/src/puzzle_clear/tables.rs` -- 说明:拼消消正式 runtime run 表,保存当前关卡、已消除次数、棋盘 snapshot、开始 / 完成时间和 run 状态;正式胜负、重试、完成、超时和交换结果以后端 procedure 裁决为准。 - -### `puzzle_clear_event` - -- Rust 结构体:`PuzzleClearEventRow` -- 源码:`server-rs/crates/spacetime-module/src/puzzle_clear/tables.rs` -- 说明:拼消消基础 runtime 事件表,记录 published run 的开局、关卡完成、全局完成、失败、超时和消除统计来源;首版不做排行榜。 - -### SpacetimeDB view:`puzzle_clear_gallery_view` - -- Rust view:`puzzle_clear_gallery_view` -- 返回类型:`Vec` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/puzzle_clear.rs` -- 说明:拼消消公开详情 source 投影,只暴露 `publication_status = published` 且 `visible = true` 的作品,包含 atlas、底图、图案组和卡牌切片等详情级字段;统一公开详情主路径通过 `public_work_detail_entry` 消费该 view,只保留平台详情页展示摘要。 - -### SpacetimeDB view:`puzzle_clear_gallery_card_view` - -- Rust view:`puzzle_clear_gallery_card_view` -- 返回类型:`Vec` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/puzzle_clear.rs` -- 说明:拼消消公开列表 source 投影,只暴露平台卡片需要的公开字段;统一公开列表主路径通过 `public_work_gallery_entry` 消费该 view,`/api/runtime/puzzle-clear/gallery` 保留玩法专属 HTTP shape。 - -### SpacetimeDB view:`puzzle_gallery_view` - -- Rust view:`puzzle_gallery_view` -- 返回类型:`Vec` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/puzzle.rs` -- 说明:拼图广场公开详情 source / 兼容投影,只暴露 `publication_status = Published` 且 `visible = true` 的作品,但返回完整 `PuzzleWorkProfile`,包含 levels / anchor_pack 等详情级字段;统一公开详情主路径通过 `public_work_detail_entry` 消费该 view,只保留平台详情页展示摘要。 - -### SpacetimeDB view:`puzzle_gallery_card_view` - -- Rust view:`puzzle_gallery_card_view` -- 返回类型:`Vec` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/puzzle.rs` -- 说明:拼图公开列表 source 投影,只暴露 `publication_status = Published` 且 `visible = true` 的公开字段,不携带 levels / anchor_pack 等详情级载荷;统一公开列表主路径通过 `public_work_gallery_entry` 消费该 view,`/api/runtime/puzzle/gallery` 保留旧 HTTP shape,并从统一 public cache 映射回 `PuzzleGalleryResponse`。 - -### 拼图公开列表 HTTP 窗口缓存 - -- 接口:`GET /api/runtime/puzzle/gallery` -- 响应契约:保留 `items` 字段兼容旧前端;当前 `items` 只返回前 10 个完整卡片,新增 `previewRefs` 返回后 10 个 `workId/profileId` 引用,并返回 `hasMore`、`nextCursor` 与 `totalCount`。 -- 缓存策略:`api-server` 在 `PuzzleGalleryCache` 中缓存最终 `PuzzleGalleryResponse` 的预序列化 data JSON。缓存 miss / 过期时单飞重建,避免并发请求重复排序、映射、DTO 深拷贝和 `serde_json::Value` 树构造;开启响应 envelope 时只按请求拼接轻量 meta,缓存短 TTL 刷新 `recentPlayCount7d`,后台 cleanup task 周期清理超过最大空闲窗口的旧响应。OTLP 通过 `genarrative.puzzle_gallery.cache.*`、`genarrative.spacetime.read.*`、`genarrative.http.server.response_bodies.in_flight` 和 `genarrative.http.server.request_permits.available` 区分缓存重建、SpacetimeDB 本地订阅读、响应 body 生命周期和 HTTP 背压状态。 -- 详情路径:公开详情、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理;前端拿到 `previewRefs` 后如果需要展开更多内容,应优先使用后续列表窗口能力或详情 cache,不要把自动详情预取变成新的 procedure 热点。 - ### api-server 长期订阅读模型 -> 现役覆盖:`spacetime-client` 不再把旧创作入口配置、公开作品聚合表或逐玩法 gallery view 作为连接池必需订阅。`REQUIRED_CACHED_READ_MODEL_QUERIES` 当前为空,`user_account` 仅作为认证兼容所需的可选缓存。新版 `/creation` 的公开内容通过可选鉴权的 `GET /api/editor/showcase/resources` 读取编辑器精选 read model;登录态的 viewer like 投影在请求事务内读取,不进入共享长期订阅 cache,HTTP 响应固定 `private, no-store` 并按 `Authorization` 区分。旧作品、入口配置和玩法统计表只保留 schema 数据壳,不再形成订阅 cache、BFF 路由或前端契约。 +> 现役覆盖:`spacetime-client` 的连接池不订阅旧创作模板 schema、逐玩法 gallery view 或公开作品聚合缓存。`REQUIRED_CACHED_READ_MODEL_QUERIES` 当前为空,`user_account` 仅作为认证兼容所需的可选缓存。新版 `/creation` 的公开内容通过可选鉴权的 `GET /api/editor/showcase/resources` 读取编辑器精选 read model;登录态的 viewer like 投影在请求事务内读取,不进入共享长期订阅 cache,HTTP 响应固定 `private, no-store` 并按 `Authorization` 区分。旧创作模板作品、旧玩法 gallery view 及公开作品聚合缓存已从当前 schema 退役,不再形成订阅 cache、BFF 路由或前端契约。 #### 退役前历史订阅清单 -`spacetime-client` 建立每个池连接时会等待下列订阅初始同步: +以下仅记录退役前历史,不代表当前 schema 或订阅契约;`spacetime-client` 当时建立每个池连接会等待这些订阅初始同步: - `SELECT * FROM public_work_gallery_entry` - `SELECT * FROM public_work_detail_entry` @@ -1305,28 +960,16 @@ Responses 的终态载荷既是工具调用的恢复源,也是正文的恢复 private `asset_object` 不进入长期订阅;安全判断通过受限 procedure 在服务端按主键或 `(bucket, object_key)` 索引读取事务内真相,避免全表复制、订阅失败和增量同步延迟把已登记私有对象误判为 legacy 未登记对象。 -跨玩法公开作品列表 / 详情主读模型是 `public_work_gallery_entry` 与 `public_work_detail_entry`。拼图、自定义世界等旧玩法公开列表 HTTP 路由保留原响应 shape,由 BFF mapper 从统一 public cache 映射回当前 DTO;旧 `*_gallery_card_view` / `*_gallery_view` / `custom_world_gallery_entry` 继续作为 source view 和兼容缓存。各玩法的个人作品列表、详情、发布、点赞、游玩记录、Remix 和其它需要鉴权或写入副作用的路径继续走 procedure / reducer;不要为了公开列表性能把这些 owner-specific 或 mutation 语义混进 public view。 +旧创作模板的逐玩法 gallery 兼容路径已退役;当前不存在 `*_gallery_card_view` / `*_gallery_view` / `custom_world_gallery_entry` 订阅或 BFF fallback。若未来重新开放统一公开作品能力,必须先新增并冻结当时正式 read model、schema、mapper 和 HTTP 契约,不能从历史 view 或源码恢复。 -`GET /api/creation-entry/config`、入口熔断和公开作品互动熔断优先从订阅 cache 读取创作入口配置;cache 缺失时使用最近一次成功读取的内存快照,再兜底调用 `get_creation_entry_config` procedure 完成空库种子或旧库兼容。 +`GET /api/creation-entry/config`、入口熔断和公开作品互动熔断通过现役 `get_creation_entry_config` procedure 读取权威配置;不得把已退役连接池订阅 cache 当作现役实现。 入口配置快照包含 start card、类型弹窗、公告位兼容字段、入口类型列表和 `publicWorkInteractions` 作品互动矩阵;入口类型列表新增 `category_id`、`category_label`、`category_sort_order` 后,后台 upsert、`shared-contracts`、`module-runtime` 和 `spacetime-client` binding 必须同步,旧迁移 JSON 通过 `migration.rs` 默认值兼容。作品互动矩阵是全局公开作品详情能力配置,不属于单个 `creation_entry_type_config`;后台通过 `/admin/api/creation-entry/config/interactions` 保存,前端据此隐藏或拦截已接入的点赞 / Remix 入口,api-server 同时对已接入后端动作执行 `public_work_interaction_disabled` 熔断。 -RPG 创作入口的配置 ID 是 `rpg`,当前 `visible=true`、`open=true`;历史 `custom-world` 路由仍是 RPG 的工程域与运行态源类型。入口熔断把 `/api/runtime/custom-world*`、`/api/story/*` 和 `/api/runtime/chat/*` 统一映射到 `rpg`,不要新增平行 `airp` 路由或用 `airp` 接管当前文字冒险链路。 +RPG 创作入口的配置 ID 是 `rpg`,当前 `visible=true`、`open=true`。历史 `custom-world`、`story` 与 `/api/runtime/chat/*` 请求链路均未挂载,不属于当前 api-server 路由或 schema 真相;不得为这些历史源码恢复路由、领域表或用平行 `airp` 链路接管。 旧结构化创作和 RPG 的 LLM JSON 链路及其 Responses `web_search` 配置已退出 api-server 编译目标;不得为历史源码恢复 `GENARRATIVE_RPG_LLM_WEB_SEARCH_ENABLED` 或 `GENARRATIVE_CREATION_AGENT_LLM_WEB_SEARCH_ENABLED`。 -统一公开作品 BFF 的历史契约曾使用 `GET /api/public-works` 与 `GET /api/public-works/{publicWorkCode}`;当前是否挂载以 `api-server/src/app.rs` 为准,当前平台入口不再恢复旧公开作品页面。若后续重新开放公开 read model,只能订阅 `public_work_gallery_entry` / `public_work_detail_entry` 这类稳定投影,不能订阅领域源表后自行拼装列表。 - -- 字段变更:`visible` 控制是否进入公开列表 / 详情,新作品默认 `false`;旧迁移数据由 `migration.rs` 按历史公开默认补 `true`。 - -### `quest_log` - -- Rust 结构体:`QuestLog` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/gameplay.rs` - -### `quest_record` - -- Rust 结构体:`QuestRecord` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/gameplay.rs` +统一公开作品 BFF 的历史契约曾使用 `GET /api/public-works` 与 `GET /api/public-works/{publicWorkCode}`;这些旧页面与旧 read model 当前不再挂载。未来若重新开放公开 read model,必须先新增当前正式 schema 与契约,不能订阅已退役 view 或领域源表后自行拼装列表。 ### `refresh_session` @@ -1345,50 +988,20 @@ RPG 创作入口的配置 ID 是 `rpg`,当前 `visible=true`、`open=true`; - Rust 结构体:`RuntimeSnapshotRow` - 源码:`server-rs/crates/spacetime-module/src/runtime/snapshots.rs` -### `square_hole_agent_message` - -- Rust 结构体:`SquareHoleAgentMessageRow` -- 源码:`server-rs/crates/spacetime-module/src/square_hole/tables.rs` - -### `square_hole_agent_session` - -- Rust 结构体:`SquareHoleAgentSessionRow` -- 源码:`server-rs/crates/spacetime-module/src/square_hole/tables.rs` - -### `square_hole_runtime_run` - -- Rust 结构体:`SquareHoleRuntimeRunRow` -- 源码:`server-rs/crates/spacetime-module/src/square_hole/tables.rs` - -### `square_hole_work_profile` - -- Rust 结构体:`SquareHoleWorkProfileRow` -- 源码:`server-rs/crates/spacetime-module/src/square_hole/tables.rs` - -### SpacetimeDB view:`square_hole_gallery_view` - -- Rust view:`square_hole_gallery_view` -- 返回类型:`Vec` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/square_hole.rs` -- 说明:方洞挑战公开 source 投影,只暴露 `publication_status = published` 的作品卡片字段;统一公开列表 / 详情主路径通过 `public_work_gallery_entry` / `public_work_detail_entry` 消费该 view 并映射成跨玩法契约。个人作品列表、详情、发布、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理。 -- 字段变更:`visible` 控制是否进入公开列表 / 详情,新作品默认 `false`;旧迁移数据由 `migration.rs` 按历史公开默认补 `true`。 - -### `story_event` - -- Rust 结构体:`StoryEvent` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/gameplay.rs` - -### `story_session` - -- Rust 结构体:`StorySession` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/gameplay.rs` - ### `tracking_daily_stat` - Rust 结构体:`TrackingDailyStat` - 源码:`server-rs/crates/spacetime-module/src/runtime/profile.rs` - 写入:由单条或批量 tracking procedure 在同一事务中随 `tracking_event` 更新,作为运营查询和个人任务进度的聚合投影。 +### `agc_tracking_event` + +- 普通私有持久表,保存客户端既有 12 类事件;以 `event_id` 为主键,不进入主站任务奖励或每日聚合。 +- 字段保留本地事件合同:schema_version、event_name、event_time、user_id、editor_session_id、project_id、creative_task_id、agent_run_id、agent_turn_id、status、error_code、source、client_version、properties_json;另存首次接收的 batch_id 和 received_at。 +- `upload_agc_analytics_batch` 只允许受信任服务身份调用,整批原子提交;相同事件重传不改首次批次和接收时间,内容冲突则整批回滚。 +- `list_agc_tracking_events` 经后台 BFF 调用,以 received_at 索引及用户/事件复合索引扫描候选(nullable 项目字段不建索引),在数据库事务中保留有界最新页;按 (received_at, event_id) 倒序及固定快照游标分页。 +- 不上传正文、快照、路径或凭据。字段/接口详见 [客户端本地埋点与主站入库契约](technical/【技术方案】客户端本地埋点与主站入库契约-2026-09-21.md) 第 13 节。 + ### `tracking_event` - Rust 结构体:`TrackingEvent` @@ -1396,11 +1009,6 @@ RPG 创作入口的配置 ID 是 `rpg`,当前 `visible=true`、`open=true`; - 写入:关键业务埋点同步调用单条 procedure;普通 HTTP route tracking 由 `api-server` 本机 outbox 批量调用 `record_tracking_events_and_return`。outbox 到达批量阈值时先封存 active 文件并切新 active,后台 worker 异步 flush sealed 文件,HTTP 请求线程不等待 SpacetimeDB。`FLUSH_INTERVAL_MS` 只负责兜底封存长时间未满批的 active 文件,`MAX_BYTES` 只做磁盘保护阈值。`event_id` 必须稳定且全局唯一,批量重试时用唯一索引做幂等跳过。 - 外部 API 失败:`event_key = external_api_call_failure` 使用同一张表落库;它是供应商失败审计事实,不新增 SpacetimeDB 表,查询时按 `module_key = 'external-api'` 或 `scope_kind = module AND scope_id = ''` 过滤。 -### `treasure_record` - -- Rust 结构体:`TreasureRecord` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/gameplay.rs` - ### `user_account` - Rust 结构体:`UserAccount` @@ -1412,41 +1020,4 @@ RPG 创作入口的配置 ID 是 `rpg`,当前 `visible=true`、`open=true`; - Rust 结构体:`UserBrowseHistory` - 源码:`server-rs/crates/spacetime-module/src/runtime/browse_history.rs` -### `visual_novel_agent_message` - -- Rust 结构体:`VisualNovelAgentMessageRow` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/visual_novel.rs` - -### `visual_novel_agent_session` - -- Rust 结构体:`VisualNovelAgentSessionRow` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/visual_novel.rs` - -### `visual_novel_runtime_event` - -- Rust 结构体:`VisualNovelRuntimeEvent` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/visual_novel.rs` - -### `visual_novel_runtime_history_entry` - -- Rust 结构体:`VisualNovelRuntimeHistoryEntryRow` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/visual_novel.rs` - -### `visual_novel_runtime_run` - -- Rust 结构体:`VisualNovelRuntimeRunRow` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/visual_novel.rs` - -### `visual_novel_work_profile` - -- Rust 结构体:`VisualNovelWorkProfileRow` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/visual_novel.rs` - -### SpacetimeDB view:`visual_novel_gallery_view` - -- Rust view:`visual_novel_gallery_view` -- 返回类型:`Vec` -- 源码:`server-rs/crates/spacetime-module/src/legacy_schema/visual_novel.rs` -- 说明:视觉小说公开 source 投影,只暴露 `publication_status = published` 的作品卡片字段,不把完整 `draft` 暴露给公开列表订阅;统一公开列表 / 详情主路径通过 `public_work_gallery_entry` / `public_work_detail_entry` 消费该 view 并映射成跨玩法契约。个人历史、详情、运行态和发布仍按原有 procedure / reducer 路径处理。 -- 字段变更:`visible` 控制是否进入公开列表 / 详情,新作品默认 `false`;旧迁移数据由 `migration.rs` 按历史公开默认补 `true`。 > 2026-09-03 修订:认证成功后的 Router provisioning 改为异步尽力修复,不再阻塞主站登录;LLM 热路径只读取本地已完成的账号密钥,控制面不可用时请求失败关闭。provisioning secret 仅从部署侧受保护环境变量或 secret file 读取,不再内置源码常量。 diff --git a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md index 3aa30b5be..767ad823b 100644 --- a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md +++ b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md @@ -678,8 +678,8 @@ journalctl -u genarrative-api -o cat | grep 'operation="release_rejected"' 发布事故或回滚窗口里用 `game-distribution:publish` 灰度开关控制写入,不需要改代码或重启: -- 开关位置:后台「灰度发布配置」(`GET/PUT /admin/api/feature-gates`),`gateKey = game-distribution:publish`。 -- 语义:没有该 gate 行或 `enabled=false` 表示**默认开放**;`enabled=true` 时只有 `allowUserIds` / `allowUserTags` / `rolloutPercent` 命中的作者能发布,`rolloutPercent=0` 且无白名单即**全部关闭**(等价紧急关闭投稿)。 +- 开关位置:后台「灰度发布配置」(`GET/PUT /admin/api/feature-gates`),`gateKey = game-distribution:publish`;后台「可配置开关」里固定列出「游戏分发 · 游戏发布」,点「配置」即按默认关闭填表(`enabled=false`),再填白名单 / 灰度比例并开启保存。灰度默认关闭:该键未创建或 `enabled=false` 时作者看不到发布入口、写入口返回 503。 +- 语义:没有该 gate 行或 `enabled=false` 表示**未开放**(灰度默认关闭);`enabled=true` 时只有 `allowUserIds` / `allowUserTags` / `rolloutPercent` 命中的作者能发布,`rolloutPercent=0` 且无白名单同样全关(等价紧急关闭投稿)。开放灰度就是把 `enabled` 打开并放白名单或提高比例。 - 关闭范围:创建游戏、创建版本、上传包、送审、撤回、作者下架,以及管理员**批准**(新版本激活)都返回 `503 GAME_DISTRIBUTION_PUBLISH_DISABLED`。 - 始终可用:目录、详情、版本回读、发行网关(已公开游戏继续游玩)、`/my-games`、审核队列读取、**拒绝审核**与管理员**安全下架**。 - 失败姿态:开关状态读取失败时按关闭处理,避免绕过运营刚下的收紧动作;本地排障时确认 SpacetimeDB 正常后再判断业务是否被误伤。 @@ -1141,20 +1141,7 @@ SELECT * FROM profile_recharge_product_config ORDER BY sort_order ASC; - 微信新用户的内部 `user_id` 改为不可复用的 `user_` 前缀 UUID 风格,避免清库后旧作品被后来的顺序号账号顶替。 - 当作品作者的 `owner_user_id` 找不到真实账号时,作品统一显示为占位作者:`失效作者`,公开陶泥号固定为 `SY-00000000`,占位账号 ID 为 `wx-openid-placeholder`。 - 该占位账号只用于作品作者域,不扩展到全站其它身份域。 -- 如需把历史孤儿作品批量回填到占位作者,使用 `scripts/rebind-orphan-work-owners.mjs` 先基于当前 auth 快照识别有效用户,再把缺失作者对应的作品表写回为占位 ID;脚本输入输出都基于 SpacetimeDB 迁移 JSON。 - -### 回填脚本用法 - -```bash -node scripts/rebind-orphan-work-owners.mjs --in --out -node scripts/rebind-orphan-work-owners.mjs --in --dry-run -node scripts/rebind-orphan-work-owners.mjs --in --out --placeholder-user-id wx-openid-placeholder -``` - -- `--in`:SpacetimeDB 导出的迁移 JSON。 -- `--out`:写回后的迁移 JSON 输出路径。 -- `--dry-run`:只统计回填行数,不写文件。 -- `--placeholder-user-id`:需要时可覆盖默认占位账号 ID。 +- 旧作品表退役后,迁移 JSON 回填工具 `scripts/rebind-orphan-work-owners.mjs` 已删除,不再提供回填脚本用法或当前操作入口;占位作者的显示与身份域语义继续保持上述规则。 ## 维护页目标文件安全边界(2026-08-05) diff --git a/docs/【玩法创作】平台入口与玩法链路-2026-05-15.md b/docs/【玩法创作】平台入口与玩法链路-2026-05-15.md index 3272fd5ca..4c4858c85 100644 --- a/docs/【玩法创作】平台入口与玩法链路-2026-05-15.md +++ b/docs/【玩法创作】平台入口与玩法链路-2026-05-15.md @@ -86,10 +86,10 @@ 2. 所有运行依赖都必须在发行包内。资源 URL 使用与发行版本目录兼容的相对地址;前导 `/assets`、本地文件 URL、外部脚本/样式/媒体/字体地址均不属于可接受发行合同。客户端给出可操作错误,服务器仍独立校验;静态校验不能代替运行时 CSP 阻断。 3. 建议首版限额:压缩包 100 MiB、展开总量 250 MiB、单文件 64 MiB、最多 10,000 个文件、展开/压缩比不超过 100。服务端拒绝加密 ZIP、重复或大小写冲突路径、绝对路径、`..`、符号链接/重解析点、设备文件和嵌套压缩包;拒绝 `.agent`、版本控制目录、`node_modules`、凭据文件与源码映射文件。超限返回明确错误,不截断后继续发布。 4. 提交声明 ZIP 的 SHA-256 与字节数,服务端对收到的真实 ZIP 重新计算,再对展开文件建立相对路径、字节数和 SHA-256 清单。摘要不一致、缺文件或入口损坏时停止;只有 metadata 而没有已确认完整对象的提交必须失败。 -5. 游戏资料随发行版本冻结:标题 2–40 字、短简介不超过 120 字、详细介绍不超过 2,000 字、一个分类、最多 5 个标签(每个不超过 20 字)、必需封面、最多 6 张截图、操作方式不超过 240 字。分类首版为休闲、益智、动作、冒险、模拟、策略、其他;封面/截图复用平台图片上传与归属校验,不接受任意外链作为审核图片。发布入口按灰度下发:后端灰度配置键固定为 `game-distribution:publish`(后台「灰度发布配置」可改,支持 `enabled` / `rolloutPercent` / `allowUserIds` / `allowUserTags`)。未配置该键、或 `enabled=false` 时对已登录作者默认开放;显式 `enabled=true` 后只有白名单或灰度命中的作者拿到开放状态,匿名恒为不开放。发布入口的开放状态随 `/api/runtime/frontend-config` 的 `gameDistributionPublishEnabled` 下发,网页广场/我的游戏入口与 AGC 聊天头「发布到游戏广场」按钮据此显示或隐藏;写入口仍独立校验,收紧期间提交返回 503 与可读文案,读接口、目录、详情、发行网关与安全下架不受影响。作者续发时按版本冻结快照回填封面与截图并复用同一批素材;公开投影只暴露对象键,素材 ID 只在作者与管理员回读时返回,快照里缺素材 ID 的旧版本必须要求作者重新选择封面。 +5. 游戏资料随发行版本冻结:标题 2–40 字、短简介不超过 120 字、详细介绍不超过 2,000 字、一个分类、最多 5 个标签(每个不超过 20 字)、必需封面、最多 6 张截图、操作方式不超过 240 字。分类首版为休闲、益智、动作、冒险、模拟、策略、其他;封面/截图复用平台图片上传与归属校验,不接受任意外链作为审核图片。作者不需要自己构建或打 ZIP:AGC 发布时对 `game/` 子工程按需执行 `npm install`(复用 `project.bootstrap`)与 `npm run build`(复用 `project.verify` 的受控 npm 运行器,脚本白名单含 `build`、禁止项目级 `.npmrc` 改写语义),再把 `game/dist` 归一化成根 `index.html` 的发行包上传;已有可玩入口(`game/index.html` 或 `dist/index.html`)时跳过构建。Phaser 4 + Vite 已按此口径端到端验证(构建产物、发行网关与网页沙箱播放)。发布入口按灰度下发:后端灰度配置键固定为 `game-distribution:publish`(后台「灰度发布配置」可改,支持 `enabled` / `rolloutPercent` / `allowUserIds` / `allowUserTags`)。灰度默认关闭:未配置该键、或 `enabled=false` 时,未登录与已登录作者都拿到不开放(发布入口不渲染、写入口 503);运营在后台创建该键并 `enabled=true` 后,只有白名单 / 灰度比例 / 用户标签命中的作者拿到开放状态。发布入口的开放状态随 `/api/runtime/frontend-config` 的 `gameDistributionPublishEnabled` 下发,网页广场/我的游戏入口与 AGC 聊天头「发布到游戏广场」按钮据此显示或隐藏;写入口仍独立校验,收紧期间提交返回 503 与可读文案,读接口、目录、详情、发行网关与安全下架不受影响。作者续发时按版本冻结快照回填封面与截图并复用同一批素材;公开投影只暴露对象键,素材 ID 只在作者与管理员回读时返回,快照里缺素材 ID 的旧版本必须要求作者重新选择封面。 6. `supportedDevices` 至少包含 `desktop` 或 `mobile`;`inputModes` 来自 `keyboard`、`mouse`、`touch`;声明移动端必须包含 `touch`。`orientation` 为 `landscape`、`portrait` 或 `responsive`。这些是待人工复核的作者声明,目录只显示已经随版本审核通过的值。 7. 原始 ZIP、未审核展开目录、审核资料均为私有对象;公开版本不暴露源码镜像键、本地路径、访问凭据或私有账号元数据。运行文件只能由发行网关按游戏、版本和文件白名单读取,不能绕过网关访问公开 OSS bucket。 -8. 现役发行网关由 `api-server` 提供:`GET /api/game-distribution/releases/{gameId}/{assetPath}` 只服务当前已公开版本包内的文件,私有 ZIP 与未公开版本不因知道 ID 而可读。响应按扩展名白名单设定内容类型,未知扩展名返回 404;全部响应带 `X-Content-Type-Options: nosniff`、`Cross-Origin-Resource-Policy: cross-origin` 与不带 credentials 的 `Access-Control-Allow-Origin: *`(发行文档运行在 `allow-scripts` 的 opaque origin 沙箱里,`same-origin` 会让游戏自己的脚本被浏览器拦下),HTML 追加最小权限 CSP。带平台 `Cookie` 的请求一律 `403`,避免发行文件被主站同源读取;发行网关必须部署在独立来源。发行包按对象键在进程内做有界缓存,单个超预算包不进入缓存。 +8. 现役发行网关由 `api-server` 提供:`GET /api/game-distribution/releases/{gameId}`(含尾斜杠)等价于该游戏的 `index.html`,`GET /api/game-distribution/releases/{gameId}/{assetPath}` 只服务当前已公开版本包内的文件,私有 ZIP 与未公开版本不因知道 ID 而可读。响应按扩展名白名单设定内容类型,未知扩展名返回 404;全部响应带 `X-Content-Type-Options: nosniff`、`Cross-Origin-Resource-Policy: cross-origin` 与不带 credentials 的 `Access-Control-Allow-Origin: *`(发行文档运行在 `allow-scripts` 的 opaque origin 沙箱里,`same-origin` 会让游戏自己的脚本被浏览器拦下),HTML 追加最小权限 CSP。带平台 `Cookie` 的请求一律 `403`,避免发行文件被主站同源读取;发行网关必须部署在独立来源。发行包按对象键在进程内做有界缓存,单个超预算包不进入缓存。 9. 审核通过时必须提交绝对 HTTPS `entryUrl`,且不接受凭据、query 和 fragment;服务端不根据请求 Host 或本地路径拼默认发行地址,避免把内网地址或主站来源写进公开投影。 非生产环境额外允许 http 回环地址(`127.0.0.1` / `localhost` / `[::1]`),口径与前端 `normalizeGameEntryUrl` 一致,便于本地在没有 TLS 的情况下验证内嵌游玩;生产环境只接受 HTTPS。 ### 身份、状态、审核与更新 @@ -119,7 +119,7 @@ | --- | --- | --- | | `GET /games` | 游客 | **已实现**:关键词与分类筛选,最多 48 项;仅公开可玩版本 | | `GET /games/{gameId}` | 游客 | **已实现**:当前公开资料与 `currentVersion.entryUrl`;不可见时 404 | -| `GET /game-distribution/releases/{gameId}/{assetPath}` | 游客 | **已实现**:发行网关只服务当前已公开版本包内文件,按扩展名白名单设内容类型,未知扩展名 404,带 Cookie 的请求 403;游玩页的入口来自详情投影的 `currentVersion.entryUrl` | +| `GET /game-distribution/releases/{gameId}[/{assetPath}]` | 游客 | **已实现**:根路径等价于 `index.html`;发行网关只服务当前已公开版本包内文件,按扩展名白名单设内容类型,未知扩展名 404,带 Cookie 的请求 403;游玩页的入口来自详情投影的 `currentVersion.entryUrl` | | `GET /my/games` | 登录作者 | **已实现**:当前账号游戏、最近版本状态与驳回理由;owner 只从认证主体派生 | | `POST /games` | 登录作者 | **已实现**:幂等创建游戏身份,尚不公开;带 `localProjectId` 时同一作者复用既有 `gameId` | | `POST /games/{gameId}/versions` | owner | **已实现**:创建不可变待上传版本,冻结包摘要/字节数/文件数与资料 | @@ -151,7 +151,7 @@ - 建议 HTML、公开状态与启动 API 使用 `no-store`;发行静态资源的浏览器与 CDN 有效期均不超过 60 秒,禁止 `stale-while-revalidate`、`stale-if-error` 和发行 Service Worker。下架主动 purge 相关 CDN 键,60 秒作为最大缓存撤销窗口,不把 purge 成功当唯一保障。旧版本被更新替代后,新启动只用当前版;旧游戏已经载入的脚本/资源不承诺远程抹除,用户退出或刷新后按当前授权重新判断。 - 发布所需部署依赖包括独立站点域名及通配 TLS、每游戏 host 路由、私有存储、网关 CSP/CORS/MIME、CDN TTL/purge、管理员审核运营入口和可恢复校验执行器;缺少任一项不能宣布公开上线。 - 观察上传失败、校验耗时、审核积压、发行 4xx/5xx、撤销传播时间与容量,日志按游戏/版本/操作 ID 关联,不记录 Token、完整用户文件内容或 signed URL。原始失败/撤回包建议保留 7 天后清理,公开版本和审核记录的保留周期在上线前确定;清理必须先检查引用,不能删除仍在服务的版本。 -- 回滚部署时关闭新提交和新版本激活,保留当前可玩版本与状态读取;数据库迁移不以删表回滚。安全事件通过服务端关闭游戏发行权限,不依赖前端隐藏按钮。现役实现:`game-distribution:publish` 灰度开关(后台「灰度发布配置」)控制作者写入与新版本激活——没有 gate 行或 `enabled=false` 时默认开放;`enabled=true` 时只有白名单/灰度命中的用户能发布(`rolloutPercent=0` 且无白名单即全部关闭)。关闭期间目录、详情、版本回读、发行网关、审核队列读取、拒绝审核与安全下架都不受影响;开关读取失败按关闭处理。 +- 回滚部署时关闭新提交和新版本激活,保留当前可玩版本与状态读取;数据库迁移不以删表回滚。安全事件通过服务端关闭游戏发行权限,不依赖前端隐藏按钮。现役实现:`game-distribution:publish` 灰度开关(后台「灰度发布配置」)控制作者写入与新版本激活——灰度默认关闭,没有 gate 行或 `enabled=false` 时不允许发布;`enabled=true` 时只有白名单/灰度命中的用户能发布(`rolloutPercent=0` 且无白名单即仍然全关)。关闭期间目录、详情、版本回读、发行网关、审核队列读取、拒绝审核与安全下架都不受影响;开关读取失败按关闭处理。 ### 验收标准与证据 diff --git a/docs/【编辑器】画板角色形象生成入口设计-2026-06-15.md b/docs/【编辑器】画板角色形象生成入口设计-2026-06-15.md index 8b993c895..3703a381e 100644 --- a/docs/【编辑器】画板角色形象生成入口设计-2026-06-15.md +++ b/docs/【编辑器】画板角色形象生成入口设计-2026-06-15.md @@ -65,7 +65,7 @@ - 角色面板增加紧凑的 `像素艺术` 勾选项,请求使用可选字符串字段 `style`:未勾选传 `"none"`,勾选传 `"pixelArt"`。该选择可以随现有生成器快照和队列 payload 保存,但不写入用户可见 `generationInputs`、素材元数据或新建的持久化记录。 - `style` 省略、为 `null`、空字符串或 `"none"` 时按内部 `None` 处理且不告警;`"pixelArt"` 在 `kind="character"` 时启用像素规整。未知字符串按 `None` 继续生成,并通过既有通用 `warning` 返回 `unsupported-image-style`;非字符串 JSON 仍返回 `400`。同一图片生成请求 DTO 被其它 `kind` 复用时,只有普通图片和 `character` 支持 `"pixelArt"`,其它 `kind` 收到该值也按不支持风格降级。 -- 2026-08-01 修订:`"pixelArt"` 不再只是后处理,同时向提交给 provider 的提示词末尾追加独立一行约束。角色链路使用「角色主体为像素风格」,**不得**使用「画面为像素风格」——角色生成后要按纯色抠像,绿幕底必须保持平整,同一段提示词里已写死「纯色背景必须平整无纹理、无渐变」,画面级像素化要求会与之互相拆台;且该提示词已禁止出现角色以外的场景内容,因此只需点名角色本身。注入发生在 `build_editor_character_image_prompt` 返回之后,该函数签名和输出契约不变。约束句**不会**进入角色链路的任何 `editor_project_resource`:原图 resource 的 prompt 列存的是 `role_setting`(用户原文),透明结果的 `output_prompt` 在抠图成功后被无条件覆盖为 `"去除纯色背景"`;完整提交提示词是否留存取决于 provider:`persist_editor_provider_source_image` 写原图 asset object 元数据时用的是 `actual_prompt.unwrap_or(prompt)`,provider 未回 `actualPrompt` 时才存 `submitted_prompt`(含约束句),此时排障可按 `object_key` 查;provider 回了 `actualPrompt` 就存 provider 改写后的文本,该次生成的 `submitted_prompt` 在系统内一处都不落——外部 API 审计的 `request_payload` 只记 `promptChars` 字符数,没有提示词原文。响应体返回的是用户原文,前端显示不变。以上 prompt 列写入与 asset object 元数据规则都是既有行为,与 `web/master` 逐行一致,本次未改动。角色提示词里既有的「严格基于图1的角色美术视觉规范的美术风格」与像素约束存在潜在冲突,本次未改写,等实测。 +- 2026-08-01 修订:`"pixelArt"` 不再只是后处理,同时向提交给 provider 的提示词末尾追加独立一行约束。角色链路使用「角色主体为像素风格」,**不得**使用「画面为像素风格」——角色生成后要按纯色抠像,绿幕底必须保持平整,同一段提示词里已写死「纯色背景必须平整无纹理、无渐变」,画面级像素化要求会与之互相拆台;且该提示词已禁止出现角色以外的场景内容,因此只需点名角色本身。注入发生在 `build_editor_character_image_prompt` 返回之后,该函数签名和输出契约不变。约束句**不会**进入角色链路的任何 `editor_project_resource`:原图 resource 的 prompt 列存的是 `role_setting`(用户原文),透明结果的 `output_prompt` 在抠图成功后被无条件覆盖为 `"去除纯色背景"`;原图 asset object 元数据由现役 `prepare_editor_generated_image` / upload-only helper 按传入的 `prompt` 构造,resource / asset 的 `actualPrompt` 由原子提交候选单独保存;排障应核对现役调用参数与记录,不能再按已退役的 provider-source 分步持久化函数推断提示词来源。角色提示词里既有的「严格基于图1的角色美术视觉规范的美术风格」与像素约束存在潜在冲突,本次未改写,等实测。 - 角色 provider 回图先按统一业务像素矩阵执行交付尺寸归一:允许无放大恢复时使用 Lanczos 重采样并居中裁切,无法安全恢复时保留 provider 实际尺寸并返回非阻断告警。归一后的带纯色背景图先持久化并作为 BgFilter 输入;BgFilter 正常成功后,把 Alpha 蒙版回贴到这张同尺寸平底原图,再执行像素规整并上传透明主图。网格分析源使用已收口到实际交付尺寸的平底原图,RGBA 采样源使用 Alpha 已回贴的透明图;软 Alpha 只参与单格覆盖率和 Alpha 加权 RGB 计算,输出 Alpha 硬化为 `0 / 255`。 - 首版参数固定为分析色数 `16`、Alpha 覆盖阈值 `0.375`、像素格尺寸自动检测、固定色板关闭、K-means 最大采样 `262144`。单格覆盖率 `Σ(A / 255) / N >= 0.375` 且 `ΣA > 0` 时输出 `A=255`,颜色按 `Σ(A × RGB) / ΣA` 计算;否则输出 `[0,0,0,0]`。分析色数不限制最终输出色数。 - 像素规整 CPU 工作使用进程级最大并发 `2`;取得并发许可的排队时间与实际处理时间共享最多 `30` 秒预算,同时不得晚于当前请求 deadline,最终以两者中更早者为准。输入图片任一边不得超过 `10000` 像素,总像素不得超过 `8294400`;超限、排队超时或处理超时均保留 Alpha 已回贴的透明图并走非致命降级。 diff --git a/scripts/agc-analytics-smoke.mjs b/scripts/agc-analytics-smoke.mjs new file mode 100644 index 000000000..d0c8504c5 --- /dev/null +++ b/scripts/agc-analytics-smoke.mjs @@ -0,0 +1,410 @@ +#!/usr/bin/env node +// 仅在临时 standalone 验证客户端埋点;显式传入带测试 bootstrap hash 的 WASM。 +import assert from 'node:assert/strict'; +import { spawn } from 'node:child_process'; +import { randomUUID } from 'node:crypto'; +import { once } from 'node:events'; +import { access, chmod, mkdtemp, rm, writeFile } from 'node:fs/promises'; +import net from 'node:net'; +import os from 'node:os'; +import path from 'node:path'; +import { setTimeout as delay } from 'node:timers/promises'; +import { fileURLToPath } from 'node:url'; + +import { createSpacetimeWebIdentity } from './spacetime-migration-common.mjs'; + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const database = 'agc-analytics-smoke'; +const testSecret = 'a'.repeat(64); // 公开测试值,绝不能用于正式部署。 +const sensitive = [testSecret]; +const redact = (value) => + sensitive.reduce( + (text, secret) => text.replaceAll(secret, '[REDACTED]'), + String(value), + ); + +function command(args) { + return new Promise((resolve, reject) => { + const child = spawn('spacetime', args, { + cwd: root, + windowsHide: true, + shell: false, + stdio: ['ignore', 'pipe', 'pipe'], + }); + let output = ''; + for (const stream of [child.stdout, child.stderr]) + stream.on('data', (chunk) => { + output = (output + chunk).slice(-16000); + }); + const timer = setTimeout(() => { + child.kill(); + reject(new Error('SpacetimeDB command timed out')); + }, 120000); + child.once('error', (error) => { + clearTimeout(timer); + reject(error); + }); + child.once('exit', (code) => { + clearTimeout(timer); + if (code === 0) resolve(output); + else reject(new Error(redact(output))); + }); + }); +} + +async function localPort() { + const listener = net.createServer(); + listener.listen(0, '127.0.0.1'); + await once(listener, 'listening'); + const port = listener.address().port; + await new Promise((resolve) => listener.close(resolve)); + return port; +} + +async function call(url, token, name, input) { + const response = await fetch(`${url}/v1/database/${database}/call/${name}`, { + method: 'POST', + headers: { + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify([input]), + signal: AbortSignal.timeout(30000), + }); + const text = await response.text(); + assert(response.ok, `${name}: HTTP ${response.status}: ${redact(text)}`); + return JSON.parse(text); +} + +function ok(result) { + assert.equal(result[0], 0, `Expected Ok, got ${JSON.stringify(result)}`); + return JSON.parse(result[1]); +} + +const event = (user = 'smoke-user-a') => ({ + schema_version: 1, + event_id: randomUUID(), + event_name: 'editor_session_start', + event_time: '2026-09-21T12:00:00.123Z', + user_id: user, + editor_session_id: randomUUID(), + project_id: null, + creative_task_id: null, + agent_run_id: null, + agent_turn_id: null, + status: 'success', + error_code: null, + source: 'editor', + client_version: 'smoke-1', + properties: { entry_source: 'direct_launch', first_project_id: null }, +}); +const batch = (events) => ({ + schema_version: 1, + batch_id: randomUUID(), + destination_origin: 'https://analytics-smoke.invalid', + user_id: events[0].user_id, + events, +}); + +function pricingInput() { + const tiered = (model, unit, keys) => ({ + model, + unit, + price: [1, []], + prices: keys.map((key) => ({ key, price: 1 })), + }); + return { + admin_user_id: 'smoke-bootstrap', + updated_at_micros: 1, + bootstrap_secret: testSecret, + models: [ + tiered('gemini-3.1-flash-image-preview', 'perGeneration', [ + '0.5K', + '1K', + '2K', + ]), + tiered('gpt-image-2', 'perGeneration', ['1K', '2K']), + ...['audio1.0', 'eleven_text_to_sound_v2', 'chirp-v5'].map((model) => ({ + model, + unit: 'perGeneration', + price: [0, 1], + prices: [], + })), + ...[ + 'seedance2.0-fast', + 'seedance2.0', + 'kling3.0', + 'kling3.0-omni', + 'veo3.1', + 'veo3.1-fast', + ].map((model) => tiered(model, 'perSecond', ['480p', '720p', '1080p'])), + ], + }; +} + +async function verify(url, serviceToken, outsiderToken) { + const upload = async (payload) => + call( + url, + serviceToken, + 'upload_agc_analytics_batch', + JSON.stringify(payload), + ); + const list = async (query = {}) => + ok( + await call( + url, + serviceToken, + 'list_agc_tracking_events', + JSON.stringify(query), + ), + ); + const first = batch([event(), event(), event()]); + first.events[0].event_time = '2026-09-21T12:01:00.123Z'; + assert.deepEqual(ok(await upload(first)), { + acknowledged_batch_ids: [first.batch_id], + event_count: 3, + }); + const initial = await list(); + assert.equal(initial.entries.length, 3); + ok(await upload(first)); + assert.deepEqual( + await list(), + initial, + 'Replay must preserve rows, first batch ID and receipt time', + ); + const reordered = structuredClone(first); + reordered.events[0].properties = { + first_project_id: null, + entry_source: 'direct_launch', + }; + ok(await upload(reordered)); + assert.deepEqual( + await list(), + initial, + 'JSON property order must not cause conflict', + ); + + const rollbackCandidate = event(); + const conflict = batch([ + rollbackCandidate, + { ...first.events[0], client_version: 'changed' }, + ]); + const rejected = await upload(conflict); + assert.equal(rejected[0], 1); + assert.equal(rejected[1], 'agc_event_conflict'); + assert.deepEqual( + await list(), + initial, + 'Earlier insert in failed batch must roll back', + ); + const userB = batch([event('smoke-user-b')]); + ok(await upload(userB)); + assert.equal( + (await list({ userId: 'smoke-user-b' })).entries[0].eventId, + userB.events[0].event_id, + ); + + const page1 = await list({ limit: 2 }); + assert(page1.nextCursor); + const late = batch([event()]); + late.events[0].event_time = '2026-09-21T11:00:00.123Z'; + ok(await upload(late)); + const seen = [...page1.entries]; + let cursor = page1.nextCursor; + while (cursor) { + const page = await list({ limit: 2, cursor }); + seen.push(...page.entries); + cursor = page.nextCursor; + } + assert.equal(seen.length, 4); + assert.equal(new Set(seen.map((row) => row.eventId)).size, 4); + assert( + !seen.some((row) => row.eventId === late.events[0].event_id), + 'Cursor snapshot must exclude later insert', + ); + for (let index = 1; index < seen.length; index++) { + const previous = seen[index - 1]; + const current = seen[index]; + assert( + previous.eventTime > current.eventTime || + (previous.eventTime === current.eventTime && + previous.eventId > current.eventId), + 'Stable event time/event ID descending order', + ); + } + const refreshed = await list(); + assert.equal(refreshed.entries.length, 5); + assert.equal(refreshed.entries[0].eventId, first.events[0].event_id); + assert.equal(refreshed.entries.at(-1).eventId, late.events[0].event_id); + assert.equal(refreshed.entries[0].projectId, null); + assert.equal(refreshed.entries[0].eventTime, '2026-09-21T12:01:00.123Z'); + for (const [name, input] of [ + ['upload_agc_analytics_batch', first], + ['list_agc_tracking_events', {}], + ]) { + const unauthorized = await call( + url, + outsiderToken, + name, + JSON.stringify(input), + ); + assert.equal(unauthorized[0], 1, 'Nonservice identity must be rejected'); + assert.match(unauthorized[1], /无权/); + } + console.log( + '[agc-analytics-smoke] PASS: first/replay, JSON order, atomic rollback, user filter, stable snapshot pagination, refresh, null/time, service authorization. 5 rows persisted.', + ); +} + +async function main() { + const wasm = process.env.GENARRATIVE_AGC_ANALYTICS_SMOKE_WASM; + assert( + wasm, + 'Set GENARRATIVE_AGC_ANALYTICS_SMOKE_WASM to an isolated test WASM compiled with SHA256(a repeated 64 times) bootstrap hash.', + ); + await access(wasm); + const version = await command(['--version']); + assert( + version.includes('version 2.8.3') && + version.includes('8e410d2842147bd8e5a32a9589cc00c19f7478e2'), + ); + const temp = await mkdtemp( + path.join(os.tmpdir(), 'genarrative-agc-analytics-smoke-'), + ); + let standalone; + try { + const port = await localPort(); + const url = `http://127.0.0.1:${port}`; + standalone = spawn( + 'spacetime', + [ + 'start', + '--data-dir', + path.join(temp, 'data'), + '--listen-addr', + `127.0.0.1:${port}`, + '--non-interactive', + ], + { windowsHide: true, shell: false, stdio: ['ignore', 'pipe', 'pipe'] }, + ); + let logs = ''; + for (const stream of [standalone.stdout, standalone.stderr]) + stream.on('data', (chunk) => { + logs = (logs + chunk).slice(-8000); + }); + const deadline = Date.now() + 30000; + for (;;) { + assert(standalone.exitCode === null, redact(logs)); + try { + if ( + (await fetch(`${url}/v1/ping`, { signal: AbortSignal.timeout(1000) })) + .ok + ) + break; + } catch { + /* 等待启动 */ + } + assert( + Date.now() < deadline, + `Standalone startup timeout: ${redact(logs)}`, + ); + await delay(200); + } + const owner = await createSpacetimeWebIdentity({ + database, + serverUrl: url, + }); + const service = await createSpacetimeWebIdentity({ + database, + serverUrl: url, + }); + sensitive.push(owner.token, service.token); + const config = path.join(temp, 'cli.toml'); + await command(['--config-path', config, 'login', '--token', owner.token]); + await chmod(config, 0o600); + await command([ + '--config-path', + config, + 'publish', + database, + '--server', + url, + '--yes=all', + '--no-config', + '--bin-path', + path.resolve(wasm), + ]); + const bootstrap = await call( + url, + service.token, + 'initialize_editor_generation_pricing_config_if_missing_and_return', + pricingInput(), + ); + assert.equal( + bootstrap[0], + true, + `Pricing service bootstrap failed: ${redact(JSON.stringify(bootstrap))}`, + ); + await verify(url, service.token, owner.token); + if (process.env.AGC_ANALYTICS_SMOKE_KEEP === '1') { + const stopFile = path.join(temp, 'stop'); + const contextPath = path.join(temp, 'connection.json'); + await writeFile( + contextPath, + JSON.stringify({ + serverUrl: url, + database, + token: service.token, + operatorToken: owner.token, + configPath: config, + stopFile, + }), + { mode: 0o600 }, + ); + console.log( + `[agc-analytics-smoke] Integration connection file: ${contextPath}`, + ); + const stopDeadline = Date.now() + 45 * 60 * 1000; + while (Date.now() < stopDeadline) { + try { + await access(stopFile); + break; + } catch { + /* 联调结束后由调用方创建 stop 文件 */ + } + await delay(1000); + } + } + } finally { + if (standalone && standalone.exitCode === null) { + if (process.platform === 'win32') { + const killer = spawn( + 'taskkill', + ['/PID', String(standalone.pid), '/T', '/F'], + { windowsHide: true, stdio: 'ignore' }, + ); + await once(killer, 'exit'); + } else { + standalone.kill('SIGTERM'); + } + if (standalone.exitCode === null) await once(standalone, 'exit'); + } + // 仅删除本脚本 mkdtemp 创建的系统临时子目录。 + assert( + path.dirname(path.resolve(temp)) === path.resolve(os.tmpdir()) && + path.basename(temp).startsWith('genarrative-agc-analytics-smoke-'), + ); + await rm(temp, { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 200, + }); + } +} + +main().catch((error) => { + console.error(redact(error.stack ?? error)); + process.exitCode = 1; +}); diff --git a/scripts/check-game-distribution-media-e2e.mjs b/scripts/check-game-distribution-media-e2e.mjs index 90599514b..fb6913ae7 100644 --- a/scripts/check-game-distribution-media-e2e.mjs +++ b/scripts/check-game-distribution-media-e2e.mjs @@ -4,10 +4,15 @@ // E2E_ADMIN_USER=<管理员用户名> E2E_ADMIN_PASSWORD=<管理员密码> \ // npm run check:game-distribution-media-e2e // E2E_API_BASE 可覆盖 api-server 地址(默认 http://127.0.0.1:12401)。 +// E2E_PACKAGE_ZIP 指向一个已经构建好的发行包(根目录含 index.html),例如真实 +// Phaser/Vite 工程 `game/dist/**` 打成的 ZIP;不传时使用脚本内置的最小 fixture。 +// E2E_GAME_TITLE 可覆盖游戏标题,便于在广场里认出这次验证。 // // 覆盖:真实素材直传 OSS → 创建游戏(素材归属校验)→ 创建版本(资料冻结)→ 送审 → // 作者回读 frozenMetadata → 待审期间匿名不可见/不可读 → 管理员审核通过 → 公开投影 // 暴露对象键且不泄露素材 ID → 匿名换签读封面与截图 → 发行网关可直接游玩。 +import { readFile } from 'node:fs/promises'; + import JSZip from 'jszip'; const API = process.env.E2E_API_BASE ?? 'http://127.0.0.1:12401'; @@ -139,7 +144,39 @@ function gameMetadata(overrides = {}) { }; } +const externalPackageZip = (process.env.E2E_PACKAGE_ZIP ?? '').trim(); +const gameTitleOverride = (process.env.E2E_GAME_TITLE ?? '').trim(); + +/** 返回待发布的发行包字节与条目数:优先使用调用方真实构建产物,否则用内置 fixture。 */ async function buildZip() { + if (externalPackageZip) { + const bytes = await readFile(externalPackageZip); + const archive = new JSZip(); + const parsed = await archive.loadAsync(bytes); + const entryNames = Object.keys(parsed.files).filter( + (name) => !parsed.files[name].dir, + ); + if (!entryNames.includes('index.html')) { + throw new Error( + `E2E_PACKAGE_ZIP 根目录缺少 index.html:${externalPackageZip}`, + ); + } + // 真实构建产物(Phaser/Vite 等)资源名带哈希:从包内派生一个资源路径做网关断言。 + const assetPath = + entryNames.find((name) => /^assets\/.+\.js$/u.test(name)) ?? + entryNames.find((name) => name.endsWith('.js')); + if (!assetPath) { + throw new Error( + `E2E_PACKAGE_ZIP 内没有可断言的 JS 资源:${externalPackageZip}`, + ); + } + return { + bytes: Buffer.from(bytes), + fileCount: entryNames.length, + assetPath, + entryMarker: null, + }; + } const zip = new JSZip(); zip.file( 'index.html', @@ -147,7 +184,12 @@ async function buildZip() { ); zip.file('assets/app.js', 'document.documentElement.dataset.e2e="media";'); const bytes = await zip.generateAsync({ type: 'uint8array' }); - return Buffer.from(bytes); + return { + bytes: Buffer.from(bytes), + fileCount: 2, + assetPath: 'assets/app.js', + entryMarker: 'E2E-MEDIA-OK', + }; } async function main() { @@ -172,6 +214,78 @@ async function main() { }); const another = otherEntry.data.token; + // 1.1 管理员登录:发布灰度默认关闭,脚本先验证关闭态再为本轮验证开启。 + const adminLogin = await api('/admin/api/login', { + method: 'POST', + body: { username: ADMIN_USER, password: ADMIN_PASSWORD }, + }); + check( + '管理员登录成功', + adminLogin.status === 200 && + Boolean(adminLogin.data?.token ?? adminLogin.data?.accessToken), + `status=${adminLogin.status}`, + ); + const admin = adminLogin.data?.token ?? adminLogin.data?.accessToken; + + const setPublishGate = (enabled, rolloutPercent) => + api('/admin/api/feature-gates', { + method: 'PUT', + token: admin, + body: { + gateKey: 'game-distribution:publish', + enabled, + rolloutPercent, + allowUserIds: [], + allowUserTags: [], + denyUserIds: [], + description: 'E2E 发布灰度', + }, + }); + + const gateClosed = await setPublishGate(false, 0); + check( + '发布灰度可配置为关闭', + gateClosed.status === 200, + `status=${gateClosed.status}`, + ); + + const closedAvailability = await api('/api/runtime/frontend-config', { + token: author, + }); + check( + '灰度关闭时作者拿不到发布入口', + closedAvailability.data?.gameDistributionPublishEnabled === false, + `value=${closedAvailability.data?.gameDistributionPublishEnabled}`, + ); + + const closedPublish = await api('/api/game-distribution/games', { + method: 'POST', + token: author, + headers: { 'Idempotency-Key': `e2e-gate-closed-${Date.now()}` }, + body: gameMetadata({ title: `灰度关闭验证 ${Date.now()}` }), + }); + check( + '灰度关闭时写入口 503', + closedPublish.status === 503, + `status=${closedPublish.status} code=${closedPublish.error?.code ?? ''}`, + ); + + const gateOpen = await setPublishGate(true, 100); + check( + '发布灰度可开启并放量', + gateOpen.status === 200, + `status=${gateOpen.status}`, + ); + + const openAvailability = await api('/api/runtime/frontend-config', { + token: author, + }); + check( + '灰度开启后作者拿到发布入口', + openAvailability.data?.gameDistributionPublishEnabled === true, + `value=${openAvailability.data?.gameDistributionPublishEnabled}`, + ); + // 2. 真实素材直传 const id = stamp(); const cover = await uploadImage(author, 'cover', id); @@ -230,7 +344,7 @@ async function main() { // 4. 创建游戏 + 版本(冻结资料) const metadata = gameMetadata({ - title: `分发媒体验证 ${id.slice(-6)}`, + title: gameTitleOverride || `分发媒体验证 ${id.slice(-6)}`, coverAssetId: cover.assetObjectId, screenshots: [shot1.assetObjectId, shot2.assetObjectId], }); @@ -284,7 +398,8 @@ async function main() { `status=${ghostVersion.status}`, ); - const zipBytes = await buildZip(); + const built = await buildZip(); + const zipBytes = built.bytes; const crypto = await import('node:crypto'); const sha256 = crypto.createHash('sha256').update(zipBytes).digest('hex'); const version = await api(`/api/game-distribution/games/${gameId}/versions`, { @@ -294,7 +409,7 @@ async function main() { body: { packageSha256: sha256, packageBytes: zipBytes.length, - packageFileCount: 2, + packageFileCount: built.fileCount, packageEntryPath: 'index.html', gameMetadata: metadata, }, @@ -401,19 +516,7 @@ async function main() { `status=${readBefore.status}`, ); - // 7. 管理员审核通过(本地非生产允许回环 http 入口) - const adminLogin = await api('/admin/api/login', { - method: 'POST', - body: { username: ADMIN_USER, password: ADMIN_PASSWORD }, - }); - check( - '管理员登录成功', - adminLogin.status === 200 && - Boolean(adminLogin.data?.token ?? adminLogin.data?.accessToken), - `status=${adminLogin.status}`, - ); - const admin = adminLogin.data?.token ?? adminLogin.data?.accessToken; - + // 7. 管理员审核通过(本地非生产允许回环 http 入口;管理员 token 在步骤 1.1 已取得) const approved = await api( `/admin/api/game-distribution/versions/${versionId}/review`, { @@ -423,7 +526,8 @@ async function main() { body: { decision: 'approve', expectedPublicationRevision: readback.data.version.publicationRevision, - entryUrl: `${API}`, + // 本地用发行网关路径当入口,让「审核通过 → 游玩」在本地也走真实网关。 + entryUrl: `${API}/api/game-distribution/releases/${gameId}/`, }, }, ); @@ -480,22 +584,27 @@ async function main() { `${API}/api/game-distribution/releases/${gameId}/index.html`, ); const releaseBody = await release.text(); + const entryOk = + release.status === 200 && + / 0, + `status=${releaseAsset.status} path=${built.assetPath} bytes=${assetBody.byteLength}`, ); console.log(`\n结果:${failures === 0 ? '全部通过' : `${failures} 项失败`}`); diff --git a/scripts/check-spacetime-schema-guard.mjs b/scripts/check-spacetime-schema-guard.mjs index 176c4aec9..528ecb6a2 100644 --- a/scripts/check-spacetime-schema-guard.mjs +++ b/scripts/check-spacetime-schema-guard.mjs @@ -12,6 +12,80 @@ const tableCatalogPath = 'docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md'; const bindingsRoot = 'server-rs/crates/spacetime-client/src/module_bindings/'; const allowBreaking = process.env.SPACETIME_SCHEMA_GUARD_ALLOW_BREAKING === '1'; + +// 本次历史表退役的一次性迁移白名单。该清单只允许这些已确认表从基线消失; +// 待删除结果进入后续主线基线后必须删除本清单,其他表仍按既有破坏性变更路径失败。 +export const APPROVED_RETIRED_TABLE_DELETIONS = Object.freeze([ + 'player_progression', + 'chapter_progression', + 'npc_state', + 'story_session', + 'story_event', + 'inventory_slot', + 'battle_state', + 'treasure_record', + 'quest_record', + 'quest_log', + 'custom_world_profile', + 'custom_world_session', + 'custom_world_agent_session', + 'custom_world_agent_message', + 'custom_world_agent_operation', + 'custom_world_draft_card', + 'custom_world_gallery_entry', + 'puzzle_agent_session', + 'puzzle_background_compile_task', + 'puzzle_agent_message', + 'puzzle_work_profile', + 'puzzle_event', + 'puzzle_runtime_run', + 'puzzle_leaderboard_entry', + 'puzzle_clear_agent_session', + 'puzzle_clear_work_profile', + 'puzzle_clear_runtime_run', + 'puzzle_clear_event', + 'bark_battle_draft_config', + 'bark_battle_published_config', + 'bark_battle_runtime_run', + 'bark_battle_score_record', + 'bark_battle_leaderboard_entry', + 'bark_battle_work_stats_projection', + 'bark_battle_personal_best_projection', + 'match3d_agent_session', + 'match3d_agent_message', + 'match_3_d_work_profile', + 'match3d_runtime_run', + 'jump_hop_agent_session', + 'jump_hop_work_profile', + 'jump_hop_runtime_run', + 'jump_hop_event', + 'jump_hop_leaderboard_entry', + 'wooden_fish_agent_session', + 'wooden_fish_work_profile', + 'wooden_fish_runtime_run', + 'wooden_fish_event', + 'square_hole_agent_session', + 'square_hole_agent_message', + 'square_hole_work_profile', + 'square_hole_runtime_run', + 'visual_novel_agent_session', + 'visual_novel_agent_message', + 'visual_novel_work_profile', + 'visual_novel_runtime_run', + 'visual_novel_runtime_history_entry', + 'visual_novel_runtime_event', + 'big_fish_creation_session', + 'big_fish_agent_message', + 'big_fish_asset_slot', + 'big_fish_runtime_run', + 'big_fish_event', +]); +const approvedRetiredTableDeletions = new Set(APPROVED_RETIRED_TABLE_DELETIONS); + +export function isApprovedRetiredTableDeletion(accessor) { + return approvedRetiredTableDeletions.has(accessor); +} + function normalizePath(path) { return path.replace(/\\/gu, '/'); } @@ -639,7 +713,7 @@ function fieldDescription(field) { return `${field.name}: ${field.type}`; } -function compareTables(baseTables, currentTables) { +export function compareTables(baseTables, currentTables) { const failures = []; let schemaChanged = false; let breakingChanged = false; @@ -648,6 +722,9 @@ function compareTables(baseTables, currentTables) { const currentTable = currentTables.get(accessor); if (!currentTable) { schemaChanged = true; + if (isApprovedRetiredTableDeletion(accessor)) { + continue; + } breakingChanged = true; failures.push( `${baseTable.path}:${baseTable.line}: SpacetimeDB 表 ${accessor} 被删除或改名。表删除/改名必须先询问用户并确认迁移计划。`, diff --git a/scripts/check-spacetime-schema-guard.test.ts b/scripts/check-spacetime-schema-guard.test.ts index 5265fe9f9..5111c139d 100644 --- a/scripts/check-spacetime-schema-guard.test.ts +++ b/scripts/check-spacetime-schema-guard.test.ts @@ -1,7 +1,9 @@ import { describe, expect, it } from 'vitest'; import { + APPROVED_RETIRED_TABLE_DELETIONS, collectTablesFromSources, + compareTables, isFormalGateEnvironment, listReachableRustFiles, resolveBaseRef, @@ -36,6 +38,15 @@ function createGitResolver(entries: Record) { return (args: string[]) => entries[args.join(' ')] ?? null; } +function collectTables(accessors: string[]) { + return collectTablesFromSources( + accessors.map((accessor, index) => ({ + path: `${sourceRoot}/schema.rs`, + text: tableSource(`Table${index}`, accessor), + })), + ).tables; +} + describe('SpacetimeDB schema guard base resolution', () => { it('prefers an explicit Jenkins-provided base ref', () => { expect( @@ -125,3 +136,61 @@ describe('SpacetimeDB schema guard module reachability', () => { expect(result.failures[0]).toMatch(/table accessor example 重复定义/u); }); }); + +describe('SpacetimeDB schema guard retired table deletion allowlist', () => { + it('allows exactly the 63 approved historical tables to disappear', () => { + expect(APPROVED_RETIRED_TABLE_DELETIONS).toHaveLength(63); + expect(new Set(APPROVED_RETIRED_TABLE_DELETIONS).size).toBe(63); + + const result = compareTables( + collectTables([...APPROVED_RETIRED_TABLE_DELETIONS]), + new Map(), + ); + + expect(result.failures).toEqual([]); + expect(result.schemaChanged).toBe(true); + expect(result.breakingChanged).toBe(false); + }); + + it('still rejects deletion of a table outside the approved list', () => { + const result = compareTables( + collectTables([APPROVED_RETIRED_TABLE_DELETIONS[0], 'active_table']), + new Map(), + ); + + expect(result.failures).toHaveLength(1); + expect(result.failures[0]).toMatch(/active_table.*被删除或改名/u); + expect(result.schemaChanged).toBe(true); + expect(result.breakingChanged).toBe(true); + }); + + it('does not suppress retained-table field deletion or rename checks', () => { + const baseTables = collectTablesFromSources([ + { + path: `${sourceRoot}/ranks.rs`, + text: `#[spacetimedb::table(accessor = retained_deleted_field)]\npub struct RetainedDeletedField {\n pub id: u64,\n pub title: String,\n}\n`, + }, + { + path: `${sourceRoot}/titles.rs`, + text: `#[spacetimedb::table(accessor = retained_renamed_field)]\npub struct RetainedRenamedField {\n pub id: u64,\n pub title: String,\n}\n`, + }, + ]).tables; + const currentTables = collectTablesFromSources([ + { + path: `${sourceRoot}/ranks.rs`, + text: `#[spacetimedb::table(accessor = retained_deleted_field)]\npub struct RetainedDeletedField {\n pub id: u64,\n}\n`, + }, + { + path: `${sourceRoot}/titles.rs`, + text: `#[spacetimedb::table(accessor = retained_renamed_field)]\npub struct RetainedRenamedField {\n pub id: u64,\n pub name: String,\n}\n`, + }, + ]).tables; + + const result = compareTables(baseTables, currentTables); + + expect(result.failures).toHaveLength(2); + expect(result.failures.join('\n')).toMatch(/字段数量减少/u); + expect(result.failures.join('\n')).toMatch(/字段被删除或改名/u); + expect(result.breakingChanged).toBe(true); + }); +}); diff --git a/scripts/export-ci-npm-download-cache.mjs b/scripts/export-ci-npm-download-cache.mjs new file mode 100644 index 000000000..de2f97bf1 --- /dev/null +++ b/scripts/export-ci-npm-download-cache.mjs @@ -0,0 +1,36 @@ +#!/usr/bin/env node +// 持久下载缓存可以保留旧版本;交付给 CI 镜像的快照只带当前 lock 已下载的包。 +import fs from 'node:fs/promises'; +import { createRequire } from 'node:module'; +import path from 'node:path'; +import { pipeline } from 'node:stream/promises'; + +const [npmRoot, lockPath, source, destination] = process.argv.slice(2); +if (!npmRoot || !lockPath || !source || !destination) { + throw new Error( + 'usage: export-ci-npm-download-cache.mjs ', + ); +} +const require = createRequire(path.resolve(npmRoot, 'package.json')); +const cacache = require('cacache'); +const lock = JSON.parse(await fs.readFile(lockPath, 'utf8')); +const integrities = new Set( + Object.values(lock.packages).flatMap((entry) => + typeof entry.integrity === 'string' ? [entry.integrity] : [], + ), +); +let count = 0; +for await (const entry of cacache.ls.stream(source)) { + if (!integrities.has(entry.integrity)) continue; + await pipeline( + cacache.get.stream(source, entry.key, { integrity: entry.integrity }), + cacache.put.stream(destination, entry.key, { + integrity: entry.integrity, + metadata: entry.metadata, + }), + ); + count += 1; +} +console.log( + `[ci-image] exported ${count} npm cache entries for the current lock`, +); diff --git a/scripts/export-ci-npm-download-cache.test.mjs b/scripts/export-ci-npm-download-cache.test.mjs new file mode 100644 index 000000000..9cfc4acfe --- /dev/null +++ b/scripts/export-ci-npm-download-cache.test.mjs @@ -0,0 +1,83 @@ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { existsSync } from 'node:fs'; +import fs from 'node:fs/promises'; +import { createRequire } from 'node:module'; +import os from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { fileURLToPath } from 'node:url'; + +const npmRoot = [ + path.resolve(path.dirname(process.execPath), 'node_modules/npm'), + path.resolve(path.dirname(process.execPath), '../lib/node_modules/npm'), + ...(process.env.npm_execpath + ? [path.resolve(path.dirname(process.env.npm_execpath), '..')] + : []), +].find((root) => existsSync(path.join(root, 'node_modules/cacache'))); +assert.ok(npmRoot, 'tests require the cacache bundled with npm'); +const cacache = createRequire(path.join(npmRoot, 'package.json'))('cacache'); +const script = fileURLToPath( + new URL('./export-ci-npm-download-cache.mjs', import.meta.url), +); + +async function fixture(t) { + const root = await fs.mkdtemp(path.join(os.tmpdir(), 'ci-npm-snapshot-')); + t.after(() => fs.rm(root, { recursive: true, force: true })); + const source = path.join(root, 'source'); + const destination = path.join(root, 'destination'); + const lock = path.join(root, 'package-lock.json'); + const key = + 'make-fetch-happen:request-cache:https://registry.npmjs.org/example/-/example-1.0.0.tgz'; + const metadata = { + url: key.slice('make-fetch-happen:request-cache:'.length), + }; + const integrity = String( + await cacache.put(source, key, 'current-package', { metadata }), + ); + await cacache.put(source, 'old-package', 'unused-old-version'); + await fs.writeFile( + lock, + JSON.stringify({ packages: { 'node_modules/example': { integrity } } }), + ); + const run = () => + spawnSync(process.execPath, [script, npmRoot, lock, source, destination], { + encoding: 'utf8', + }); + return { source, destination, key, metadata, integrity, run }; +} + +test('exports only current lock content, preserving npm request metadata for offline use', async (t) => { + const f = await fixture(t); + const result = f.run(); + assert.equal(result.status, 0, result.stderr); + assert.deepEqual(Object.keys(await cacache.ls(f.destination)), [f.key]); + const output = await cacache.get(f.destination, f.key); + assert.equal(output.data.toString(), 'current-package'); + assert.deepEqual(output.metadata, f.metadata); + // 输出是独立快照;移走持久缓存仍可使用,不依赖挂载、链接或旧 builder。 + await fs.rm(f.source, { recursive: true }); + assert.equal( + (await cacache.get(f.destination, f.key)).data.toString(), + 'current-package', + ); +}); + +test('rejects a corrupted cached package instead of publishing it', async (t) => { + const f = await fixture(t); + const digest = Buffer.from(f.integrity.split('-')[1], 'base64').toString( + 'hex', + ); + const contentPath = path.join( + f.source, + 'content-v2', + 'sha512', + digest.slice(0, 2), + digest.slice(2, 4), + digest.slice(4), + ); + await fs.writeFile(contentPath, 'corrupted-package'); + const result = f.run(); + assert.notEqual(result.status, 0); + assert.match(result.stderr, /EINTEGRITY|EBADSIZE/); +}); diff --git a/scripts/gitea-ci-job-image.sh b/scripts/gitea-ci-job-image.sh index b0e3cac4c..526c0ad7b 100644 --- a/scripts/gitea-ci-job-image.sh +++ b/scripts/gitea-ci-job-image.sh @@ -6,12 +6,31 @@ repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" dockerfile_context_path="deploy/container/gitea-ci-job.Dockerfile" image_tag="${GENARRATIVE_GITEA_CI_IMAGE_TAG:-genarrative/gitea-project-ci:20260920.2}" runner_container="${GENARRATIVE_GITEA_RUNNER_CONTAINER:-gitea-runner}" +builder_name="genarrative-ci-images" + +prepare_builder() { + if ! docker buildx version >/dev/null 2>&1; then + echo 'Gitea CI image builds require the Docker Buildx plugin; see deploy/container/README.md.' >&2 + return 1 + fi + if ! docker buildx inspect "${builder_name}" >/dev/null 2>&1; then + docker buildx create --name "${builder_name}" --driver docker-container \ + --driver-opt image=moby/buildkit:v0.23.2@sha256:ddd1ca44b21eda906e81ab14a3d467fa6c39cd73b9a39df1196210edcb8db59e \ + --buildkitd-config "${repo_root}/deploy/container/gitea-ci-buildkitd.toml" + fi + if [[ "$(docker buildx inspect "${builder_name}" | awk '$1 == "Driver:" { print $2 }')" != docker-container ]]; then + echo "${builder_name} must use the isolated docker-container driver" >&2 + return 1 + fi +} write_build_context_file_list() { printf '%s\0' \ deploy/container/gitea-ci-job.Dockerfile \ deploy/container/gitea-ci-job.Dockerfile.dockerignore \ + deploy/container/gitea-ci-buildkitd.toml \ deploy/container/gitea-ci-checkout.sh \ + scripts/export-ci-npm-download-cache.mjs \ package.json \ package-lock.json \ apps/admin-web/package.json \ @@ -29,8 +48,9 @@ write_build_context_file_list() { server-rs/Cargo.lock \ apps/desktop-shell/src-tauri/Cargo.toml \ apps/desktop-shell/src-tauri/Cargo.lock - find server-rs/crates plugins/agc-*-editor/native/*-editor-bridge \ - \( -name Cargo.toml -o -path 'plugins/agc-*-editor/native/*-editor-bridge/*' \) \ + find server-rs/crates apps/ai-game-creator-shell/src-tauri/vendor \ + plugins/agc-*-editor/native/*-editor-bridge \ + -name Cargo.toml \ -type f -print0 \ | sort -z } @@ -39,6 +59,7 @@ usage() { cat <<'EOF' 用法: bash scripts/gitea-ci-job-image.sh build + bash scripts/gitea-ci-job-image.sh seed-downloads <可信 CI 镜像完整 Image ID> bash scripts/gitea-ci-job-image.sh revision bash scripts/gitea-ci-job-image.sh verify [镜像引用] bash scripts/gitea-ci-job-image.sh load-runner [镜像引用] @@ -66,6 +87,28 @@ verify_image() { command_name="${1:-}" case "${command_name}" in + seed-downloads) + # 运维显式指定的可信镜像只贡献下载包,不作为新基础镜像的父层。 + seed_image="${2:-}" + [[ "${seed_image}" =~ ^sha256:[0-9a-f]{64}$ ]] || { echo 'seed requires a full trusted Image ID' >&2; exit 2; } + prepare_builder + seed_dir="$(mktemp -d)" + seed_container="" + cleanup_seed() { + if [[ -n "${seed_container}" ]]; then docker rm --volumes "${seed_container}" >/dev/null; fi + rm -rf -- "${seed_dir}" + } + trap cleanup_seed EXIT + seed_container="$(docker create "${seed_image}")" + mkdir -p "${seed_dir}/cargo-cache" "${seed_dir}/cargo-index" "${seed_dir}/npm" + docker cp "${seed_container}:/usr/local/cargo/registry/cache/." "${seed_dir}/cargo-cache/" + docker cp "${seed_container}:/usr/local/cargo/registry/index/." "${seed_dir}/cargo-index/" + docker cp "${seed_container}:/root/.npm/_cacache/." "${seed_dir}/npm/" + docker buildx build --builder "${builder_name}" --progress plain \ + --target download-cache-seed --no-cache-filter download-cache-seed \ + --build-context "download-seed=${seed_dir}" \ + --file "${repo_root}/${dockerfile_context_path}" "${seed_dir}" + ;; revision) # 与 build 的 IMAGE_REVISION 使用同一份输入顺序,用于维护器判断基础镜像是否过期。 ( @@ -74,6 +117,7 @@ case "${command_name}" in ) ;; build) + prepare_builder image_revision="$(bash "${BASH_SOURCE[0]}" revision)" npm_lock_sha256="$(sha256sum "${repo_root}/package-lock.json")" npm_lock_sha256="${npm_lock_sha256%% *}" @@ -87,7 +131,7 @@ case "${command_name}" in cd "${repo_root}" write_build_context_file_list \ | tar --null --create --file - --files-from=- \ - | docker build \ + | docker buildx build --builder "${builder_name}" --load --progress plain \ --pull=false \ --build-arg "IMAGE_REVISION=${image_revision}" \ --build-arg "NPM_LOCK_SHA256=${npm_lock_sha256}" \ diff --git a/scripts/gitea_cache_snapshot.py b/scripts/gitea_cache_snapshot.py index 46e117e15..f270ea1b8 100644 --- a/scripts/gitea_cache_snapshot.py +++ b/scripts/gitea_cache_snapshot.py @@ -167,6 +167,14 @@ def _snapshot_member(archive: Path) -> tuple[zipfile.ZipFile, zipfile.ZipInfo]: raise +def validate_artifact_zip(archive: Path) -> None: + """Validate the bounded stored ZIP envelope before consuming an artifact.""" + bundle, _ = _snapshot_member(archive) + with bundle: + if bundle.testzip() is not None: + raise SnapshotError("artifact ZIP CRC check failed") + + def _tar_stream(archive: Path): bundle, member = _snapshot_member(archive) try: @@ -440,6 +448,94 @@ def _file_sha256(path: Path) -> str: digest.update(chunk) +def _object_zip_signature(stream: BinaryIO, expected: _Object) -> tuple: + """只允许 sccache 对象的 ZIP 成员排列不同,不放宽内容或元数据校验。""" + with tempfile.TemporaryFile() as temporary: + digest = hashlib.sha256() + total = 0 + while chunk := stream.read(1024 * 1024): + total += len(chunk) + if total > expected.size: + raise SnapshotError("cache object grew while comparing ZIP contents") + digest.update(chunk) + temporary.write(chunk) + if (total, digest.hexdigest()) != (expected.size, expected.sha256): + raise SnapshotError("cache object checksum changed while comparing ZIP contents") + temporary.seek(0) + with zipfile.ZipFile(temporary) as bundle: + infos = bundle.infolist() + if (not infos or len(infos) > MAX_OBJECTS + or len({info.filename for info in infos}) != len(infos) + or sum(info.file_size for info in infos) > expected.size): + raise SnapshotError("invalid sccache ZIP member set") + members = [] + for info in sorted(infos, key=lambda entry: entry.filename): + _safe_zip_path(info.filename) + mode = info.external_attr >> 16 + if (info.is_dir() or info.flag_bits & 1 or stat.S_ISLNK(mode) + or stat.S_IFMT(mode) not in (0, stat.S_IFREG) + or info.compress_type != zipfile.ZIP_STORED): + raise SnapshotError("unsupported sccache ZIP member") + with bundle.open(info) as contents: + size, checksum = _hash_stream(contents, info.file_size) + members.append(( + info.filename, size, checksum, info.CRC, info.compress_size, + info.compress_type, info.date_time, info.flag_bits, + info.external_attr, info.internal_attr, info.create_system, + info.create_version, info.extract_version, info.reserved, + info.extra, info.comment, + )) + return bundle.comment, tuple(members) + + +def _equivalent_delta_paths(archives: Sequence[_Archive]) -> set[str]: + variants: dict[str, set[tuple[int, str | None]]] = {} + for archive in archives: + for obj in archive.objects: + variants.setdefault(obj.path, set()).add((obj.size, obj.sha256)) + conflicts = {path for path, versions in variants.items() if len(versions) > 1} + if not conflicts: + return conflicts + for path in conflicts: + if len({size for size, _ in variants[path]}) != 1: + raise SnapshotError(f"conflicting content for duplicate object: {path}") + signatures = {} + # 每份归档最多额外顺序读取一次,仅将冲突对象暂存到磁盘供 ZIP 随机读取。 + for archive in archives: + wanted = {obj.path: obj for obj in archive.objects if obj.path in conflicts} + if not wanted: + continue + if _archive_signature(archive.input.archive) != archive.signature: + raise SnapshotError("artifact archive changed while comparing cache objects") + bundle, raw, tar = _tar_stream(archive.input.archive) + try: + for member in tar: + expected = wanted.get(member.name) + if expected is None: + continue + if not member.isreg() or member.size != expected.size: + raise SnapshotError("cache object changed while comparing ZIP contents") + stream = tar.extractfile(member) + if stream is None: + raise SnapshotError("cache object is missing while comparing ZIP contents") + try: + with stream: + signature = _object_zip_signature(stream, expected) + except (SnapshotError, zipfile.BadZipFile, NotImplementedError) as error: + raise SnapshotError(f"conflicting content for duplicate object: {member.name}") from error + if member.name in signatures and signatures[member.name] != signature: + raise SnapshotError(f"conflicting content for duplicate object: {member.name}") + signatures[member.name] = signature + del wanted[member.name] + if wanted: + raise SnapshotError("cache objects disappeared while comparing ZIP contents") + finally: + tar.close() + raw.close() + bundle.close() + return conflicts + + def _select_objects( archives: Sequence[_Archive], base_root: Path, @@ -447,6 +543,7 @@ def _select_objects( maximum: int, ) -> tuple[_Object, ...]: merged = dict(base) + equivalent_paths = _equivalent_delta_paths(archives) delta_paths = {obj.path for archive in archives for obj in archive.objects} touched_paths = {touch.path for archive in archives for touch in archive.touched} overlap = delta_paths & touched_paths @@ -490,7 +587,8 @@ def _select_objects( mtime_ns=max(current.mtime_ns, candidate.mtime_ns), source_index=None, ) - elif (current.size, current.sha256) != (candidate.size, candidate.sha256): + elif ((current.size, current.sha256) != (candidate.size, candidate.sha256) + and candidate.path not in equivalent_paths): raise SnapshotError(f"conflicting content for duplicate object: {candidate.path}") elif candidate.mtime_ns > current.mtime_ns: merged[candidate.path] = _Object( diff --git a/scripts/maintain-gitea-rust-cache.py b/scripts/maintain-gitea-rust-cache.py index d4dedde86..6d2421e6d 100644 --- a/scripts/maintain-gitea-rust-cache.py +++ b/scripts/maintain-gitea-rust-cache.py @@ -2,8 +2,10 @@ """宿主专用的 Rust 缓存维护器;仅使用 Python 标准库,不在 CI job 中运行。""" import argparse +import contextlib import datetime import hashlib +import http.client import json import os from pathlib import Path @@ -17,8 +19,11 @@ import time import urllib.error import urllib.parse import urllib.request +import zipfile -from gitea_cache_snapshot import ArtifactIdentity, ArtifactInput, merge_snapshots +from gitea_cache_snapshot import ( + ArtifactIdentity, ArtifactInput, SnapshotError, merge_snapshots, validate_artifact_zip, +) from gitea_cache_upload_cleanup import cleanup_upload_chunks @@ -45,6 +50,7 @@ RUST_JOBS = set(RUST_JOB_IDS) ARTIFACT_PREFIX = "rust-cache-v1-" MAX_DOWNLOAD = 4 * 1024 ** 3 + 129 * 1024 ** 2 EXPORT_STEP = "Publish master Rust cache artifact" +DOWNLOAD_ATTEMPTS = 3 def now(): @@ -59,6 +65,23 @@ def log(message): print(f"[cache-maintenance] {message}", flush=True) +@contextlib.contextmanager +def operation(name, *, build_log=None): + """Record long maintenance stages without exposing command arguments or API data.""" + started = time.monotonic() + location = f"; build log={build_log}" if build_log is not None else "" + log(f"{name}: started{location}") + try: + yield + except Exception: + elapsed = time.monotonic() - started + log(f"{name}: failed after {elapsed:.1f}s{location}") + raise + else: + elapsed = time.monotonic() - started + log(f"{name}: completed in {elapsed:.1f}s") + + def command(*args, cwd=None, data=None, env=None, output=None, timeout=120, combined=False): result = subprocess.run( args, cwd=cwd, input=data, text=True, env=env, timeout=timeout, @@ -165,35 +188,90 @@ class Api: raise RuntimeError(f"Gitea API HTTP {error.code}") from None return content if raw else (json.loads(content) if content else None) - def download(self, path, destination): - """REST V4 archive redirects to a signed URL; never forward the API token.""" + def download(self, path, destination, expected_size): + """Fetch one artifact archive, retrying incomplete signed-URL transfers.""" + if (isinstance(expected_size, bool) or not isinstance(expected_size, int) + or expected_size <= 0): + raise RuntimeError("artifact has invalid size metadata") + if expected_size > MAX_DOWNLOAD: + raise RuntimeError("artifact exceeds per-job size limit") + + for attempt in range(DOWNLOAD_ATTEMPTS): + try: + self._download_once(path, destination, expected_size) + return + except RetryableArtifactDownload as error: + destination.unlink(missing_ok=True) + log(f"artifact download attempt {attempt + 1}/{DOWNLOAD_ATTEMPTS} failed: {error}") + if attempt + 1 == DOWNLOAD_ATTEMPTS: + raise RuntimeError("artifact download remained incomplete after retries") from error + time.sleep(1 << attempt) + except Exception: + destination.unlink(missing_ok=True) + raise + + def _download_once(self, path, destination, expected_size): + """Obtain a fresh signed URL and validate its complete ZIP response.""" token = self.token_file.read_text().strip() url = self.url + "/" + path.lstrip("/") opener = urllib.request.build_opener(NoRedirect()) request = urllib.request.Request(url, headers={"Authorization": "token " + token}) + target = None try: - response = opener.open(request, timeout=60) - except urllib.error.HTTPError as error: - error.close() - if error.code not in (301, 302, 303, 307, 308): - raise RuntimeError(f"artifact download HTTP {error.code}") from None - target = urllib.parse.urljoin(url, error.headers.get("Location", "")) - parsed, origin = urllib.parse.urlsplit(target), urllib.parse.urlsplit(self.url) - if (parsed.scheme != "https" or parsed.netloc != origin.netloc - or parsed.username or parsed.password or target == url): - raise RuntimeError("artifact redirect must stay on configured HTTPS Gitea origin") from None - response = opener.open(target, timeout=60) - try: - with response, destination.open("wb") as out: - total = 0 - while chunk := response.read(1024 * 1024): - total += len(chunk) - if total > MAX_DOWNLOAD: + try: + response = opener.open(request, timeout=60) + except urllib.error.HTTPError as error: + error.close() + if error.code not in (301, 302, 303, 307, 308): + if error.code >= 500: + raise RetryableArtifactDownload(f"artifact download HTTP {error.code}") from None + raise RuntimeError(f"artifact download HTTP {error.code}") from None + target = urllib.parse.urljoin(url, error.headers.get("Location", "")) + parsed, origin = urllib.parse.urlsplit(target), urllib.parse.urlsplit(self.url) + if (parsed.scheme != "https" or parsed.netloc != origin.netloc + or parsed.username or parsed.password or target == url): + raise RuntimeError("artifact redirect must stay on configured HTTPS Gitea origin") from None + if target is not None: + try: + response = opener.open(target, timeout=60) + except urllib.error.HTTPError as error: + error.close() + if error.code >= 500: + raise RetryableArtifactDownload(f"artifact download HTTP {error.code}") from None + raise RuntimeError(f"artifact download HTTP {error.code}") from None + with response: + content_length = getattr(response, "headers", {}).get("Content-Length") + if content_length is not None: + try: + content_length = int(content_length) + except (TypeError, ValueError): + raise RetryableArtifactDownload("artifact response has invalid Content-Length") from None + if content_length > MAX_DOWNLOAD: raise RuntimeError("artifact exceeds per-job size limit") - out.write(chunk) - except Exception: - destination.unlink(missing_ok=True) - raise + if content_length != expected_size: + raise RetryableArtifactDownload( + f"artifact response size differs: expected {expected_size} bytes, " + f"Content-Length is {content_length}") + with destination.open("wb") as out: + total = 0 + while chunk := response.read(1024 * 1024): + total += len(chunk) + if total > MAX_DOWNLOAD: + raise RuntimeError("artifact exceeds per-job size limit") + if total > expected_size: + raise RetryableArtifactDownload( + f"artifact response exceeds metadata: expected {expected_size} bytes, " + f"received at least {total}") + out.write(chunk) + if total != expected_size: + raise RetryableArtifactDownload( + f"artifact response is truncated: expected {expected_size} bytes, received {total}") + try: + validate_artifact_zip(destination) + except (SnapshotError, zipfile.BadZipFile): + raise RetryableArtifactDownload("artifact response is not a valid ZIP") from None + except (http.client.HTTPException, urllib.error.URLError, OSError) as error: + raise RetryableArtifactDownload("artifact transfer failed") from error def pages(self, path, key): separator = "&" if "?" in path else "?" @@ -212,6 +290,10 @@ class NoRedirect(urllib.request.HTTPRedirectHandler): return None +class RetryableArtifactDownload(RuntimeError): + """A signed archive transfer may be retried with a newly issued URL.""" + + class Maintenance: def __init__(self, config): self.config = config @@ -291,10 +373,11 @@ class Maintenance: tree = command("git", "ls-tree", "-rz", sha, cwd=self.repo) return sha, cache_inputs(tree) - def build_command(self, log_file, script, *args, env=None): - with log_file.open("a") as out: - command("bash", str(self.repo / "scripts" / script), *args, cwd=self.repo, - env=env, output=out, timeout=7200) + def build_command(self, log_file, script, *args, env=None, description=None): + with operation(description or f"run {script}", build_log=log_file): + with log_file.open("a") as out: + command("bash", str(self.repo / "scripts" / script), *args, cwd=self.repo, + env=env, output=out, timeout=7200) def master_run(self, run): return (run.get("path") == "project-ci.yml@refs/heads/master" @@ -352,7 +435,10 @@ class Maintenance: if len(used) != 1: break images.update(used) - selected.append({"id": matches[0]["id"], "name": name, + size = matches[0].get("size_in_bytes") + if isinstance(size, bool) or not isinstance(size, int) or size <= 0 or size > MAX_DOWNLOAD: + break + selected.append({"id": matches[0]["id"], "name": name, "size_in_bytes": size, "job": RUST_JOB_IDS[job["name"]], "attempt": job["run_attempt"]}) if len(selected) != len(RUST_JOB_IDS) or len(images) != 1: continue @@ -387,13 +473,17 @@ class Maintenance: base_labels = self.image_info(base)["Config"].get("Labels") or {} if base_labels.get("com.genarrative.ci.definition-sha256") != revision: env["GENARRATIVE_GITEA_CI_IMAGE_TAG"] = base_tag - self.build_command(build_log, "gitea-ci-job-image.sh", "build", env=env) + self.build_command(build_log, "gitea-ci-job-image.sh", "build", env=env, + description="rebuild cache base image") base = self.image_info(base_tag)["Id"] self.state.setdefault("bases", {})[base] = base_tag self.save() + else: + log("reuse compatible cache base image") # 与旧缓存镜像分离;绝不把 Docker 可写层、源码或 target commit 成镜像。 - self.docker("run", "--rm", "--network", "none", "--read-only", "--cap-drop=ALL", - "--entrypoint", "bash", base, "-c", "test ! -e /opt/genarrative-ci/rust-cache") + with operation("validate cache base image", build_log=build_log): + self.docker("run", "--rm", "--network", "none", "--read-only", "--cap-drop=ALL", + "--entrypoint", "bash", base, "-c", "test ! -e /opt/genarrative-ci/rust-cache") with tempfile.TemporaryDirectory(prefix="assemble-", dir=artifact) as temporary: work = Path(temporary) inherited = work / "inherited" @@ -406,32 +496,47 @@ class Maintenance: inputs = [] for export in source["exports"]: archive = work / (str(export["id"]) + ".zip") - self.api.download(self.repo_api + f'/actions/artifacts/{export["id"]}/zip', archive) + with operation(f"download cache artifact job={export['job']} attempt={export['attempt']}", + build_log=build_log): + self.api.download(self.repo_api + f'/actions/artifacts/{export["id"]}/zip', archive, + export["size_in_bytes"]) inputs.append(ArtifactInput(archive, ArtifactIdentity( self.config["repository"], source["run_id"], export["attempt"], export["job"], sha))) snapshot = work / "snapshot" - merged = merge_snapshots(inputs, snapshot, base_objects=inherited / "objects", - expected_inherited_source_sha=inherited_source) + with operation(f"merge {len(inputs)} cache artifacts", build_log=build_log): + merged = merge_snapshots(inputs, snapshot, base_objects=inherited / "objects", + expected_inherited_source_sha=inherited_source) if merged.sccache_version != "sccache 0.18.0": raise RuntimeError("unsupported sccache version") if merged.base_image is not None and merged.base_image != labels["world.genarrative.ci.rust-cache-base"]: raise RuntimeError("artifact base differs from its actual source image") - rustc = self.docker("run", "--rm", "--network", "none", "--read-only", base, "rustc", "-vV") - if rustc.strip() != merged.rustc.strip(): - raise RuntimeError("artifact toolchain differs from target base image") - if merged.workspace != "/workspace/" + self.config["repository"]: - raise RuntimeError("artifact workspace differs from CI checkout") + with operation("validate merged snapshot against target image", build_log=build_log): + rustc = self.docker("run", "--rm", "--network", "none", "--read-only", base, "rustc", "-vV") + if rustc.strip() != merged.rustc.strip(): + raise RuntimeError("artifact toolchain differs from target base image") + if merged.workspace != "/workspace/" + self.config["repository"]: + raise RuntimeError("artifact workspace differs from CI checkout") shutil.copyfile(inherited / "sccache", snapshot / "sccache") (snapshot / "sccache").chmod(0o755) (snapshot / "base-image.txt").write_text(base + "\n") + # BuildKit 的 FROM 不接受裸 Image ID;维护锁内使用一个临时本地别名。 + # 别名不登记为 owned base,避免把接管前的基础镜像纳入自动清理。 + assembly_base = "genarrative/gitea-project-ci:assembly-base" (work / "Dockerfile").write_text( - f"FROM {base}\nCOPY snapshot/ /opt/genarrative-ci/rust-cache/\n" + f"FROM {assembly_base}\nCOPY snapshot/ /opt/genarrative-ci/rust-cache/\n" f'LABEL world.genarrative.ci.rust-cache-source="{sha}"\n' f'LABEL world.genarrative.ci.rust-cache-base="{base}"\n') (work / ".dockerignore").write_text("**\n!Dockerfile\n!snapshot/\n!snapshot/**\n") - with build_log.open("a") as out: - self.docker("build", "--pull=false", "--tag", tag, str(work), output=out, timeout=1800) - self.build_command(build_log, "gitea-ci-job-image.sh", "verify", tag, env=env) + with operation("assemble cache candidate image", build_log=build_log): + self.docker("image", "tag", base, assembly_base) + try: + with build_log.open("a") as out: + self.docker("build", "--builder", "default", "--pull=false", "--tag", tag, + str(work), output=out, timeout=1800) + finally: + self.docker("image", "rm", assembly_base) + self.build_command(build_log, "gitea-ci-job-image.sh", "verify", tag, env=env, + description="verify cache candidate image") image = self.image_info(tag)["Id"] self.state["versions"].append({**attempt, "image": image, "base": base, "owned": True, "verified_run": None}) @@ -449,17 +554,22 @@ class Maintenance: sidecar = archive.with_suffix(".zst.sha256") if (candidate.get("staged") and archive.is_file() and sidecar.is_file() and candidate["image"] in self.docker("image", "ls", "--all", "--no-trunc", "--quiet", inner=True).split()): + log("reuse exported and loaded candidate image") return env = {**os.environ, "GENARRATIVE_GITEA_RUNNER_CONTAINER": self.runner} build_log = artifact / "build.log" if not sidecar.exists(): # 只删除登记目录中的未完成导出文件,不覆盖已验证归档。 archive.unlink(missing_ok=True) - self.build_command(build_log, "gitea-ci-job-image.sh", "export", str(archive), candidate["image"], env=env) - command("sha256sum", "--check", sidecar.name, cwd=artifact, timeout=600) - self.build_command(build_log, "gitea-ci-job-image.sh", "load-runner", candidate["image"], env=env) - if self.image_info(candidate["image"], inner=True)["Id"] != candidate["image"]: - raise RuntimeError("inner runner image mismatch") + self.build_command(build_log, "gitea-ci-job-image.sh", "export", str(archive), candidate["image"], env=env, + description="export cache candidate image") + with operation("validate exported cache candidate image", build_log=build_log): + command("sha256sum", "--check", sidecar.name, cwd=artifact, timeout=600) + self.build_command(build_log, "gitea-ci-job-image.sh", "load-runner", candidate["image"], env=env, + description="load cache candidate image into runner") + with operation("verify loaded cache candidate image", build_log=build_log): + if self.image_info(candidate["image"], inner=True)["Id"] != candidate["image"]: + raise RuntimeError("inner runner image mismatch") candidate["staged"] = True self.save() @@ -473,6 +583,13 @@ class Maintenance: "--filter", "status=created", "--filter", "status=restarting", "--filter", "status=paused", inner=True).strip()) + def wait_for_idle(self, purpose): + with operation(f"wait for idle runner before {purpose}"): + ready = self.idle() + if not ready: + log(f"runner is busy; defer {purpose}") + return ready + def verify_current(self): current = self.version(self.state["current"]) if current.get("verified_run"): @@ -628,12 +745,12 @@ class Maintenance: if source is None: log("waiting for a complete set of master CI cache exports") return + log(f"selected cache source run={source['run_id']} source={source['source']}") if not retry and self.state.get("failed_run") == source["run_id"]: log(f'previous assembly failed at run={source["run_id"]}; waiting for new run or --retry') return # 下载、合并和镜像装载也消耗宿主 IO;繁忙时留给 CI,下轮再收集。 - if not self.idle(): - log("CI active; defer refresh") + if not self.wait_for_idle("cache assembly"): return try: self.build(source) @@ -737,7 +854,7 @@ class Maintenance: if gate.get("paused") is not False and not self.state.get("pause_owned"): log("runner gate paused by operator; defer switch") return False - if not self.state.get("switch") and not self.idle(): + if not self.state.get("switch") and not self.wait_for_idle("runner switch"): log("CI active; candidate stays staged") return False # 先持久化恢复意图;控制请求超时也可能已生效,ExecStopPost/下次 tick 会恢复。 @@ -748,19 +865,20 @@ class Maintenance: raise RuntimeError("runner pause could not be confirmed") # 不用 FetchTask 客户端超时猜测服务端事务是否已经结束。 # 入口必须完整读完已转发的响应;不确定时拒绝自动重启。 - for _ in range(30): - gate = self.gate("status") - if gate.get("uncertain"): - raise RuntimeError("in-flight FetchTask completion is uncertain; manual gate inspection required") - if gate.get("paused") is not True: - raise RuntimeError("runner gate unexpectedly resumed") - if gate.get("inflight") == 0: - break - time.sleep(1) - else: - log("FetchTask still in flight; defer switch") - return False - if not self.idle(): + with operation("wait for FetchTask completion before runner switch"): + for _ in range(30): + gate = self.gate("status") + if gate.get("uncertain"): + raise RuntimeError("in-flight FetchTask completion is uncertain; manual gate inspection required") + if gate.get("paused") is not True: + raise RuntimeError("runner gate unexpectedly resumed") + if gate.get("inflight") == 0: + break + time.sleep(1) + else: + log("FetchTask still in flight; defer switch") + return False + if not self.wait_for_idle("runner restart"): log("in-flight task appeared; defer switch without stopping runner") return False latest_config = self.read_config() @@ -789,22 +907,24 @@ class Maintenance: self.save() log("idle check changed before restart; restored configuration") return False - self.docker("restart", "--timeout", "660", self.runner, timeout=720) + with operation("restart runner with cache candidate image"): + self.docker("restart", "--timeout", "660", self.runner, timeout=720) started = self.docker("inspect", "--format", "{{.State.StartedAt}}", self.runner).strip() ready = False - for _ in range(30): - try: - info = self.docker("inspect", "--format", "{{.State.Status}}", self.runner).strip() - recent = self.docker("logs", "--since", started, self.runner, combined=True) - ready = (info == "running" and "declare successfully" in recent - and self.image_info(candidate["image"], inner=True)["Id"] == candidate["image"]) - except RuntimeError: - ready = False - if ready: - break - time.sleep(2) - if not ready: - raise RuntimeError("runner registration not confirmed; pending switch retained for recovery") + with operation("wait for runner image registration"): + for _ in range(30): + try: + info = self.docker("inspect", "--format", "{{.State.Status}}", self.runner).strip() + recent = self.docker("logs", "--since", started, self.runner, combined=True) + ready = (info == "running" and "declare successfully" in recent + and self.image_info(candidate["image"], inner=True)["Id"] == candidate["image"]) + except RuntimeError: + ready = False + if ready: + break + time.sleep(2) + if not ready: + raise RuntimeError("runner registration not confirmed; pending switch retained for recovery") candidate["activated"] = now() self.state["rollback"] = pending["old"] self.state["current"] = pending["new"] diff --git a/scripts/project-ci-workflow.test.ts b/scripts/project-ci-workflow.test.ts index 7304408dc..6f793634a 100644 --- a/scripts/project-ci-workflow.test.ts +++ b/scripts/project-ci-workflow.test.ts @@ -379,9 +379,8 @@ describe('project CI workflow', () => { expect(imageDockerignore).toContain(`!${path}`); } - // AGC 通过本地 path 依赖引用三个编辑器 bridge crate。镜像预热会对 - // AGC manifest 执行 cargo fetch --locked,构建上下文与 dockerignore - // 必须同时放行这些 crate,否则镜像在 cargo fetch 阶段必然失败。 + // AGC 通过本地 path 依赖引用三个编辑器 bridge crate。Cargo fetch 只需要 + // manifest;完整源码不得进入镜像构建上下文,实际清单闭包由 Python tar 测试核验。 for (const bridgeDir of [ 'plugins/agc-cocos-editor/native/cocos-editor-bridge', 'plugins/agc-unity-editor/native/unity-editor-bridge', @@ -394,6 +393,18 @@ describe('project CI workflow', () => { `COPY ${bridgeDir} /tmp/genarrative-cargo-cache/${bridgeDir}`, ); } + expect(imageBuildScript).toContain( + 'apps/ai-game-creator-shell/src-tauri/vendor', + ); + expect(imageDockerignore).toContain( + '!apps/ai-game-creator-shell/src-tauri/vendor/*/Cargo.toml', + ); + expect(imageDockerignore).toContain( + '!plugins/agc-*-editor/native/*-editor-bridge/Cargo.toml', + ); + expect(imageDockerfile).toContain( + 'COPY apps/ai-game-creator-shell/src-tauri /tmp/genarrative-cargo-cache/apps/ai-game-creator-shell/src-tauri', + ); expect(imageBuildScript).toContain( '--build-arg "AGC_RUST_LOCK_SHA256=${agc_rust_lock_sha256}"', @@ -431,6 +442,25 @@ describe('project CI workflow', () => { expect(imageCheckScript).toContain( '::warning title=CI dependency cache is partial::', ); + + // 下载缓存由 BuildKit 的固定 ID 独占写入,最终镜像只复制受控快照,不继承旧镜像层。 + for (const mount of [ + 'id=genarrative-ci-cargo-cache-v1,target=/usr/local/cargo/registry/cache,sharing=locked', + 'id=genarrative-ci-cargo-index-v1,target=/usr/local/cargo/registry/index,sharing=locked', + 'id=genarrative-ci-npm-v1,target=/var/cache/genarrative-ci-npm,sharing=locked', + ]) { + expect(imageDockerfile).toContain(mount); + } + expect(imageDockerfile).toContain( + 'FROM rust-toolchain AS download-cache-seed', + ); + expect(imageBuildScript).toContain('--target download-cache-seed'); + expect(imageDockerfile).toContain( + 'COPY --from=rust-dependency-cache /opt/ci-downloads/registry /usr/local/cargo/registry', + ); + expect(imageDockerfile).toContain( + '/var/cache/genarrative-ci-npm/_cacache /root/.npm/_cacache', + ); }); it('copies every workspace manifest before the API image web-builder clean install', () => { diff --git a/scripts/rebind-orphan-work-owners.mjs b/scripts/rebind-orphan-work-owners.mjs deleted file mode 100644 index a9319f54f..000000000 --- a/scripts/rebind-orphan-work-owners.mjs +++ /dev/null @@ -1,202 +0,0 @@ -#!/usr/bin/env node - -import { readFile, writeFile } from 'node:fs/promises'; -import path from 'node:path'; - -export const DEFAULT_ORPHAN_WORK_OWNER_USER_ID = 'wx-openid-placeholder'; - -export const WORK_OWNER_TABLES = [ - 'custom_world_profile', - 'custom_world_gallery_entry', - 'custom_world_session', - 'custom_world_agent_session', - 'custom_world_draft_card', - 'puzzle_agent_session', - 'puzzle_work_profile', - 'bark_battle_draft_config', - 'bark_battle_published_config', - 'match3d_agent_session', - 'match3d_work_profile', - 'jump_hop_agent_session', - 'jump_hop_work_profile', - 'wooden_fish_agent_session', - 'wooden_fish_work_profile', - 'square_hole_agent_session', - 'square_hole_work_profile', - 'visual_novel_agent_session', - 'visual_novel_work_profile', - 'big_fish_creation_session', -]; - -const ROW_KEY_FIELDS = [ - 'profile_id', - 'work_id', - 'session_id', - 'draft_id', - 'gallery_entry_id', - 'id', -]; - -if (isCliEntry()) { - runCli(process.argv.slice(2)).catch((error) => { - console.error( - `[rebind-orphan-work-owners] ${error instanceof Error ? error.message : String(error)}`, - ); - process.exit(1); - }); -} - -export function rebindOrphanWorkOwnersInMigration( - migration, - { - placeholderUserId = DEFAULT_ORPHAN_WORK_OWNER_USER_ID, - validUserIds = [], - } = {}, -) { - if (!migration || !Array.isArray(migration.tables)) { - throw new Error('迁移 JSON 必须包含 tables 数组。'); - } - - const normalizedPlaceholderUserId = placeholderUserId.trim(); - const validUserIdSet = new Set( - (Array.isArray(validUserIds) ? validUserIds : []) - .map((value) => String(value).trim()) - .filter(Boolean), - ); - validUserIdSet.add(normalizedPlaceholderUserId); - - const reboundRows = []; - for (const table of migration.tables) { - if ( - !table || - !WORK_OWNER_TABLES.includes(table.name) || - !Array.isArray(table.rows) - ) { - continue; - } - - for (const row of table.rows) { - if (!row || typeof row !== 'object') { - continue; - } - const currentOwner = - typeof row.owner_user_id === 'string' ? row.owner_user_id.trim() : ''; - if ( - currentOwner === normalizedPlaceholderUserId || - validUserIdSet.has(currentOwner) - ) { - continue; - } - - const originalOwner = - typeof row.owner_user_id === 'string' ? row.owner_user_id : ''; - row.owner_user_id = normalizedPlaceholderUserId; - reboundRows.push({ - table: table.name, - rowKey: resolveRowKey(row), - from: originalOwner, - to: normalizedPlaceholderUserId, - }); - } - } - - return { reboundRows, validUserCount: validUserIdSet.size }; -} - -function resolveRowKey(row) { - for (const field of ROW_KEY_FIELDS) { - const value = row[field]; - if (typeof value === 'string' && value.trim()) { - return value; - } - } - return ''; -} - -async function runCli(argv) { - const options = parseCliArgs(argv); - const inputPath = path.resolve(options.in); - const outputPath = path.resolve(options.out); - const migration = JSON.parse(await readFile(inputPath, 'utf8')); - const result = rebindOrphanWorkOwnersInMigration(migration, { - placeholderUserId: options.placeholderUserId, - validUserIds: collectValidUserIds(migration), - }); - - if (!options.dryRun) { - await writeFile( - outputPath, - `${JSON.stringify(migration, null, 2)}\n`, - 'utf8', - ); - } - - console.log( - `[rebind-orphan-work-owners] ${options.dryRun ? 'dry-run' : `已写入 ${outputPath}`},回填 ${result.reboundRows.length} 行`, - ); -} - -function parseCliArgs(argv) { - const options = { - in: '', - out: '', - placeholderUserId: DEFAULT_ORPHAN_WORK_OWNER_USER_ID, - dryRun: false, - }; - - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - const readValue = (name) => { - const value = argv[index + 1]; - if (!value || value.startsWith('--')) { - throw new Error(`${name} 缺少参数值。`); - } - index += 1; - return value; - }; - - if (arg === '--in') { - options.in = readValue(arg); - } else if (arg === '--out') { - options.out = readValue(arg); - } else if (arg === '--placeholder-user-id') { - options.placeholderUserId = readValue(arg); - } else if (arg === '--dry-run') { - options.dryRun = true; - } else { - throw new Error(`未知参数: ${arg}`); - } - } - - if (!options.in) { - throw new Error('必须传入 --in。'); - } - if (!options.out && !options.dryRun) { - throw new Error('非 dry-run 必须传入 --out。'); - } - return options; -} - -function collectValidUserIds(migration) { - const result = new Set(); - for (const table of migration.tables ?? []) { - if (!table || !Array.isArray(table.rows)) { - continue; - } - if (table.name === 'user_account') { - for (const row of table.rows) { - if (typeof row?.user_id === 'string' && row.user_id.trim()) { - result.add(row.user_id.trim()); - } - } - } - } - return result; -} - -function isCliEntry() { - const entry = process.argv[1]; - return entry - ? import.meta.url === `file://${entry.replace(/\\/gu, '/')}` - : false; -} diff --git a/scripts/rebind-orphan-work-owners.test.ts b/scripts/rebind-orphan-work-owners.test.ts deleted file mode 100644 index 46eb48086..000000000 --- a/scripts/rebind-orphan-work-owners.test.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { describe, expect, it } from 'vitest'; - -import { rebindOrphanWorkOwnersInMigration } from './rebind-orphan-work-owners.mjs'; - -const placeholderUserId = 'wx-openid-placeholder'; - -function table(name, rows) { - return { name, rows }; -} - -describe('rebindOrphanWorkOwnersInMigration', () => { - it('把作品表里认证表不存在的 owner_user_id 回填到占位用户', () => { - const migration = { - schema_version: 1, - exported_at_micros: 1, - tables: [ - table('user_account', [ - { user_id: 'user_alive' }, - { user_id: placeholderUserId }, - ]), - table('puzzle_work_profile', [ - { profile_id: 'p1', owner_user_id: 'user_missing' }, - { profile_id: 'p2', owner_user_id: 'user_alive' }, - { profile_id: 'p3', owner_user_id: placeholderUserId }, - ]), - table('puzzle_agent_session', [ - { session_id: 'draft-1', owner_user_id: '' }, - ]), - table('tracking_event', [ - { event_id: 't1', owner_user_id: 'user_missing' }, - ]), - ], - }; - - const result = rebindOrphanWorkOwnersInMigration(migration, { - placeholderUserId, - validUserIds: ['user_alive'], - }); - - expect(result.reboundRows).toEqual([ - { - table: 'puzzle_work_profile', - rowKey: 'p1', - from: 'user_missing', - to: placeholderUserId, - }, - { - table: 'puzzle_agent_session', - rowKey: 'draft-1', - from: '', - to: placeholderUserId, - }, - ]); - expect(migration.tables[1].rows[0].owner_user_id).toBe(placeholderUserId); - expect(migration.tables[1].rows[1].owner_user_id).toBe('user_alive'); - expect(migration.tables[1].rows[2].owner_user_id).toBe(placeholderUserId); - expect(migration.tables[2].rows[0].owner_user_id).toBe(placeholderUserId); - expect(migration.tables[3].rows[0].owner_user_id).toBe('user_missing'); - }); -}); diff --git a/scripts/test_gitea_cache_image_context.py b/scripts/test_gitea_cache_image_context.py new file mode 100644 index 000000000..eea8286b8 --- /dev/null +++ b/scripts/test_gitea_cache_image_context.py @@ -0,0 +1,200 @@ +#!/usr/bin/env python3 +"""Regression tests for the minimal trusted Gitea CI download-cache build context.""" + +from __future__ import annotations + +import os +from pathlib import Path +import shutil +import shlex +import stat +import subprocess +import tarfile +import tempfile +import textwrap +import tomllib +import unittest + + +REPOSITORY_ROOT = Path(__file__).resolve().parent.parent +IMAGE_SCRIPT = REPOSITORY_ROOT / "scripts" / "gitea-ci-job-image.sh" +STATIC_CONTEXT_FILES = ( + "deploy/container/gitea-ci-job.Dockerfile", + "deploy/container/gitea-ci-job.Dockerfile.dockerignore", + "deploy/container/gitea-ci-buildkitd.toml", + "deploy/container/gitea-ci-checkout.sh", + "scripts/export-ci-npm-download-cache.mjs", + "package.json", + "package-lock.json", + "apps/admin-web/package.json", + "apps/ai-game-creator-shell/package.json", + "apps/desktop-shell/package.json", + "apps/mobile-shell/package.json", + "apps/preview-deployer-web/package.json", + "packages/image-canvas-core/package.json", + "packages/image-canvas-react/package.json", + "packages/shared/package.json", + "tools/spine-json-export-validator/package.json", + "apps/ai-game-creator-shell/src-tauri/Cargo.toml", + "apps/ai-game-creator-shell/src-tauri/Cargo.lock", + "server-rs/Cargo.toml", + "server-rs/Cargo.lock", + "apps/desktop-shell/src-tauri/Cargo.toml", + "apps/desktop-shell/src-tauri/Cargo.lock", +) + + +class GiteaCiImageContextTest(unittest.TestCase): + def setUp(self) -> None: + self.temporary_directory = tempfile.TemporaryDirectory(ignore_cleanup_errors=True) + self.root = Path(self.temporary_directory.name) + self.context_archive = self.root / "context.tar" + self.bin = self.root / "bin" + self.bin.mkdir() + self.write_fake_docker() + self.execution_bin = self.wsl_path(self.bin) + self.wsl_fake_root: str | None = None + if os.name == "nt": + self.wsl_fake_root = f"/tmp/gitea-ci-image-context-{self.root.name}" + subprocess.run( + [ + "bash", + "-c", + "rm -rf {root}; mkdir -p {root}/bin; cp {source}/* {root}/bin/; chmod +x {root}/bin/*".format( + root=shlex.quote(self.wsl_fake_root), + source=shlex.quote(self.wsl_path(self.bin)), + ), + ], + check=True, + ) + self.execution_bin = f"{self.wsl_fake_root}/bin" + + def tearDown(self) -> None: + if self.wsl_fake_root is not None: + subprocess.run( + ["bash", "-c", f"rm -rf {shlex.quote(self.wsl_fake_root)}"], check=False + ) + self.temporary_directory.cleanup() + + @staticmethod + def wsl_path(path: Path) -> str: + value = path.resolve().as_posix() + if len(value) >= 3 and value[1] == ":": + return f"/mnt/{value[0].lower()}{value[2:]}" + return value + + def write_fake_docker(self) -> None: + docker = self.bin / "docker" + docker.write_bytes(textwrap.dedent( + """#!/usr/bin/env bash + set -eu + if [[ "$1" == buildx && "$2" == version ]]; then exit 0; fi + if [[ "$1" == buildx && "$2" == inspect ]]; then + if [[ "$#" != 3 ]]; then echo 'unsupported buildx inspect arguments' >&2; exit 2; fi + printf 'Name: genarrative-ci-images\\nDriver: %s\\n' "${FAKE_BUILDX_DRIVER:-docker-container}" + exit 0 + fi + if [[ "$1" == buildx && "$2" == build ]]; then + cat > "$TAR_CAPTURE" + exit 0 + fi + if [[ "$1" == image && "$2" == inspect ]]; then + printf 'sha256:%064d\\n' 0 + exit 0 + fi + if [[ "$1" == run ]]; then exit 0; fi + echo "unexpected docker invocation" >&2 + exit 9 + """ + ).encode("utf-8")) + docker.chmod(docker.stat().st_mode | stat.S_IXUSR) + + def run_script(self, script: Path, *arguments: str, capture_context: bool = False, + builder_driver: str = "docker-container") -> subprocess.CompletedProcess[str]: + exports = [f"export PATH={shlex.quote(self.execution_bin)}:\"$PATH\""] + exports.append(f"export FAKE_BUILDX_DRIVER={shlex.quote(builder_driver)}") + if capture_context: + exports.append(f"export TAR_CAPTURE={shlex.quote(self.wsl_path(self.context_archive))}") + command = "; ".join(exports) + "; cd /; exec bash " + shlex.quote(self.wsl_path(script)) + command += " " + " ".join(shlex.quote(argument) for argument in arguments) + return subprocess.run( + ["bash", "-c", command], env=os.environ, text=True, capture_output=True, check=False + ) + + @staticmethod + def dependency_paths(value): + if not isinstance(value, dict): + return + for key, child in value.items(): + if key in {"dependencies", "build-dependencies", "dev-dependencies"} and isinstance(child, dict): + for dependency in child.values(): + if isinstance(dependency, dict) and isinstance(dependency.get("path"), str): + yield dependency["path"] + yield from GiteaCiImageContextTest.dependency_paths(child) + + def test_build_rejects_a_builder_with_the_wrong_driver(self) -> None: + result = self.run_script(IMAGE_SCRIPT, "build", capture_context=True, builder_driver="docker") + self.assertNotEqual(result.returncode, 0) + self.assertIn("must use the isolated docker-container driver", result.stderr) + self.assertFalse(self.context_archive.exists()) + + def test_build_context_contains_all_local_dependency_manifests_and_no_source(self) -> None: + result = self.run_script(IMAGE_SCRIPT, "build", capture_context=True) + self.assertEqual(result.returncode, 0, result.stderr) + with tarfile.open(self.context_archive) as archive: + names = {member.name.removeprefix("./") for member in archive.getmembers() if member.isfile()} + + manifests = {Path(name) for name in names if name.endswith("Cargo.toml")} + self.assertTrue(manifests) + expected = set() + for manifest in manifests: + data = tomllib.loads((REPOSITORY_ROOT / manifest).read_text(encoding="utf-8")) + for path in self.dependency_paths(data): + dependency = (REPOSITORY_ROOT / manifest.parent / path).resolve() + try: + cargo_toml = (dependency / "Cargo.toml").relative_to(REPOSITORY_ROOT) + except ValueError: + continue + expected.add(cargo_toml) + self.assertTrue(expected) + self.assertTrue(expected.issubset(manifests), sorted(expected - manifests)) + + self.assertFalse(any(Path(name).suffix in {".rs", ".c", ".cc", ".cpp", ".h"} for name in names)) + self.assertFalse(any("target" in Path(name).parts for name in names)) + self.assertFalse(any( + Path(name).name.startswith(".env") or Path(name).suffix in {".pem", ".key"} + for name in names + )) + + def test_revision_tracks_vendor_manifests_but_ignores_regular_source(self) -> None: + fixture = self.root / "revision-fixture" + script = fixture / "scripts" / "gitea-ci-job-image.sh" + script.parent.mkdir(parents=True) + shutil.copy2(IMAGE_SCRIPT, script) + script.chmod(script.stat().st_mode | stat.S_IXUSR) + for name in STATIC_CONTEXT_FILES: + target = fixture / name + target.parent.mkdir(parents=True, exist_ok=True) + target.write_text("fixture\n", encoding="utf-8") + vendor_manifest = fixture / "apps/ai-game-creator-shell/src-tauri/vendor/example/Cargo.toml" + vendor_manifest.parent.mkdir(parents=True) + vendor_manifest.write_text('[package]\nname = "example"\nversion = "0.1.0"\n', encoding="utf-8") + bridge_manifest = fixture / "plugins/agc-example-editor/native/example-editor-bridge/Cargo.toml" + bridge_manifest.parent.mkdir(parents=True) + bridge_manifest.write_text('[package]\nname = "bridge"\nversion = "0.1.0"\n', encoding="utf-8") + (fixture / "server-rs/crates").mkdir(parents=True) + + first = self.run_script(script, "revision") + self.assertEqual(first.returncode, 0, first.stderr) + source = fixture / "apps/ai-game-creator-shell/src-tauri/src/lib.rs" + source.parent.mkdir(parents=True) + source.write_text("pub fn ignored() {}\n", encoding="utf-8") + self.assertEqual(self.run_script(script, "revision").stdout, first.stdout) + vendor_manifest.write_text('[package]\nname = "example"\nversion = "0.2.0"\n', encoding="utf-8") + changed = self.run_script(script, "revision") + self.assertEqual(changed.returncode, 0, changed.stderr) + self.assertNotEqual(changed.stdout, first.stdout) + + +if __name__ == "__main__": + unittest.main() diff --git a/scripts/test_gitea_cache_maintenance.py b/scripts/test_gitea_cache_maintenance.py index 00a746b4c..7f9d78469 100644 --- a/scripts/test_gitea_cache_maintenance.py +++ b/scripts/test_gitea_cache_maintenance.py @@ -11,6 +11,7 @@ import re import tempfile import unittest from unittest.mock import patch +import zipfile SCRIPT = Path(__file__).with_name("maintain-gitea-rust-cache.py") @@ -29,6 +30,26 @@ def runner_config(image: str) -> str: return f'runners:\n - "genarrative-ci:docker://{image}"\n' +def zip_bytes(*, size=None) -> bytes: + """Make a valid stored ZIP, optionally padded to an exact download size.""" + content = b"x" * 40000 if size else b"cache artifact" + output = io.BytesIO() + with zipfile.ZipFile(output, "w", zipfile.ZIP_STORED) as archive: + archive.writestr("snapshot.tar", content) + value = output.getvalue() + if size is None: + return value + if not len(value) < size <= len(value) + 65535: + raise AssertionError("requested ZIP size cannot be represented by its comment") + output = io.BytesIO(value) + with zipfile.ZipFile(output, "a") as archive: + archive.comment = b"p" * (size - len(value)) + value = output.getvalue() + if len(value) != size: + raise AssertionError("ZIP comment did not produce the requested size") + return value + + class FakeApi: def __init__(self): self.requests: list[str] = [] @@ -75,6 +96,18 @@ class GiteaCacheMaintenanceTest(unittest.TestCase): self.assertEqual(request.get_method(), method) self.assertEqual(request.data, None if body is None else json.dumps(body).encode()) + def test_operation_logs_duration_and_build_log_without_exception_secrets(self): + build_log = self.root / "artifacts" / SHA / "build.log" + with patch.object(maintenance_module.time, "monotonic", side_effect=[10.0, 13.25]), \ + patch("builtins.print") as printed: + with self.assertRaisesRegex(RuntimeError, "test failure"): + with maintenance_module.operation("merge cache artifacts", build_log=build_log): + raise RuntimeError("test failure") + messages = [call.args[0] for call in printed.call_args_list] + self.assertEqual(messages[0], f"[cache-maintenance] merge cache artifacts: started; build log={build_log}") + self.assertEqual(messages[1], + f"[cache-maintenance] merge cache artifacts: failed after 3.2s; build log={build_log}") + def test_workflow_jobs_and_cache_producers_match_maintenance_contract(self): workflow = (SCRIPT.parent.parent / ".gitea/workflows/project-ci.yml").read_text(encoding="utf-8") # 沿用 workflow 的显式 job/step 格式,枚举实际 job,避免另一份名单漏掉新增项。 @@ -287,7 +320,7 @@ class GiteaCacheMaintenanceTest(unittest.TestCase): "steps": [{"name": maintenance_module.EXPORT_STEP, "conclusion": "success"}]} for i, name in enumerate(maintenance_module.RUST_JOB_IDS, start=1)] artifacts = [{"id": job["id"], "name": "rust-cache-v1-" + maintenance_module.RUST_JOB_IDS[job["name"]] - + "-attempt-1", "expired": False, "workflow_run": run} for job in jobs] + + "-attempt-1", "size_in_bytes": 10, "expired": False, "workflow_run": run} for job in jobs] class Api: def pages(self, path, key): return iter({"workflow_runs": [run], "jobs": jobs, "artifacts": artifacts}[key]) @@ -308,6 +341,7 @@ class GiteaCacheMaintenanceTest(unittest.TestCase): result = self.select_source(instance) self.assertEqual(result["run_id"], 44) self.assertEqual(len(result["exports"]), 6) + self.assertEqual({item["size_in_bytes"] for item in result["exports"]}, {10}) run["event"] = "pull_request" self.assertIsNone(self.select_source(instance)) run["event"] = "push" @@ -340,15 +374,27 @@ class GiteaCacheMaintenanceTest(unittest.TestCase): self.assertIsNone(self.select_source(instance)) def test_assembly_uses_ci_objects_and_trusted_binary_without_warming_compiler(self): + self.assert_assembly() + + def test_assembly_uses_rebuilt_local_base(self): + self.assert_assembly(rebuild=True) + + def test_failed_assembly_removes_temporary_base_alias(self): + self.assert_assembly(build_fails=True) + + def assert_assembly(self, *, rebuild=False, build_fails=False): instance, _, _, _ = self.source_fixture() source = self.select_source(instance) shell_calls, docker_calls = [], [] + base_tag = "genarrative/gitea-project-ci:base-auto-" + SHA + assembly_base = "genarrative/gitea-project-ci:assembly-base" instance.build_command = lambda log, script, *args, **kw: shell_calls.append((script, args)) def info(image, inner=False): - return {"Id": IMAGE if image.startswith("genarrative/") else image, "Config": {"Labels": { + image_id = BASE_IMAGE if image == base_tag else IMAGE if image.startswith("genarrative/") else image + return {"Id": image_id, "Config": {"Labels": { "world.genarrative.ci.rust-cache-source": "b" * 40, "world.genarrative.ci.rust-cache-base": BASE_IMAGE, - "com.genarrative.ci.definition-sha256": "definition", + "com.genarrative.ci.definition-sha256": "old-definition" if rebuild else "definition", }}} instance.image_info = info def docker(*args, **kw): @@ -361,9 +407,19 @@ class GiteaCacheMaintenanceTest(unittest.TestCase): (root / "sccache").write_bytes(b"trusted binary") if args[-2:] == ("rustc", "-vV"): return "rustc test\n" + if args[0] == "build": + self.assertEqual(args[1:5], ("--builder", "default", "--pull=false", "--tag")) + work = Path(args[-1]) + self.assertTrue((work / "Dockerfile").read_text().startswith(f"FROM {assembly_base}\n")) + self.assertIn(f'world.genarrative.ci.rust-cache-base="{BASE_IMAGE}"', + (work / "Dockerfile").read_text()) + self.assertEqual((work / "snapshot/base-image.txt").read_text(), BASE_IMAGE + "\n") + self.assertEqual(docker_calls[-2], ("image", "tag", BASE_IMAGE, assembly_base)) + if build_fails: + raise RuntimeError("assembly failed") return "" instance.docker = docker - instance.api.download = lambda path, destination: destination.write_bytes(b"download") + instance.api.download = lambda path, destination, expected_size: destination.write_bytes(b"download") def merge(inputs, output, **kwargs): self.assertEqual(len(inputs), 6) self.assertEqual(kwargs["expected_inherited_source_sha"], "b" * 40) @@ -373,10 +429,22 @@ class GiteaCacheMaintenanceTest(unittest.TestCase): "workspace": "/workspace/team/project", "base_image": BASE_IMAGE})() with patch.object(maintenance_module, "command", return_value="definition\n"), \ patch.object(maintenance_module, "merge_snapshots", merge): - instance.build(source) - self.assertEqual(shell_calls, [("gitea-ci-job-image.sh", ("verify", "genarrative/gitea-project-ci:rust-cache-auto-" + SHA))]) + if build_fails: + with self.assertRaisesRegex(RuntimeError, "assembly failed"): + instance.build(source) + else: + instance.build(source) + expected_calls = [("gitea-ci-job-image.sh", ("build",))] if rebuild else [] + if not build_fails: + expected_calls.append(("gitea-ci-job-image.sh", ("verify", "genarrative/gitea-project-ci:rust-cache-auto-" + SHA))) + self.assertEqual(shell_calls, expected_calls) self.assertIn(("create", OLD_IMAGE), docker_calls) self.assertIn(("rm", "--volumes", "temporary-copy-container"), docker_calls) + self.assertEqual(docker_calls[-1], ("image", "rm", assembly_base)) + self.assertEqual(instance.state.get("bases", {}), {BASE_IMAGE: base_tag} if rebuild else {}) + if build_fails: + self.assertIsNone(instance.state.get("candidate")) + return self.assertEqual(instance.state["candidate"], IMAGE) self.assertEqual(instance.version(IMAGE)["run_id"], 44) @@ -407,23 +475,111 @@ class GiteaCacheMaintenanceTest(unittest.TestCase): def test_signed_download_drops_token_and_rejects_other_origins(self): api = maintenance_module.Api(self.config["api_url"], self.token) destination = self.root / "artifact.zip" + archive = zip_bytes() seen = [] target = ["https://gitea.example.test/api/v1/repos/team/project/actions/artifacts/1/zip/raw?sig=test"] + + class Response(io.BytesIO): + def __init__(self, value): + super().__init__(value) + self.headers = {"Content-Length": str(len(value))} + class Opener: def open(self, request, timeout): seen.append(request) if not isinstance(request, str): raise maintenance_module.urllib.error.HTTPError(request.full_url, 302, "Found", {"Location": target[0]}, None) - return io.BytesIO(b"archive") + return Response(archive) + with patch.object(maintenance_module.urllib.request, "build_opener", return_value=Opener()): - api.download("repos/team/project/actions/artifacts/1/zip", destination) - self.assertEqual(destination.read_bytes(), b"archive") + api.download("repos/team/project/actions/artifacts/1/zip", destination, len(archive)) + self.assertEqual(destination.read_bytes(), archive) self.assertEqual(seen[0].get_header("Authorization"), "token test-token") self.assertIsInstance(seen[1], str) # signed URL request has no Authorization header target[0] = "https://other.example.test/download" with self.assertRaisesRegex(RuntimeError, "configured HTTPS Gitea origin"): - api.download("repos/team/project/actions/artifacts/1/zip", self.root / "rejected.zip") + api.download("repos/team/project/actions/artifacts/1/zip", self.root / "rejected.zip", len(archive)) self.assertFalse((self.root / "rejected.zip").exists()) + self.assertEqual(len(seen), 3) # invalid redirect is deterministic and is not retried + + def test_download_retries_transport_and_truncated_response_with_fresh_signed_urls(self): + api = maintenance_module.Api(self.config["api_url"], self.token) + destination = self.root / "artifact.zip" + archive = zip_bytes(size=100000) + seen, signed_responses = [], [] + origin_requests = 0 + target = "https://gitea.example.test/api/v1/repos/team/project/actions/artifacts/1/zip/raw?sig=test" + + class Response(io.BytesIO): + def __init__(self, value): + super().__init__(value) + self.headers = {"Content-Length": "100000"} + + class Opener: + def open(self, request, timeout): + nonlocal origin_requests + seen.append(request) + if not isinstance(request, str): + origin_requests += 1 + if origin_requests == 1: + raise maintenance_module.urllib.error.URLError("connection reset") + raise maintenance_module.urllib.error.HTTPError(request.full_url, 302, "Found", {"Location": target}, None) + signed_responses.append(request) + return Response(b"x" * 512 if len(signed_responses) == 1 else archive) + + with patch.object(maintenance_module.urllib.request, "build_opener", return_value=Opener()), \ + patch.object(maintenance_module.time, "sleep") as sleep: + api.download("repos/team/project/actions/artifacts/1/zip", destination, 100000) + self.assertEqual(destination.read_bytes(), archive) + self.assertEqual(len(signed_responses), 2) + self.assertEqual(origin_requests, 3) + self.assertEqual([item.args for item in sleep.call_args_list], [(1,), (2,)]) + + def test_download_rejects_malformed_zip_after_retries(self): + api = maintenance_module.Api(self.config["api_url"], self.token) + destination = self.root / "artifact.zip" + seen = [] + target = "https://gitea.example.test/api/v1/repos/team/project/actions/artifacts/1/zip/raw?sig=test" + + class Response(io.BytesIO): + headers = {"Content-Length": "9"} + + class Opener: + def open(self, request, timeout): + seen.append(request) + if not isinstance(request, str): + raise maintenance_module.urllib.error.HTTPError(request.full_url, 302, "Found", {"Location": target}, None) + return Response(b"not a zip") + + with patch.object(maintenance_module.urllib.request, "build_opener", return_value=Opener()), \ + patch.object(maintenance_module.time, "sleep") as sleep: + with self.assertRaisesRegex(RuntimeError, "incomplete after retries"): + api.download("repos/team/project/actions/artifacts/1/zip", destination, 9) + self.assertFalse(destination.exists()) + self.assertEqual(sum(not isinstance(item, str) for item in seen), 3) + self.assertEqual([item.args for item in sleep.call_args_list], [(1,), (2,)]) + + def test_download_rejects_valid_zip_when_its_size_differs_from_metadata(self): + api = maintenance_module.Api(self.config["api_url"], self.token) + destination = self.root / "artifact.zip" + archive = zip_bytes() + seen = [] + target = "https://gitea.example.test/api/v1/repos/team/project/actions/artifacts/1/zip/raw?sig=test" + + class Opener: + def open(self, request, timeout): + seen.append(request) + if not isinstance(request, str): + raise maintenance_module.urllib.error.HTTPError(request.full_url, 302, "Found", {"Location": target}, None) + return io.BytesIO(archive) + + with patch.object(maintenance_module.urllib.request, "build_opener", return_value=Opener()), \ + patch.object(maintenance_module.time, "sleep") as sleep: + with self.assertRaisesRegex(RuntimeError, "incomplete after retries"): + api.download("repos/team/project/actions/artifacts/1/zip", destination, len(archive) + 1) + self.assertFalse(destination.exists()) + self.assertEqual(sum(not isinstance(item, str) for item in seen), 3) + self.assertEqual([item.args for item in sleep.call_args_list], [(1,), (2,)]) def test_pending_chunk_cleanup_requires_old_terminal_master_run(self): instance = self.maintenance({"versions": [], "current": None, "attempts": [{"run_id": 4}]}) diff --git a/scripts/test_gitea_cache_snapshot.py b/scripts/test_gitea_cache_snapshot.py index 135cd903b..e94bf2742 100644 --- a/scripts/test_gitea_cache_snapshot.py +++ b/scripts/test_gitea_cache_snapshot.py @@ -37,6 +37,16 @@ def object_path(character: str) -> str: return f"objects/{key[0]}/{key[1]}/{key}" +def cache_object(entries, *, mode=0o100644) -> bytes: + output = io.BytesIO() + with zipfile.ZipFile(output, "w", compression=zipfile.ZIP_STORED) as bundle: + for name, contents in entries: + info = zipfile.ZipInfo(name) + info.external_attr = mode << 16 + bundle.writestr(info, contents) + return output.getvalue() + + class SnapshotMergeTest(unittest.TestCase): def setUp(self) -> None: self.temporary_directory = tempfile.TemporaryDirectory(ignore_cleanup_errors=True) @@ -207,6 +217,42 @@ class SnapshotMergeTest(unittest.TestCase): with self.assertRaisesRegex(snapshot.SnapshotError, "conflicting content"): self.merge(inputs) + def test_deduplicates_cache_zip_member_order_preserving_payload_and_newest_touch(self) -> None: + path = object_path("a") + entries = [("lib.rlib", b"compiled"), ("lib.rmeta", b"metadata"), ("stderr", b"warning")] + first = cache_object(entries) + second = cache_object(list(reversed(entries))) + self.assertEqual(len(first), len(second)) + self.assertNotEqual(hashlib.sha256(first).digest(), hashlib.sha256(second).digest()) + inputs = [ + self.archive("smoke", "smoke", 45, [(path, first, 100)]), + self.archive("lane-1", "lane-1", 45, [(path, second, 300)]), + self.archive("lane-2", "lane-2", 45, [(path, second, 200)]), + ] + result = self.merge(inputs) + output = self.root / "merged" / path + self.assertEqual((result.object_count, result.total_bytes), (1, len(first))) + self.assertEqual(output.read_bytes(), first) + self.assertEqual(output.stat().st_mtime_ns, 300) + + def test_rejects_cache_zip_payload_or_permissions_conflicts(self) -> None: + path = object_path("a") + first = cache_object([("lib.rlib", b"one"), ("stderr", b"err")]) + variants = { + "payload": cache_object([("stderr", b"err"), ("lib.rlib", b"two")]), + "permissions": cache_object([("stderr", b"err"), ("lib.rlib", b"one")], mode=0o100755), + } + for name, second in variants.items(): + with self.subTest(name=name): + self.assertEqual(len(first), len(second)) + inputs = [ + self.archive("first", "smoke", 45, [(path, first, 100)]), + self.archive("second", "lane-1", 45, [(path, second, 200)]), + ] + with self.assertRaisesRegex(snapshot.SnapshotError, "conflicting content"): + self.merge(inputs) + self.assertFalse((self.root / "merged").exists()) + def test_rejects_delta_that_conflicts_with_inherited_key(self) -> None: path = object_path("f") self.base_object(path, b"base", 1) diff --git a/server-rs/Cargo.lock b/server-rs/Cargo.lock index 8fee3df57..ac57523c6 100644 --- a/server-rs/Cargo.lock +++ b/server-rs/Cargo.lock @@ -2916,9 +2916,12 @@ version = "0.1.0" dependencies = [ "serde", "serde_json", + "shared-contracts", "shared-kernel", "spacetimedb", "time", + "url", + "uuid", ] [[package]] diff --git a/server-rs/crates/api-server/src/admin.rs b/server-rs/crates/api-server/src/admin.rs index f66bb1b3a..2f9838531 100644 --- a/server-rs/crates/api-server/src/admin.rs +++ b/server-rs/crates/api-server/src/admin.rs @@ -2195,6 +2195,7 @@ fn admin_permission_requirement(_method: &Method, path: &str) -> AdminPermission "/admin/api/external-api-keys" => AnyTab(&["tables"]), "/admin/api/debug/http" => AnyTab(&["debug"]), "/admin/api/tracking/events" => AnyTab(&["tracking"]), + "/admin/api/agc/tracking-events" => AnyTab(&["agc-tracking"]), "/admin/api/tracking/event-keys" => AnyTab(&["tracking", "tasks"]), "/admin/api/error-reports" => AnyTab(&["error-reports"]), "/admin/api/project-snapshots" => AnyTab(&["project-snapshots"]), @@ -2222,6 +2223,7 @@ fn admin_permission_requirement(_method: &Method, path: &str) -> AdminPermission "/admin/api/profile/users/detail" => AnyTab(&[ "tables", "tracking", + "agc-tracking", "recharge-orders", "editor-showcase", "editor-assets", @@ -6883,6 +6885,26 @@ mod tests { #[test] fn admin_tab_permissions_cover_shared_and_sensitive_routes() { + assert!( + enforce_admin_request_permission( + "member", + &["agc-tracking".into()], + &[], + &Method::GET, + "/admin/api/profile/users/detail" + ) + .is_ok() + ); + assert!( + enforce_admin_request_permission( + "member", + &["tracking".into()], + &[], + &Method::GET, + "/admin/api/agc/tracking-events" + ) + .is_err() + ); assert!( enforce_admin_request_permission( "member", @@ -6913,6 +6935,11 @@ mod tests { ("tables", Method::GET, "/admin/api/database/tables"), ("debug", Method::POST, "/admin/api/debug/http"), ("tracking", Method::GET, "/admin/api/tracking/events"), + ( + "agc-tracking", + Method::GET, + "/admin/api/agc/tracking-events", + ), ("error-reports", Method::GET, "/admin/api/error-reports"), ( "project-snapshots", diff --git a/server-rs/crates/api-server/src/agc_analytics.rs b/server-rs/crates/api-server/src/agc_analytics.rs new file mode 100644 index 000000000..b69542f28 --- /dev/null +++ b/server-rs/crates/api-server/src/agc_analytics.rs @@ -0,0 +1,226 @@ +//! 客户端埋点只在数据库提交后确认;不使用普通路由 tracking outbox。 +use axum::{ + Json, Router, + extract::{DefaultBodyLimit, Extension, Query, State}, + http::StatusCode, + middleware, + routing::{get, post}, +}; +use serde_json::Value; +use shared_contracts::{admin::AdminAgcTrackingEventListQuery, agc_analytics::AgcAnalyticsBatch}; +use spacetime_client::SpacetimeClientError; + +use crate::{ + admin::{AuthenticatedAdmin, require_admin_auth}, + api_response::json_success_body, + auth::{AuthenticatedAccessToken, require_bearer_auth}, + http_error::AppError, + request_context::RequestContext, + state::AppState, +}; + +const MAX_REQUEST_BYTES: usize = 2 * 1024 * 1024; + +pub fn router(state: AppState) -> Router { + Router::new() + .route( + "/api/agc/analytics/batches", + post(upload_batch) + .route_layer(middleware::from_fn_with_state( + state.clone(), + require_bearer_auth, + )) + .layer(DefaultBodyLimit::max(MAX_REQUEST_BYTES)), + ) + .route( + "/admin/api/agc/tracking-events", + get(list_events).route_layer(middleware::from_fn_with_state(state, require_admin_auth)), + ) +} + +async fn upload_batch( + State(state): State, + Extension(context): Extension, + Extension(auth): Extension, + payload: Result, axum::extract::rejection::JsonRejection>, +) -> Result, AppError> { + let Json(raw) = payload.map_err(|error| { + let status = if error.status() == StatusCode::PAYLOAD_TOO_LARGE { + StatusCode::PAYLOAD_TOO_LARGE + } else { + StatusCode::BAD_REQUEST + }; + AppError::from_status(status).with_message("客户端埋点请求格式无效") + })?; + // serde 也能将位置数组解成 struct;上传合同只接受命名字段的 JSON 对象。 + if !raw.is_object() + || !raw + .get("events") + .and_then(Value::as_array) + .is_some_and(|events| events.iter().all(Value::is_object)) + { + return Err(AppError::from_status(StatusCode::BAD_REQUEST) + .with_message("客户端埋点必须使用事件对象")); + } + let batch: AgcAnalyticsBatch = serde_json::from_value(raw).map_err(|_| { + AppError::from_status(StatusCode::BAD_REQUEST).with_message("客户端埋点字段不符合合同") + })?; + validate_subject_and_origin( + &batch, + auth.claims().user_id(), + &state.config.agc_analytics_origin, + )?; + module_runtime::agc_analytics::validate_agc_analytics_batch(&batch).map_err(|error| { + let status = if error == "events_too_large" { + StatusCode::PAYLOAD_TOO_LARGE + } else { + StatusCode::BAD_REQUEST + }; + AppError::from_status(status).with_message("客户端埋点批次格式不符合合同") + })?; + let acknowledgement = state + .spacetime_client() + .upload_agc_analytics_batch(batch) + .await + .map_err(map_database_error)?; + Ok(json_success_body(Some(&context), acknowledgement)) +} + +async fn list_events( + State(state): State, + Extension(context): Extension, + Extension(_admin): Extension, + Query(query): Query, +) -> Result, AppError> { + module_runtime::agc_analytics::validate_agc_tracking_query(&query).map_err(|_| { + AppError::from_status(StatusCode::BAD_REQUEST).with_message("客户端埋点查询参数无效") + })?; + let payload = state + .spacetime_client() + .list_agc_tracking_events(query) + .await + .map_err(map_database_error)?; + Ok(json_success_body(Some(&context), payload)) +} + +fn validate_subject_and_origin( + batch: &AgcAnalyticsBatch, + user_id: &str, + expected_origin: &str, +) -> Result<(), AppError> { + // 公开地址必须来自部署配置;客户端 body 和 Host 头均不是配置来源。 + let origin = url::Url::parse(expected_origin).ok().filter(|url| { + let loopback = url.host_str().is_some_and(|host| { + host == "localhost" + || host + .trim_matches(['[', ']']) + .parse::() + .is_ok_and(|ip| ip.is_loopback()) + }); + (url.scheme() == "https" || (url.scheme() == "http" && loopback)) + && url.host_str().is_some() + && url.username().is_empty() + && url.password().is_none() + && url.origin().ascii_serialization() == expected_origin + }); + if origin.is_none() { + return Err(AppError::from_status(StatusCode::SERVICE_UNAVAILABLE) + .with_message("客户端埋点接收地址尚未配置")); + } + if batch.user_id != user_id + || batch.destination_origin != expected_origin + || batch + .events + .iter() + .any(|event| event.user_id.as_deref() != Some(user_id)) + { + return Err( + AppError::from_status(StatusCode::FORBIDDEN).with_message("客户端埋点身份或平台不匹配") + ); + } + Ok(()) +} + +fn map_database_error(error: SpacetimeClientError) -> AppError { + match error { + SpacetimeClientError::Procedure(message) if message == "agc_event_conflict" => { + AppError::from_status(StatusCode::CONFLICT).with_message("客户端埋点事件 ID 内容冲突") + } + SpacetimeClientError::Procedure(message) + if matches!(message.as_str(), "invalid_agc_query" | "invalid_agc_cursor") => + { + AppError::from_status(StatusCode::BAD_REQUEST).with_message("客户端埋点查询参数无效") + } + // 不回显数据库或上传内容,超时/未知提交结果不产生确认。 + _ => AppError::from_status(StatusCode::SERVICE_UNAVAILABLE) + .with_message("客户端埋点数据服务暂不可用"), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn batch() -> AgcAnalyticsBatch { + AgcAnalyticsBatch { + schema_version: 1, + batch_id: uuid::Uuid::new_v4().to_string(), + destination_origin: "https://dev.genarrative.world".into(), + user_id: "user-a".into(), + events: vec![], + } + } + + #[test] + fn agc_analytics_subject_and_deployment_are_both_required() { + let batch = batch(); + assert!(validate_subject_and_origin(&batch, "user-a", &batch.destination_origin).is_ok()); + for (user, origin, expected) in [ + ( + "user-b", + "https://dev.genarrative.world", + StatusCode::FORBIDDEN, + ), + ( + "user-a", + "https://www.genarrative.world", + StatusCode::FORBIDDEN, + ), + ("user-a", "", StatusCode::SERVICE_UNAVAILABLE), + ( + "user-a", + "https://dev.genarrative.world/path", + StatusCode::SERVICE_UNAVAILABLE, + ), + ( + "user-a", + "http://dev.genarrative.world", + StatusCode::SERVICE_UNAVAILABLE, + ), + ] { + assert_eq!( + validate_subject_and_origin(&batch, user, origin) + .unwrap_err() + .status_code(), + expected + ); + } + let mut local = batch; + local.destination_origin = "http://127.0.0.1:8082".into(); + assert!(validate_subject_and_origin(&local, "user-a", &local.destination_origin).is_ok()); + } + + #[test] + fn agc_analytics_database_failure_never_becomes_acknowledgement() { + for (message, status) in [ + ("agc_event_conflict", StatusCode::CONFLICT), + ("invalid_agc_cursor", StatusCode::BAD_REQUEST), + ("unknown", StatusCode::SERVICE_UNAVAILABLE), + ] { + assert_eq!( + map_database_error(SpacetimeClientError::Procedure(message.into())).status_code(), + status + ); + } + } +} diff --git a/server-rs/crates/api-server/src/api_response.rs b/server-rs/crates/api-server/src/api_response.rs index c9e7ffee0..35a8bc64e 100644 --- a/server-rs/crates/api-server/src/api_response.rs +++ b/server-rs/crates/api-server/src/api_response.rs @@ -1,13 +1,4 @@ -use std::convert::Infallible; - -use axum::{ - Json, - body::Body, - http::{HeaderValue, header}, - response::{IntoResponse, Response}, -}; -use bytes::Bytes; -use futures_util::stream; +use axum::Json; use serde::Serialize; use serde_json::Value; #[cfg(test)] @@ -41,30 +32,6 @@ where Json(serde_json::to_value(data).unwrap_or(Value::Null)) } -pub fn json_success_data_bytes_response( - request_context: Option<&RequestContext>, - data_json: Bytes, -) -> Response { - if let Some(context) = request_context - && context.wants_envelope() - { - let meta = serde_json::to_vec(&build_api_response_meta(Some(context))) - .map(Bytes::from) - .unwrap_or_else(|_| Bytes::from_static(b"null")); - let chunks = [ - Bytes::from_static(b"{\"ok\":true,\"data\":"), - data_json, - Bytes::from_static(b",\"error\":null,\"meta\":"), - meta, - Bytes::from_static(b"}"), - ]; - let stream = stream::iter(chunks.into_iter().map(Ok::)); - return json_body_response(Body::from_stream(stream)); - } - - json_bytes_response(data_json) -} - pub fn json_error_body( request_context: Option<&RequestContext>, error: &ApiErrorPayload, @@ -98,19 +65,6 @@ fn build_api_response_meta(request_context: Option<&RequestContext>) -> ApiRespo ) } -fn json_bytes_response(bytes: Bytes) -> Response { - json_body_response(Body::from(bytes)) -} - -fn json_body_response(body: Body) -> Response { - let mut response = body.into_response(); - response.headers_mut().insert( - header::CONTENT_TYPE, - HeaderValue::from_static("application/json; charset=utf-8"), - ); - response -} - #[cfg(test)] mod tests { use super::*; @@ -152,31 +106,6 @@ mod tests { assert!(body.get("meta").is_none()); } - #[tokio::test] - async fn success_response_streams_cached_data_inside_standard_envelope() { - use http_body_util::BodyExt; - - let request_context = build_request_context(true); - let response = json_success_data_bytes_response( - Some(&request_context), - Bytes::from_static(br#"{"items":[]}"#), - ); - let body = response - .into_body() - .collect() - .await - .expect("response body should collect") - .to_bytes(); - let payload: Value = serde_json::from_slice(&body).expect("body should be json"); - - assert_eq!(payload["ok"], Value::Bool(true)); - assert_eq!(payload["data"]["items"], Value::Array(Vec::new())); - assert_eq!( - payload["meta"]["requestId"], - Value::String("req-test".to_string()) - ); - } - #[test] fn error_body_returns_legacy_shape_without_envelope_header() { let request_context = build_request_context(false); diff --git a/server-rs/crates/api-server/src/app.rs b/server-rs/crates/api-server/src/app.rs index d9136e5c3..e4b0b2d7d 100644 --- a/server-rs/crates/api-server/src/app.rs +++ b/server-rs/crates/api-server/src/app.rs @@ -57,6 +57,7 @@ pub fn build_router(state: AppState) -> Router { .merge(modules::raw::router(state.clone())) .merge(modules::project_snapshots::router(state.clone())) .merge(crate::error_reports::router(state.clone())) + .merge(crate::agc_analytics::router(state.clone())) .route( "/api/profile/recharge/wechat/notify", post(handle_wechat_pay_notify), @@ -255,7 +256,234 @@ mod tests { use super::{build_router, build_spacetime_unavailable_router}; const TEST_PASSWORD: &str = "secret123"; - const INTERNAL_TEST_SECRET: &str = "test-internal-secret"; + + /// 需 scripts/agc-analytics-smoke.mjs 创建的隔离数据库;认证用户为测试夹具, + /// HTTP、facade、数据库事务和后台查询均走正式实现。 + #[tokio::test] + #[ignore = "requires isolated AGC analytics smoke database"] + async fn agc_analytics_real_database_http_roundtrip() { + let path = + std::env::var("AGC_ANALYTICS_SMOKE_CONNECTION").expect("isolated connection file"); + let connection: Value = serde_json::from_slice(&std::fs::read(path).unwrap()).unwrap(); + let db_url = connection["serverUrl"].as_str().unwrap(); + assert!( + db_url.starts_with("http://127.0.0.1:"), + "only isolated local database" + ); + assert!( + connection["database"] + .as_str() + .unwrap() + .starts_with("agc-analytics-smoke") + ); + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let origin = format!("http://{}", listener.local_addr().unwrap()); + let state = AppState::new(AppConfig { + spacetime_server_url: db_url.into(), + spacetime_database: connection["database"].as_str().unwrap().into(), + spacetime_token: Some(connection["token"].as_str().unwrap().into()), + agc_analytics_origin: origin.clone(), + admin_username: Some("analytics-smoke-owner".into()), + admin_password: Some("analytics-smoke-fixture-password".into()), + ..AppConfig::default() + }) + .unwrap(); + let user = seed_phone_user_with_password(&state, "13800138001", TEST_PASSWORD).await; + let token = sign_test_user_token(&state, &user, "analytics-live-db"); + let app = build_router(state); + let server = tokio::spawn(async move { axum::serve(listener, app).await.unwrap() }); + let client = Client::builder() + .no_proxy() + .timeout(std::time::Duration::from_secs(30)) + .build() + .unwrap(); + let id = uuid::Uuid::new_v4().to_string(); + let batch_id = uuid::Uuid::new_v4().to_string(); + let payload = serde_json::json!({ + "schema_version":1, "batch_id":batch_id, "destination_origin":origin, "user_id":user.id, + "events":[{ + "schema_version":1, "event_id":id, "event_name":"editor_session_start", + "event_time":"2026-09-21T00:00:00.000Z", "user_id":user.id, + "editor_session_id":uuid::Uuid::new_v4().to_string(), "project_id":null, + "creative_task_id":null, "agent_run_id":null, "agent_turn_id":null, + "status":"success", "error_code":null, "source":"editor", "client_version":"smoke", + "properties":{"entry_source":"direct_launch", "first_project_id":null} + }] + }); + for _ in 0..2 { + let response = client + .post(format!("{origin}/api/agc/analytics/batches")) + .bearer_auth(&token) + .header("x-genarrative-response-envelope", "1") + .json(&payload) + .send() + .await + .unwrap(); + assert_eq!(response.status().as_u16(), 200); + let ack: Value = response.json().await.unwrap(); + assert_eq!(ack["ok"], true); + assert_eq!( + ack["data"]["acknowledged_batch_ids"], + serde_json::json!([batch_id]) + ); + assert_eq!(ack["data"]["event_count"], 1); + } + let response = client.post(format!("{origin}/admin/api/login")) + .json(&serde_json::json!({"username":"analytics-smoke-owner", "password":"analytics-smoke-fixture-password"})) + .send().await.unwrap(); + assert_eq!(response.status().as_u16(), 200); + let login: Value = response.json().await.unwrap(); + let admin_token = login["token"].as_str().unwrap(); + let response = client + .get(format!("{origin}/admin/api/agc/tracking-events")) + .bearer_auth(admin_token) + .query(&[("userId", user.id.as_str())]) + .send() + .await + .unwrap(); + assert_eq!(response.status().as_u16(), 200); + let rows: Value = response.json().await.unwrap(); + let matches = rows["entries"] + .as_array() + .unwrap() + .iter() + .filter(|row| row["eventId"] == id) + .count(); + assert_eq!( + matches, 1, + "two uploads produce one persisted row in admin read" + ); + // 启动客户端现役 store/upload 集成用例,关联实际磁盘批次与同一个主站数据库。 + let bridge_dir = tempfile::tempdir().unwrap(); + let bridge = bridge_dir.path().join("bridge.json"); + let result_path = bridge_dir.path().join("result.json"); + std::fs::write( + &bridge, + serde_json::to_vec(&serde_json::json!({ + "origin":origin, "userId":user.id, "accessToken":token, "resultPath":result_path + })) + .unwrap(), + ) + .unwrap(); + let executable = std::env::var("AGC_ANALYTICS_SMOKE_CLIENT_BINARY") + .expect("compiled client test binary"); + let mut child = tokio::process::Command::new(executable); + child + .args([ + "analytics::store::tests::analytics_live_api_upload_cleans_confirmed_batch", + "--ignored", + "--exact", + "--test-threads=1", + ]) + .env("AGC_ANALYTICS_SMOKE_BRIDGE", &bridge) + .kill_on_drop(true); + #[cfg(windows)] + child.creation_flags(0x08000000); + let output = tokio::time::timeout(std::time::Duration::from_secs(90), child.output()) + .await + .unwrap() + .unwrap(); + assert!( + output.status.success(), + "client live upload fixture failed: {}", + String::from_utf8_lossy(&output.stderr) + ); + let uploaded: Value = serde_json::from_slice( + &std::fs::read(result_path) + .expect("client result required, zero matched tests is not success"), + ) + .unwrap(); + let response = client + .get(format!("{origin}/admin/api/agc/tracking-events")) + .bearer_auth(admin_token) + .query(&[("userId", user.id.as_str())]) + .send() + .await + .unwrap(); + assert_eq!(response.status().as_u16(), 200); + let rows: Value = response.json().await.unwrap(); + assert_eq!( + rows["entries"] + .as_array() + .unwrap() + .iter() + .filter(|row| row["eventId"] == uploaded["eventId"] + && row["batchId"] == uploaded["batchId"]) + .count(), + 1 + ); + server.abort(); + } + + #[tokio::test] + async fn agc_analytics_upload_enforces_auth_identity_contract_and_body_limit() { + let state = AppState::new(AppConfig { + agc_analytics_origin: "https://dev.genarrative.world".into(), + admin_username: Some("analytics-smoke-owner".into()), + admin_password: Some("analytics-smoke-fixture-password".into()), + ..AppConfig::default() + }) + .expect("state"); + let user = seed_phone_user_with_password(&state, "13800138001", TEST_PASSWORD).await; + let token = sign_test_user_token(&state, &user, "analytics-upload-test"); + let app = build_router(state); + let payload = serde_json::json!({ + "schema_version":1, "batch_id":uuid::Uuid::new_v4().to_string(), + "destination_origin":"https://dev.genarrative.world", "user_id":user.id, + "events": [{ + "schema_version":1, "event_id":uuid::Uuid::new_v4().to_string(), + "event_name":"editor_session_start", "event_time":"2026-09-21T00:00:00.000Z", + "user_id":user.id, "editor_session_id":uuid::Uuid::new_v4().to_string(), + "project_id":null, "creative_task_id":null, "agent_run_id":null, + "agent_turn_id":null, "status":"success", "error_code":null, + "source":"editor", "client_version":"1.0.0", + "properties":{"entry_source":"direct_launch", "first_project_id":null} + }] + }); + let mut wrong_user = payload.clone(); + wrong_user["user_id"] = "other-user".into(); + let mut wrong_origin = payload.clone(); + wrong_origin["destination_origin"] = "https://www.genarrative.world".into(); + let mut bad_contract = payload.clone(); + bad_contract["events"][0]["properties"]["prompt"] = "not collected".into(); + for (body, authenticated, expected) in [ + (payload.to_string(), false, StatusCode::UNAUTHORIZED), + (wrong_user.to_string(), true, StatusCode::FORBIDDEN), + (wrong_origin.to_string(), true, StatusCode::FORBIDDEN), + (bad_contract.to_string(), true, StatusCode::BAD_REQUEST), + ("{".into(), true, StatusCode::BAD_REQUEST), + ( + " ".repeat(2 * 1024 * 1024 + 1), + true, + StatusCode::PAYLOAD_TOO_LARGE, + ), + ] { + let mut request = Request::builder() + .method("POST") + .uri("/api/agc/analytics/batches") + .header("content-type", "application/json") + .header("x-genarrative-response-envelope", "1"); + if authenticated { + request = request.header("authorization", format!("Bearer {token}")); + } + let response = app + .clone() + .oneshot(request.body(Body::from(body)).unwrap()) + .await + .unwrap(); + assert_eq!(response.status(), expected); + } + let response = app + .oneshot( + Request::builder() + .uri("/admin/api/agc/tracking-events") + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!(response.status(), StatusCode::UNAUTHORIZED); + } mod http_tracing { use std::{ @@ -891,25 +1119,6 @@ mod tests { let _ = std::fs::remove_dir_all(outbox_dir); } - #[cfg(any())] - fn build_internal_creative_agent_app() -> Router { - let mut config = AppConfig::default(); - config.internal_api_secret = Some(INTERNAL_TEST_SECRET.to_string()); - build_router(AppState::new(config).expect("state should build")) - } - - #[cfg(any())] - fn internal_creative_agent_request(method: &str, uri: &str, body: Value) -> Request { - Request::builder() - .method(method) - .uri(uri) - .header("content-type", "application/json") - .header("x-genarrative-authenticated-user-id", "user-creative-test") - .header("x-genarrative-internal-api-secret", INTERNAL_TEST_SECRET) - .body(Body::from(body.to_string())) - .expect("creative agent request should build") - } - async fn read_json_response(response: axum::response::Response) -> Value { let body = response .into_body() @@ -920,16 +1129,6 @@ mod tests { serde_json::from_slice(&body).expect("response body should be valid json") } - async fn read_text_response(response: axum::response::Response) -> String { - let body = response - .into_body() - .collect() - .await - .expect("response body should collect") - .to_bytes(); - String::from_utf8(body.to_vec()).expect("response body should be utf8") - } - #[tokio::test] async fn healthz_returns_legacy_compatible_payload_and_headers() { let app = build_router(AppState::new(AppConfig::default()).expect("state should build")); @@ -1063,15 +1262,15 @@ mod tests { let user = seed_phone_user_with_password(&state, "13800138195", TEST_PASSWORD).await; let token = sign_test_user_token(&state, &user, "sess_game_distribution_publish_gate"); let mut gate = test_feature_gate(module_runtime::GAME_DISTRIBUTION_PUBLISH_GATE_KEY); - // 无 gate 行时默认开放:已登录作者拿到 true,匿名仍为 false。 - let mut cases = vec![(vec![], true)]; + // 灰度默认关闭:无 gate 行、enabled=false、rollout 0 都拿不到入口。 + let mut cases = vec![(vec![], false)]; cases.push((vec![gate.clone()], false)); gate.allow_user_ids = vec![user.id.clone()]; cases.push((vec![gate.clone()], true)); gate.deny_user_ids = vec![user.id.clone()]; cases.push((vec![gate.clone()], false)); gate.enabled = false; - cases.push((vec![gate.clone()], true)); + cases.push((vec![gate.clone()], false)); gate.enabled = true; gate.allow_user_ids.clear(); gate.deny_user_ids.clear(); @@ -1361,6 +1560,52 @@ mod tests { ); } + #[tokio::test] + async fn game_distribution_publish_open_ignores_author_allowlist_for_activation() { + let state = AppState::new(AppConfig::default()).expect("state should build"); + // 默认关闭:作者判定与总开关都为 false。 + assert!( + !state + .is_game_distribution_publish_enabled_for_user(None) + .await + .expect("author decision") + ); + assert!( + !state + .is_game_distribution_publish_open() + .await + .expect("open decision") + ); + + // 开启但只放白名单作者:作者判定限白名单,管理员激活按总开关放行。 + let mut gate = test_feature_gate(module_runtime::GAME_DISTRIBUTION_PUBLISH_GATE_KEY); + gate.enabled = true; + gate.rollout_percent = 0; + gate.allow_user_ids = vec!["user-allowlisted".to_string()]; + state.set_test_feature_gate_config(vec![gate]); + assert!( + state + .is_game_distribution_publish_enabled_for_user(Some("user-allowlisted")) + .await + .expect("allowlisted author decision"), + "白名单作者应拿到发布入口" + ); + assert!( + !state + .is_game_distribution_publish_enabled_for_user(Some("user-other")) + .await + .expect("other author decision"), + "白名单外作者不应拿到发布入口" + ); + assert!( + state + .is_game_distribution_publish_open() + .await + .expect("open decision"), + "灰度开启后管理员激活新版本不应被作者白名单挡住" + ); + } + #[tokio::test] async fn game_distribution_publish_switch_blocks_writes_but_keeps_reads_and_allowlist() { let state = AppState::new(AppConfig::default()).expect("state should build"); @@ -1390,22 +1635,37 @@ mod tests { .expect("request should build") }; - // 默认没有 gate 行:写入进入业务,不能被发布开关拦下。 - let open = app + // 灰度默认关闭:没有 gate 行时发布写入必须 503 + 专用错误码。 + let default_blocked = app .clone() .oneshot(publish_request()) .await .expect("request should succeed"); - assert_ne!( - open.status(), - StatusCode::SERVICE_UNAVAILABLE, - "默认状态不应拦截发布" + assert_eq!(default_blocked.status(), StatusCode::SERVICE_UNAVAILABLE); + let default_payload = read_json_response(default_blocked).await; + assert_eq!( + default_payload["error"]["code"], + "GAME_DISTRIBUTION_PUBLISH_DISABLED" ); - // 运营收紧到 rollout 0 且无白名单:作者写入 503 + 专用错误码。 - state.set_test_feature_gate_config(vec![test_feature_gate( - module_runtime::GAME_DISTRIBUTION_PUBLISH_GATE_KEY, - )]); + // gate 行 enabled=false 同样未开放。 + let mut disabled_gate = + test_feature_gate(module_runtime::GAME_DISTRIBUTION_PUBLISH_GATE_KEY); + disabled_gate.enabled = false; + state.set_test_feature_gate_config(vec![disabled_gate]); + let disabled = app + .clone() + .oneshot(publish_request()) + .await + .expect("request should succeed"); + assert_eq!(disabled.status(), StatusCode::SERVICE_UNAVAILABLE); + + // 开启但 rollout 0 且无白名单:仍然拦截。 + let mut zero_rollout = + test_feature_gate(module_runtime::GAME_DISTRIBUTION_PUBLISH_GATE_KEY); + zero_rollout.enabled = true; + zero_rollout.rollout_percent = 0; + state.set_test_feature_gate_config(vec![zero_rollout]); let blocked = app .clone() .oneshot(publish_request()) @@ -1433,6 +1693,7 @@ mod tests { // 白名单内用户仍可发布(灰度放行)。 let mut gate = test_feature_gate(module_runtime::GAME_DISTRIBUTION_PUBLISH_GATE_KEY); + gate.enabled = true; gate.allow_user_ids = vec![user.id.clone()]; state.set_test_feature_gate_config(vec![gate]); let allowed = app @@ -1707,247 +1968,6 @@ mod tests { ); } - #[cfg(any())] - #[tokio::test] - async fn creative_agent_draft_edit_rejects_unconfirmed_template_session() { - let app = build_internal_creative_agent_app(); - - let create_response = app - .clone() - .oneshot(internal_creative_agent_request( - "POST", - "/api/runtime/creative-agent/sessions", - serde_json::json!({ - "text": "做一个生日拼图", - "entryContext": "creation_home" - }), - )) - .await - .expect("create session request should succeed"); - assert_eq!(create_response.status(), StatusCode::OK); - let create_payload = read_json_response(create_response).await; - let session_id = create_payload["session"]["sessionId"] - .as_str() - .expect("session id should exist"); - - let edit_response = app - .clone() - .oneshot(internal_creative_agent_request( - "POST", - &format!("/api/runtime/creative-agent/sessions/{session_id}/draft-edits/stream"), - serde_json::json!({ - "clientMessageId": "creative-edit-test", - "instruction": "把标题改轻松一点", - "targetPuzzleSessionId": "puzzle-session-unconfirmed", - "currentDraft": { - "workTitle": "旧标题", - "workDescription": "旧描述", - "summary": "旧描述", - "themeTags": ["创意", "拼图", "灵感"], - "levels": [{ - "levelId": "puzzle-level-1", - "levelName": "第一关", - "pictureDescription": "旧图面", - "pictureReference": null, - "generationStatus": "idle", - "candidates": [] - }] - } - }), - )) - .await - .expect("draft edit request should be handled"); - - assert_eq!(edit_response.status(), StatusCode::BAD_REQUEST); - let edit_payload = read_json_response(edit_response).await; - assert_eq!( - edit_payload["error"]["details"]["message"], - Value::String("尚未绑定拼图草稿".to_string()) - ); - - let session_response = app - .oneshot(internal_creative_agent_request( - "GET", - &format!("/api/runtime/creative-agent/sessions/{session_id}"), - Value::Null, - )) - .await - .expect("get session request should succeed"); - let session_payload = read_json_response(session_response).await; - assert_eq!(session_payload["session"]["targetBinding"], Value::Null); - } - - #[cfg(any())] - #[tokio::test] - async fn creative_agent_message_stream_returns_template_confirmation_events() { - let app = build_internal_creative_agent_app(); - - let create_response = app - .clone() - .oneshot(internal_creative_agent_request( - "POST", - "/api/runtime/creative-agent/sessions", - serde_json::json!({ - "text": "做一个生日拼图", - "entryContext": "creation_home" - }), - )) - .await - .expect("create session request should succeed"); - assert_eq!(create_response.status(), StatusCode::OK); - let create_payload = read_json_response(create_response).await; - let session_id = create_payload["session"]["sessionId"] - .as_str() - .expect("session id should exist"); - - let stream_response = app - .clone() - .oneshot(internal_creative_agent_request( - "POST", - &format!("/api/runtime/creative-agent/sessions/{session_id}/messages/stream"), - serde_json::json!({ - "clientMessageId": "creative-message-stream-test", - "content": [{ - "type": "input_text", - "text": "做一个温暖的生日拼图" - }] - }), - )) - .await - .expect("message stream request should be handled"); - - assert_eq!(stream_response.status(), StatusCode::OK); - assert_eq!( - stream_response - .headers() - .get("content-type") - .and_then(|value| value.to_str().ok()), - Some("text/event-stream") - ); - let stream_body = read_text_response(stream_response).await; - - assert!(stream_body.contains("event: stage")); - assert!(stream_body.contains("event: tool_started")); - assert!(stream_body.contains("event: tool_completed")); - assert!(stream_body.contains("event: puzzle_template_catalog")); - assert!(!stream_body.contains("event: puzzle_template_selection")); - assert!(!stream_body.contains("event: puzzle_cost_range")); - assert!(stream_body.contains("event: done")); - let tool_started_id = stream_body - .lines() - .skip_while(|line| *line != "event: tool_started") - .nth(1) - .and_then(|line| line.strip_prefix("data: ")) - .and_then(|data| serde_json::from_str::(data).ok()) - .and_then(|payload| payload["toolCallId"].as_str().map(ToString::to_string)) - .expect("tool_started should include toolCallId"); - let tool_completed_id = stream_body - .lines() - .skip_while(|line| *line != "event: tool_completed") - .nth(1) - .and_then(|line| line.strip_prefix("data: ")) - .and_then(|data| serde_json::from_str::(data).ok()) - .and_then(|payload| payload["toolCallId"].as_str().map(ToString::to_string)) - .expect("tool_completed should include toolCallId"); - assert_eq!(tool_started_id, tool_completed_id); - - let session_response = app - .oneshot(internal_creative_agent_request( - "GET", - &format!("/api/runtime/creative-agent/sessions/{session_id}"), - Value::Null, - )) - .await - .expect("get session request should succeed"); - let session_payload = read_json_response(session_response).await; - assert_eq!( - session_payload["session"]["stage"], - Value::String("waiting_template_confirmation".to_string()) - ); - assert_eq!( - session_payload["session"]["puzzleTemplateSelection"], - Value::Null - ); - assert!( - session_payload["session"]["puzzleTemplateCatalog"] - .as_array() - .map(|templates| templates.len() >= 3) - .unwrap_or(false) - ); - } - - #[cfg(any())] - #[tokio::test] - async fn creative_agent_confirm_template_rejects_non_puzzle_template() { - let app = build_internal_creative_agent_app(); - - let create_response = app - .clone() - .oneshot(internal_creative_agent_request( - "POST", - "/api/runtime/creative-agent/sessions", - serde_json::json!({ - "text": "做一个角色扮演开场", - "entryContext": "creation_home" - }), - )) - .await - .expect("create session request should succeed"); - assert_eq!(create_response.status(), StatusCode::OK); - let create_payload = read_json_response(create_response).await; - let session_id = create_payload["session"]["sessionId"] - .as_str() - .expect("session id should exist"); - - let confirm_response = app - .clone() - .oneshot(internal_creative_agent_request( - "POST", - &format!("/api/runtime/creative-agent/sessions/{session_id}/confirm-template"), - serde_json::json!({ - "selection": { - "templateId": "rpg.unsupported", - "title": "RPG", - "reason": "用户想创建 RPG", - "costRange": { - "minPoints": 2, - "maxPoints": 12, - "pricingUnit": "point", - "reason": "按关卡数和每关图片生成次数估算,实际扣费以后端任务结算为准" - }, - "supportedLevelMode": "single_or_multi", - "selectedLevelMode": "single_level", - "plannedLevelCount": 1, - "requiresUserConfirmation": true - } - }), - )) - .await - .expect("confirm template request should be handled"); - - assert_eq!(confirm_response.status(), StatusCode::BAD_REQUEST); - let confirm_payload = read_json_response(confirm_response).await; - assert_eq!( - confirm_payload["error"]["details"]["provider"], - Value::String("module-puzzle".to_string()) - ); - - let session_response = app - .oneshot(internal_creative_agent_request( - "GET", - &format!("/api/runtime/creative-agent/sessions/{session_id}"), - Value::Null, - )) - .await - .expect("get session request should succeed"); - let session_payload = read_json_response(session_response).await; - assert_eq!( - session_payload["session"]["stage"], - Value::String("idle".to_string()) - ); - assert_eq!(session_payload["session"]["targetBinding"], Value::Null); - } - #[tokio::test] async fn runtime_story_legacy_routes_are_not_mounted() { let app = build_router(AppState::new(AppConfig::default()).expect("state should build")); diff --git a/server-rs/crates/api-server/src/asset_billing.rs b/server-rs/crates/api-server/src/asset_billing.rs index f9eb99573..9ba5795db 100644 --- a/server-rs/crates/api-server/src/asset_billing.rs +++ b/server-rs/crates/api-server/src/asset_billing.rs @@ -13,8 +13,6 @@ use crate::{ wallet_refund_outbox::{WalletRefundOutboxEnqueueOutcome, WalletRefundOutboxRecord}, }; -pub(crate) const ASSET_OPERATION_POINTS_COST: u64 = 1; - #[derive(Clone, Debug)] struct ExternalGenerationBillingContext { job_id: String, @@ -145,29 +143,7 @@ where .await } -/// 资产操作统一执行入口:业务层只声明操作类型与资源 ID,钱包扣退费由服务层收口。 -pub(crate) async fn execute_billable_asset_operation( - state: &AppState, - owner_user_id: &str, - asset_kind: &str, - asset_id: &str, - operation: Fut, -) -> Result -where - Fut: Future>, -{ - execute_billable_asset_operation_with_cost( - state, - owner_user_id, - asset_kind, - asset_id, - ASSET_OPERATION_POINTS_COST, - operation, - ) - .await -} - -/// 生图等特殊操作可声明独立泥点成本,避免修改全局资产操作默认价格。 +/// 资产操作统一执行入口:业务层声明后端计算的泥点成本,钱包扣退费由服务层收口。 pub(crate) async fn execute_billable_asset_operation_with_cost( state: &AppState, owner_user_id: &str, @@ -706,25 +682,6 @@ pub(crate) fn map_asset_operation_wallet_error(error: SpacetimeClientError) -> A } } -pub(crate) fn should_skip_asset_operation_billing_for_connectivity( - error: &SpacetimeClientError, -) -> bool { - match error { - SpacetimeClientError::ConnectDropped | SpacetimeClientError::Timeout(_) => true, - SpacetimeClientError::Build(message) - | SpacetimeClientError::Procedure(message) - | SpacetimeClientError::Runtime(message) => { - message.contains("503") - || message.contains("Service Unavailable") - || message.contains("Failed to connect") - || message.contains("WebSocket") - || message.contains("No such procedure") - || message.contains("连接已断开") - || message.contains("连接在返回结果前已断开") - } - } -} - fn should_use_wallet_refund_emergency_spool(error: &SpacetimeClientError) -> bool { match error { SpacetimeClientError::ConnectDropped | SpacetimeClientError::Timeout(_) => true, @@ -875,27 +832,6 @@ mod tests { assert_eq!(wallet.balance_delta, -37); } - #[test] - fn asset_operation_connectivity_errors_are_classified_for_non_billing_fallbacks() { - assert_eq!(ASSET_OPERATION_POINTS_COST, 1); - assert!(should_skip_asset_operation_billing_for_connectivity( - &SpacetimeClientError::ConnectDropped - )); - assert!(should_skip_asset_operation_billing_for_connectivity( - &SpacetimeClientError::Runtime( - "Failed to connect: HTTP error: 503 Service Unavailable".to_string(), - ), - )); - assert!(should_skip_asset_operation_billing_for_connectivity( - &SpacetimeClientError::Procedure( - "No such procedure: consume_profile_wallet_points_and_return".to_string(), - ), - )); - assert!(!should_skip_asset_operation_billing_for_connectivity( - &SpacetimeClientError::Procedure("泥点余额不足".to_string()), - )); - } - #[test] fn wallet_refund_emergency_spool_requires_database_unavailability() { assert!(should_use_wallet_refund_emergency_spool( diff --git a/server-rs/crates/api-server/src/config.rs b/server-rs/crates/api-server/src/config.rs index 6bf7edc92..b75504dbe 100644 --- a/server-rs/crates/api-server/src/config.rs +++ b/server-rs/crates/api-server/src/config.rs @@ -92,6 +92,8 @@ pub struct AppConfig { pub editor_bgfilter_circuit_cooldown: Duration, pub image_editor_agent_sidebar_enabled: bool, pub client_download_channel: String, + /// 客户端埋点接收所绑定的公开 origin;未配置时拒绝上传。 + pub agc_analytics_origin: String, /// AGC 项目快照的部署渠道:上传与后台默认查询都按它分区。 pub project_snapshot_channel: String, pub log_filter: String, @@ -296,13 +298,6 @@ pub enum ExternalGenerationMode { } impl ExternalGenerationMode { - pub fn as_str(self) -> &'static str { - match self { - Self::Inline => "inline", - Self::Queue => "queue", - } - } - pub fn is_inline(self) -> bool { matches!(self, Self::Inline) } @@ -404,6 +399,7 @@ impl Default for AppConfig { ), image_editor_agent_sidebar_enabled: false, client_download_channel: "dev".to_string(), + agc_analytics_origin: String::new(), project_snapshot_channel: "dev".to_string(), log_filter: "info,tower_http=info".to_string(), otel_enabled: false, @@ -727,6 +723,9 @@ impl AppConfig { // 显式空值或非法值也保留,由下载入口失败关闭,不能悄悄改读 dev。 config.client_download_channel = channel.trim().to_string(); } + if let Ok(origin) = std::env::var("GENARRATIVE_AGC_ANALYTICS_ORIGIN") { + config.agc_analytics_origin = origin.trim().to_string(); + } // 快照渠道缺省沿用同一个部署渠道(本部署的客户端渠道),显式配置优先; // 显式空值或非法值同样保留,由快照入口失败关闭。 config.project_snapshot_channel = config.client_download_channel.clone(); diff --git a/server-rs/crates/api-server/src/editor_agent/mod.rs b/server-rs/crates/api-server/src/editor_agent/mod.rs index c7a62010f..55a9b2d17 100644 --- a/server-rs/crates/api-server/src/editor_agent/mod.rs +++ b/server-rs/crates/api-server/src/editor_agent/mod.rs @@ -11,6 +11,3 @@ pub use api::{ create_editor_agent_conversation, delete_editor_agent_conversation, get_editor_agent_conversation, list_editor_agent_conversations, }; - -#[cfg(test)] -pub(crate) use reconcile::reconcile_completed_editor_agent_tool_call_for_test; diff --git a/server-rs/crates/api-server/src/editor_agent/reconcile.rs b/server-rs/crates/api-server/src/editor_agent/reconcile.rs index 80f6f97ce..44e10f454 100644 --- a/server-rs/crates/api-server/src/editor_agent/reconcile.rs +++ b/server-rs/crates/api-server/src/editor_agent/reconcile.rs @@ -226,15 +226,6 @@ fn reconcile_completed_editor_agent_tool_call( Ok(()) } -#[cfg(test)] -pub(crate) fn reconcile_completed_editor_agent_tool_call_for_test( - message: &mut EditorAgentMessage, - result_payload_json: Option<&str>, -) -> Result<(), String> { - reconcile_completed_editor_agent_tool_call(message, result_payload_json) - .map_err(|error| format!("{error:?}")) -} - #[cfg(test)] mod tests { use super::*; diff --git a/server-rs/crates/api-server/src/editor_green_screen.rs b/server-rs/crates/api-server/src/editor_green_screen.rs index 6bd011bdb..8dd365dbc 100644 --- a/server-rs/crates/api-server/src/editor_green_screen.rs +++ b/server-rs/crates/api-server/src/editor_green_screen.rs @@ -146,17 +146,6 @@ fn editor_screen_background_color_prompt(color: EditorScreenBackgroundColor) -> ) } -pub(crate) fn editor_green_screen_asset_prompt_clause( - color: EditorScreenBackgroundColor, -) -> String { - format!( - "背景必须是{},且{},方便扣除背景;{}", - editor_screen_background_color_prompt(color), - EDITOR_GREEN_SCREEN_BACKGROUND_GUARDRAILS, - EDITOR_GREEN_SCREEN_ASSET_GUARDRAILS - ) -} - pub(crate) fn editor_green_screen_character_prompt_clause( color: EditorScreenBackgroundColor, ) -> String { diff --git a/server-rs/crates/api-server/src/editor_project.rs b/server-rs/crates/api-server/src/editor_project.rs index cd4e3542e..f6ec1d0ed 100644 --- a/server-rs/crates/api-server/src/editor_project.rs +++ b/server-rs/crates/api-server/src/editor_project.rs @@ -1268,7 +1268,7 @@ fn serialize_atomic_editor_generation_job_result( Ok(payload_json) } -/// 队列结果落库前的通用紧凑化。原子提交与 worker 直接 complete 两条路径共用同一份实现, +/// 队列结果原子提交前的通用紧凑化, /// 避免任何 consumer 把内部 provider 带入可重放的结果快照。 pub(crate) fn compact_editor_generation_result(mut result: Value) -> Value { let Some(object) = result.as_object_mut() else { @@ -1586,7 +1586,6 @@ struct EditorCanvasGenerationCompletionResult { #[derive(Debug)] pub(crate) struct PersistEditorGeneratedAssetInput { pub(crate) project_id: Option, - pub(crate) owner_user_id: String, pub(crate) folder_id: Option, pub(crate) label: String, pub(crate) image_src: String, @@ -1610,30 +1609,6 @@ pub(crate) struct PersistEditorGeneratedAssetInput { pub(crate) image_sequence_duration_ms: Option, } -pub(crate) struct PersistEditorGeneratedAssetRequest { - pub(crate) project_id: Option, - pub(crate) owner_user_id: String, - pub(crate) folder_id: Option, - pub(crate) label: String, - pub(crate) image_src: String, - pub(crate) object_key: Option, - pub(crate) asset_object_id: Option, - pub(crate) width: u32, - pub(crate) height: u32, - pub(crate) prompt: String, - pub(crate) actual_prompt: Option, - pub(crate) model: String, - pub(crate) provider: String, - pub(crate) task_id: String, - pub(crate) source_resource_id: Option, - pub(crate) asset_kind: Option, - pub(crate) generation_inputs: Option, - pub(crate) thumbnail_src: Option, - pub(crate) generation_cost_mud_points: u64, - pub(crate) image_sequence_frames: Option, - pub(crate) image_sequence_duration_ms: Option, -} - #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct EditorGeneratedImageStorageProfile { asset_kind: &'static str, @@ -2655,17 +2630,6 @@ pub async fn toggle_editor_showcase_asset_like( )) } -fn editor_scene_style_label(style_preset: &str) -> &'static str { - match style_preset.trim() { - "anime" => "日系动画", - "watercolor" => "清透水彩", - "flat" => "平面几何", - "stop-motion" => "定格模型", - "custom" => "自定义", - _ => "未知", - } -} - fn build_editor_scene_generation_inputs( payload: &EditorSceneGenerateRequest, generation_options: &EditorGenerationOptions, @@ -2933,81 +2897,6 @@ pub(crate) async fn enqueue_editor_image_generation_for_owner( .await } -/// Runs the non-generating validation and authorization required before a caller performs -/// preparatory provider work such as icon-spec metadata completion. Final dispatch deliberately -/// validates again because queued execution can happen later in another process. -pub(crate) async fn validate_editor_image_generation_parameters_for_owner( - state: &AppState, - request_context: &RequestContext, - caller: &EditorGenerationCaller, - payload: &EditorImageGenerationRequest, -) -> Result<(), AppError> { - ensure_editor_reference_image_sources_are_stable( - payload.reference_image_srcs.as_deref(), - "editor-image-generation", - "referenceImageSrcs", - "生成参考图", - )?; - let normalized_kind = payload.kind.as_deref().map(str::trim); - if matches!(normalized_kind, Some("character")) { - parse_editor_bgfilter_seg_model(payload.seg_model.as_deref())?; - } - let is_ui_design_generation = matches!(normalized_kind, Some("ui-design")); - let is_publication_material_generation = - matches!(normalized_kind, Some("publication-material")); - let generation_options = normalize_editor_generation_options( - if is_ui_design_generation || is_publication_material_generation { - Some(GPT_IMAGE_2_MODEL) - } else { - payload.model.as_deref() - }, - payload.aspect_ratio.as_deref(), - payload.image_size.as_deref(), - ); - let reference_limit = if matches!(normalized_kind, Some("quick-edit")) { - EDITOR_QUICK_EDIT_REFERENCE_LIMIT - .min(editor_provider_reference_limit(generation_options.model)) - } else { - EDITOR_IMAGE_GENERATION_REFERENCE_LIMIT - }; - ensure_editor_reference_image_source_limit( - payload.reference_image_srcs.as_deref(), - reference_limit, - "editor-image-generation", - "referenceImageSrcs", - "生成参考图", - )?; - for source in normalize_editor_reference_image_sources(payload.reference_image_srcs.as_deref()) - { - parse_editor_reference_image(state, caller.owner_user_id.as_str(), source).await?; - } - - let settings = require_openai_image_settings(state)?.with_external_api_audit_context( - request_context, - caller.audit_subject_user_id.clone(), - caller - .audit_project_id - .clone() - .or_else(|| payload.project_id.clone()), - ); - build_openai_image_http_client(&settings)?; - state - .editor_generation_pricing() - .await - .map_err(|error| { - AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR).with_details(json!({ - "provider": "editor-generation-pricing", - "message": error.to_string(), - })) - })? - .image_generation_mud_points( - normalized_kind, - Some(generation_options.model), - Some(generation_options.image_size), - ); - Ok(()) -} - pub(crate) async fn generate_editor_image_for_owner( state: &AppState, request_context: &RequestContext, @@ -3401,7 +3290,6 @@ where Some(source_persisted.asset_object), PersistEditorGeneratedAssetInput { project_id: payload.project_id.clone(), - owner_user_id: caller.owner_user_id.clone(), folder_id: payload .asset_folder_id .clone() @@ -3664,7 +3552,6 @@ where Some(prepared_image.asset_object.clone()), PersistEditorGeneratedAssetInput { project_id: payload.project_id.clone(), - owner_user_id: caller.owner_user_id.clone(), folder_id: payload.asset_folder_id, label: asset_label, image_src: image_src.clone(), @@ -6196,7 +6083,6 @@ pub(crate) async fn edit_editor_image_for_owner_with_source_snapshot( Some(prepared_image.asset_object.clone()), PersistEditorGeneratedAssetInput { project_id: payload.project_id.clone(), - owner_user_id: owner_user_id.clone(), folder_id: payload.asset_folder_id, label: asset_label.clone(), image_src: image_src.clone(), @@ -6883,7 +6769,6 @@ pub(crate) async fn remove_editor_image_background_for_owner( Some(prepared_image.asset_object.clone()), PersistEditorGeneratedAssetInput { project_id: payload.project_id.clone(), - owner_user_id: caller.owner_user_id.clone(), folder_id: payload.asset_folder_id, label: asset_label.clone(), image_src: image_src.clone(), @@ -8624,7 +8509,6 @@ pub(crate) async fn extract_editor_ui_design_assets_for_owner( Some(source_prepared_image.asset_object.clone()), PersistEditorGeneratedAssetInput { project_id: payload.project_id.clone(), - owner_user_id: caller.owner_user_id.clone(), folder_id: asset_folder_id.clone(), label: editor_generated_asset_variant_label(source_label.as_str(), "原图"), image_src: source_image_src.clone(), @@ -8828,7 +8712,6 @@ pub(crate) async fn extract_editor_ui_design_assets_for_owner( Some(spritesheet_prepared_image.asset_object.clone()), PersistEditorGeneratedAssetInput { project_id: payload.project_id.clone(), - owner_user_id: owner_user_id.clone(), folder_id: asset_folder_id.clone(), label: source_label, image_src: spritesheet_image_src.clone(), @@ -10169,99 +10052,6 @@ fn fill_missing_media_identity_field( } } -pub(crate) async fn persist_editor_generated_asset( - state: &AppState, - mut input: PersistEditorGeneratedAssetInput, -) -> Result { - let generation_inputs_json = serialize_editor_generation_inputs( - input.asset_kind.as_deref(), - input.generation_inputs.clone(), - )?; - let image_sequence_frames_json = - serialize_editor_image_sequence_frames(input.image_sequence_frames.take())?; - let object_key = normalize_editor_object_key(input.object_key); - let asset_object_id = normalize_optional_string(input.asset_object_id); - let model = normalize_optional_string(Some(input.model)); - let image_src = normalize_editor_persisted_media_src(input.image_src, object_key.as_deref())?; - let now_micros = current_utc_micros(); - let resource = if let Some(project_id) = normalize_optional_string(input.project_id.clone()) { - let record = state - .spacetime_client() - .create_editor_project_resource(EditorProjectResourceCreateRecordInput { - resource_id: build_prefixed_uuid_id(EDITOR_RESOURCE_ID_PREFIX), - project_id, - owner_user_id: input.owner_user_id.clone(), - asset_object_id: asset_object_id.clone(), - image_src: image_src.clone(), - object_key: object_key.clone(), - width: input.width, - height: input.height, - source_type: "generated".to_string(), - prompt: Some(input.prompt.clone()), - actual_prompt: input.actual_prompt.clone(), - model: model.clone(), - provider: Some(input.provider.clone()), - task_id: Some(input.task_id.clone()), - source_resource_id: normalize_optional_string(input.source_resource_id.clone()), - asset_kind: normalize_optional_string(input.asset_kind.clone()), - generation_inputs_json: generation_inputs_json.clone(), - updated_at_micros: now_micros, - image_sequence_frames_json: image_sequence_frames_json.clone(), - image_sequence_duration_ms: input.image_sequence_duration_ms, - }) - .await - .map_err(map_editor_project_error)?; - Some(editor_project_resource_payload_from_record(record)) - } else { - None - }; - - let folder_id = - normalize_generated_asset_folder_id(input.folder_id, input.owner_user_id.as_str()); - let created_resource_id = resource - .as_ref() - .map(|resource| resource.resource_id.clone()) - .or_else(|| normalize_optional_string(input.source_resource_id.clone())); - let asset = if let Some(folder_id) = folder_id { - let record = state - .spacetime_client() - .create_editor_asset(EditorAssetCreateRecordInput { - asset_id: build_prefixed_uuid_id(EDITOR_ASSET_ID_PREFIX), - owner_user_id: input.owner_user_id.clone(), - folder_id, - label: input.label, - asset_object_id, - image_src, - object_key, - width: input.width, - height: input.height, - source_type: "generated".to_string(), - prompt: Some(input.prompt), - actual_prompt: input.actual_prompt, - model, - provider: Some(input.provider), - task_id: Some(input.task_id), - asset_kind: normalize_optional_string(input.asset_kind), - generation_inputs_json, - source_resource_id: created_resource_id, - generation_cost_mud_points: input.generation_cost_mud_points, - now_micros, - thumbnail_src: normalize_optional_string(input.thumbnail_src), - group_task_id: normalize_optional_string(input.group_task_id), - group_task_expected_asset_count: input.group_task_expected_asset_count, - image_sequence_frames_json, - image_sequence_duration_ms: input.image_sequence_duration_ms, - }) - .await - .map_err(map_editor_project_error)?; - Some(editor_asset_payload_from_record(record)) - } else { - None - }; - - Ok(EditorGeneratedAssetRecord { resource, asset }) -} - pub(crate) fn prepare_editor_generated_asset( caller: &EditorGenerationCaller, slot: &str, @@ -10444,113 +10234,6 @@ pub(crate) fn prepare_editor_generated_asset( }) } -pub(crate) async fn persist_editor_generated_media_asset( - state: &AppState, - mut input: PersistEditorGeneratedAssetRequest, -) -> Result< - ( - Option, - Option, - ), - AppError, -> { - input.generation_inputs = - sanitize_editor_client_generation_inputs(input.generation_inputs.take()); - let persisted = persist_editor_generated_asset( - state, - PersistEditorGeneratedAssetInput { - project_id: input.project_id, - owner_user_id: input.owner_user_id, - folder_id: input.folder_id, - label: input.label, - image_src: input.image_src, - object_key: input.object_key, - asset_object_id: input.asset_object_id, - width: input.width, - height: input.height, - prompt: input.prompt, - actual_prompt: input.actual_prompt, - model: input.model, - provider: input.provider, - task_id: input.task_id, - group_task_id: None, - group_task_expected_asset_count: None, - source_resource_id: input.source_resource_id, - asset_kind: input.asset_kind, - generation_inputs: input.generation_inputs, - thumbnail_src: input.thumbnail_src, - generation_cost_mud_points: input.generation_cost_mud_points, - image_sequence_frames: input.image_sequence_frames, - image_sequence_duration_ms: input.image_sequence_duration_ms, - }, - ) - .await?; - Ok((persisted.resource, persisted.asset)) -} - -pub(crate) async fn complete_editor_canvas_generation( - state: &AppState, - owner_user_id: &str, - project_id: Option<&str>, - completion: Option<&EditorCanvasGenerationCompletionRequest>, - resource: Option<&EditorProjectResourcePayload>, -) -> Result, AppError> { - let (Some(project_id), Some(completion), Some(resource)) = (project_id, completion, resource) - else { - return Ok(None); - }; - let project_id = project_id.trim(); - if project_id.is_empty() { - return Ok(None); - } - - let project = state - .spacetime_client() - .get_editor_project(EditorProjectGetRecordInput { - project_id: project_id.to_string(), - owner_user_id: owner_user_id.to_string(), - }) - .await - .map_err(map_editor_project_error)?; - let project = repair_editor_project_record_inline_media( - &EditorMediaStorageState::from_ref(state), - project, - ) - .await; - let expected_revision = project.canvas.revision; - let viewport = project.viewport.clone(); - let project_payload = editor_project_payload_from_record(project); - let Some(placeholder) = - resolve_canvas_completion_placeholder(project_payload.layers.clone(), completion)? - else { - return Ok(None); - }; - let layer_id = generated_canvas_layer_id(resource.resource_id.as_str()); - let item = - build_generated_canvas_layer_item(completion, &placeholder, resource, layer_id.as_str(), 0); - let completion_result = apply_editor_canvas_generation_items( - project_payload.layers, - completion, - placeholder, - vec![item], - Some(layer_id), - )?; - if !completion_result.changed { - return Ok(None); - } - let saved = save_editor_project_layout_with_revision_and_get( - state, - project_id, - owner_user_id, - viewport, - completion_result.layers, - expected_revision, - ) - .await?; - - Ok(Some(editor_project_payload_from_record(saved))) -} - #[derive(Clone, Copy)] pub(crate) struct EditorSourceOnlyFallbackResultContext<'a> { pub(crate) width: u32, @@ -10706,39 +10389,6 @@ pub(crate) async fn persist_editor_source_only_fallback_atomically( Ok((source_record, project, warning)) } -pub(crate) async fn complete_editor_source_only_fallback( - state: &AppState, - owner_user_id: &str, - project_id: Option<&str>, - completion: Option<&EditorCanvasGenerationCompletionRequest>, - source_record: &EditorGeneratedAssetRecord, - current_warning: Option, - dimension_warning: Option<&EditorGenerationWarningResponse>, -) -> Result< - ( - Option, - Option, - ), - AppError, -> { - let project = complete_editor_canvas_generation( - state, - owner_user_id, - project_id, - completion, - source_record.resource.as_ref(), - ) - .await?; - let warning = merge_editor_generation_warnings( - current_warning, - Some(editor_postprocess_fallback_warning_with_dimension( - "生成任务成功,后处理失败。", - dimension_warning, - )), - ); - Ok((project, warning)) -} - pub(crate) async fn complete_editor_canvas_generation_with_items( state: &AppState, owner_user_id: &str, @@ -10827,38 +10477,6 @@ pub(crate) async fn prepare_editor_canvas_generation_layout( })) } -pub(crate) async fn complete_editor_canvas_background_removal( - state: &AppState, - owner_user_id: &str, - project_id: Option<&str>, - target_layer_id: Option<&str>, - resource: Option<&EditorProjectResourcePayload>, - replacement_title: Option<&str>, - recenter_replacement: bool, -) -> Result, AppError> { - let Some(layout) = prepare_editor_canvas_background_removal_layout( - state, - owner_user_id, - project_id, - target_layer_id, - None, - resource, - replacement_title, - recenter_replacement, - ) - .await? - else { - return Ok(None); - }; - let saved = state - .spacetime_client() - .save_editor_project_layout_v2(layout) - .await - .map_err(map_editor_project_error)?; - - Ok(Some(editor_project_payload_from_record(saved))) -} - #[allow(clippy::too_many_arguments)] async fn prepare_editor_canvas_background_removal_layout( state: &AppState, @@ -12209,55 +11827,6 @@ fn prepare_editor_generated_image_object_data( }) } -pub(crate) struct PersistEditorProviderSourceResourceInput { - pub(crate) project_id: Option, - pub(crate) owner_user_id: String, - pub(crate) folder_id: Option, - pub(crate) label: String, - pub(crate) width: u32, - pub(crate) height: u32, - pub(crate) prompt: String, - pub(crate) actual_prompt: Option, - pub(crate) model: String, - pub(crate) task_id: String, - pub(crate) source_resource_id: Option, - pub(crate) asset_kind: Option, - pub(crate) generation_inputs: Option, - pub(crate) generation_cost_mud_points: u64, -} - -pub(crate) async fn persist_editor_generated_image( - state: &AppState, - owner_user_id: &str, - task_id: &str, - image: &DownloadedOpenAiImage, - prompt: &str, - actual_prompt: Option<&str>, - asset_kind: &str, - path_kind: &str, - file_stem: &str, - slot: &str, - provider: &str, -) -> Result { - persist_editor_generated_image_data( - &EditorMediaStorageState::from_ref(state), - owner_user_id, - task_id, - GeneratedImageAssetDataUrl { - format: normalize_generated_image_asset_mime(image.mime_type.as_str()), - bytes: image.bytes.clone(), - }, - prompt, - actual_prompt, - asset_kind, - path_kind, - file_stem, - slot, - provider, - ) - .await -} - #[allow(clippy::too_many_arguments)] pub(crate) async fn prepare_editor_generated_image( state: &AppState, @@ -12306,39 +11875,6 @@ pub(crate) async fn prepare_editor_generated_image( }) } -async fn persist_editor_generated_image_owned( - state: &AppState, - owner_user_id: &str, - task_id: &str, - image: DownloadedOpenAiImage, - prompt: &str, - actual_prompt: Option<&str>, - asset_kind: &str, - path_kind: &str, - file_stem: &str, - slot: &str, - provider: &str, -) -> Result { - let image_data = GeneratedImageAssetDataUrl { - format: normalize_generated_image_asset_mime(image.mime_type.as_str()), - bytes: image.bytes, - }; - persist_editor_generated_image_data( - &EditorMediaStorageState::from_ref(state), - owner_user_id, - task_id, - image_data, - prompt, - actual_prompt, - asset_kind, - path_kind, - file_stem, - slot, - provider, - ) - .await -} - async fn persist_editor_generated_image_data( state: &EditorMediaStorageState, owner_user_id: &str, @@ -12499,69 +12035,6 @@ async fn upload_editor_generated_image_object_prepared( }) } -pub(crate) async fn persist_editor_provider_source_image( - state: &AppState, - owner_user_id: &str, - task_id: &str, - image: DownloadedOpenAiImage, - prompt: &str, - actual_prompt: Option<&str>, - asset_kind: &str, - path_kind: &str, - file_stem: &str, -) -> Result { - persist_editor_generated_image_owned( - state, - owner_user_id, - task_id, - image, - prompt, - actual_prompt, - asset_kind, - path_kind, - &format!("{file_stem}-provider-source"), - EDITOR_PROVIDER_SOURCE_SLOT, - "vector-engine", - ) - .await -} - -pub(crate) async fn persist_editor_provider_source_resource( - state: &AppState, - persisted: PersistedEditorGeneratedImage, - input: PersistEditorProviderSourceResourceInput, -) -> Result { - persist_editor_generated_asset( - state, - PersistEditorGeneratedAssetInput { - project_id: input.project_id, - owner_user_id: input.owner_user_id, - folder_id: input.folder_id, - label: input.label, - image_src: editor_media_src_from_object_key(persisted.object_key.as_str()), - object_key: Some(persisted.object_key), - asset_object_id: Some(persisted.asset_object_id), - width: input.width, - height: input.height, - prompt: input.prompt, - actual_prompt: input.actual_prompt, - model: input.model, - provider: "VectorEngine".to_string(), - task_id: input.task_id, - group_task_id: None, - group_task_expected_asset_count: None, - source_resource_id: input.source_resource_id, - asset_kind: input.asset_kind, - generation_inputs: input.generation_inputs, - thumbnail_src: None, - generation_cost_mud_points: input.generation_cost_mud_points, - image_sequence_frames: None, - image_sequence_duration_ms: None, - }, - ) - .await -} - const EDITOR_REFERENCE_IMAGE_READ_EXPIRE_SECONDS: u64 = 300; const EDITOR_REFERENCE_IMAGE_MAX_SIZE_BYTES: u64 = 32 * 1024 * 1024; const EDITOR_BACKGROUND_REMOVAL_SOURCE_PROBE_BYTES: u64 = 16; @@ -13175,27 +12648,6 @@ fn editor_background_removal_source_identity_conflict( })) } -fn resolve_editor_background_removal_source_model_from_records( - projects: &[EditorProjectRecord], - assets: &[EditorAssetRecord], - project_id: Option<&str>, - source_resource_id: Option<&str>, - source_reference: &str, - source_object_key: &str, -) -> Result, AppError> { - Ok( - resolve_editor_background_removal_source_metadata_from_records( - projects, - assets, - project_id, - source_resource_id, - source_reference, - source_object_key, - )? - .model, - ) -} - fn find_editor_background_removal_resource<'a>( projects: &'a [EditorProjectRecord], project_id: Option<&str>, @@ -14635,7 +14087,7 @@ mod tests { ( editor_source, "async fn persist_editor_source_only_fallback_atomically", - "async fn complete_editor_source_only_fallback", + "pub(crate) async fn complete_editor_canvas_generation_with_items", ), ( character_source, @@ -15370,99 +14822,6 @@ mod tests { ); } - #[test] - fn background_removal_source_model_recovers_normal_ancestor() { - let source_key = "generated-character-drafts/editor/result.png"; - let projects = vec![test_editor_project_record( - "project-1", - vec![ - test_editor_project_resource_record( - "resource-original", - "project-1", - "generated-character-drafts/editor/original.png", - Some("gpt-image-2"), - None, - ), - test_editor_project_resource_record( - "resource-internal", - "project-1", - "generated-character-drafts/editor/internal.png", - Some("birefnet"), - Some("resource-original"), - ), - test_editor_project_resource_record( - "resource-result", - "project-1", - source_key, - Some("BgFilter complex"), - Some("resource-internal"), - ), - ], - )]; - - let model = resolve_editor_background_removal_source_model_from_records( - projects.as_slice(), - &[], - Some("project-1"), - Some("resource-result"), - "resource-result", - source_key, - ) - .expect("matching resource should resolve"); - - assert_eq!(model.as_deref(), Some("gpt-image-2")); - } - - #[test] - fn background_removal_source_model_is_none_without_normal_ancestor() { - let source_key = "generated-character-drafts/editor/result.png"; - let projects = vec![test_editor_project_record( - "project-1", - vec![test_editor_project_resource_record( - "resource-result", - "project-1", - source_key, - Some("BgFilter complex"), - None, - )], - )]; - - let model = resolve_editor_background_removal_source_model_from_records( - projects.as_slice(), - &[], - Some("project-1"), - Some("resource-result"), - source_key, - source_key, - ) - .expect("matching resource should resolve"); - - assert_eq!(model, None); - } - - #[test] - fn background_removal_source_model_resolves_owned_asset_model() { - let source_key = "generated-character-drafts/editor/asset.png"; - let assets = vec![test_editor_asset_record( - "asset-1", - source_key, - Some("nanobanana2"), - None, - )]; - - let model = resolve_editor_background_removal_source_model_from_records( - &[], - assets.as_slice(), - None, - None, - "asset-1", - source_key, - ) - .expect("owned asset should resolve"); - - assert_eq!(model.as_deref(), Some("nanobanana2")); - } - #[test] fn background_removal_source_metadata_keeps_authoritative_kind_and_object_identity() { let source_key = "generated-character-drafts/editor/character.png"; @@ -15715,44 +15074,6 @@ mod tests { assert!(error.body_text().contains("sourceResourceId")); } - #[test] - fn background_removal_source_model_allows_source_from_another_owned_project() { - let projects = vec![ - test_editor_project_record( - "project-1", - vec![test_editor_project_resource_record( - "resource-1", - "project-1", - "generated-character-drafts/editor/project-1.png", - Some("gpt-image-2"), - None, - )], - ), - test_editor_project_record( - "project-2", - vec![test_editor_project_resource_record( - "resource-2", - "project-2", - "generated-character-drafts/editor/project-2.png", - Some("gpt-image-2"), - None, - )], - ), - ]; - - let model = resolve_editor_background_removal_source_model_from_records( - projects.as_slice(), - &[], - Some("project-1"), - Some("resource-2"), - "resource-2", - "generated-character-drafts/editor/project-2.png", - ) - .expect("projectId is the output target and must not scope an owned source resource"); - - assert_eq!(model.as_deref(), Some("gpt-image-2")); - } - #[test] fn editor_project_resource_public_payload_falls_back_to_public_user_code() { let state = AppState::new(AppConfig::default()).expect("state should build"); @@ -18302,34 +17623,6 @@ mod tests { ); } - #[test] - fn image_generation_preflight_checks_references_provider_and_pricing() { - let source = concat!( - include_str!("editor_project_icon.rs"), - include_str!("editor_project.rs") - ); - - assert_function_contains_in_order( - source, - "pub(crate) async fn validate_editor_image_generation_parameters_for_owner", - "pub(crate) async fn generate_editor_image_for_owner", - &[ - "ensure_editor_reference_image_sources_are_stable(", - "ensure_editor_reference_image_source_limit(", - "parse_editor_reference_image(", - "require_openai_image_settings(", - "build_openai_image_http_client(", - ".editor_generation_pricing()", - ], - ); - assert_function_not_contains( - source, - "pub(crate) async fn validate_editor_image_generation_parameters_for_owner", - "pub(crate) async fn generate_editor_image_for_owner", - &[".take(reference_limit)"], - ); - } - #[test] fn editor_ui_design_generation_keeps_ui_controls_out_of_negative_prompt() { let ui_design_negative_prompt = editor_image_generation_negative_prompt(true); @@ -18476,13 +17769,13 @@ mod tests { assert_function_contains( source, "async fn persist_editor_generated_image_data", - "async fn persist_editor_provider_source_image", + "const EDITOR_REFERENCE_IMAGE_READ_EXPIRE_SECONDS", &["Some(prompt.to_string())"], ); assert_function_not_contains( source, "async fn persist_editor_generated_image_data", - "async fn persist_editor_provider_source_image", + "const EDITOR_REFERENCE_IMAGE_READ_EXPIRE_SECONDS", &["actual_prompt.unwrap_or(prompt)"], ); } @@ -22337,14 +21630,14 @@ mod tests { assert_function_occurrence_count( source, "async fn resolve_editor_background_removal_source(", - "fn resolve_editor_background_removal_source_model_from_records(", + "fn find_editor_background_removal_resource", ".list_editor_projects(", 1, ); assert_function_occurrence_count( source, "async fn resolve_editor_background_removal_source(", - "fn resolve_editor_background_removal_source_model_from_records(", + "fn find_editor_background_removal_resource", ".get_editor_asset_library(", 1, ); @@ -23033,12 +22326,6 @@ mod tests { ], ); } - assert_function_contains( - source, - "async fn persist_editor_provider_source_image", - "async fn persist_editor_provider_source_resource", - &["persist_editor_generated_image_owned"], - ); // 中文注释:尺寸一致时必须在回读 provider 原图之前就返回,只有漂移才发起 GET。 assert_function_contains_in_order( source, @@ -23085,18 +22372,6 @@ mod tests { "async fn fallback_editor_screen_background_removal", &["fallback_image"], ); - assert_function_contains( - source, - "async fn persist_editor_generated_image_owned", - "async fn persist_editor_generated_image_data", - &["bytes: image.bytes"], - ); - assert_function_not_contains( - source, - "async fn persist_editor_generated_image_owned", - "async fn persist_editor_generated_image_data", - &["image.bytes.clone()"], - ); assert_function_contains( source, "async fn read_editor_reference_image_object", @@ -23126,13 +22401,13 @@ mod tests { assert_function_contains( source, "async fn persist_editor_generated_image_data", - "async fn persist_editor_provider_source_image", + "const EDITOR_REFERENCE_IMAGE_READ_EXPIRE_SECONDS", &["state.editor_oss_http_client()"], ); assert_function_not_contains( source, "async fn persist_editor_generated_image_data", - "async fn persist_editor_provider_source_image", + "const EDITOR_REFERENCE_IMAGE_READ_EXPIRE_SECONDS", &["reqwest::Client::new()"], ); // 中文注释:旧包装仍在 upload-only helper 之后 confirm asset object,供兄弟链路 @@ -23150,7 +22425,7 @@ mod tests { assert_function_not_contains( source, "async fn upload_editor_generated_image_object_data", - "async fn persist_editor_provider_source_image", + "const EDITOR_REFERENCE_IMAGE_READ_EXPIRE_SECONDS", &["confirm_asset_object("], ); // 中文注释:调用方拿到的是同一个 AppError,无法自行判断本函数内部走到了哪一步, @@ -23159,14 +22434,14 @@ mod tests { assert_function_occurrence_count( source, "async fn persist_editor_generated_image_data", - "async fn persist_editor_provider_source_image", + "const EDITOR_REFERENCE_IMAGE_READ_EXPIRE_SECONDS", "EDITOR_RESULT_PERSISTENCE_STARTED_DETAIL", 4, ); assert_function_occurrence_count( source, "async fn upload_editor_generated_image_object_data", - "async fn persist_editor_provider_source_image", + "const EDITOR_REFERENCE_IMAGE_READ_EXPIRE_SECONDS", "EDITOR_RESULT_PERSISTENCE_STARTED_DETAIL", 3, ); @@ -23174,13 +22449,13 @@ mod tests { assert_function_contains( source, "fn prepare_editor_generated_image_object_data", - "struct PersistEditorProviderSourceResourceInput", + "pub(crate) async fn prepare_editor_generated_image", &["prepare_put_object"], ); assert_function_not_contains( source, "fn prepare_editor_generated_image_object_data", - "struct PersistEditorProviderSourceResourceInput", + "pub(crate) async fn prepare_editor_generated_image", &[ "EDITOR_RESULT_PERSISTENCE_STARTED_DETAIL", ".put_object(", @@ -23192,7 +22467,7 @@ mod tests { assert_function_contains_in_order( source, "async fn upload_editor_generated_image_object_prepared", - "async fn persist_editor_provider_source_image", + "const EDITOR_REFERENCE_IMAGE_READ_EXPIRE_SECONDS", &[ "result_persistence_started.store(true, Ordering::Release)", ".put_object(http_client, prepared.request)", @@ -23377,7 +22652,7 @@ mod tests { for (start, end, local_validation, first_remote_step, terminal) in [ ( "pub(crate) async fn enqueue_editor_image_generation_for_owner", - "pub(crate) async fn validate_editor_image_generation_parameters_for_owner", + "pub(crate) async fn generate_editor_image_for_owner", "ensure_editor_reference_image_sources_are_stable", ".editor_generation_pricing()", "enqueue_editor_generation_job_for_caller", @@ -23493,7 +22768,7 @@ mod tests { for (start, end, resolver) in [ ( "pub(crate) async fn enqueue_editor_image_generation_for_owner", - "pub(crate) async fn validate_editor_image_generation_parameters_for_owner", + "pub(crate) async fn generate_editor_image_for_owner", "resolve_editor_image_generation_target_folder_id(", ), ( diff --git a/server-rs/crates/api-server/src/editor_project_icon.rs b/server-rs/crates/api-server/src/editor_project_icon.rs index c109dab63..be15e4583 100644 --- a/server-rs/crates/api-server/src/editor_project_icon.rs +++ b/server-rs/crates/api-server/src/editor_project_icon.rs @@ -1249,7 +1249,6 @@ pub(crate) async fn prepare_editor_spritesheet_slices_for_generation( Some(upload.asset_object), PersistEditorGeneratedAssetInput { project_id: input.project_id.clone(), - owner_user_id: caller.owner_user_id.clone(), folder_id: input.asset_folder_id.clone(), label: upload.name.clone(), image_src: upload.image_src.clone(), @@ -1830,7 +1829,6 @@ pub(crate) async fn generate_editor_icon_spritesheet_for_owner( Some(source_persisted.asset_object), PersistEditorGeneratedAssetInput { project_id: payload.project_id.clone(), - owner_user_id: caller.owner_user_id.clone(), folder_id: asset_folder_id.clone(), label: editor_generated_asset_variant_label(spritesheet_label.as_str(), "原图"), image_src: source_image_src.clone(), @@ -2066,7 +2064,6 @@ pub(crate) async fn generate_editor_icon_spritesheet_for_owner( Some(spritesheet_prepared_image.asset_object.clone()), PersistEditorGeneratedAssetInput { project_id: payload.project_id.clone(), - owner_user_id: owner_user_id.clone(), folder_id: asset_folder_id.clone(), label: spritesheet_label, image_src: spritesheet_image_src.clone(), diff --git a/server-rs/crates/api-server/src/external_api_keys.rs b/server-rs/crates/api-server/src/external_api_keys.rs index 30af7d894..dcc7b9ab1 100644 --- a/server-rs/crates/api-server/src/external_api_keys.rs +++ b/server-rs/crates/api-server/src/external_api_keys.rs @@ -1897,10 +1897,6 @@ fn extract_router_token_info( } } -fn extract_router_token_id(payload: &Value, token_name: &str) -> Result, String> { - extract_router_token_info(payload, token_name).map(|token| token.map(|token| token.id)) -} - fn provider_payload_data(value: &Value) -> &Value { value.get("data").unwrap_or(value) } @@ -2377,32 +2373,6 @@ mod tests { assert_eq!(payload["group"], "default"); } - #[test] - fn duplicate_fixed_router_tokens_require_reconciliation() { - let payload = json!({ - "data": [ - {"id": 77, "name": LLM_ROUTER_TOKEN_IDENTIFIER}, - {"id": 88, "name": LLM_ROUTER_TOKEN_IDENTIFIER} - ] - }); - - let error = extract_router_token_id(&payload, LLM_ROUTER_TOKEN_IDENTIFIER) - .expect_err("multiple fixed-name tokens must be rejected"); - assert!(error.contains("多个不同 token id")); - - let duplicate_same_id = json!({ - "data": [ - {"id": 77, "name": LLM_ROUTER_TOKEN_IDENTIFIER}, - {"id": 77, "name": LLM_ROUTER_TOKEN_IDENTIFIER} - ] - }); - assert_eq!( - extract_router_token_id(&duplicate_same_id, LLM_ROUTER_TOKEN_IDENTIFIER) - .expect("same token repeated in an envelope is not ambiguous"), - Some("77".to_string()) - ); - } - #[test] fn new_api_user_update_uses_numeric_id_and_fixed_group() { let payload = router_user_update_request(42, "router_abcd", "user_full-id"); diff --git a/server-rs/crates/api-server/src/external_generation_worker.rs b/server-rs/crates/api-server/src/external_generation_worker.rs index 6c89e8fb2..4eeb20c6a 100644 --- a/server-rs/crates/api-server/src/external_generation_worker.rs +++ b/server-rs/crates/api-server/src/external_generation_worker.rs @@ -6,12 +6,12 @@ use std::{ }; use axum::Json; -use serde_json::{Value, json}; +use serde_json::Value; use shared_kernel::offset_datetime_to_unix_micros; use spacetime_client::{ - ExternalGenerationJobClaimRecordInput, ExternalGenerationJobCompleteRecordInput, - ExternalGenerationJobFailRecordInput, ExternalGenerationJobRecord, - ExternalGenerationJobRenewLeaseRecordInput, ExternalGenerationQueueWakeSubscription, + ExternalGenerationJobClaimRecordInput, ExternalGenerationJobFailRecordInput, + ExternalGenerationJobRecord, ExternalGenerationJobRenewLeaseRecordInput, + ExternalGenerationQueueWakeSubscription, }; use tokio::{ sync::{OwnedSemaphorePermit, Semaphore}, @@ -20,12 +20,8 @@ use tokio::{ }; use tracing::{error, info, warn}; -const MAX_EDITOR_GENERATION_WARNING_CHARS: usize = 2_048; // provider 必须先结束,给失败审计、计费结算和队列终态写回保留有效 lease 内的收尾窗口。 const EXTERNAL_GENERATION_WORKER_TERMINAL_WRITE_RESERVE: Duration = Duration::from_secs(60); -const EDITOR_GENERATION_SLICE_WARNING_PREFIX: &str = "图集已生成,但自动拆分未完成:"; -const EDITOR_GENERATION_WARNING_REDACTED_MESSAGE: &str = - "自动拆分未完成(告警详情含内联媒体引用,已省略)"; use crate::{ asset_billing::with_external_generation_billing_attempt_context, @@ -39,15 +35,13 @@ use crate::{ EDITOR_ICON_SPRITESHEET_GENERATION_JOB_KIND, EDITOR_IMAGE_EDIT_JOB_KIND, EDITOR_IMAGE_GENERATION_JOB_KIND, EDITOR_SOUND_EFFECT_GENERATION_JOB_KIND, EDITOR_UI_DESIGN_ASSET_EXTRACTION_JOB_KIND, EDITOR_VIDEO_GENERATION_JOB_KIND, - GAME_CREATOR_CLIENT_GENERATION_DEDUPE_PREFIX, }, editor_project::{ - EDITOR_GENERATION_MULTIPLE_WARNINGS_CODE, EDITOR_IMAGE_EDIT_QUEUE_PAYLOAD_VERSION, - EditorBackgroundRemovalRequest, EditorGenerationCaller, EditorGenerationOperationContext, - EditorGenerationPhaseReporter, EditorGenerationQueueResultContext, - EditorImageEditQueuePayload, EditorImageEditRequest, EditorImageEditResolvedSource, - EditorImageGenerationRequest, EditorUiDesignAssetExtractionRequest, - compact_editor_generation_result, edit_editor_image_for_owner_with_source_snapshot, + EDITOR_IMAGE_EDIT_QUEUE_PAYLOAD_VERSION, EditorBackgroundRemovalRequest, + EditorGenerationCaller, EditorGenerationOperationContext, EditorGenerationPhaseReporter, + EditorGenerationQueueResultContext, EditorImageEditQueuePayload, EditorImageEditRequest, + EditorImageEditResolvedSource, EditorImageGenerationRequest, + EditorUiDesignAssetExtractionRequest, edit_editor_image_for_owner_with_source_snapshot, extract_editor_ui_design_assets_for_owner, generate_editor_image_for_owner, remove_editor_image_background_for_owner, }, @@ -1275,342 +1269,6 @@ fn editor_generation_phase_reporter( )) } -async fn complete_editor_generation_job( - state: &AppState, - worker_id: &str, - job: &ExternalGenerationJobRecord, - response: Value, -) -> Result<(), String> { - complete_job( - state, - worker_id, - job, - Some(editor_generation_result_payload_json(job, &response)), - ) - .await -} - -fn editor_generation_result_payload_json( - job: &ExternalGenerationJobRecord, - response: &Value, -) -> String { - let mut payload = json!({ - "sourceModule": job.source_module.clone(), - "sourceEntityId": job.source_entity_id.clone(), - }); - if is_editor_agent_generation_job(job) - && let Some(object) = payload.as_object_mut() - { - // The Agent needs this compact result to restore its tool-call card. Other jobs keep - // master's metadata-only completion payload to avoid turning the queue into an asset API. - object.insert( - // TODO extract const - "editor-agent-tool-call-result".to_string(), - compact_editor_generation_result(response.clone()), - ); - } - if is_result_recovery_generation_job(job) - && let Some(object) = payload.as_object_mut() - { - object.insert( - "result".to_string(), - compact_external_api_generation_result(response.clone()), - ); - } - if let Some(warning) = extract_editor_generation_warning(response) - && let Some(object) = payload.as_object_mut() - { - object.insert("warning".to_string(), warning); - } - payload.to_string() -} - -fn is_result_recovery_generation_job(job: &ExternalGenerationJobRecord) -> bool { - let dedupe_key = job.dedupe_key.trim(); - dedupe_key.starts_with("external-api-generation:") - || dedupe_key.starts_with(&format!("{GAME_CREATOR_CLIENT_GENERATION_DEDUPE_PREFIX}:")) -} - -fn is_editor_agent_generation_job(job: &ExternalGenerationJobRecord) -> bool { - job.dedupe_key.trim().starts_with("editor-agent:") -} - -fn compact_external_api_generation_result(result: Value) -> Value { - let mut result = result.get("data").cloned().unwrap_or(result); - let Some(object) = result.as_object_mut() else { - return Value::Null; - }; - object.retain(|key, _| { - matches!( - key.as_str(), - "ok" | "imageSrc" - | "videoSrc" - | "audioSrc" - | "previewVideoPath" - | "thumbnailSrc" - | "objectKey" - | "assetObjectId" - | "width" - | "height" - | "sourceType" - | "model" - | "taskId" - | "durationSeconds" - | "loop" - | "resolution" - | "priceMudPoints" - | "audioKind" - | "spritesheetImageSrc" - | "spritesheetWidth" - | "spritesheetHeight" - | "iconImageSrcs" - | "sliceMode" - | "gridX" - | "gridY" - | "sliceCount" - | "frames" - | "frameCount" - | "frameWidth" - | "frameHeight" - | "fps" - | "resource" - | "asset" - | "spritesheetResource" - | "spritesheetAsset" - | "warning" - | "sliceWarning" - ) - }); - for field in ["resource", "spritesheetResource"] { - if let Some(resource) = object.get_mut(field).and_then(Value::as_object_mut) { - compact_external_generation_resource(resource); - } - } - for field in ["asset", "spritesheetAsset"] { - if let Some(asset) = object.get_mut(field).and_then(Value::as_object_mut) { - compact_external_generation_asset(asset); - } - } - if let Some(icons) = object - .get_mut("iconImageSrcs") - .and_then(Value::as_array_mut) - { - for icon in icons { - let Some(icon) = icon.as_object_mut() else { - continue; - }; - icon.retain(|key, _| { - matches!( - key.as_str(), - "name" | "imageSrc" | "objectKey" | "width" | "height" | "resource" | "asset" - ) - }); - if let Some(resource) = icon.get_mut("resource").and_then(Value::as_object_mut) { - compact_external_generation_resource(resource); - } - if let Some(asset) = icon.get_mut("asset").and_then(Value::as_object_mut) { - compact_external_generation_asset(asset); - } - remove_unstable_external_generation_media_fields(icon); - } - } - if let Some(frames) = object.get_mut("frames").and_then(Value::as_array_mut) { - for frame in frames { - let Some(frame) = frame.as_object_mut() else { - continue; - }; - frame.retain(|key, _| { - matches!( - key.as_str(), - "frameIndex" | "imageSrc" | "objectKey" | "assetObjectId" | "width" | "height" - ) - }); - remove_unstable_external_generation_media_fields(frame); - } - } - for field in ["warning", "sliceWarning"] { - if let Some(warning) = object.get_mut(field).and_then(Value::as_object_mut) - && let Some(reason) = warning.get_mut("reason") - && let Some(value) = reason.as_str() - { - *reason = Value::String(normalize_editor_generation_warning_reason(value)); - } - } - remove_unstable_external_generation_media_fields(object); - result -} - -fn compact_external_generation_resource(resource: &mut serde_json::Map) { - resource.retain(|key, _| { - matches!( - key.as_str(), - "resourceId" - | "projectId" - | "objectKey" - | "assetObjectId" - | "imageSrc" - | "width" - | "height" - | "sourceType" - | "assetKind" - | "taskId" - | "sourceResourceId" - ) - }); - remove_unstable_external_generation_media_fields(resource); -} - -fn compact_external_generation_asset(asset: &mut serde_json::Map) { - asset.retain(|key, _| { - matches!( - key.as_str(), - "assetId" - | "folderId" - | "objectKey" - | "assetObjectId" - | "imageSrc" - | "thumbnailSrc" - | "width" - | "height" - | "sourceType" - | "assetKind" - | "taskId" - ) - }); - remove_unstable_external_generation_media_fields(asset); -} - -fn remove_unstable_external_generation_media_fields(object: &mut serde_json::Map) { - object.retain(|key, value| { - if !matches!( - key.as_str(), - "imageSrc" - | "videoSrc" - | "audioSrc" - | "previewVideoPath" - | "thumbnailSrc" - | "spritesheetImageSrc" - ) { - return true; - } - value - .as_str() - .is_some_and(is_stable_external_generation_media_reference) - }); -} - -fn is_stable_external_generation_media_reference(value: &str) -> bool { - let value = value.trim(); - !value.is_empty() - && value.starts_with('/') - && !value.starts_with("//") - && !value.contains('?') - && !value.contains('#') - && !value.to_ascii_lowercase().starts_with("data:") - && !value.to_ascii_lowercase().starts_with("blob:") - && !value.to_ascii_lowercase().starts_with("http://") - && !value.to_ascii_lowercase().starts_with("https://") -} - -fn is_editor_internal_processing_model(model: &str) -> bool { - matches!( - model.trim().to_ascii_lowercase().as_str(), - "anime-seg" - | "bgfilter complex" - | "birefnet" - | "connected-components" - | "screen-color-keying" - | "segment-common-image" - ) -} - -fn extract_editor_generation_warning_fields( - warning: Option<&Value>, - is_slice_warning: bool, -) -> Option<(String, String)> { - let warning = warning?; - let code = warning.get("code")?.as_str()?.trim(); - let reason = warning.get("reason")?.as_str()?.trim(); - if code.is_empty() || reason.is_empty() { - return None; - } - let reason = if is_slice_warning { - format!("{EDITOR_GENERATION_SLICE_WARNING_PREFIX}{reason}") - } else { - reason.to_string() - }; - Some((code.to_string(), reason)) -} - -fn extract_editor_generation_warning(response: &Value) -> Option { - let data = response.get("data").unwrap_or(response); - // 中文注释:风格归一化和像素规整产生的通用 warning 可以与 sliceWarning 并存。 - // 队列结果只有一个有界 warning 字段,因此按与 inline 响应相同的策略归一: - // code 不同时收敛为 multiple-generation-warnings,reason 按“通用在前、拆分在后” - // 顺序拼接,再交给既有上界收敛,不允许其中任何一条被静默丢弃。 - let common = extract_editor_generation_warning_fields(data.get("warning"), false); - let slice = extract_editor_generation_warning_fields(data.get("sliceWarning"), true); - let (code, reason) = match (common, slice) { - (None, None) => return None, - (Some(warning), None) | (None, Some(warning)) => warning, - (Some((common_code, common_reason)), Some((slice_code, slice_reason))) => { - let code = if common_code == slice_code { - common_code - } else { - EDITOR_GENERATION_MULTIPLE_WARNINGS_CODE.to_string() - }; - (code, format!("{common_reason} {slice_reason}")) - } - }; - let reason = normalize_editor_generation_warning_reason(reason.as_str()); - Some(json!({ - "code": code, - "reason": reason, - })) -} - -fn normalize_editor_generation_warning_reason(reason: &str) -> String { - let normalized = reason.to_ascii_lowercase(); - if normalized.contains("data:") - || normalized.contains("blob:") - || normalized.contains("http://") - || normalized.contains("https://") - || normalized.contains("x-amz-") - || normalized.contains("signature=") - { - return EDITOR_GENERATION_WARNING_REDACTED_MESSAGE.to_string(); - } - let mut chars = reason.chars(); - let mut bounded = chars - .by_ref() - .take(MAX_EDITOR_GENERATION_WARNING_CHARS) - .collect::(); - if chars.next().is_some() { - bounded.push('…'); - } - bounded -} - -async fn complete_job( - state: &AppState, - worker_id: &str, - job: &ExternalGenerationJobRecord, - result_payload_json: Option, -) -> Result<(), String> { - state - .spacetime_client() - .complete_external_generation_job(ExternalGenerationJobCompleteRecordInput { - job_id: job.job_id.clone(), - worker_id: worker_id.to_string(), - lease_token: require_job_lease_token(job)?, - result_payload_json, - completed_at_micros: current_utc_micros(), - }) - .await - .map(|_| ()) - .map_err(|error| error.to_string()) -} - async fn fail_job( state: &AppState, worker_id: &str, @@ -1758,6 +1416,7 @@ fn current_utc_micros() -> i64 { #[cfg(test)] mod tests { use super::*; + use serde_json::json; #[cfg(any())] #[test] @@ -2099,393 +1758,6 @@ mod tests { ); } - #[test] - fn editor_generation_result_payload_keeps_only_lightweight_slice_warning() { - let job = external_generation_job_record_fixture(Some("lease-1")); - let response = json!({ - "spritesheetImageSrc": "data:image/png;base64,SHOULD_NOT_PERSIST", - "iconImageSrcs": [{"imageSrc": "data:image/png;base64,SHOULD_NOT_PERSIST"}], - "sliceWarning": { - "code": "insufficient-connected-components", - "reason": "连通域数量不足" - } - }); - - let payload: Value = - serde_json::from_str(&editor_generation_result_payload_json(&job, &response)) - .expect("worker 结果应是合法 JSON"); - - assert_eq!(payload["sourceModule"], json!("editor")); - assert_eq!(payload["sourceEntityId"], json!("project-1")); - assert_eq!( - payload["warning"], - json!({ - "code": "insufficient-connected-components", - "reason": "图集已生成,但自动拆分未完成:连通域数量不足" - }) - ); - assert!(payload.get("spritesheetImageSrc").is_none()); - assert!(payload.get("iconImageSrcs").is_none()); - assert!(payload.get("editor-agent-tool-call-result").is_none()); - } - - #[test] - fn editor_agent_result_payload_keeps_compact_response() { - let mut job = external_generation_job_record_fixture(Some("lease-1")); - job.dedupe_key = "editor-agent:conversation-1:7:generate-image".to_string(); - job.request_payload_json = json!({ - "generationInputs": { "source": "editor-agent" }, - }) - .to_string(); - let response = json!({ - "imageSrc": "/api/assets/object/generated.png", - "objectKey": "users/user-1/generated.png", - "assetObjectId": "asset-object-1", - "width": 1024, - "height": 1024, - "sourceType": "generated", - "prompt": "castle", - "actualPrompt": null, - "model": "gpt-image-2", - "provider": "VectorEngine", - "generationInputs": { - "fields": { "prompt": "castle" }, - "characterAnimation": { "frameCount": 8 }, - "screenColorHex": "#CFEFFF", - "mattingProvider": "BgFilter", - "mattingModel": "birefnet", - }, - "taskId": "provider-task-1", - "resource": { - "resourceId": "resource-1", - "objectKey": "users/user-1/generated.png", - "assetObjectId": "asset-object-1", - "imageSrc": "data:image/png;base64,SHOULD_NOT_PERSIST", - }, - "asset": { "assetId": "asset-1" }, - "project": { "projectId": "project-1" }, - }); - - let payload: Value = - serde_json::from_str(&editor_generation_result_payload_json(&job, &response)) - .expect("worker result should be valid JSON"); - - assert_eq!( - payload["editor-agent-tool-call-result"]["imageSrc"], - json!("/api/assets/object/generated.png") - ); - assert_eq!( - payload["editor-agent-tool-call-result"]["resource"], - json!({ - "resourceId": "resource-1", - "objectKey": "users/user-1/generated.png", - "assetObjectId": "asset-object-1", - }) - ); - assert!( - payload["editor-agent-tool-call-result"] - .get("asset") - .is_none() - ); - assert!( - payload["editor-agent-tool-call-result"] - .get("project") - .is_none() - ); - assert_eq!( - payload["editor-agent-tool-call-result"]["model"], - json!("gpt-image-2") - ); - assert!( - payload["editor-agent-tool-call-result"] - .get("provider") - .is_none() - ); - assert_eq!( - payload["editor-agent-tool-call-result"]["generationInputs"], - json!({ - "fields": { "prompt": "castle" }, - "characterAnimation": { "frameCount": 8 }, - }) - ); - assert!(!payload.to_string().contains("data:image")); - } - - #[test] - fn compact_editor_generation_result_removes_internal_models_case_insensitively() { - for model in [ - "anime-seg", - " BgFilter Complex ", - "BIREFNET", - "connected-components", - "screen-color-keying", - "segment-common-image", - ] { - let compact = compact_editor_generation_result(json!({ - "model": model, - "provider": "internal-provider", - })); - - assert!(compact.get("model").is_none(), "model={model}"); - assert!(compact.get("provider").is_none(), "model={model}"); - } - } - - #[test] - fn editor_agent_audio_compact_results_remain_reconcileable() { - use crate::editor_agent::reconcile_completed_editor_agent_tool_call_for_test; - use platform_editor_agent::{ - agent::tools::{ - generate_background_music::GenerateBackgroundMusicTool, - generate_sound_effect::GenerateSoundEffectTool, - }, - framework::tool::Tool, - }; - use shared_contracts::editor_agent::{EditorAgentMessage, EditorAgentToolCallStatus}; - - for (tool_name, prompt, actual_prompt, audio_kind, model, provider) in [ - ( - GenerateSoundEffectTool::NAME, - "按钮点击声", - "A short button click", - "sound-effect", - "eleven_text_to_sound_v2", - "elevenlabs", - ), - ( - GenerateBackgroundMusicTool::NAME, - "森林背景音乐", - "森林背景音乐", - "background-music", - "chirp-v5", - "vectorengine", - ), - ] { - let mut job = external_generation_job_record_fixture(Some("lease-1")); - job.dedupe_key = format!("editor-agent:conversation-1:7:{tool_name}"); - job.request_payload_json = json!({ - "generationInputs": { "source": "editor-agent" }, - }) - .to_string(); - let response = json!({ - "ok": true, - "audioSrc": "/generated/audio.mp3", - "width": 420, - "height": 120, - "sourceType": "generated", - "prompt": prompt, - "actualPrompt": actual_prompt, - "model": model, - "provider": provider, - "taskId": "task-1", - "priceMudPoints": 5, - "audioKind": audio_kind, - "durationSeconds": if audio_kind == "sound-effect" { json!(5.25) } else { Value::Null }, - "loop": if audio_kind == "sound-effect" { json!(false) } else { Value::Null }, - }); - let payload: Value = - serde_json::from_str(&editor_generation_result_payload_json(&job, &response)) - .expect("worker compact payload should serialize"); - assert!(payload.get("editor-agent-tool-call-result").is_some()); - assert!( - payload["editor-agent-tool-call-result"] - .get("provider") - .is_none() - ); - let mut message: EditorAgentMessage = serde_json::from_value(json!({ - "id": 1, - "role": "system", - "text": "waiting", - "attachments": [], - "toolCall": { - "toolName": tool_name, - "status": "not_completed", - "args": { "prompt": prompt }, - "displayArgs": { - "stringArgs": [], - "imageArgs": [], - "extras": { "priceMudPoints": 5 } - }, - "externalJobId": "job-1", - "images": [], - "audios": [] - }, - "createdAt": "2026-08-06T00:00:00Z" - })) - .expect("pending audio Agent message should deserialize"); - let payload_json = payload.to_string(); - reconcile_completed_editor_agent_tool_call_for_test( - &mut message, - Some(payload_json.as_str()), - ) - .expect("worker compact audio result should reconcile"); - let tool_call = message.tool_call.expect("tool call should remain present"); - assert_eq!(tool_call.status, EditorAgentToolCallStatus::Completed); - assert_eq!(tool_call.audios[0].audio_src, "/generated/audio.mp3"); - } - } - - #[test] - fn editor_agent_spritesheet_result_keeps_all_persisted_slices() { - let mut job = external_generation_job_record_fixture(Some("lease-1")); - job.dedupe_key = "editor-agent:conversation-1:7:generate-icon-spritesheet".to_string(); - job.request_payload_json = json!({ - "generationInputs": { "source": "editor-agent" }, - }) - .to_string(); - let response = json!({ - "spritesheetImageSrc": "/api/assets/object/sheet.png", - "spritesheetWidth": 512, - "spritesheetHeight": 512, - "taskId": "provider-task-1", - "spritesheetResource": { - "resourceId": "sheet-resource", - "objectKey": "users/user-1/sheet.png", - "assetObjectId": "sheet-object", - }, - "iconImageSrcs": [ - { - "name": "backpack", - "imageSrc": "/api/assets/object/backpack.png", - "width": 64, - "height": 64, - "resource": { - "resourceId": "icon-resource-1", - "objectKey": "users/user-1/backpack.png", - "assetObjectId": "icon-object-1", - "sourceResourceId": "sheet-resource", - "imageSrc": "data:image/png;base64,SHOULD_NOT_PERSIST", - }, - "asset": { "assetId": "icon-asset-1" }, - }, - { - "name": "map", - "imageSrc": "/api/assets/object/map.png", - "width": 64, - "height": 64, - "resource": { - "resourceId": "icon-resource-2", - "objectKey": "users/user-1/map.png", - "assetObjectId": "icon-object-2", - "sourceResourceId": "sheet-resource", - }, - }, - ], - }); - - let payload: Value = - serde_json::from_str(&editor_generation_result_payload_json(&job, &response)) - .expect("worker result should be valid JSON"); - - assert_eq!( - payload["editor-agent-tool-call-result"]["iconImageSrcs"] - .as_array() - .map(Vec::len), - Some(2) - ); - assert_eq!( - payload["editor-agent-tool-call-result"]["iconImageSrcs"][0]["resource"], - json!({ - "resourceId": "icon-resource-1", - "objectKey": "users/user-1/backpack.png", - "assetObjectId": "icon-object-1", - "sourceResourceId": "sheet-resource", - }) - ); - assert!( - payload["editor-agent-tool-call-result"]["iconImageSrcs"][0] - .get("asset") - .is_none() - ); - assert!(!payload.to_string().contains("data:image")); - } - - #[test] - fn editor_generation_result_payload_merges_common_and_slice_warnings() { - let job = external_generation_job_record_fixture(Some("lease-1")); - let response = json!({ - "data": { - "imageSrc": "data:image/png;base64,SHOULD_NOT_PERSIST", - "warning": { - "code": "unsupported-image-style", - "reason": "不支持的图片风格,已按无风格继续生成。" - }, - "sliceWarning": { - "code": "insufficient-connected-components", - "reason": "有效连通域不足" - } - } - }); - - let payload: Value = - serde_json::from_str(&editor_generation_result_payload_json(&job, &response)) - .expect("worker 结果应是合法 JSON"); - - // 中文注释:风格归一化告警与拆分告警可以并存,队列只有一个 warning 字段, - // 必须拼接后收敛 code,不能让其中任何一条消失。 - assert_eq!( - payload["warning"], - json!({ - "code": "multiple-generation-warnings", - "reason": "不支持的图片风格,已按无风格继续生成。 图集已生成,但自动拆分未完成:有效连通域不足" - }) - ); - assert!(payload.get("imageSrc").is_none()); - } - - #[test] - fn external_generation_result_payload_keeps_fixed_spritesheet_layout() { - let mut job = external_generation_job_record_fixture(Some("lease-1")); - job.dedupe_key = "external-api-generation:conversation-1:7:icon-spritesheet".to_string(); - let response = json!({ - "sliceMode": "grid", - "gridX": 2, - "gridY": 2, - "iconImageSrcs": [ - { "name": "素材 1", "imageSrc": "/api/assets/object/one.png" }, - { "name": "素材 2", "imageSrc": "/api/assets/object/two.png" }, - { "name": "素材 3", "imageSrc": "/api/assets/object/three.png" }, - { "name": "素材 4", "imageSrc": "/api/assets/object/four.png" } - ] - }); - - let payload: Value = - serde_json::from_str(&editor_generation_result_payload_json(&job, &response)) - .expect("worker result should be valid JSON"); - - assert_eq!(payload["result"]["sliceMode"], json!("grid")); - assert_eq!( - payload["result"]["iconImageSrcs"].as_array().map(Vec::len), - Some(4) - ); - } - - #[test] - fn editor_generation_result_payload_keeps_single_warning_untouched() { - let job = external_generation_job_record_fixture(Some("lease-1")); - let response = json!({ - "data": { - "warning": { - "code": "postprocess-failed-source-preserved", - "reason": "生成任务成功,后处理失败。" - } - } - }); - - let payload: Value = - serde_json::from_str(&editor_generation_result_payload_json(&job, &response)) - .expect("worker 结果应是合法 JSON"); - - // 中文注释:透明背景最终失败不会进入拆分,此时仍是单条告警,原样保留。 - assert_eq!( - payload["warning"], - json!({ - "code": "postprocess-failed-source-preserved", - "reason": "生成任务成功,后处理失败。" - }) - ); - } - #[test] fn editor_image_job_completion_is_committed_by_atomic_persistence() { let source = include_str!("external_generation_worker.rs"); @@ -2524,252 +1796,6 @@ mod tests { ); } - #[test] - fn editor_generation_result_payload_accepts_envelope_and_redacts_inline_media() { - let job = external_generation_job_record_fixture(Some("lease-1")); - let response = json!({ - "data": { - "sliceWarning": { - "code": "slice-persistence-failed", - "reason": "provider returned data:image/png;base64,AAAA" - } - } - }); - - let payload: Value = - serde_json::from_str(&editor_generation_result_payload_json(&job, &response)) - .expect("worker 结果应是合法 JSON"); - - assert_eq!( - payload["warning"]["reason"], - json!(EDITOR_GENERATION_WARNING_REDACTED_MESSAGE) - ); - assert!(!payload.to_string().contains("data:image")); - } - - #[test] - fn external_api_result_keeps_stable_artifacts_and_removes_unstable_media() { - let mut job = external_generation_job_record_fixture(Some("lease-1")); - job.dedupe_key = "external-api-generation:editor_image_generation:fingerprint".to_string(); - let response = json!({ - "data": { - "imageSrc": "data:image/png;base64,SHOULD_NOT_PERSIST", - "videoSrc": "blob:https://example.test/video", - "audioSrc": "https://cdn.example.test/audio.mp3?X-Amz-Signature=secret", - "previewVideoPath": "https://cdn.example.test/stable-looking-but-external.mp4", - "thumbnailSrc": "/api/assets/object/thumbnail.png?expires=1&signature=secret", - "objectKey": "users/user-1/generated/main.png", - "assetObjectId": "asset-object-main", - "width": 1024, - "height": 1024, - "durationSeconds": 7.42, - "loop": true, - "provider": "internal-provider-must-not-persist", - "resource": { - "resourceId": "resource-main", - "projectId": "project-1", - "objectKey": "users/user-1/generated/main.png", - "assetObjectId": "asset-object-main", - "sourceResourceId": "source-resource-main", - "imageSrc": "https://cdn.example.test/main.png?signature=secret", - "width": 1024, - "height": 1024, - "prompt": "不应复制完整资源元数据" - }, - "asset": { - "assetId": "asset-main", - "folderId": "folder-1", - "objectKey": "users/user-1/generated/main.png", - "assetObjectId": "asset-object-main", - "imageSrc": "/api/assets/object/main.png", - "thumbnailSrc": "https://cdn.example.test/thumb.png?signature=secret", - "width": 1024, - "height": 1024, - "generationInputs": {"private": true} - }, - "frames": [ - { - "imageSrc": "/generated/action/frame-01.png", - "objectKey": "generated/action/frame-01.png", - "assetObjectId": "asset-object-frame-01", - "width": 192, - "height": 256, - "provider": "internal-provider-must-not-persist" - }, - { - "imageSrc": "/generated/action/frame-02.png", - "objectKey": "generated/action/frame-02.png", - "assetObjectId": "asset-object-frame-02", - "width": 192, - "height": 256 - } - ], - "project": { - "projectId": "project-1", - "canvas": {"layers": ["large-layout-must-not-persist"]} - }, - "warning": { - "code": "dimension-restore-fallback", - "reason": "已保留 provider 实际输出尺寸。" - } - }, - "meta": { - "requestId": "worker-envelope-must-not-persist" - } - }); - - let payload: Value = - serde_json::from_str(&editor_generation_result_payload_json(&job, &response)) - .expect("外部生成结果应是合法 JSON"); - let result = &payload["result"]; - - assert!(result.get("project").is_none()); - assert!(result.get("provider").is_none()); - for unstable_field in [ - "imageSrc", - "videoSrc", - "audioSrc", - "previewVideoPath", - "thumbnailSrc", - ] { - assert!( - result.get(unstable_field).is_none(), - "不稳定媒体字段 {unstable_field} 不得持久化" - ); - } - assert_eq!( - result["objectKey"], - json!("users/user-1/generated/main.png") - ); - assert_eq!(result["assetObjectId"], json!("asset-object-main")); - assert_eq!(result["durationSeconds"], json!(7.42)); - assert_eq!(result["loop"], json!(true)); - assert_eq!(result["resource"]["resourceId"], json!("resource-main")); - assert_eq!( - result["resource"]["sourceResourceId"], - json!("source-resource-main") - ); - assert_eq!( - result["resource"]["objectKey"], - json!("users/user-1/generated/main.png") - ); - assert!(result["resource"].get("imageSrc").is_none()); - assert!(result["resource"].get("prompt").is_none()); - assert_eq!(result["asset"]["assetId"], json!("asset-main")); - assert_eq!( - result["asset"]["imageSrc"], - json!("/api/assets/object/main.png") - ); - assert!(result["asset"].get("thumbnailSrc").is_none()); - assert!(result["asset"].get("generationInputs").is_none()); - assert_eq!( - result["frames"][0], - json!({ - "imageSrc": "/generated/action/frame-01.png", - "objectKey": "generated/action/frame-01.png", - "assetObjectId": "asset-object-frame-01", - "width": 192, - "height": 256 - }) - ); - assert_eq!( - result["warning"], - json!({ - "code": "dimension-restore-fallback", - "reason": "已保留 provider 实际输出尺寸。" - }) - ); - assert_eq!(payload["warning"], result["warning"]); - assert!(result.get("prompt").is_none()); - assert!(result.get("actualPrompt").is_none()); - let serialized = payload.to_string().to_ascii_lowercase(); - for forbidden in [ - "data:", - "blob:", - "x-amz-signature", - "?signature=", - "large-layout", - ] { - assert!( - !serialized.contains(forbidden), - "compact result 不应包含 {forbidden}" - ); - } - } - - #[test] - fn game_creator_client_result_keeps_completed_grid_spritesheet_for_recovery() { - let mut job = external_generation_job_record_fixture(Some("lease-1")); - job.dedupe_key = format!( - "{GAME_CREATOR_CLIENT_GENERATION_DEDUPE_PREFIX}:editor_icon_spritesheet_generation:fingerprint" - ); - job.job_kind = EDITOR_ICON_SPRITESHEET_GENERATION_JOB_KIND.to_string(); - let response = json!({ - "data": { - "spritesheetImageSrc": "/api/assets/object/core-sheet.png", - "spritesheetWidth": 1024, - "spritesheetHeight": 1024, - "sliceMode": "grid", - "gridX": 2, - "gridY": 2, - "spritesheetResource": { - "resourceId": "sheet-resource-1", - "objectKey": "users/user-1/core-sheet.png", - "imageSrc": "/api/assets/object/core-sheet.png" - }, - "spritesheetAsset": { - "assetId": "sheet-asset-1", - "objectKey": "users/user-1/core-sheet.png", - "imageSrc": "/api/assets/object/core-sheet.png" - }, - "iconImageSrcs": [ - {"name": "玩家", "objectKey": "users/user-1/player.png", "imageSrc": "/api/assets/object/player.png"}, - {"name": "目标", "objectKey": "users/user-1/targets.png", "imageSrc": "/api/assets/object/targets.png"}, - {"name": "场景", "objectKey": "users/user-1/scene.png", "imageSrc": "/api/assets/object/scene.png"}, - {"name": "反馈", "objectKey": "users/user-1/feedback.png", "imageSrc": "/api/assets/object/feedback.png"} - ] - } - }); - - let payload: Value = - serde_json::from_str(&editor_generation_result_payload_json(&job, &response)) - .expect("游戏创作客户端完成结果应持久化为合法 JSON"); - - assert_eq!(payload["result"]["sliceMode"], json!("grid")); - assert_eq!( - payload["result"]["iconImageSrcs"].as_array().map(Vec::len), - Some(4) - ); - assert_eq!( - payload["result"]["spritesheetResource"]["resourceId"], - json!("sheet-resource-1") - ); - assert_eq!( - payload["result"]["spritesheetAsset"]["assetId"], - json!("sheet-asset-1") - ); - assert_eq!( - payload["result"]["iconImageSrcs"][0]["objectKey"], - json!("users/user-1/player.png") - ); - assert!(!payload.to_string().contains("prompt")); - } - - #[test] - fn non_external_job_does_not_publish_query_result() { - let job = external_generation_job_record_fixture(Some("lease-1")); - let payload: Value = serde_json::from_str(&editor_generation_result_payload_json( - &job, - &json!({ - "objectKey": "users/user-1/generated/main.png", - "resource": {"resourceId": "resource-main"} - }), - )) - .expect("普通编辑器任务结果应为合法 JSON"); - - assert!(payload.get("result").is_none()); - } - #[test] fn worker_job_timeout_uses_long_budget_for_image_and_video_jobs() { let config = AppConfig { diff --git a/server-rs/crates/api-server/src/llm/mod.rs b/server-rs/crates/api-server/src/llm/mod.rs index 9d53dd690..32ee19402 100644 --- a/server-rs/crates/api-server/src/llm/mod.rs +++ b/server-rs/crates/api-server/src/llm/mod.rs @@ -839,36 +839,6 @@ fn is_responses_terminal_sse_event(event: &str) -> bool { .is_some_and(|kind| matches!(kind.as_str(), "response.completed" | "response.incomplete")) } -const SSE_DONE_MARKER: &[u8] = b"data: [DONE]"; - -fn find_sse_done_marker(bytes: &[u8]) -> Option { - bytes - .windows(SSE_DONE_MARKER.len()) - .enumerate() - .find_map(|(position, window)| { - (window == SSE_DONE_MARKER && (position == 0 || bytes[position - 1] == b'\n')) - .then_some(position) - }) -} - -fn find_sse_event_end(bytes: &[u8], event_start: usize) -> Option { - let event = &bytes[event_start..]; - if let Some(offset) = event.windows(2).position(|window| window == b"\n\n") { - return Some(event_start + offset + 2); - } - event - .windows(4) - .position(|window| window == b"\r\n\r\n") - .map(|offset| event_start + offset + 4) -} - -fn sse_done_marker_suffix_len(bytes: &[u8]) -> usize { - (1..SSE_DONE_MARKER.len()) - .rev() - .find(|&length| bytes.ends_with(&SSE_DONE_MARKER[..length])) - .unwrap_or(0) -} - async fn resolve_llm_router_client( state: &AppState, owner_user_id: &str, @@ -1588,18 +1558,6 @@ mod tests { } } - #[test] - fn responses_sse_done_marker_is_found_only_at_event_line_start() { - let bytes = b"data: {\"text\":\"data: [DONE]\"}\n\ndata: [DONE]\n\n"; - let done_start = find_sse_done_marker(bytes).expect("done event should be found"); - assert_eq!( - &bytes[done_start..done_start + SSE_DONE_MARKER.len()], - SSE_DONE_MARKER - ); - assert_eq!(find_sse_event_end(bytes, done_start), Some(bytes.len())); - assert_eq!(sse_done_marker_suffix_len(b"data: [DON"), 10); - } - #[test] fn append_utf8_chunk_preserves_multibyte_characters_split_across_chunks() { let mut text = String::new(); diff --git a/server-rs/crates/api-server/src/main.rs b/server-rs/crates/api-server/src/main.rs index ed69e82d2..241551c49 100644 --- a/server-rs/crates/api-server/src/main.rs +++ b/server-rs/crates/api-server/src/main.rs @@ -5,6 +5,7 @@ mod admin_accounts; mod admin_project_snapshots; mod admin_recharge; mod admin_templates; +mod agc_analytics; mod agc_models; mod ai_tasks; mod aliyun_matting; diff --git a/server-rs/crates/api-server/src/modules/game_distribution.rs b/server-rs/crates/api-server/src/modules/game_distribution.rs index 5ed4b8608..6d07359f0 100644 --- a/server-rs/crates/api-server/src/modules/game_distribution.rs +++ b/server-rs/crates/api-server/src/modules/game_distribution.rs @@ -224,10 +224,29 @@ pub fn router(state: AppState) -> Router { "/api/game-distribution/releases/{game_id}/{*asset_path}", get(serve_release_asset), ) + // 根路径等价于入口页:生产由发行来源(每游戏 origin)把 `/` 映射到 index.html, + // 本地直连网关或入口直接填网关地址时也必须能打开游戏。 + .route( + "/api/game-distribution/releases/{game_id}", + get(serve_release_entry), + ) + .route( + "/api/game-distribution/releases/{game_id}/", + get(serve_release_entry), + ) .merge(protected) .merge(admin) } +/// 发行网关根路径:等价于请求该游戏的 `index.html`。 +async fn serve_release_entry( + state: State, + headers: HeaderMap, + Path(game_id): Path, +) -> Result { + serve_release_asset(state, headers, Path((game_id, "index.html".to_string()))).await +} + /// 公开发行网关。 /// /// 只服务当前已公开版本的游戏文件,路径必须在白名单内容类型内;私有 ZIP 对象和 @@ -1425,10 +1444,17 @@ fn private_version_payload(version: &GameDistributionVersionRecord) -> Value { /// 拒绝审核与安全下架都不受影响,用于发布事故或回滚窗口期间“关投稿、保在线”。 /// 开关状态读取失败时按关闭处理,避免绕过运营刚下的收紧动作。 async fn ensure_publish_enabled(state: &AppState, user_id: Option<&str>) -> Result<(), AppError> { - match state - .is_game_distribution_publish_enabled_for_user(user_id) - .await - { + // 作者写入按白名单/灰度判定;管理员激活新版本没有作者身份,只按总开关判定, + // 否则审核通过会被作者灰度挡住。 + let decision = match user_id { + Some(user_id) => { + state + .is_game_distribution_publish_enabled_for_user(Some(user_id)) + .await + } + None => state.is_game_distribution_publish_open().await, + }; + match decision { Ok(true) => Ok(()), Ok(false) => { warn!( @@ -1902,6 +1928,7 @@ mod tests { // 未在白名单内的扩展名直接 404,不进入 SpacetimeDB 与对象存储。 let unknown_extension = app + .clone() .oneshot( Request::builder() .uri("/api/game-distribution/releases/game_1/payload.bin") @@ -1911,6 +1938,29 @@ mod tests { .await .expect("路由响应"); assert_eq!(unknown_extension.status(), StatusCode::NOT_FOUND); + + // 根路径(含尾斜杠)等价于入口页:生产由发行来源映射,直接连网关时也必须能开。 + for uri in [ + "/api/game-distribution/releases/game_1", + "/api/game-distribution/releases/game_1/", + ] { + let with_cookie = app + .clone() + .oneshot( + Request::builder() + .uri(uri) + .header("cookie", "genarrative.refresh-token=1") + .body(Body::empty()) + .expect("请求"), + ) + .await + .expect("路由响应"); + assert_eq!( + with_cookie.status(), + StatusCode::FORBIDDEN, + "{uri} 必须先过 Cookie 拒绝门,而不是 404" + ); + } } #[tokio::test] diff --git a/server-rs/crates/api-server/src/openai_image_generation.rs b/server-rs/crates/api-server/src/openai_image_generation.rs index 2cf90c425..f3e6228fe 100644 --- a/server-rs/crates/api-server/src/openai_image_generation.rs +++ b/server-rs/crates/api-server/src/openai_image_generation.rs @@ -2,7 +2,6 @@ use axum::http::StatusCode; use platform_image::{ DownloadedImage, GeneratedImages, PlatformImageError, PlatformImageStatusHint, ReferenceImage, VECTOR_ENGINE_PROVIDER, VectorEngineImageSettings, build_vector_engine_image_http_client, - create_vector_engine_image_edit, create_vector_engine_image_edit_with_references, create_vector_engine_image_edit_with_references_and_model, create_vector_engine_image_generation, create_vector_engine_image_generation_with_model, create_vector_engine_nanobanana_generate_content, @@ -18,8 +17,7 @@ use time::OffsetDateTime; use crate::{ external_api_audit::{ - ExternalApiFailureDraft, build_external_api_failure_draft_from_platform_image_audit, - record_external_api_failure, + build_external_api_failure_draft_from_platform_image_audit, record_external_api_failure, }, http_error::AppError, request_context::RequestContext, @@ -248,83 +246,6 @@ pub(crate) async fn create_openai_nanobanana_generate_content( .await } -pub(crate) async fn create_openai_image_edit( - http_client: &reqwest::Client, - settings: &OpenAiImageSettings, - prompt: &str, - negative_prompt: Option<&str>, - size: &str, - reference_image: &OpenAiReferenceImage, - failure_context: &str, -) -> Result { - let started_at_micros = current_utc_micros(); - let request_payload = json!({ - "size": size, - "promptChars": prompt.chars().count(), - "negativePromptChars": negative_prompt.map(str::chars).map(Iterator::count), - "referenceImageCount": 1, - }); - let result = create_vector_engine_image_edit( - http_client, - &settings.provider_settings(), - prompt, - negative_prompt, - size, - reference_image, - failure_context, - ) - .await; - map_platform_image_result( - settings, - result, - "image_edit", - failure_context, - request_payload, - started_at_micros, - ) - .await -} - -pub(crate) async fn create_openai_image_edit_with_references( - http_client: &reqwest::Client, - settings: &OpenAiImageSettings, - prompt: &str, - negative_prompt: Option<&str>, - size: &str, - candidate_count: u32, - reference_images: &[OpenAiReferenceImage], - failure_context: &str, -) -> Result { - let started_at_micros = current_utc_micros(); - let request_payload = json!({ - "size": size, - "candidateCount": candidate_count, - "promptChars": prompt.chars().count(), - "negativePromptChars": negative_prompt.map(str::chars).map(Iterator::count), - "referenceImageCount": reference_images.len(), - }); - let result = create_vector_engine_image_edit_with_references( - http_client, - &settings.provider_settings(), - prompt, - negative_prompt, - size, - candidate_count, - reference_images, - failure_context, - ) - .await; - map_platform_image_result( - settings, - result, - "image_edit_with_references", - failure_context, - request_payload, - started_at_micros, - ) - .await -} - #[allow(clippy::too_many_arguments)] pub(crate) async fn create_openai_image_edit_with_references_and_model( http_client: &reqwest::Client, @@ -386,16 +307,6 @@ pub(crate) fn build_openai_image_request_body( } impl OpenAiImageSettings { - pub(crate) fn with_external_api_audit_actor( - mut self, - user_id: Option, - profile_id: Option, - ) -> Self { - self.external_api_audit_user_id = user_id; - self.external_api_audit_profile_id = profile_id; - self - } - pub(crate) fn with_external_api_audit_context( mut self, request_context: &RequestContext, @@ -501,14 +412,6 @@ async fn record_openai_image_failure_audit_if_configured( record_external_api_failure(state, draft).await; } -pub(crate) fn build_openai_image_failure_audit_draft( - error: &PlatformImageError, -) -> Option { - error - .audit() - .map(build_external_api_failure_draft_from_platform_image_audit) -} - pub(crate) fn map_platform_image_error(error: PlatformImageError) -> AppError { let error = error.into_final_error(); let status = match error.status_hint() { @@ -705,37 +608,6 @@ mod tests { ); } - #[tokio::test] - async fn vector_engine_multi_reference_edit_rejects_empty_references() { - let settings = OpenAiImageSettings { - base_url: "https://vector.example".to_string(), - api_key: "test-key".to_string(), - request_timeout_ms: 1_000_000, - request_deadline: None, - external_api_audit_state: None, - external_api_audit_user_id: None, - external_api_audit_profile_id: None, - external_api_audit_request_id: None, - }; - let http_client = reqwest::Client::new(); - - let result = create_openai_image_edit_with_references( - &http_client, - &settings, - "提示词", - None, - "1:1", - 1, - &[], - "测试图片编辑失败", - ) - .await; - - let error = result.expect_err("empty references should be rejected locally"); - assert_eq!(error.status_code(), StatusCode::BAD_REQUEST); - assert!(error.body_text().contains("缺少参考图")); - } - #[test] fn reference_data_url_stays_provider_owned() { let source = format!( diff --git a/server-rs/crates/api-server/src/state.rs b/server-rs/crates/api-server/src/state.rs index d2a4208a3..a7b970bfc 100644 --- a/server-rs/crates/api-server/src/state.rs +++ b/server-rs/crates/api-server/src/state.rs @@ -1181,23 +1181,44 @@ impl AppState { Ok(module_runtime::is_feature_gate_allowed(gate, &user_context)) } - /// 游戏分发写入开关:默认开放,只有运营在灰度配置里显式收紧(白名单/灰度/全关)才拦截。 - /// 读取、目录、详情、发行网关与安全下架不经过这里。 + /// 游戏分发发布开关:灰度未配置时**不开放**(运营在后台配置后才对白名单/灰度命中 + /// 的作者开放),未登录、gate 行缺失或 `enabled=false` 都返回 false。 + /// 读取、目录、详情、发行网关与安全下架不经过这里,已公开游戏始终可玩。 pub async fn is_game_distribution_publish_enabled_for_user( &self, user_id: Option<&str>, ) -> Result { + let Some(user_id) = user_id.map(str::trim).filter(|id| !id.is_empty()) else { + return Ok(false); + }; let gates = self.get_feature_gate_config().await?; - let gate = gates + let Some(gate) = gates .iter() - .find(|item| item.gate_key == module_runtime::GAME_DISTRIBUTION_PUBLISH_GATE_KEY); + .find(|item| item.gate_key == module_runtime::GAME_DISTRIBUTION_PUBLISH_GATE_KEY) + else { + return Ok(false); + }; + if !gate.enabled { + return Ok(false); + } let user_context = self - .feature_gate_user_context( - user_id, - gate.map(feature_gate_requires_user_tags).unwrap_or(false), - ) + .feature_gate_user_context(Some(user_id), feature_gate_requires_user_tags(gate)) .await; - Ok(module_runtime::is_feature_gate_allowed(gate, &user_context)) + Ok(module_runtime::is_feature_gate_allowed( + Some(gate), + &user_context, + )) + } + + /// 游戏分发发布总开关(与具体作者无关):gate 行存在且 `enabled=true` 即为开放。 + /// + /// 管理员审核通过(激活新版本)没有作者身份,只能按总开关判定;作者写入仍走 + /// `is_game_distribution_publish_enabled_for_user` 的白名单/灰度判定。 + pub async fn is_game_distribution_publish_open(&self) -> Result { + let gates = self.get_feature_gate_config().await?; + Ok(gates.iter().any(|gate| { + gate.gate_key == module_runtime::GAME_DISTRIBUTION_PUBLISH_GATE_KEY && gate.enabled + })) } pub async fn is_agc_template_library_enabled_for_user( diff --git a/server-rs/crates/api-server/src/tracking.rs b/server-rs/crates/api-server/src/tracking.rs index 0632f992f..9a02ec3ea 100644 --- a/server-rs/crates/api-server/src/tracking.rs +++ b/server-rs/crates/api-server/src/tracking.rs @@ -804,7 +804,7 @@ fn resolve_route_tracking_spec(method: &Method, path: &str) -> Option bool { - path.starts_with("/admin/") + path.starts_with("/admin/") || path == "/api/agc/analytics/batches" } fn route_spec( diff --git a/server-rs/crates/api-server/src/vector_engine_audio_generation/errors.rs b/server-rs/crates/api-server/src/vector_engine_audio_generation/errors.rs index a1bd54c48..8fd90c83d 100644 --- a/server-rs/crates/api-server/src/vector_engine_audio_generation/errors.rs +++ b/server-rs/crates/api-server/src/vector_engine_audio_generation/errors.rs @@ -6,40 +6,6 @@ use crate::{http_error::AppError, request_context::RequestContext}; use super::types::VECTOR_ENGINE_PROVIDER; -pub(super) fn normalize_limited_text( - value: &str, - field: &'static str, - max_chars: usize, -) -> Result { - let normalized = value.trim().to_string(); - if normalized.is_empty() { - return Err( - AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({ - "provider": VECTOR_ENGINE_PROVIDER, - "field": field, - "message": format!("{field} 不能为空"), - })), - ); - } - if normalized.chars().count() > max_chars { - return Err( - AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({ - "provider": VECTOR_ENGINE_PROVIDER, - "field": field, - "message": format!("{field} 超过 {} 字符", max_chars), - })), - ); - } - Ok(normalized) -} - -pub(super) fn normalize_optional_text(value: Option<&str>) -> Option { - value - .map(str::trim) - .filter(|value| !value.is_empty()) - .map(ToOwned::to_owned) -} - pub(super) fn map_asset_field_error(error: module_assets::AssetObjectFieldError) -> AppError { AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({ "provider": "asset-object", @@ -47,13 +13,6 @@ pub(super) fn map_asset_field_error(error: module_assets::AssetObjectFieldError) })) } -pub(super) fn map_spacetime_error(error: spacetime_client::SpacetimeClientError) -> AppError { - AppError::from_status(StatusCode::BAD_GATEWAY).with_details(json!({ - "provider": "spacetimedb", - "message": error.to_string(), - })) -} - pub(super) fn map_platform_audio_error(error: AudioError) -> AppError { let status = match error.status_hint() { AudioStatusHint::BadRequest => StatusCode::BAD_REQUEST, diff --git a/server-rs/crates/api-server/src/vector_engine_audio_generation/generation.rs b/server-rs/crates/api-server/src/vector_engine_audio_generation/generation.rs index bfe6c55ac..0a77eea5b 100644 --- a/server-rs/crates/api-server/src/vector_engine_audio_generation/generation.rs +++ b/server-rs/crates/api-server/src/vector_engine_audio_generation/generation.rs @@ -571,7 +571,6 @@ impl SoundEffectWorkerStages for ProductionSoundEffectWorkerStages<'_> { Some(asset_object), PersistEditorGeneratedAssetInput { project_id: normalize_optional_string(self.project_id.clone()), - owner_user_id: self.owner_user_id.to_string(), folder_id: self.asset_folder_id.clone(), label, image_src: input.persisted_audio.audio_src.clone(), @@ -1374,7 +1373,6 @@ async fn persist_editor_audio_generation( Some(input.generated.prepared.asset_object.clone()), PersistEditorGeneratedAssetInput { project_id: project_id.clone(), - owner_user_id: caller.owner_user_id.clone(), folder_id: input.asset_folder_id.clone(), label, image_src: input.generated.audio_src.clone(), diff --git a/server-rs/crates/api-server/src/vector_engine_audio_generation/persist.rs b/server-rs/crates/api-server/src/vector_engine_audio_generation/persist.rs index 9285d2fba..0686bff21 100644 --- a/server-rs/crates/api-server/src/vector_engine_audio_generation/persist.rs +++ b/server-rs/crates/api-server/src/vector_engine_audio_generation/persist.rs @@ -12,18 +12,9 @@ use serde_json::json; use crate::{http_error::AppError, platform_errors::map_oss_error, state::AppState}; use super::{ - clock::current_utc_micros, - errors::map_asset_field_error, - types::{AudioAssetBindingTarget, AudioAssetSlot}, + clock::current_utc_micros, errors::map_asset_field_error, types::AudioAssetBindingTarget, }; -#[derive(Clone, Debug)] -pub(super) struct PersistedAudioAsset { - pub(super) asset_object_id: String, - pub(super) object_key: String, - pub(super) audio_src: String, -} - #[derive(Clone, Debug)] pub(super) struct PreparedAudioAsset { pub(super) asset_object: AssetObjectUpsertInput, @@ -32,24 +23,6 @@ pub(super) struct PreparedAudioAsset { pub(super) audio_src: String, } -pub(super) async fn persist_generated_audio_asset( - _state: &AppState, - _http_client: &reqwest::Client, - _owner_user_id: &str, - _task_id: &str, - _slot: AudioAssetSlot, - _task_kind: platform_audio::AudioTaskKind, - _target: AudioAssetBindingTarget, - _audio: DownloadedAudio, -) -> Result { - Err( - AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR).with_details(json!({ - "provider": "editor-generation-operation", - "message": "旧音频分步持久化路径已禁用;编辑器生成必须使用原子结果提交。", - })), - ) -} - #[allow(clippy::too_many_arguments)] pub(super) async fn prepare_generated_audio_asset( state: &AppState, diff --git a/server-rs/crates/api-server/src/vector_engine_audio_generation/publish.rs b/server-rs/crates/api-server/src/vector_engine_audio_generation/publish.rs index bcd1d7974..cda1e667a 100644 --- a/server-rs/crates/api-server/src/vector_engine_audio_generation/publish.rs +++ b/server-rs/crates/api-server/src/vector_engine_audio_generation/publish.rs @@ -1,187 +1,7 @@ -use std::time::Duration; - -use shared_contracts::creation_audio; - -use crate::{ - asset_billing::execute_billable_asset_operation_with_cost, http_error::AppError, - state::AppState, +use super::types::{ + AudioAssetBindingTarget, AudioAssetSlot, CREATION_BACKGROUND_MUSIC_POINTS_COST, }; -use super::{ - errors::{map_platform_audio_error, vector_engine_bad_gateway}, - persist::persist_generated_audio_asset, - settings::require_vector_engine_audio_settings, - types::{AudioAssetBindingTarget, AudioAssetSlot, CREATION_BACKGROUND_MUSIC_POINTS_COST}, -}; - -#[cfg(any())] -pub(super) async fn publish_generated_audio_asset( - state: &AppState, - owner_user_id: &str, - task_id: String, - slot: AudioAssetSlot, - target: AudioAssetBindingTarget, -) -> Result { - publish_generated_audio_asset_with_task_kind( - state, - owner_user_id, - task_id, - slot, - slot.task_kind(), - target, - ) - .await -} - -pub(super) async fn publish_generated_audio_asset_with_task_kind( - state: &AppState, - owner_user_id: &str, - task_id: String, - slot: AudioAssetSlot, - task_kind: platform_audio::AudioTaskKind, - target: AudioAssetBindingTarget, -) -> Result { - let task_id = platform_audio::normalize_limited_text(&task_id, "taskId", 160) - .map_err(map_platform_audio_error)?; - let settings = require_vector_engine_audio_settings(state)?; - let http_client = platform_audio::build_vector_engine_audio_http_client(&settings) - .map_err(map_platform_audio_error)?; - let (status, audio_urls): (String, Vec) = - platform_audio::resolve_audio_task_download_urls( - &http_client, - &settings, - task_kind, - &task_id, - ) - .await - .map_err(map_platform_audio_error)?; - - if platform_audio::is_pending_task_status(&status) && audio_urls.is_empty() { - return Ok(creation_audio::GeneratedAudioAssetResponse { - kind: slot.creation_contract_kind(), - task_id, - provider: task_kind.provider().to_string(), - status: status.clone(), - asset_object_id: None, - object_key: None, - asset_kind: None, - audio_src: None, - }); - } - - if platform_audio::is_failed_task_status(&status) { - return Err(vector_engine_bad_gateway( - "音频生成任务失败,请调整提示词后重试", - )); - } - - let audio_url = audio_urls - .into_iter() - .next() - .ok_or_else(|| vector_engine_bad_gateway("音频生成尚未返回可下载地址"))?; - let billing_asset_kind = target.asset_kind.clone(); - let billing_asset_id = build_audio_billing_asset_id(&task_id, slot, &target); - let points_cost = resolve_creation_audio_points_cost(slot, &target); - let persisted = execute_billable_asset_operation_with_cost( - state, - owner_user_id, - billing_asset_kind.as_str(), - billing_asset_id.as_str(), - points_cost, - async { - let audio = platform_audio::download_generated_audio( - &http_client, - &audio_url, - task_kind.provider(), - ) - .await - .map_err(map_platform_audio_error)?; - persist_generated_audio_asset( - state, - &http_client, - owner_user_id, - &task_id, - slot, - task_kind, - target.clone(), - audio, - ) - .await - }, - ) - .await?; - - Ok(creation_audio::GeneratedAudioAssetResponse { - kind: slot.creation_contract_kind(), - task_id, - provider: task_kind.provider().to_string(), - status: "completed".to_string(), - asset_object_id: Some(persisted.asset_object_id), - object_key: Some(persisted.object_key), - asset_kind: Some(target.asset_kind), - audio_src: Some(persisted.audio_src), - }) -} - -pub(super) async fn wait_for_generated_audio_asset( - state: &AppState, - owner_user_id: &str, - task_id: String, - slot: AudioAssetSlot, - target: AudioAssetBindingTarget, -) -> Result { - wait_for_generated_audio_asset_with_task_kind( - state, - owner_user_id, - task_id, - slot, - slot.task_kind(), - target, - ) - .await -} - -pub(super) async fn wait_for_generated_audio_asset_with_task_kind( - state: &AppState, - owner_user_id: &str, - task_id: String, - slot: AudioAssetSlot, - task_kind: platform_audio::AudioTaskKind, - target: AudioAssetBindingTarget, -) -> Result { - let mut latest_status = String::new(); - for _ in 0..40 { - let response = publish_generated_audio_asset_with_task_kind( - state, - owner_user_id, - task_id.clone(), - slot, - task_kind, - target.clone(), - ) - .await?; - if response - .audio_src - .as_deref() - .map(str::trim) - .is_some_and(|value| !value.is_empty()) - { - return Ok(response); - } - latest_status = response.status; - tokio::time::sleep(Duration::from_millis(3_000)).await; - } - - Err(vector_engine_bad_gateway(format!( - "音频生成超时:{}", - if latest_status.trim().is_empty() { - task_id - } else { - latest_status - } - ))) -} - pub(super) fn build_audio_billing_asset_id( task_id: &str, slot: AudioAssetSlot, diff --git a/server-rs/crates/api-server/src/vector_engine_audio_generation/targets.rs b/server-rs/crates/api-server/src/vector_engine_audio_generation/targets.rs deleted file mode 100644 index 47e5233ae..000000000 --- a/server-rs/crates/api-server/src/vector_engine_audio_generation/targets.rs +++ /dev/null @@ -1,53 +0,0 @@ -use axum::http::StatusCode; -use platform_oss::LegacyAssetPrefix; -use serde_json::json; -use shared_contracts::{creation_audio, visual_novel as contract}; - -use crate::http_error::AppError; - -use super::{ - errors::{normalize_limited_text, normalize_optional_text}, - types::{AUDIO_ENTITY_KIND, AudioAssetBindingTarget, AudioAssetSlot, VECTOR_ENGINE_PROVIDER}, -}; - -pub(super) fn build_visual_novel_audio_target( - payload: contract::PublishVisualNovelGeneratedAudioAssetRequest, - slot: AudioAssetSlot, -) -> Result { - let entity_id = normalize_limited_text(&payload.scene_id, "sceneId", 160)?; - Ok(AudioAssetBindingTarget { - entity_kind: AUDIO_ENTITY_KIND.to_string(), - entity_id, - slot: slot.slot().to_string(), - asset_kind: slot.asset_kind().to_string(), - profile_id: normalize_optional_text(payload.profile_id.as_deref()), - storage_prefix: LegacyAssetPrefix::CustomWorldScenes, - storage_scope: "visual-novel".to_string(), - billing_points_cost: None, - }) -} - -pub(super) fn build_creation_audio_target( - payload: creation_audio::PublishGeneratedAudioAssetRequest, - _slot: AudioAssetSlot, -) -> Result { - Err(creation_audio_generation_disabled_error_for_target(payload)) -} - -pub(super) fn creation_audio_generation_disabled_error() -> AppError { - AppError::from_status(StatusCode::GONE).with_details(json!({ - "provider": VECTOR_ENGINE_PROVIDER, - "message": "当前创作音频目标未开放", - })) -} - -pub(super) fn creation_audio_generation_disabled_error_for_target( - payload: creation_audio::PublishGeneratedAudioAssetRequest, -) -> AppError { - creation_audio_generation_disabled_error().with_details(json!({ - "provider": VECTOR_ENGINE_PROVIDER, - "message": "当前创作音频目标未开放", - "entityKind": payload.entity_kind.trim(), - "slot": payload.slot.trim(), - })) -} diff --git a/server-rs/crates/api-server/src/vector_engine_audio_generation/types.rs b/server-rs/crates/api-server/src/vector_engine_audio_generation/types.rs index 7af8eedbc..094694872 100644 --- a/server-rs/crates/api-server/src/vector_engine_audio_generation/types.rs +++ b/server-rs/crates/api-server/src/vector_engine_audio_generation/types.rs @@ -3,16 +3,6 @@ use platform_oss::LegacyAssetPrefix; use shared_contracts::creation_audio; pub(super) const VECTOR_ENGINE_PROVIDER: &str = platform_audio::VECTOR_ENGINE_PROVIDER; -#[cfg(any())] -pub(super) const AUDIO_ENTITY_KIND: &str = "visual_novel_scene"; -#[cfg(any())] -pub(super) const MUSIC_ASSET_KIND: &str = "visual_novel_music"; -#[cfg(any())] -pub(super) const AMBIENT_SOUND_ASSET_KIND: &str = "visual_novel_ambient_sound"; -#[cfg(any())] -pub(super) const MUSIC_SLOT: &str = "music"; -#[cfg(any())] -pub(super) const AMBIENT_SOUND_SLOT: &str = "ambient_sound"; pub(super) const CREATION_BACKGROUND_MUSIC_POINTS_COST: u64 = 5; #[derive(Clone, Debug)] @@ -39,22 +29,6 @@ impl AudioAssetSlot { } } - #[cfg(any())] - pub(super) fn asset_kind(self) -> &'static str { - match self { - Self::BackgroundMusic => MUSIC_ASSET_KIND, - Self::SoundEffect => AMBIENT_SOUND_ASSET_KIND, - } - } - - #[cfg(any())] - pub(super) fn slot(self) -> &'static str { - match self { - Self::BackgroundMusic => MUSIC_SLOT, - Self::SoundEffect => AMBIENT_SOUND_SLOT, - } - } - pub(super) fn file_stem(self) -> &'static str { self.task_kind().file_stem() } diff --git a/server-rs/crates/api-server/src/wallet_refund_outbox.rs b/server-rs/crates/api-server/src/wallet_refund_outbox.rs index 6d79051ff..cb2a6e70c 100644 --- a/server-rs/crates/api-server/src/wallet_refund_outbox.rs +++ b/server-rs/crates/api-server/src/wallet_refund_outbox.rs @@ -678,15 +678,6 @@ fn ledger_id_hash(ledger_id: &str) -> String { hex::encode(Sha256::digest(ledger_id.as_bytes())) } -fn is_pending_outbox_file_name(name: &std::ffi::OsStr) -> bool { - name.to_str().is_some_and(|value| { - (value.starts_with(PENDING_FILE_PREFIX) - || value.starts_with(OVERFLOW_FILE_PREFIX) - || value.starts_with(TEMP_FILE_PREFIX)) - && value.ends_with(OUTBOX_FILE_EXTENSION) - }) -} - fn is_capped_outbox_file_name(name: &std::ffi::OsStr) -> bool { name.to_str().is_some_and(|value| { ((value.starts_with(PENDING_FILE_PREFIX) && !value.starts_with(OVERFLOW_FILE_PREFIX)) @@ -718,6 +709,15 @@ async fn sync_directory_metadata(path: &Path) -> Result<(), WalletRefundOutboxEr mod tests { use super::*; + fn is_pending_outbox_file_name(name: &std::ffi::OsStr) -> bool { + name.to_str().is_some_and(|value| { + (value.starts_with(PENDING_FILE_PREFIX) + || value.starts_with(OVERFLOW_FILE_PREFIX) + || value.starts_with(TEMP_FILE_PREFIX)) + && value.ends_with(OUTBOX_FILE_EXTENSION) + }) + } + fn sample_record(ledger_id: &str) -> WalletRefundOutboxRecord { WalletRefundOutboxRecord { owner_user_id: "user-1".to_string(), diff --git a/server-rs/crates/module-runtime/Cargo.toml b/server-rs/crates/module-runtime/Cargo.toml index 786ff327a..a37c20d67 100644 --- a/server-rs/crates/module-runtime/Cargo.toml +++ b/server-rs/crates/module-runtime/Cargo.toml @@ -14,3 +14,7 @@ serde_json = { workspace = true } shared-kernel = { workspace = true } spacetimedb = { workspace = true, optional = true } time = { workspace = true, features = ["formatting", "parsing"] } + +shared-contracts = { workspace = true } +uuid = { workspace = true } +url = { workspace = true } diff --git a/server-rs/crates/module-runtime/src/agc_analytics.rs b/server-rs/crates/module-runtime/src/agc_analytics.rs new file mode 100644 index 000000000..c0c2ed4a4 --- /dev/null +++ b/server-rs/crates/module-runtime/src/agc_analytics.rs @@ -0,0 +1,428 @@ +//! 客户端观测事件校验,不推导项目所有权或奖励资格。 +use serde_json::Value; +use shared_contracts::agc_analytics::*; +use uuid::Uuid; +const MAX_SAFE_INTEGER: u64 = 9_007_199_254_740_991; +trait EventDataRules { + fn status(&self) -> Option; + fn has_goal(&self) -> bool; +} +pub trait EventRules { + fn data(&self) -> Result; + fn validate(&self) -> Result<(), &'static str>; +} +impl EventDataRules for EventData { + fn status(&self) -> Option { + match self { + Self::EditorFocusStart(_) | Self::EditorFocusEnd(_) => None, + Self::AgentRunFailed(_) => Some(Status::Failed), + _ => Some(Status::Success), + } + } + + fn has_goal(&self) -> bool { + matches!( + self, + Self::CreativeTaskSubmit(_) + | Self::AgentRunCompleted(_) + | Self::AgentRunFailed(_) + | Self::ProjectRevisionCreated(_) + | Self::PreviewReady(_) + | Self::ProjectSave(_) + ) + } +} + +impl EventRules for Event { + fn data(&self) -> Result { + if !self.properties.is_object() { + return Err("invalid_properties"); + } + // 可选字段不可得时省略;显式 null 仅用于合同指定的 nullable 字段。 + let optional = match self.event_name.as_str() { + "project_create_success" => &["project_template_id"][..], + "agent_run_completed" | "agent_run_failed" | "project_save" => &["revision_id"][..], + "project_revision_created" => &["files_changed_count"][..], + "preview_ready" => &["ready_duration_ms"][..], + _ => &[][..], + }; + if optional + .iter() + .any(|key| self.properties.get(key).is_some_and(Value::is_null)) + { + return Err("invalid_optional_property"); + } + serde_json::from_value(serde_json::json!({ + "event_name": self.event_name, + "properties": self.properties, + })) + .map_err(|_| "invalid_properties") + } + + fn validate(&self) -> Result<(), &'static str> { + if self.schema_version != 1 + || !uuid(&self.event_id) + || !uuid(&self.editor_session_id) + || !id(&self.client_version) + || !optional_id(&self.user_id) + || !optional_id(&self.project_id) + || !optional_id(&self.creative_task_id) + || !optional_id(&self.agent_turn_id) + || !valid_time(&self.event_time) + { + return Err("invalid_envelope"); + } + let data = self.data()?; + if self.status != data.status() + || self.error_code.is_some() != matches!(data, EventData::AgentRunFailed(_)) + { + return Err("invalid_status"); + } + if data.has_goal() { + if self.project_id.is_none() || self.creative_task_id != self.project_id { + return Err("invalid_goal"); + } + } else if self.creative_task_id.is_some() { + return Err("unexpected_goal"); + } + let is_run = matches!( + data, + EventData::AgentRunCompleted(_) | EventData::AgentRunFailed(_) + ); + if is_run { + if !self.agent_run_id.as_deref().is_some_and(uuid) { + return Err("invalid_run"); + } + } else if self.agent_run_id.is_some() || self.agent_turn_id.is_some() { + return Err("unexpected_run"); + } + let editor = self.source == Source::Editor; + let agent = matches!(self.source, Source::Direct | Source::DesignAgent); + let valid = match data { + EventData::EditorSessionStart(p) => editor && p.first_project_id == self.project_id, + EventData::EditorSessionEnd(p) => { + editor && p.last_project_id == self.project_id && safe(p.session_duration_ms) + } + EventData::EditorFocusStart(p) => { + editor && uuid(&p.focus_interval_id) && p.active_project_id == self.project_id + } + EventData::EditorFocusEnd(p) => { + editor + && uuid(&p.focus_interval_id) + && p.active_project_id == self.project_id + && safe(p.focus_duration_ms) + } + EventData::ProjectCreateSuccess(p) => { + editor && self.project_id.is_some() && optional_id(&p.project_template_id) + } + EventData::ProjectOpen(_) => editor && self.project_id.is_some(), + EventData::CreativeTaskSubmit(_) => agent, + EventData::AgentRunCompleted(p) | EventData::AgentRunFailed(p) => { + agent + && ((self.source == Source::Direct) == (p.agent_type == AgentType::GameAgent)) + && ((self.status == Some(Status::Failed)) + == (p.end_reason == RunEndReason::Failed)) + && safe(p.duration_ms) + && safe(Some(p.retry_index)) + && optional_id(&p.revision_id) + } + EventData::ProjectRevisionCreated(p) => { + id(&p.revision_id) + && safe(p.files_changed_count) + && match p.revision_source { + RevisionSource::Agent => agent, + RevisionSource::AssetCanvas => self.source == Source::AssetCanvas, + RevisionSource::ResourceEditor => self.source == Source::ResourceEditor, + RevisionSource::UiEditor => self.source == Source::UiEditor, + RevisionSource::ManualEdit => self.source == Source::Manual, + RevisionSource::SystemProjection => self.source == Source::System, + } + } + EventData::PreviewReady(p) => id(&p.preview_version) && safe(p.ready_duration_ms), + EventData::ProjectSave(p) => optional_id(&p.revision_id), + }; + if valid { + Ok(()) + } else { + Err("invalid_event_fields") + } + } +} + +fn id(value: &str) -> bool { + !value.trim().is_empty() && value.len() <= 256 && !value.chars().any(char::is_control) +} +fn optional_id(value: &Option) -> bool { + value.as_deref().is_none_or(id) +} +fn uuid(value: &str) -> bool { + Uuid::parse_str(value).is_ok_and(|v| v.get_version_num() == 4 && v.to_string() == value) +} +fn safe(value: Option) -> bool { + value.is_none_or(|v| v <= MAX_SAFE_INTEGER) +} +fn valid_time(value: &str) -> bool { + value.len() == 24 + && value.ends_with("Z") + && value.as_bytes()[10] == b'T' + && value.as_bytes()[19] == b'.' + && time::OffsetDateTime::parse(value, &time::format_description::well_known::Rfc3339) + .is_ok() +} + +pub fn validate_agc_analytics_batch(batch: &AgcAnalyticsBatch) -> Result<(), &'static str> { + if batch.schema_version != 1 + || batch.destination_origin.len() > 2048 + || !uuid(&batch.batch_id) + || !id(&batch.user_id) + || batch.events.is_empty() + || batch.events.len() > 500 + { + return Err("invalid_batch"); + } + let origin = url::Url::parse(&batch.destination_origin).map_err(|_| "invalid_origin")?; + if !matches!(origin.scheme(), "https" | "http") + || origin.host_str().is_none() + || !origin.username().is_empty() + || origin.password().is_some() + || origin.origin().ascii_serialization() != batch.destination_origin + { + return Err("invalid_origin"); + } + let mut ids = std::collections::HashSet::new(); + let mut bytes = 0usize; + for event in &batch.events { + event.validate()?; + if event.user_id.as_deref() != Some(batch.user_id.as_str()) { + return Err("identity_mismatch"); + } + if !ids.insert(&event.event_id) { + return Err("duplicate_event_id"); + } + bytes += serde_json::to_vec(event) + .map_err(|_| "invalid_event")? + .len() + + 1; + } + if bytes > 1024 * 1024 { + return Err("events_too_large"); + } + Ok(()) +} + +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[serde(deny_unknown_fields)] +pub struct AgcTrackingCursor { + pub snapshot: i64, + pub event_time: i64, + pub event_id: String, + pub filter_key: String, +} +/// 游标绑定查询条件;分页大小不参与条件,刷新时不带游标。 +pub fn agc_tracking_filter_key( + query: &shared_contracts::admin::AdminAgcTrackingEventListQuery, +) -> String { + let mut filters = query.clone(); + filters.cursor = None; + filters.limit = None; + serde_json::to_string(&filters).expect("query serializes") +} +pub fn agc_time_micros(value: &str) -> Result { + let time = time::OffsetDateTime::parse(value, &time::format_description::well_known::Rfc3339) + .map_err(|_| "invalid_agc_query")?; + i64::try_from(time.unix_timestamp_nanos() / 1000).map_err(|_| "invalid_agc_query") +} +pub fn validate_agc_tracking_query( + query: &shared_contracts::admin::AdminAgcTrackingEventListQuery, +) -> Result, &'static str> { + for value in [ + &query.user_id, + &query.project_id, + &query.creative_task_id, + &query.agent_run_id, + &query.event_name, + &query.client_version, + ] + .into_iter() + .flatten() + { + if !id(value) { + return Err("invalid_agc_query"); + } + } + let start = query + .start_time + .as_deref() + .map(agc_time_micros) + .transpose()?; + let end = query.end_time.as_deref().map(agc_time_micros).transpose()?; + if start.zip(end).is_some_and(|(a, b)| a >= b) { + return Err("invalid_agc_query"); + } + if let Some(raw) = &query.cursor { + if raw.len() > 8192 { + return Err("invalid_agc_cursor"); + } + let cursor: AgcTrackingCursor = + serde_json::from_str(raw).map_err(|_| "invalid_agc_cursor")?; + if cursor.filter_key != agc_tracking_filter_key(query) || !uuid(&cursor.event_id) { + return Err("invalid_agc_cursor"); + } + Ok(Some(cursor)) + } else { + Ok(None) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + const ID: &str = "790a1275-a0a0-405c-8bfd-287201bef10a"; + fn event(name: &str, properties: Value) -> Event { + serde_json::from_value(json!({ + "schema_version": 1, "event_id": ID, "event_name": name, + "event_time": "2026-09-21T12:00:00.000Z", "user_id": "user-a", + "editor_session_id": ID, "project_id": null, "creative_task_id": null, + "agent_run_id": null, "agent_turn_id": null, "status": "success", + "error_code": null, "source": "editor", "client_version": "1.0.0", "properties": properties + })).unwrap() + } + fn batch(event: Event) -> AgcAnalyticsBatch { + AgcAnalyticsBatch { + schema_version: 1, + batch_id: ID.into(), + destination_origin: "https://example.com".into(), + user_id: "user-a".into(), + events: vec![event], + } + } + #[test] + fn agc_accepts_twelve_existing_event_contracts() { + let cases = [ + ( + "editor_session_start", + json!({"entry_source":"direct_launch","first_project_id":null}), + ), + ( + "editor_session_end", + json!({"end_reason":"user_exit","session_duration_ms":null,"last_project_id":null}), + ), + ( + "editor_focus_start", + json!({"focus_interval_id":ID,"focus_reason":"window_focus","active_project_id":null}), + ), + ( + "editor_focus_end", + json!({"focus_interval_id":ID,"blur_reason":"window_blur","focus_duration_ms":1,"active_project_id":null}), + ), + ( + "project_create_success", + json!({"creation_source":"home_game"}), + ), + ( + "project_open", + json!({"open_source":"recent","is_first_open":null}), + ), + ("creative_task_submit", json!({})), + ( + "agent_run_completed", + json!({"agent_type":"game_agent","run_source":"user_submit","duration_ms":1,"retry_index":0,"output_change_detected":null,"end_reason":"waiting_for_approval"}), + ), + ( + "agent_run_failed", + json!({"agent_type":"game_agent","run_source":"user_submit","duration_ms":1,"retry_index":0,"output_change_detected":true,"end_reason":"failed"}), + ), + ( + "project_revision_created", + json!({"revision_id":"design:session:phase","revision_source":"agent","change_kind":"design_document"}), + ), + ( + "preview_ready", + json!({"preview_source":"user","preview_version":"version1"}), + ), + ("project_save", json!({"save_source":"checkpoint"})), + ]; + for (index, (name, properties)) in cases.into_iter().enumerate() { + let mut e = event(name, properties); + if index == 2 || index == 3 { + e.status = None; + } + if index >= 4 { + e.project_id = Some("project-a".into()); + } + if index >= 6 { + e.creative_task_id = e.project_id.clone(); + e.source = Source::Direct; + } + if index == 7 || index == 8 { + e.agent_run_id = Some(ID.into()); + } + if index == 8 { + e.status = Some(Status::Failed); + e.error_code = Some(ErrorCode::ProviderTimeout); + } + assert_eq!(validate_agc_analytics_batch(&batch(e)), Ok(()), "{name}"); + } + } + #[test] + fn agc_rejects_identity_duplicate_and_unknown_content() { + let e = event( + "editor_session_start", + json!({"entry_source":"direct_launch","first_project_id":null}), + ); + let mut b = batch(e.clone()); + b.user_id = "other-user".into(); + assert_eq!(validate_agc_analytics_batch(&b), Err("identity_mismatch")); + let mut b = batch(e.clone()); + b.events.push(e.clone()); + assert_eq!(validate_agc_analytics_batch(&b), Err("duplicate_event_id")); + let mut b = batch(e.clone()); + b.events[0].properties["prompt"] = json!("should never be accepted"); + assert_eq!(validate_agc_analytics_batch(&b), Err("invalid_properties")); + b.events[0].properties = json!(["direct_launch", null]); + assert_eq!(validate_agc_analytics_batch(&b), Err("invalid_properties")); + let mut raw = serde_json::to_value(e).unwrap(); + raw["file_path"] = json!("secret"); + assert!(serde_json::from_value::(raw).is_err()); + } + #[test] + fn agc_requires_explicit_nullable_fields_and_no_optional_nulls() { + let mut raw = + serde_json::to_value(event("project_save", json!({"save_source":"manual"}))).unwrap(); + raw.as_object_mut().unwrap().remove("agent_turn_id"); + assert!(serde_json::from_value::(raw).is_err()); + let mut e = event( + "project_save", + json!({"save_source":"manual","revision_id":null}), + ); + e.project_id = Some("p".into()); + e.creative_task_id = e.project_id.clone(); + assert_eq!(e.validate(), Err("invalid_optional_property")); + } + #[test] + fn agc_query_cursor_is_bound_to_filters_and_rejects_invalid_time_range() { + let mut query = shared_contracts::admin::AdminAgcTrackingEventListQuery::default(); + let cursor = AgcTrackingCursor { + snapshot: 100, + // 客户端时钟可能领先;快照限制入库时间,不能限制发生时间。 + event_time: 110, + event_id: ID.into(), + filter_key: agc_tracking_filter_key(&query), + }; + query.cursor = Some(serde_json::to_string(&cursor).unwrap()); + assert!(validate_agc_tracking_query(&query).is_ok()); + query.user_id = Some("changed-user".into()); + assert_eq!( + validate_agc_tracking_query(&query).unwrap_err(), + "invalid_agc_cursor" + ); + query.cursor = None; + query.start_time = Some("2026-09-22T00:00:00Z".into()); + query.end_time = Some("2026-09-21T00:00:00Z".into()); + assert_eq!( + validate_agc_tracking_query(&query).unwrap_err(), + "invalid_agc_query" + ); + } +} diff --git a/server-rs/crates/module-runtime/src/application.rs b/server-rs/crates/module-runtime/src/application.rs index e7f1ead08..f40b8388a 100644 --- a/server-rs/crates/module-runtime/src/application.rs +++ b/server-rs/crates/module-runtime/src/application.rs @@ -84,8 +84,8 @@ pub fn creation_entry_feature_gate_key(creation_type_id: &str) -> String { pub const IMAGE_EDITOR_AGENT_SIDEBAR_GATE_KEY: &str = "image-editor:agent-sidebar"; pub const AGC_TEMPLATE_LIBRARY_GATE_KEY: &str = "agc:template-library"; -/// 游戏分发写入开关:gate 行缺失或 `enabled=false` 时默认开放;`enabled=true` 时 -/// 只有白名单/灰度命中的用户能发布新版本(`rollout_percent=0` 且无白名单即全部关闭)。 +/// 游戏分发发布开关:`gate 行缺失`或 `enabled=false` 都表示**未开放**(灰度默认关闭); +/// 只有 `enabled=true` 且白名单 / 灰度比例 / 用户标签命中时才允许发布。 pub const GAME_DISTRIBUTION_PUBLISH_GATE_KEY: &str = "game-distribution:publish"; #[cfg(any())] diff --git a/server-rs/crates/module-runtime/src/lib.rs b/server-rs/crates/module-runtime/src/lib.rs index adc3b96e1..c6698f7a6 100644 --- a/server-rs/crates/module-runtime/src/lib.rs +++ b/server-rs/crates/module-runtime/src/lib.rs @@ -1,3 +1,4 @@ +pub mod agc_analytics; mod agc_models; mod llm_billing; pub use llm_billing::*; diff --git a/server-rs/crates/shared-contracts/src/admin.rs b/server-rs/crates/shared-contracts/src/admin.rs index e899fefbb..f9730feb4 100644 --- a/server-rs/crates/shared-contracts/src/admin.rs +++ b/server-rs/crates/shared-contracts/src/admin.rs @@ -10,12 +10,13 @@ use crate::creation_entry_config::{ }; /// 后台 member 可被授予的一级 Tab 权限;账号管理仅 owner 可见,不进入该集合。 -pub const ADMIN_TAB_PERMISSIONS: [&str; 18] = [ +pub const ADMIN_TAB_PERMISSIONS: [&str; 19] = [ "dashboard", "overview", "tables", "debug", "tracking", + "agc-tracking", "gray-release", "redeem", "invite", @@ -1495,3 +1496,47 @@ pub struct AdminAgcModelCatalog { pub default_model_id: String, pub models: Vec, } + +// 客户端埋点明细;时间范围按发生时间,按 (event_time, event_id) 倒序分页。 +// received_at 仅用于固定分页快照的入库时间上界。 +#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct AdminAgcTrackingEventListQuery { + pub user_id: Option, + pub project_id: Option, + pub creative_task_id: Option, + pub agent_run_id: Option, + pub event_name: Option, + pub client_version: Option, + pub start_time: Option, + pub end_time: Option, + pub cursor: Option, + pub limit: Option, +} +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "camelCase")] +pub struct AdminAgcTrackingEventEntry { + pub event_id: String, + pub schema_version: u32, + pub event_name: String, + pub event_time: String, + pub user_id: String, + pub editor_session_id: String, + pub project_id: Option, + pub creative_task_id: Option, + pub agent_run_id: Option, + pub agent_turn_id: Option, + pub status: Option, + pub error_code: Option, + pub source: String, + pub client_version: String, + pub properties: serde_json::Value, + pub batch_id: String, + pub received_at: String, +} +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "camelCase")] +pub struct AdminAgcTrackingEventListPayload { + pub entries: Vec, + pub next_cursor: Option, +} diff --git a/server-rs/crates/shared-contracts/src/agc_analytics.rs b/server-rs/crates/shared-contracts/src/agc_analytics.rs new file mode 100644 index 000000000..bb26bdebd --- /dev/null +++ b/server-rs/crates/shared-contracts/src/agc_analytics.rs @@ -0,0 +1,282 @@ +//! 客户端埋点上传合同;字段与本地 schema v1 保持一致。 +use serde::{Deserialize, Deserializer, Serialize}; +use serde_json::Value; + +fn required_nullable<'de, D, T>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, + T: Deserialize<'de>, +{ + Option::::deserialize(deserializer) +} + +macro_rules! values { + ($name:ident { $($variant:ident),+ $(,)? }) => { + #[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)] + #[serde(rename_all = "snake_case")] + pub enum $name { $($variant),+ } + }; +} + +values!(Source { + Editor, + Direct, + DesignAgent, + AssetCanvas, + ResourceEditor, + UiEditor, + Manual, + System +}); +values!(Status { Success, Failed }); +values!(EntrySource { + DirectLaunch, + ProjectAssociation, + AppRestore +}); +values!(SessionEndReason { + UserExit, + AppRestart +}); +values!(FocusReason { + InitialFocus, + WindowFocus, + Restore, + AccountChange +}); +values!(BlurReason { + WindowBlur, + Minimized, + AppExit, + SystemSuspend, + AccountChange +}); +values!(CreationSource { + HomeGame, + HomeDesign, + Template, + SelectedDirectory +}); +values!(OpenSource { + Create, + Picker, + Recent, + AppRestore, + ProjectAssociation +}); +values!(AgentType { + GameAgent, + DesignAgent +}); +values!(RunSource { + UserSubmit, + UserContinue, + Clarification, + Approval, + UserRetry +}); +values!(RunEndReason { + Finished, + WaitingForUser, + WaitingForApproval, + Failed +}); +values!(ErrorCode { + ProviderAuthFailed, + ProviderRateLimited, + ProviderUnavailable, + ProviderTimeout, + ProviderInvalidResponse, + LocalIoFailed, + RuntimeFailed, + RuntimeErrorUnclassified +}); +values!(RevisionSource { + Agent, + AssetCanvas, + ResourceEditor, + UiEditor, + ManualEdit, + SystemProjection +}); +values!(ChangeKind { + Code, + Asset, + Ui, + DesignDocument, + Mixed +}); +values!(PreviewSource { + User, + Agent, + AutoRestore +}); +values!(SaveSource { + Manual, + Auto, + Checkpoint +}); +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct SessionStart { + pub entry_source: EntrySource, + #[serde(deserialize_with = "required_nullable")] + pub first_project_id: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct SessionEnd { + pub end_reason: SessionEndReason, + #[serde(deserialize_with = "required_nullable")] + pub session_duration_ms: Option, + #[serde(deserialize_with = "required_nullable")] + pub last_project_id: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct FocusStart { + pub focus_interval_id: String, + pub focus_reason: FocusReason, + #[serde(deserialize_with = "required_nullable")] + pub active_project_id: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct FocusEnd { + pub focus_interval_id: String, + pub blur_reason: BlurReason, + #[serde(deserialize_with = "required_nullable")] + pub focus_duration_ms: Option, + #[serde(deserialize_with = "required_nullable")] + pub active_project_id: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ProjectCreated { + pub creation_source: CreationSource, + #[serde(skip_serializing_if = "Option::is_none")] + pub project_template_id: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ProjectOpened { + pub open_source: OpenSource, + #[serde(deserialize_with = "required_nullable")] + pub is_first_open: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct EmptyProperties {} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct RunFinished { + pub agent_type: AgentType, + pub run_source: RunSource, + #[serde(deserialize_with = "required_nullable")] + pub duration_ms: Option, + pub retry_index: u64, + #[serde(deserialize_with = "required_nullable")] + pub output_change_detected: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub revision_id: Option, + pub end_reason: RunEndReason, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct RevisionCreated { + pub revision_id: String, + pub revision_source: RevisionSource, + pub change_kind: ChangeKind, + #[serde(skip_serializing_if = "Option::is_none")] + pub files_changed_count: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct PreviewReady { + pub preview_source: PreviewSource, + pub preview_version: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub ready_duration_ms: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ProjectSaved { + pub save_source: SaveSource, + #[serde(skip_serializing_if = "Option::is_none")] + pub revision_id: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde( + tag = "event_name", + content = "properties", + rename_all = "snake_case", + deny_unknown_fields +)] +pub enum EventData { + EditorSessionStart(SessionStart), + EditorSessionEnd(SessionEnd), + EditorFocusStart(FocusStart), + EditorFocusEnd(FocusEnd), + ProjectCreateSuccess(ProjectCreated), + ProjectOpen(ProjectOpened), + CreativeTaskSubmit(EmptyProperties), + AgentRunCompleted(RunFinished), + AgentRunFailed(RunFinished), + ProjectRevisionCreated(RevisionCreated), + PreviewReady(PreviewReady), + ProjectSave(ProjectSaved), +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct Event { + pub schema_version: u32, + pub event_id: String, + pub event_name: String, + pub event_time: String, + #[serde(deserialize_with = "required_nullable")] + pub user_id: Option, + pub editor_session_id: String, + #[serde(deserialize_with = "required_nullable")] + pub project_id: Option, + #[serde(deserialize_with = "required_nullable")] + pub creative_task_id: Option, + #[serde(deserialize_with = "required_nullable")] + pub agent_run_id: Option, + #[serde(deserialize_with = "required_nullable")] + pub agent_turn_id: Option, + #[serde(deserialize_with = "required_nullable")] + pub status: Option, + #[serde(deserialize_with = "required_nullable")] + pub error_code: Option, + pub source: Source, + pub client_version: String, + pub properties: Value, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct AgcAnalyticsBatch { + pub schema_version: u32, + pub batch_id: String, + pub destination_origin: String, + pub user_id: String, + pub events: Vec, +} +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct AgcAnalyticsAcknowledgement { + pub acknowledged_batch_ids: Vec, + pub event_count: u32, +} diff --git a/server-rs/crates/shared-contracts/src/lib.rs b/server-rs/crates/shared-contracts/src/lib.rs index 255253954..377e9d75f 100644 --- a/server-rs/crates/shared-contracts/src/lib.rs +++ b/server-rs/crates/shared-contracts/src/lib.rs @@ -1,4 +1,5 @@ pub mod admin; +pub mod agc_analytics; pub mod agc_project_snapshots; pub mod ai; pub mod api; diff --git a/server-rs/crates/spacetime-client/src/active.rs b/server-rs/crates/spacetime-client/src/active.rs index c20123daf..f53356bed 100644 --- a/server-rs/crates/spacetime-client/src/active.rs +++ b/server-rs/crates/spacetime-client/src/active.rs @@ -9,6 +9,7 @@ pub use mapper::*; pub mod admin_account; pub mod admin_dashboard; +pub mod agc_analytics; pub mod agc_models; #[path = "active/ai.rs"] pub mod ai; diff --git a/server-rs/crates/spacetime-client/src/agc_analytics.rs b/server-rs/crates/spacetime-client/src/agc_analytics.rs new file mode 100644 index 000000000..dff3d0b13 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/agc_analytics.rs @@ -0,0 +1,64 @@ +use super::*; +use shared_contracts::admin::{AdminAgcTrackingEventListPayload, AdminAgcTrackingEventListQuery}; +use shared_contracts::agc_analytics::{AgcAnalyticsAcknowledgement, AgcAnalyticsBatch}; +impl SpacetimeClient { + pub async fn upload_agc_analytics_batch( + &self, + input: AgcAnalyticsBatch, + ) -> Result { + let input_json = serde_json::to_string(&input) + .map_err(|_| SpacetimeClientError::validation_failed("invalid_agc_payload"))?; + self.call_after_connect("upload_agc_analytics_batch", move |connection, sender| { + connection.procedures().upload_agc_analytics_batch_then( + input_json, + move |_, result| { + let mapped = result + .map_err(SpacetimeClientError::from_sdk_error) + .and_then(|r| { + r.map_err(|message| { + SpacetimeClientError::procedure_failed(Some(message)) + }) + }) + .and_then(|json| { + serde_json::from_str(&json).map_err(|_| { + SpacetimeClientError::procedure_failed(Some( + "invalid_agc_response".into(), + )) + }) + }); + send_once(&sender, mapped); + }, + ); + }) + .await + } + pub async fn list_agc_tracking_events( + &self, + input: AdminAgcTrackingEventListQuery, + ) -> Result { + let input_json = serde_json::to_string(&input) + .map_err(|_| SpacetimeClientError::validation_failed("invalid_agc_payload"))?; + self.call_after_connect("list_agc_tracking_events", move |connection, sender| { + connection + .procedures() + .list_agc_tracking_events_then(input_json, move |_, result| { + let mapped = result + .map_err(SpacetimeClientError::from_sdk_error) + .and_then(|r| { + r.map_err(|message| { + SpacetimeClientError::procedure_failed(Some(message)) + }) + }) + .and_then(|json| { + serde_json::from_str(&json).map_err(|_| { + SpacetimeClientError::procedure_failed(Some( + "invalid_agc_response".into(), + )) + }) + }); + send_once(&sender, mapped); + }); + }) + .await + } +} diff --git a/server-rs/crates/spacetime-client/src/module_bindings.rs b/server-rs/crates/spacetime-client/src/module_bindings.rs index ae7484ee8..94d10bb47 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings.rs @@ -53,6 +53,8 @@ pub mod admin_upsert_profile_wallet_manual_restriction_and_return_procedure; pub mod advance_profile_recharge_refund_bill_checkpoint_and_return_procedure; pub mod agc_model_catalog_row_type; pub mod agc_model_catalog_table; +pub mod agc_tracking_event_table; +pub mod agc_tracking_event_type; pub mod ai_result_reference_input_type; pub mod ai_result_reference_kind_type; pub mod ai_result_reference_snapshot_type; @@ -135,56 +137,16 @@ pub mod authenticate_external_api_key_and_return_procedure; pub mod authorize_database_migration_operator_procedure; pub mod backfill_editor_canvas_layout_and_return_procedure; pub mod backfill_external_generation_job_summaries_and_return_procedure; -pub mod bark_battle_draft_config_row_type; -pub mod bark_battle_draft_config_table; -pub mod bark_battle_leaderboard_entry_row_type; -pub mod bark_battle_leaderboard_entry_table; -pub mod bark_battle_personal_best_projection_row_type; -pub mod bark_battle_personal_best_projection_table; -pub mod bark_battle_published_config_row_type; -pub mod bark_battle_published_config_table; -pub mod bark_battle_runtime_run_row_type; -pub mod bark_battle_runtime_run_table; -pub mod bark_battle_score_record_row_type; -pub mod bark_battle_score_record_table; -pub mod bark_battle_work_stats_projection_row_type; -pub mod bark_battle_work_stats_projection_table; -pub mod battle_mode_type; -pub mod battle_state_table; -pub mod battle_state_type; -pub mod battle_status_type; -pub mod big_fish_agent_message_kind_type; -pub mod big_fish_agent_message_role_type; -pub mod big_fish_agent_message_table; -pub mod big_fish_agent_message_type; -pub mod big_fish_asset_kind_type; -pub mod big_fish_asset_slot_table; -pub mod big_fish_asset_slot_type; -pub mod big_fish_asset_status_type; -pub mod big_fish_creation_session_table; -pub mod big_fish_creation_session_type; -pub mod big_fish_creation_stage_type; -pub mod big_fish_event_kind_type; -pub mod big_fish_event_table; -pub mod big_fish_event_type; -pub mod big_fish_run_status_type; -pub mod big_fish_runtime_run_table; -pub mod big_fish_runtime_run_type; pub mod bind_asset_object_to_entity_and_return_procedure; pub mod bind_asset_object_to_entity_reducer; pub mod cancel_ai_task_and_return_procedure; pub mod cancel_game_distribution_version_and_return_procedure; -pub mod chapter_pace_band_type; -pub mod chapter_progression_table; -pub mod chapter_progression_type; pub mod claim_external_generation_jobs_and_return_procedure; pub mod claim_profile_recharge_order_expiration_schedule_and_return_procedure; pub mod claim_profile_task_reward_and_return_procedure; pub mod clean_editor_image_asset_kind_and_return_procedure; pub mod clear_database_migration_import_chunks_procedure; -pub mod clear_retired_database_tables_procedure; pub mod close_profile_recharge_order_and_return_procedure; -pub mod combat_outcome_type; pub mod compact_external_generation_job_payloads_and_return_procedure; pub mod complete_ai_stage_and_return_procedure; pub mod complete_ai_task_and_return_procedure; @@ -212,29 +174,7 @@ pub mod creation_entry_config_table; pub mod creation_entry_config_type; pub mod creation_entry_type_config_table; pub mod creation_entry_type_config_type; -pub mod custom_world_agent_message_table; -pub mod custom_world_agent_message_type; -pub mod custom_world_agent_operation_table; -pub mod custom_world_agent_operation_type; -pub mod custom_world_agent_session_table; -pub mod custom_world_agent_session_type; -pub mod custom_world_draft_card_table; -pub mod custom_world_draft_card_type; -pub mod custom_world_gallery_entry_table; -pub mod custom_world_gallery_entry_type; -pub mod custom_world_generation_mode_type; -pub mod custom_world_profile_table; -pub mod custom_world_profile_type; -pub mod custom_world_publication_status_type; -pub mod custom_world_role_asset_status_type; -pub mod custom_world_session_status_type; -pub mod custom_world_session_table; -pub mod custom_world_session_type; -pub mod custom_world_theme_mode_type; pub mod database_migration_authorize_operator_input_type; -pub mod database_migration_clear_retired_tables_input_type; -pub mod database_migration_clear_retired_tables_result_type; -pub mod database_migration_clear_table_stat_type; pub mod database_migration_export_input_type; pub mod database_migration_import_chunk_input_type; pub mod database_migration_import_chunk_table; @@ -527,23 +467,8 @@ pub mod import_database_migration_from_file_procedure; pub mod import_database_migration_incremental_from_chunks_procedure; pub mod import_database_migration_incremental_from_file_procedure; pub mod initialize_editor_generation_pricing_config_if_missing_and_return_procedure; -pub mod inventory_container_kind_type; -pub mod inventory_equipment_slot_type; -pub mod inventory_item_rarity_type; -pub mod inventory_item_source_kind_type; -pub mod inventory_slot_table; -pub mod inventory_slot_type; -pub mod jump_hop_agent_session_row_type; -pub mod jump_hop_agent_session_table; -pub mod jump_hop_event_row_type; -pub mod jump_hop_event_table; -pub mod jump_hop_leaderboard_entry_row_type; -pub mod jump_hop_leaderboard_entry_table; -pub mod jump_hop_runtime_run_row_type; -pub mod jump_hop_runtime_run_table; -pub mod jump_hop_work_profile_row_type; -pub mod jump_hop_work_profile_table; pub mod list_admin_accounts_and_return_procedure; +pub mod list_agc_tracking_events_procedure; pub mod list_asset_history_and_return_procedure; pub mod list_editor_agent_conversations_and_return_procedure; pub mod list_editor_projects_and_return_procedure; @@ -575,26 +500,10 @@ pub mod llm_router_quota_settlement_result_type; pub mod mark_editor_showcase_asset_refunded_and_return_procedure; pub mod mark_profile_recharge_order_expiration_checked_procedure; pub mod mark_profile_recharge_order_paid_and_return_procedure; -pub mod match_3_d_agent_message_row_type; -pub mod match_3_d_agent_message_table; -pub mod match_3_d_agent_session_row_type; -pub mod match_3_d_agent_session_table; -pub mod match_3_d_runtime_run_row_type; -pub mod match_3_d_runtime_run_table; -pub mod match_3_d_work_profile_row_type; -pub mod match_3_d_work_profile_table; pub mod normalize_editor_character_animation_metadata_and_return_procedure; -pub mod npc_relation_stance_type; -pub mod npc_relation_state_type; -pub mod npc_stance_profile_type; -pub mod npc_state_table; -pub mod npc_state_type; pub mod persist_editor_generation_result_and_return_procedure; pub mod persist_editor_pixel_art_result_and_return_procedure; pub mod persist_editor_spritesheet_slice_batch_and_return_procedure; -pub mod player_progression_grant_source_type; -pub mod player_progression_table; -pub mod player_progression_type; pub mod preflight_editor_generation_target_and_return_procedure; pub mod preflight_editor_pixel_art_result_and_return_procedure; pub mod prepare_profile_recharge_refund_hold_and_return_procedure; @@ -662,59 +571,7 @@ pub mod public_work_like_type; pub mod public_work_play_daily_stat_table; pub mod public_work_play_daily_stat_type; pub mod put_database_migration_import_chunk_procedure; -pub mod puzzle_agent_message_kind_type; -pub mod puzzle_agent_message_role_type; -pub mod puzzle_agent_message_row_type; -pub mod puzzle_agent_message_table; -pub mod puzzle_agent_session_row_type; -pub mod puzzle_agent_session_table; -pub mod puzzle_agent_stage_type; -pub mod puzzle_background_compile_task_row_type; -pub mod puzzle_background_compile_task_table; -pub mod puzzle_clear_agent_session_row_type; -pub mod puzzle_clear_agent_session_table; -pub mod puzzle_clear_event_row_type; -pub mod puzzle_clear_event_table; -pub mod puzzle_clear_runtime_run_row_type; -pub mod puzzle_clear_runtime_run_table; -pub mod puzzle_clear_work_profile_row_type; -pub mod puzzle_clear_work_profile_table; -pub mod puzzle_event_kind_type; -pub mod puzzle_event_table; -pub mod puzzle_event_type; -pub mod puzzle_leaderboard_entry_row_type; -pub mod puzzle_leaderboard_entry_table; -pub mod puzzle_publication_status_type; -pub mod puzzle_runtime_run_row_type; -pub mod puzzle_runtime_run_table; -pub mod puzzle_work_profile_row_type; -pub mod puzzle_work_profile_table; pub mod query_analytics_metric_procedure; -pub mod quest_hostile_npc_defeated_signal_type; -pub mod quest_item_delivered_signal_type; -pub mod quest_log_event_kind_type; -pub mod quest_log_table; -pub mod quest_log_type; -pub mod quest_narrative_binding_snapshot_type; -pub mod quest_narrative_origin_type; -pub mod quest_narrative_type_type; -pub mod quest_npc_spar_completed_signal_type; -pub mod quest_npc_talk_completed_signal_type; -pub mod quest_objective_kind_type; -pub mod quest_objective_snapshot_type; -pub mod quest_progress_signal_type; -pub mod quest_record_table; -pub mod quest_record_type; -pub mod quest_reward_equipment_slot_type; -pub mod quest_reward_intel_type; -pub mod quest_reward_item_rarity_type; -pub mod quest_reward_item_type; -pub mod quest_reward_snapshot_type; -pub mod quest_scene_reached_signal_type; -pub mod quest_signal_kind_type; -pub mod quest_status_type; -pub mod quest_step_snapshot_type; -pub mod quest_treasure_inspected_signal_type; pub mod read_agc_model_catalog_procedure; pub mod record_daily_login_tracking_event_and_return_procedure; pub mod record_profile_recharge_refund_observation_and_return_procedure; @@ -738,17 +595,7 @@ pub mod revoke_database_migration_operator_procedure; pub mod revoke_external_api_key_and_return_procedure; pub mod rollback_editor_canvas_layout_and_return_procedure; pub mod rotate_editor_generation_runtime_service_identity_and_return_procedure; -pub mod rpg_agent_draft_card_kind_type; -pub mod rpg_agent_draft_card_status_type; -pub mod rpg_agent_message_kind_type; -pub mod rpg_agent_message_role_type; -pub mod rpg_agent_operation_status_type; -pub mod rpg_agent_operation_type_type; -pub mod rpg_agent_stage_type; pub mod runtime_browse_history_theme_mode_type; -pub mod runtime_item_equipment_slot_type; -pub mod runtime_item_reward_item_rarity_type; -pub mod runtime_item_reward_item_snapshot_type; pub mod runtime_platform_theme_type; pub mod runtime_profile_admin_wallet_detail_procedure_result_type; pub mod runtime_profile_admin_wallet_get_input_type; @@ -897,22 +744,8 @@ pub mod save_editor_project_layout_v_2_and_return_procedure; pub mod seed_analytics_date_dimensions_reducer; pub mod set_editor_showcase_asset_like_for_viewer_and_return_procedure; pub mod settle_llm_router_quota_and_return_procedure; -pub mod square_hole_agent_message_row_type; -pub mod square_hole_agent_message_table; -pub mod square_hole_agent_session_row_type; -pub mod square_hole_agent_session_table; -pub mod square_hole_runtime_run_row_type; -pub mod square_hole_runtime_run_table; -pub mod square_hole_work_profile_row_type; -pub mod square_hole_work_profile_table; pub mod start_ai_task_reducer; pub mod start_ai_task_stage_reducer; -pub mod story_event_kind_type; -pub mod story_event_table; -pub mod story_event_type; -pub mod story_session_status_type; -pub mod story_session_table; -pub mod story_session_type; pub mod submit_editor_showcase_asset_and_return_procedure; pub mod submit_game_distribution_version_for_review_and_return_procedure; pub mod submit_profile_feedback_and_return_procedure; @@ -923,9 +756,6 @@ pub mod tracking_daily_stat_table; pub mod tracking_daily_stat_type; pub mod tracking_event_table; pub mod tracking_event_type; -pub mod treasure_interaction_action_type; -pub mod treasure_record_table; -pub mod treasure_record_type; pub mod unpublish_game_distribution_game_and_return_procedure; pub mod update_admin_account_and_return_procedure; pub mod update_editor_asset_and_return_procedure; @@ -934,6 +764,7 @@ pub mod update_editor_project_resource_showcase_and_return_procedure; pub mod update_editor_showcase_asset_display_and_return_procedure; pub mod update_error_report_and_return_procedure; pub mod update_external_generation_job_phase_and_return_procedure; +pub mod upload_agc_analytics_batch_procedure; pub mod upsert_editor_generation_pricing_config_and_return_procedure; pub mod upsert_editor_showcase_campaign_config_and_return_procedure; pub mod upsert_feature_gate_config_procedure; @@ -944,26 +775,6 @@ pub mod user_account_type; pub mod user_browse_history_table; pub mod user_browse_history_type; pub mod validate_auth_session_procedure; -pub mod visual_novel_agent_message_row_type; -pub mod visual_novel_agent_message_table; -pub mod visual_novel_agent_session_row_type; -pub mod visual_novel_agent_session_table; -pub mod visual_novel_runtime_event_table; -pub mod visual_novel_runtime_event_type; -pub mod visual_novel_runtime_history_entry_row_type; -pub mod visual_novel_runtime_history_entry_table; -pub mod visual_novel_runtime_run_row_type; -pub mod visual_novel_runtime_run_table; -pub mod visual_novel_work_profile_row_type; -pub mod visual_novel_work_profile_table; -pub mod wooden_fish_agent_session_row_type; -pub mod wooden_fish_agent_session_table; -pub mod wooden_fish_event_row_type; -pub mod wooden_fish_event_table; -pub mod wooden_fish_runtime_run_row_type; -pub mod wooden_fish_runtime_run_table; -pub mod wooden_fish_work_profile_row_type; -pub mod wooden_fish_work_profile_table; pub use acknowledge_external_generation_job_summaries_and_return_procedure::acknowledge_external_generation_job_summaries_and_return; pub use acknowledge_external_generation_jobs_and_return_procedure::acknowledge_external_generation_jobs_and_return; @@ -1012,6 +823,8 @@ pub use admin_upsert_profile_wallet_manual_restriction_and_return_procedure::adm pub use advance_profile_recharge_refund_bill_checkpoint_and_return_procedure::advance_profile_recharge_refund_bill_checkpoint_and_return; pub use agc_model_catalog_row_type::AgcModelCatalogRow; pub use agc_model_catalog_table::*; +pub use agc_tracking_event_table::*; +pub use agc_tracking_event_type::AgcTrackingEvent; pub use ai_result_reference_input_type::AiResultReferenceInput; pub use ai_result_reference_kind_type::AiResultReferenceKind; pub use ai_result_reference_snapshot_type::AiResultReferenceSnapshot; @@ -1094,56 +907,16 @@ pub use authenticate_external_api_key_and_return_procedure::authenticate_externa pub use authorize_database_migration_operator_procedure::authorize_database_migration_operator; pub use backfill_editor_canvas_layout_and_return_procedure::backfill_editor_canvas_layout_and_return; pub use backfill_external_generation_job_summaries_and_return_procedure::backfill_external_generation_job_summaries_and_return; -pub use bark_battle_draft_config_row_type::BarkBattleDraftConfigRow; -pub use bark_battle_draft_config_table::*; -pub use bark_battle_leaderboard_entry_row_type::BarkBattleLeaderboardEntryRow; -pub use bark_battle_leaderboard_entry_table::*; -pub use bark_battle_personal_best_projection_row_type::BarkBattlePersonalBestProjectionRow; -pub use bark_battle_personal_best_projection_table::*; -pub use bark_battle_published_config_row_type::BarkBattlePublishedConfigRow; -pub use bark_battle_published_config_table::*; -pub use bark_battle_runtime_run_row_type::BarkBattleRuntimeRunRow; -pub use bark_battle_runtime_run_table::*; -pub use bark_battle_score_record_row_type::BarkBattleScoreRecordRow; -pub use bark_battle_score_record_table::*; -pub use bark_battle_work_stats_projection_row_type::BarkBattleWorkStatsProjectionRow; -pub use bark_battle_work_stats_projection_table::*; -pub use battle_mode_type::BattleMode; -pub use battle_state_table::*; -pub use battle_state_type::BattleState; -pub use battle_status_type::BattleStatus; -pub use big_fish_agent_message_kind_type::BigFishAgentMessageKind; -pub use big_fish_agent_message_role_type::BigFishAgentMessageRole; -pub use big_fish_agent_message_table::*; -pub use big_fish_agent_message_type::BigFishAgentMessage; -pub use big_fish_asset_kind_type::BigFishAssetKind; -pub use big_fish_asset_slot_table::*; -pub use big_fish_asset_slot_type::BigFishAssetSlot; -pub use big_fish_asset_status_type::BigFishAssetStatus; -pub use big_fish_creation_session_table::*; -pub use big_fish_creation_session_type::BigFishCreationSession; -pub use big_fish_creation_stage_type::BigFishCreationStage; -pub use big_fish_event_kind_type::BigFishEventKind; -pub use big_fish_event_table::*; -pub use big_fish_event_type::BigFishEvent; -pub use big_fish_run_status_type::BigFishRunStatus; -pub use big_fish_runtime_run_table::*; -pub use big_fish_runtime_run_type::BigFishRuntimeRun; pub use bind_asset_object_to_entity_and_return_procedure::bind_asset_object_to_entity_and_return; pub use bind_asset_object_to_entity_reducer::bind_asset_object_to_entity; pub use cancel_ai_task_and_return_procedure::cancel_ai_task_and_return; pub use cancel_game_distribution_version_and_return_procedure::cancel_game_distribution_version_and_return; -pub use chapter_pace_band_type::ChapterPaceBand; -pub use chapter_progression_table::*; -pub use chapter_progression_type::ChapterProgression; pub use claim_external_generation_jobs_and_return_procedure::claim_external_generation_jobs_and_return; pub use claim_profile_recharge_order_expiration_schedule_and_return_procedure::claim_profile_recharge_order_expiration_schedule_and_return; pub use claim_profile_task_reward_and_return_procedure::claim_profile_task_reward_and_return; pub use clean_editor_image_asset_kind_and_return_procedure::clean_editor_image_asset_kind_and_return; pub use clear_database_migration_import_chunks_procedure::clear_database_migration_import_chunks; -pub use clear_retired_database_tables_procedure::clear_retired_database_tables; pub use close_profile_recharge_order_and_return_procedure::close_profile_recharge_order_and_return; -pub use combat_outcome_type::CombatOutcome; pub use compact_external_generation_job_payloads_and_return_procedure::compact_external_generation_job_payloads_and_return; pub use complete_ai_stage_and_return_procedure::complete_ai_stage_and_return; pub use complete_ai_task_and_return_procedure::complete_ai_task_and_return; @@ -1171,29 +944,7 @@ pub use creation_entry_config_table::*; pub use creation_entry_config_type::CreationEntryConfig; pub use creation_entry_type_config_table::*; pub use creation_entry_type_config_type::CreationEntryTypeConfig; -pub use custom_world_agent_message_table::*; -pub use custom_world_agent_message_type::CustomWorldAgentMessage; -pub use custom_world_agent_operation_table::*; -pub use custom_world_agent_operation_type::CustomWorldAgentOperation; -pub use custom_world_agent_session_table::*; -pub use custom_world_agent_session_type::CustomWorldAgentSession; -pub use custom_world_draft_card_table::*; -pub use custom_world_draft_card_type::CustomWorldDraftCard; -pub use custom_world_gallery_entry_table::*; -pub use custom_world_gallery_entry_type::CustomWorldGalleryEntry; -pub use custom_world_generation_mode_type::CustomWorldGenerationMode; -pub use custom_world_profile_table::*; -pub use custom_world_profile_type::CustomWorldProfile; -pub use custom_world_publication_status_type::CustomWorldPublicationStatus; -pub use custom_world_role_asset_status_type::CustomWorldRoleAssetStatus; -pub use custom_world_session_status_type::CustomWorldSessionStatus; -pub use custom_world_session_table::*; -pub use custom_world_session_type::CustomWorldSession; -pub use custom_world_theme_mode_type::CustomWorldThemeMode; pub use database_migration_authorize_operator_input_type::DatabaseMigrationAuthorizeOperatorInput; -pub use database_migration_clear_retired_tables_input_type::DatabaseMigrationClearRetiredTablesInput; -pub use database_migration_clear_retired_tables_result_type::DatabaseMigrationClearRetiredTablesResult; -pub use database_migration_clear_table_stat_type::DatabaseMigrationClearTableStat; pub use database_migration_export_input_type::DatabaseMigrationExportInput; pub use database_migration_import_chunk_input_type::DatabaseMigrationImportChunkInput; pub use database_migration_import_chunk_table::*; @@ -1486,23 +1237,8 @@ pub use import_database_migration_from_file_procedure::import_database_migration pub use import_database_migration_incremental_from_chunks_procedure::import_database_migration_incremental_from_chunks; pub use import_database_migration_incremental_from_file_procedure::import_database_migration_incremental_from_file; pub use initialize_editor_generation_pricing_config_if_missing_and_return_procedure::initialize_editor_generation_pricing_config_if_missing_and_return; -pub use inventory_container_kind_type::InventoryContainerKind; -pub use inventory_equipment_slot_type::InventoryEquipmentSlot; -pub use inventory_item_rarity_type::InventoryItemRarity; -pub use inventory_item_source_kind_type::InventoryItemSourceKind; -pub use inventory_slot_table::*; -pub use inventory_slot_type::InventorySlot; -pub use jump_hop_agent_session_row_type::JumpHopAgentSessionRow; -pub use jump_hop_agent_session_table::*; -pub use jump_hop_event_row_type::JumpHopEventRow; -pub use jump_hop_event_table::*; -pub use jump_hop_leaderboard_entry_row_type::JumpHopLeaderboardEntryRow; -pub use jump_hop_leaderboard_entry_table::*; -pub use jump_hop_runtime_run_row_type::JumpHopRuntimeRunRow; -pub use jump_hop_runtime_run_table::*; -pub use jump_hop_work_profile_row_type::JumpHopWorkProfileRow; -pub use jump_hop_work_profile_table::*; pub use list_admin_accounts_and_return_procedure::list_admin_accounts_and_return; +pub use list_agc_tracking_events_procedure::list_agc_tracking_events; pub use list_asset_history_and_return_procedure::list_asset_history_and_return; pub use list_editor_agent_conversations_and_return_procedure::list_editor_agent_conversations_and_return; pub use list_editor_projects_and_return_procedure::list_editor_projects_and_return; @@ -1534,26 +1270,10 @@ pub use llm_router_quota_settlement_result_type::LlmRouterQuotaSettlementResult; pub use mark_editor_showcase_asset_refunded_and_return_procedure::mark_editor_showcase_asset_refunded_and_return; pub use mark_profile_recharge_order_expiration_checked_procedure::mark_profile_recharge_order_expiration_checked; pub use mark_profile_recharge_order_paid_and_return_procedure::mark_profile_recharge_order_paid_and_return; -pub use match_3_d_agent_message_row_type::Match3DAgentMessageRow; -pub use match_3_d_agent_message_table::*; -pub use match_3_d_agent_session_row_type::Match3DAgentSessionRow; -pub use match_3_d_agent_session_table::*; -pub use match_3_d_runtime_run_row_type::Match3DRuntimeRunRow; -pub use match_3_d_runtime_run_table::*; -pub use match_3_d_work_profile_row_type::Match3DWorkProfileRow; -pub use match_3_d_work_profile_table::*; pub use normalize_editor_character_animation_metadata_and_return_procedure::normalize_editor_character_animation_metadata_and_return; -pub use npc_relation_stance_type::NpcRelationStance; -pub use npc_relation_state_type::NpcRelationState; -pub use npc_stance_profile_type::NpcStanceProfile; -pub use npc_state_table::*; -pub use npc_state_type::NpcState; pub use persist_editor_generation_result_and_return_procedure::persist_editor_generation_result_and_return; pub use persist_editor_pixel_art_result_and_return_procedure::persist_editor_pixel_art_result_and_return; pub use persist_editor_spritesheet_slice_batch_and_return_procedure::persist_editor_spritesheet_slice_batch_and_return; -pub use player_progression_grant_source_type::PlayerProgressionGrantSource; -pub use player_progression_table::*; -pub use player_progression_type::PlayerProgression; pub use preflight_editor_generation_target_and_return_procedure::preflight_editor_generation_target_and_return; pub use preflight_editor_pixel_art_result_and_return_procedure::preflight_editor_pixel_art_result_and_return; pub use prepare_profile_recharge_refund_hold_and_return_procedure::prepare_profile_recharge_refund_hold_and_return; @@ -1621,59 +1341,7 @@ pub use public_work_like_type::PublicWorkLike; pub use public_work_play_daily_stat_table::*; pub use public_work_play_daily_stat_type::PublicWorkPlayDailyStat; pub use put_database_migration_import_chunk_procedure::put_database_migration_import_chunk; -pub use puzzle_agent_message_kind_type::PuzzleAgentMessageKind; -pub use puzzle_agent_message_role_type::PuzzleAgentMessageRole; -pub use puzzle_agent_message_row_type::PuzzleAgentMessageRow; -pub use puzzle_agent_message_table::*; -pub use puzzle_agent_session_row_type::PuzzleAgentSessionRow; -pub use puzzle_agent_session_table::*; -pub use puzzle_agent_stage_type::PuzzleAgentStage; -pub use puzzle_background_compile_task_row_type::PuzzleBackgroundCompileTaskRow; -pub use puzzle_background_compile_task_table::*; -pub use puzzle_clear_agent_session_row_type::PuzzleClearAgentSessionRow; -pub use puzzle_clear_agent_session_table::*; -pub use puzzle_clear_event_row_type::PuzzleClearEventRow; -pub use puzzle_clear_event_table::*; -pub use puzzle_clear_runtime_run_row_type::PuzzleClearRuntimeRunRow; -pub use puzzle_clear_runtime_run_table::*; -pub use puzzle_clear_work_profile_row_type::PuzzleClearWorkProfileRow; -pub use puzzle_clear_work_profile_table::*; -pub use puzzle_event_kind_type::PuzzleEventKind; -pub use puzzle_event_table::*; -pub use puzzle_event_type::PuzzleEvent; -pub use puzzle_leaderboard_entry_row_type::PuzzleLeaderboardEntryRow; -pub use puzzle_leaderboard_entry_table::*; -pub use puzzle_publication_status_type::PuzzlePublicationStatus; -pub use puzzle_runtime_run_row_type::PuzzleRuntimeRunRow; -pub use puzzle_runtime_run_table::*; -pub use puzzle_work_profile_row_type::PuzzleWorkProfileRow; -pub use puzzle_work_profile_table::*; pub use query_analytics_metric_procedure::query_analytics_metric; -pub use quest_hostile_npc_defeated_signal_type::QuestHostileNpcDefeatedSignal; -pub use quest_item_delivered_signal_type::QuestItemDeliveredSignal; -pub use quest_log_event_kind_type::QuestLogEventKind; -pub use quest_log_table::*; -pub use quest_log_type::QuestLog; -pub use quest_narrative_binding_snapshot_type::QuestNarrativeBindingSnapshot; -pub use quest_narrative_origin_type::QuestNarrativeOrigin; -pub use quest_narrative_type_type::QuestNarrativeType; -pub use quest_npc_spar_completed_signal_type::QuestNpcSparCompletedSignal; -pub use quest_npc_talk_completed_signal_type::QuestNpcTalkCompletedSignal; -pub use quest_objective_kind_type::QuestObjectiveKind; -pub use quest_objective_snapshot_type::QuestObjectiveSnapshot; -pub use quest_progress_signal_type::QuestProgressSignal; -pub use quest_record_table::*; -pub use quest_record_type::QuestRecord; -pub use quest_reward_equipment_slot_type::QuestRewardEquipmentSlot; -pub use quest_reward_intel_type::QuestRewardIntel; -pub use quest_reward_item_rarity_type::QuestRewardItemRarity; -pub use quest_reward_item_type::QuestRewardItem; -pub use quest_reward_snapshot_type::QuestRewardSnapshot; -pub use quest_scene_reached_signal_type::QuestSceneReachedSignal; -pub use quest_signal_kind_type::QuestSignalKind; -pub use quest_status_type::QuestStatus; -pub use quest_step_snapshot_type::QuestStepSnapshot; -pub use quest_treasure_inspected_signal_type::QuestTreasureInspectedSignal; pub use read_agc_model_catalog_procedure::read_agc_model_catalog; pub use record_daily_login_tracking_event_and_return_procedure::record_daily_login_tracking_event_and_return; pub use record_profile_recharge_refund_observation_and_return_procedure::record_profile_recharge_refund_observation_and_return; @@ -1697,17 +1365,7 @@ pub use revoke_database_migration_operator_procedure::revoke_database_migration_ pub use revoke_external_api_key_and_return_procedure::revoke_external_api_key_and_return; pub use rollback_editor_canvas_layout_and_return_procedure::rollback_editor_canvas_layout_and_return; pub use rotate_editor_generation_runtime_service_identity_and_return_procedure::rotate_editor_generation_runtime_service_identity_and_return; -pub use rpg_agent_draft_card_kind_type::RpgAgentDraftCardKind; -pub use rpg_agent_draft_card_status_type::RpgAgentDraftCardStatus; -pub use rpg_agent_message_kind_type::RpgAgentMessageKind; -pub use rpg_agent_message_role_type::RpgAgentMessageRole; -pub use rpg_agent_operation_status_type::RpgAgentOperationStatus; -pub use rpg_agent_operation_type_type::RpgAgentOperationType; -pub use rpg_agent_stage_type::RpgAgentStage; pub use runtime_browse_history_theme_mode_type::RuntimeBrowseHistoryThemeMode; -pub use runtime_item_equipment_slot_type::RuntimeItemEquipmentSlot; -pub use runtime_item_reward_item_rarity_type::RuntimeItemRewardItemRarity; -pub use runtime_item_reward_item_snapshot_type::RuntimeItemRewardItemSnapshot; pub use runtime_platform_theme_type::RuntimePlatformTheme; pub use runtime_profile_admin_wallet_detail_procedure_result_type::RuntimeProfileAdminWalletDetailProcedureResult; pub use runtime_profile_admin_wallet_get_input_type::RuntimeProfileAdminWalletGetInput; @@ -1856,22 +1514,8 @@ pub use save_editor_project_layout_v_2_and_return_procedure::save_editor_project pub use seed_analytics_date_dimensions_reducer::seed_analytics_date_dimensions; pub use set_editor_showcase_asset_like_for_viewer_and_return_procedure::set_editor_showcase_asset_like_for_viewer_and_return; pub use settle_llm_router_quota_and_return_procedure::settle_llm_router_quota_and_return; -pub use square_hole_agent_message_row_type::SquareHoleAgentMessageRow; -pub use square_hole_agent_message_table::*; -pub use square_hole_agent_session_row_type::SquareHoleAgentSessionRow; -pub use square_hole_agent_session_table::*; -pub use square_hole_runtime_run_row_type::SquareHoleRuntimeRunRow; -pub use square_hole_runtime_run_table::*; -pub use square_hole_work_profile_row_type::SquareHoleWorkProfileRow; -pub use square_hole_work_profile_table::*; pub use start_ai_task_reducer::start_ai_task; pub use start_ai_task_stage_reducer::start_ai_task_stage; -pub use story_event_kind_type::StoryEventKind; -pub use story_event_table::*; -pub use story_event_type::StoryEvent; -pub use story_session_status_type::StorySessionStatus; -pub use story_session_table::*; -pub use story_session_type::StorySession; pub use submit_editor_showcase_asset_and_return_procedure::submit_editor_showcase_asset_and_return; pub use submit_game_distribution_version_for_review_and_return_procedure::submit_game_distribution_version_for_review_and_return; pub use submit_profile_feedback_and_return_procedure::submit_profile_feedback_and_return; @@ -1882,9 +1526,6 @@ pub use tracking_daily_stat_table::*; pub use tracking_daily_stat_type::TrackingDailyStat; pub use tracking_event_table::*; pub use tracking_event_type::TrackingEvent; -pub use treasure_interaction_action_type::TreasureInteractionAction; -pub use treasure_record_table::*; -pub use treasure_record_type::TreasureRecord; pub use unpublish_game_distribution_game_and_return_procedure::unpublish_game_distribution_game_and_return; pub use update_admin_account_and_return_procedure::update_admin_account_and_return; pub use update_editor_asset_and_return_procedure::update_editor_asset_and_return; @@ -1893,6 +1534,7 @@ pub use update_editor_project_resource_showcase_and_return_procedure::update_edi pub use update_editor_showcase_asset_display_and_return_procedure::update_editor_showcase_asset_display_and_return; pub use update_error_report_and_return_procedure::update_error_report_and_return; pub use update_external_generation_job_phase_and_return_procedure::update_external_generation_job_phase_and_return; +pub use upload_agc_analytics_batch_procedure::upload_agc_analytics_batch; pub use upsert_editor_generation_pricing_config_and_return_procedure::upsert_editor_generation_pricing_config_and_return; pub use upsert_editor_showcase_campaign_config_and_return_procedure::upsert_editor_showcase_campaign_config_and_return; pub use upsert_feature_gate_config_procedure::upsert_feature_gate_config; @@ -1903,26 +1545,6 @@ pub use user_account_type::UserAccount; pub use user_browse_history_table::*; pub use user_browse_history_type::UserBrowseHistory; pub use validate_auth_session_procedure::validate_auth_session; -pub use visual_novel_agent_message_row_type::VisualNovelAgentMessageRow; -pub use visual_novel_agent_message_table::*; -pub use visual_novel_agent_session_row_type::VisualNovelAgentSessionRow; -pub use visual_novel_agent_session_table::*; -pub use visual_novel_runtime_event_table::*; -pub use visual_novel_runtime_event_type::VisualNovelRuntimeEvent; -pub use visual_novel_runtime_history_entry_row_type::VisualNovelRuntimeHistoryEntryRow; -pub use visual_novel_runtime_history_entry_table::*; -pub use visual_novel_runtime_run_row_type::VisualNovelRuntimeRunRow; -pub use visual_novel_runtime_run_table::*; -pub use visual_novel_work_profile_row_type::VisualNovelWorkProfileRow; -pub use visual_novel_work_profile_table::*; -pub use wooden_fish_agent_session_row_type::WoodenFishAgentSessionRow; -pub use wooden_fish_agent_session_table::*; -pub use wooden_fish_event_row_type::WoodenFishEventRow; -pub use wooden_fish_event_table::*; -pub use wooden_fish_runtime_run_row_type::WoodenFishRuntimeRunRow; -pub use wooden_fish_runtime_run_table::*; -pub use wooden_fish_work_profile_row_type::WoodenFishWorkProfileRow; -pub use wooden_fish_work_profile_table::*; #[derive(Clone, PartialEq, Debug)] @@ -2034,6 +1656,7 @@ impl __sdk::Reducer for Reducer { pub struct DbUpdate { admin_account: __sdk::TableUpdate, agc_model_catalog: __sdk::TableUpdate, + agc_tracking_event: __sdk::TableUpdate, ai_result_reference: __sdk::TableUpdate, ai_task: __sdk::TableUpdate, ai_task_event: __sdk::TableUpdate, @@ -2046,29 +1669,8 @@ pub struct DbUpdate { asset_operation_wallet_settlement: __sdk::TableUpdate, auth_identity: __sdk::TableUpdate, auth_store_projection_meta: __sdk::TableUpdate, - bark_battle_draft_config: __sdk::TableUpdate, - bark_battle_leaderboard_entry: __sdk::TableUpdate, - bark_battle_personal_best_projection: __sdk::TableUpdate, - bark_battle_published_config: __sdk::TableUpdate, - bark_battle_runtime_run: __sdk::TableUpdate, - bark_battle_score_record: __sdk::TableUpdate, - bark_battle_work_stats_projection: __sdk::TableUpdate, - battle_state: __sdk::TableUpdate, - big_fish_agent_message: __sdk::TableUpdate, - big_fish_asset_slot: __sdk::TableUpdate, - big_fish_creation_session: __sdk::TableUpdate, - big_fish_event: __sdk::TableUpdate, - big_fish_runtime_run: __sdk::TableUpdate, - chapter_progression: __sdk::TableUpdate, creation_entry_config: __sdk::TableUpdate, creation_entry_type_config: __sdk::TableUpdate, - custom_world_agent_message: __sdk::TableUpdate, - custom_world_agent_operation: __sdk::TableUpdate, - custom_world_agent_session: __sdk::TableUpdate, - custom_world_draft_card: __sdk::TableUpdate, - custom_world_gallery_entry: __sdk::TableUpdate, - custom_world_profile: __sdk::TableUpdate, - custom_world_session: __sdk::TableUpdate, database_migration_import_chunk: __sdk::TableUpdate, database_migration_operator: __sdk::TableUpdate, editor_agent_conversation: __sdk::TableUpdate, @@ -2099,20 +1701,8 @@ pub struct DbUpdate { game_distribution_game: __sdk::TableUpdate, game_distribution_idempotency_receipt: __sdk::TableUpdate, game_distribution_version: __sdk::TableUpdate, - inventory_slot: __sdk::TableUpdate, - jump_hop_agent_session: __sdk::TableUpdate, - jump_hop_event: __sdk::TableUpdate, - jump_hop_leaderboard_entry: __sdk::TableUpdate, - jump_hop_runtime_run: __sdk::TableUpdate, - jump_hop_work_profile: __sdk::TableUpdate, llm_router_account: __sdk::TableUpdate, llm_router_billing_checkpoint: __sdk::TableUpdate, - match_3_d_agent_message: __sdk::TableUpdate, - match_3_d_agent_session: __sdk::TableUpdate, - match_3_d_runtime_run: __sdk::TableUpdate, - match_3_d_work_profile: __sdk::TableUpdate, - npc_state: __sdk::TableUpdate, - player_progression: __sdk::TableUpdate, profile_code_operation: __sdk::TableUpdate, profile_daily_free_points: __sdk::TableUpdate, profile_dashboard_state: __sdk::TableUpdate, @@ -2147,43 +1737,13 @@ pub struct DbUpdate { profile_wallet_refund_outbox: __sdk::TableUpdate, public_work_like: __sdk::TableUpdate, public_work_play_daily_stat: __sdk::TableUpdate, - puzzle_agent_message: __sdk::TableUpdate, - puzzle_agent_session: __sdk::TableUpdate, - puzzle_background_compile_task: __sdk::TableUpdate, - puzzle_clear_agent_session: __sdk::TableUpdate, - puzzle_clear_event: __sdk::TableUpdate, - puzzle_clear_runtime_run: __sdk::TableUpdate, - puzzle_clear_work_profile: __sdk::TableUpdate, - puzzle_event: __sdk::TableUpdate, - puzzle_leaderboard_entry: __sdk::TableUpdate, - puzzle_runtime_run: __sdk::TableUpdate, - puzzle_work_profile: __sdk::TableUpdate, - quest_log: __sdk::TableUpdate, - quest_record: __sdk::TableUpdate, refresh_session: __sdk::TableUpdate, runtime_setting: __sdk::TableUpdate, runtime_snapshot: __sdk::TableUpdate, - square_hole_agent_message: __sdk::TableUpdate, - square_hole_agent_session: __sdk::TableUpdate, - square_hole_runtime_run: __sdk::TableUpdate, - square_hole_work_profile: __sdk::TableUpdate, - story_event: __sdk::TableUpdate, - story_session: __sdk::TableUpdate, tracking_daily_stat: __sdk::TableUpdate, tracking_event: __sdk::TableUpdate, - treasure_record: __sdk::TableUpdate, user_account: __sdk::TableUpdate, user_browse_history: __sdk::TableUpdate, - visual_novel_agent_message: __sdk::TableUpdate, - visual_novel_agent_session: __sdk::TableUpdate, - visual_novel_runtime_event: __sdk::TableUpdate, - visual_novel_runtime_history_entry: __sdk::TableUpdate, - visual_novel_runtime_run: __sdk::TableUpdate, - visual_novel_work_profile: __sdk::TableUpdate, - wooden_fish_agent_session: __sdk::TableUpdate, - wooden_fish_event: __sdk::TableUpdate, - wooden_fish_runtime_run: __sdk::TableUpdate, - wooden_fish_work_profile: __sdk::TableUpdate, } impl TryFrom<__ws::v2::TransactionUpdate> for DbUpdate { @@ -2198,6 +1758,9 @@ impl TryFrom<__ws::v2::TransactionUpdate> for DbUpdate { "agc_model_catalog" => db_update .agc_model_catalog .append(agc_model_catalog_table::parse_table_update(table_update)?), + "agc_tracking_event" => db_update + .agc_tracking_event + .append(agc_tracking_event_table::parse_table_update(table_update)?), "ai_result_reference" => db_update .ai_result_reference .append(ai_result_reference_table::parse_table_update(table_update)?), @@ -2236,81 +1799,12 @@ impl TryFrom<__ws::v2::TransactionUpdate> for DbUpdate { "auth_store_projection_meta" => db_update.auth_store_projection_meta.append( auth_store_projection_meta_table::parse_table_update(table_update)?, ), - "bark_battle_draft_config" => db_update.bark_battle_draft_config.append( - bark_battle_draft_config_table::parse_table_update(table_update)?, - ), - "bark_battle_leaderboard_entry" => db_update.bark_battle_leaderboard_entry.append( - bark_battle_leaderboard_entry_table::parse_table_update(table_update)?, - ), - "bark_battle_personal_best_projection" => { - db_update.bark_battle_personal_best_projection.append( - bark_battle_personal_best_projection_table::parse_table_update( - table_update, - )?, - ) - } - "bark_battle_published_config" => db_update.bark_battle_published_config.append( - bark_battle_published_config_table::parse_table_update(table_update)?, - ), - "bark_battle_runtime_run" => db_update.bark_battle_runtime_run.append( - bark_battle_runtime_run_table::parse_table_update(table_update)?, - ), - "bark_battle_score_record" => db_update.bark_battle_score_record.append( - bark_battle_score_record_table::parse_table_update(table_update)?, - ), - "bark_battle_work_stats_projection" => { - db_update.bark_battle_work_stats_projection.append( - bark_battle_work_stats_projection_table::parse_table_update(table_update)?, - ) - } - "battle_state" => db_update - .battle_state - .append(battle_state_table::parse_table_update(table_update)?), - "big_fish_agent_message" => db_update.big_fish_agent_message.append( - big_fish_agent_message_table::parse_table_update(table_update)?, - ), - "big_fish_asset_slot" => db_update - .big_fish_asset_slot - .append(big_fish_asset_slot_table::parse_table_update(table_update)?), - "big_fish_creation_session" => db_update.big_fish_creation_session.append( - big_fish_creation_session_table::parse_table_update(table_update)?, - ), - "big_fish_event" => db_update - .big_fish_event - .append(big_fish_event_table::parse_table_update(table_update)?), - "big_fish_runtime_run" => db_update.big_fish_runtime_run.append( - big_fish_runtime_run_table::parse_table_update(table_update)?, - ), - "chapter_progression" => db_update - .chapter_progression - .append(chapter_progression_table::parse_table_update(table_update)?), "creation_entry_config" => db_update.creation_entry_config.append( creation_entry_config_table::parse_table_update(table_update)?, ), "creation_entry_type_config" => db_update.creation_entry_type_config.append( creation_entry_type_config_table::parse_table_update(table_update)?, ), - "custom_world_agent_message" => db_update.custom_world_agent_message.append( - custom_world_agent_message_table::parse_table_update(table_update)?, - ), - "custom_world_agent_operation" => db_update.custom_world_agent_operation.append( - custom_world_agent_operation_table::parse_table_update(table_update)?, - ), - "custom_world_agent_session" => db_update.custom_world_agent_session.append( - custom_world_agent_session_table::parse_table_update(table_update)?, - ), - "custom_world_draft_card" => db_update.custom_world_draft_card.append( - custom_world_draft_card_table::parse_table_update(table_update)?, - ), - "custom_world_gallery_entry" => db_update.custom_world_gallery_entry.append( - custom_world_gallery_entry_table::parse_table_update(table_update)?, - ), - "custom_world_profile" => db_update.custom_world_profile.append( - custom_world_profile_table::parse_table_update(table_update)?, - ), - "custom_world_session" => db_update.custom_world_session.append( - custom_world_session_table::parse_table_update(table_update)?, - ), "database_migration_import_chunk" => { db_update.database_migration_import_chunk.append( database_migration_import_chunk_table::parse_table_update(table_update)?, @@ -2424,48 +1918,12 @@ impl TryFrom<__ws::v2::TransactionUpdate> for DbUpdate { "game_distribution_version" => db_update.game_distribution_version.append( game_distribution_version_table::parse_table_update(table_update)?, ), - "inventory_slot" => db_update - .inventory_slot - .append(inventory_slot_table::parse_table_update(table_update)?), - "jump_hop_agent_session" => db_update.jump_hop_agent_session.append( - jump_hop_agent_session_table::parse_table_update(table_update)?, - ), - "jump_hop_event" => db_update - .jump_hop_event - .append(jump_hop_event_table::parse_table_update(table_update)?), - "jump_hop_leaderboard_entry" => db_update.jump_hop_leaderboard_entry.append( - jump_hop_leaderboard_entry_table::parse_table_update(table_update)?, - ), - "jump_hop_runtime_run" => db_update.jump_hop_runtime_run.append( - jump_hop_runtime_run_table::parse_table_update(table_update)?, - ), - "jump_hop_work_profile" => db_update.jump_hop_work_profile.append( - jump_hop_work_profile_table::parse_table_update(table_update)?, - ), "llm_router_account" => db_update .llm_router_account .append(llm_router_account_table::parse_table_update(table_update)?), "llm_router_billing_checkpoint" => db_update.llm_router_billing_checkpoint.append( llm_router_billing_checkpoint_table::parse_table_update(table_update)?, ), - "match_3_d_agent_message" => db_update.match_3_d_agent_message.append( - match_3_d_agent_message_table::parse_table_update(table_update)?, - ), - "match_3_d_agent_session" => db_update.match_3_d_agent_session.append( - match_3_d_agent_session_table::parse_table_update(table_update)?, - ), - "match_3_d_runtime_run" => db_update.match_3_d_runtime_run.append( - match_3_d_runtime_run_table::parse_table_update(table_update)?, - ), - "match_3_d_work_profile" => db_update.match_3_d_work_profile.append( - match_3_d_work_profile_table::parse_table_update(table_update)?, - ), - "npc_state" => db_update - .npc_state - .append(npc_state_table::parse_table_update(table_update)?), - "player_progression" => db_update - .player_progression - .append(player_progression_table::parse_table_update(table_update)?), "profile_code_operation" => db_update.profile_code_operation.append( profile_code_operation_table::parse_table_update(table_update)?, ), @@ -2582,47 +2040,6 @@ impl TryFrom<__ws::v2::TransactionUpdate> for DbUpdate { "public_work_play_daily_stat" => db_update.public_work_play_daily_stat.append( public_work_play_daily_stat_table::parse_table_update(table_update)?, ), - "puzzle_agent_message" => db_update.puzzle_agent_message.append( - puzzle_agent_message_table::parse_table_update(table_update)?, - ), - "puzzle_agent_session" => db_update.puzzle_agent_session.append( - puzzle_agent_session_table::parse_table_update(table_update)?, - ), - "puzzle_background_compile_task" => { - db_update.puzzle_background_compile_task.append( - puzzle_background_compile_task_table::parse_table_update(table_update)?, - ) - } - "puzzle_clear_agent_session" => db_update.puzzle_clear_agent_session.append( - puzzle_clear_agent_session_table::parse_table_update(table_update)?, - ), - "puzzle_clear_event" => db_update - .puzzle_clear_event - .append(puzzle_clear_event_table::parse_table_update(table_update)?), - "puzzle_clear_runtime_run" => db_update.puzzle_clear_runtime_run.append( - puzzle_clear_runtime_run_table::parse_table_update(table_update)?, - ), - "puzzle_clear_work_profile" => db_update.puzzle_clear_work_profile.append( - puzzle_clear_work_profile_table::parse_table_update(table_update)?, - ), - "puzzle_event" => db_update - .puzzle_event - .append(puzzle_event_table::parse_table_update(table_update)?), - "puzzle_leaderboard_entry" => db_update.puzzle_leaderboard_entry.append( - puzzle_leaderboard_entry_table::parse_table_update(table_update)?, - ), - "puzzle_runtime_run" => db_update - .puzzle_runtime_run - .append(puzzle_runtime_run_table::parse_table_update(table_update)?), - "puzzle_work_profile" => db_update - .puzzle_work_profile - .append(puzzle_work_profile_table::parse_table_update(table_update)?), - "quest_log" => db_update - .quest_log - .append(quest_log_table::parse_table_update(table_update)?), - "quest_record" => db_update - .quest_record - .append(quest_record_table::parse_table_update(table_update)?), "refresh_session" => db_update .refresh_session .append(refresh_session_table::parse_table_update(table_update)?), @@ -2632,71 +2049,18 @@ impl TryFrom<__ws::v2::TransactionUpdate> for DbUpdate { "runtime_snapshot" => db_update .runtime_snapshot .append(runtime_snapshot_table::parse_table_update(table_update)?), - "square_hole_agent_message" => db_update.square_hole_agent_message.append( - square_hole_agent_message_table::parse_table_update(table_update)?, - ), - "square_hole_agent_session" => db_update.square_hole_agent_session.append( - square_hole_agent_session_table::parse_table_update(table_update)?, - ), - "square_hole_runtime_run" => db_update.square_hole_runtime_run.append( - square_hole_runtime_run_table::parse_table_update(table_update)?, - ), - "square_hole_work_profile" => db_update.square_hole_work_profile.append( - square_hole_work_profile_table::parse_table_update(table_update)?, - ), - "story_event" => db_update - .story_event - .append(story_event_table::parse_table_update(table_update)?), - "story_session" => db_update - .story_session - .append(story_session_table::parse_table_update(table_update)?), "tracking_daily_stat" => db_update .tracking_daily_stat .append(tracking_daily_stat_table::parse_table_update(table_update)?), "tracking_event" => db_update .tracking_event .append(tracking_event_table::parse_table_update(table_update)?), - "treasure_record" => db_update - .treasure_record - .append(treasure_record_table::parse_table_update(table_update)?), "user_account" => db_update .user_account .append(user_account_table::parse_table_update(table_update)?), "user_browse_history" => db_update .user_browse_history .append(user_browse_history_table::parse_table_update(table_update)?), - "visual_novel_agent_message" => db_update.visual_novel_agent_message.append( - visual_novel_agent_message_table::parse_table_update(table_update)?, - ), - "visual_novel_agent_session" => db_update.visual_novel_agent_session.append( - visual_novel_agent_session_table::parse_table_update(table_update)?, - ), - "visual_novel_runtime_event" => db_update.visual_novel_runtime_event.append( - visual_novel_runtime_event_table::parse_table_update(table_update)?, - ), - "visual_novel_runtime_history_entry" => { - db_update.visual_novel_runtime_history_entry.append( - visual_novel_runtime_history_entry_table::parse_table_update(table_update)?, - ) - } - "visual_novel_runtime_run" => db_update.visual_novel_runtime_run.append( - visual_novel_runtime_run_table::parse_table_update(table_update)?, - ), - "visual_novel_work_profile" => db_update.visual_novel_work_profile.append( - visual_novel_work_profile_table::parse_table_update(table_update)?, - ), - "wooden_fish_agent_session" => db_update.wooden_fish_agent_session.append( - wooden_fish_agent_session_table::parse_table_update(table_update)?, - ), - "wooden_fish_event" => db_update - .wooden_fish_event - .append(wooden_fish_event_table::parse_table_update(table_update)?), - "wooden_fish_runtime_run" => db_update.wooden_fish_runtime_run.append( - wooden_fish_runtime_run_table::parse_table_update(table_update)?, - ), - "wooden_fish_work_profile" => db_update.wooden_fish_work_profile.append( - wooden_fish_work_profile_table::parse_table_update(table_update)?, - ), unknown => { return Err(__sdk::InternalError::unknown_name( @@ -2729,6 +2093,9 @@ impl __sdk::DbUpdate for DbUpdate { diff.agc_model_catalog = cache .apply_diff_to_table::("agc_model_catalog", &self.agc_model_catalog) .with_updates_by_pk(|row| &row.id); + diff.agc_tracking_event = cache + .apply_diff_to_table::("agc_tracking_event", &self.agc_tracking_event) + .with_updates_by_pk(|row| &row.event_id); diff.ai_result_reference = cache .apply_diff_to_table::( "ai_result_reference", @@ -2776,82 +2143,6 @@ impl __sdk::DbUpdate for DbUpdate { &self.auth_store_projection_meta, ) .with_updates_by_pk(|row| &row.meta_id); - diff.bark_battle_draft_config = cache - .apply_diff_to_table::( - "bark_battle_draft_config", - &self.bark_battle_draft_config, - ) - .with_updates_by_pk(|row| &row.draft_id); - diff.bark_battle_leaderboard_entry = cache - .apply_diff_to_table::( - "bark_battle_leaderboard_entry", - &self.bark_battle_leaderboard_entry, - ) - .with_updates_by_pk(|row| &row.leaderboard_entry_id); - diff.bark_battle_personal_best_projection = cache - .apply_diff_to_table::( - "bark_battle_personal_best_projection", - &self.bark_battle_personal_best_projection, - ) - .with_updates_by_pk(|row| &row.personal_best_id); - diff.bark_battle_published_config = cache - .apply_diff_to_table::( - "bark_battle_published_config", - &self.bark_battle_published_config, - ) - .with_updates_by_pk(|row| &row.work_id); - diff.bark_battle_runtime_run = cache - .apply_diff_to_table::( - "bark_battle_runtime_run", - &self.bark_battle_runtime_run, - ) - .with_updates_by_pk(|row| &row.run_id); - diff.bark_battle_score_record = cache - .apply_diff_to_table::( - "bark_battle_score_record", - &self.bark_battle_score_record, - ) - .with_updates_by_pk(|row| &row.score_id); - diff.bark_battle_work_stats_projection = cache - .apply_diff_to_table::( - "bark_battle_work_stats_projection", - &self.bark_battle_work_stats_projection, - ) - .with_updates_by_pk(|row| &row.work_id); - diff.battle_state = cache - .apply_diff_to_table::("battle_state", &self.battle_state) - .with_updates_by_pk(|row| &row.battle_state_id); - diff.big_fish_agent_message = cache - .apply_diff_to_table::( - "big_fish_agent_message", - &self.big_fish_agent_message, - ) - .with_updates_by_pk(|row| &row.message_id); - diff.big_fish_asset_slot = cache - .apply_diff_to_table::( - "big_fish_asset_slot", - &self.big_fish_asset_slot, - ) - .with_updates_by_pk(|row| &row.slot_id); - diff.big_fish_creation_session = cache - .apply_diff_to_table::( - "big_fish_creation_session", - &self.big_fish_creation_session, - ) - .with_updates_by_pk(|row| &row.session_id); - diff.big_fish_event = self.big_fish_event.into_event_diff(); - diff.big_fish_runtime_run = cache - .apply_diff_to_table::( - "big_fish_runtime_run", - &self.big_fish_runtime_run, - ) - .with_updates_by_pk(|row| &row.run_id); - diff.chapter_progression = cache - .apply_diff_to_table::( - "chapter_progression", - &self.chapter_progression, - ) - .with_updates_by_pk(|row| &row.chapter_progression_id); diff.creation_entry_config = cache .apply_diff_to_table::( "creation_entry_config", @@ -2864,48 +2155,6 @@ impl __sdk::DbUpdate for DbUpdate { &self.creation_entry_type_config, ) .with_updates_by_pk(|row| &row.id); - diff.custom_world_agent_message = cache - .apply_diff_to_table::( - "custom_world_agent_message", - &self.custom_world_agent_message, - ) - .with_updates_by_pk(|row| &row.message_id); - diff.custom_world_agent_operation = cache - .apply_diff_to_table::( - "custom_world_agent_operation", - &self.custom_world_agent_operation, - ) - .with_updates_by_pk(|row| &row.operation_id); - diff.custom_world_agent_session = cache - .apply_diff_to_table::( - "custom_world_agent_session", - &self.custom_world_agent_session, - ) - .with_updates_by_pk(|row| &row.session_id); - diff.custom_world_draft_card = cache - .apply_diff_to_table::( - "custom_world_draft_card", - &self.custom_world_draft_card, - ) - .with_updates_by_pk(|row| &row.card_id); - diff.custom_world_gallery_entry = cache - .apply_diff_to_table::( - "custom_world_gallery_entry", - &self.custom_world_gallery_entry, - ) - .with_updates_by_pk(|row| &row.profile_id); - diff.custom_world_profile = cache - .apply_diff_to_table::( - "custom_world_profile", - &self.custom_world_profile, - ) - .with_updates_by_pk(|row| &row.profile_id); - diff.custom_world_session = cache - .apply_diff_to_table::( - "custom_world_session", - &self.custom_world_session, - ) - .with_updates_by_pk(|row| &row.session_id); diff.database_migration_import_chunk = cache .apply_diff_to_table::( "database_migration_import_chunk", @@ -3065,36 +2314,6 @@ impl __sdk::DbUpdate for DbUpdate { &self.game_distribution_version, ) .with_updates_by_pk(|row| &row.version_id); - diff.inventory_slot = cache - .apply_diff_to_table::("inventory_slot", &self.inventory_slot) - .with_updates_by_pk(|row| &row.slot_id); - diff.jump_hop_agent_session = cache - .apply_diff_to_table::( - "jump_hop_agent_session", - &self.jump_hop_agent_session, - ) - .with_updates_by_pk(|row| &row.session_id); - diff.jump_hop_event = cache - .apply_diff_to_table::("jump_hop_event", &self.jump_hop_event) - .with_updates_by_pk(|row| &row.event_id); - diff.jump_hop_leaderboard_entry = cache - .apply_diff_to_table::( - "jump_hop_leaderboard_entry", - &self.jump_hop_leaderboard_entry, - ) - .with_updates_by_pk(|row| &row.entry_id); - diff.jump_hop_runtime_run = cache - .apply_diff_to_table::( - "jump_hop_runtime_run", - &self.jump_hop_runtime_run, - ) - .with_updates_by_pk(|row| &row.run_id); - diff.jump_hop_work_profile = cache - .apply_diff_to_table::( - "jump_hop_work_profile", - &self.jump_hop_work_profile, - ) - .with_updates_by_pk(|row| &row.profile_id); diff.llm_router_account = cache .apply_diff_to_table::("llm_router_account", &self.llm_router_account) .with_updates_by_pk(|row| &row.account_key); @@ -3104,39 +2323,6 @@ impl __sdk::DbUpdate for DbUpdate { &self.llm_router_billing_checkpoint, ) .with_updates_by_pk(|row| &row.account_key); - diff.match_3_d_agent_message = cache - .apply_diff_to_table::( - "match_3_d_agent_message", - &self.match_3_d_agent_message, - ) - .with_updates_by_pk(|row| &row.message_id); - diff.match_3_d_agent_session = cache - .apply_diff_to_table::( - "match_3_d_agent_session", - &self.match_3_d_agent_session, - ) - .with_updates_by_pk(|row| &row.session_id); - diff.match_3_d_runtime_run = cache - .apply_diff_to_table::( - "match_3_d_runtime_run", - &self.match_3_d_runtime_run, - ) - .with_updates_by_pk(|row| &row.run_id); - diff.match_3_d_work_profile = cache - .apply_diff_to_table::( - "match_3_d_work_profile", - &self.match_3_d_work_profile, - ) - .with_updates_by_pk(|row| &row.profile_id); - diff.npc_state = cache - .apply_diff_to_table::("npc_state", &self.npc_state) - .with_updates_by_pk(|row| &row.npc_state_id); - diff.player_progression = cache - .apply_diff_to_table::( - "player_progression", - &self.player_progression, - ) - .with_updates_by_pk(|row| &row.user_id); diff.profile_code_operation = cache .apply_diff_to_table::( "profile_code_operation", @@ -3314,73 +2500,6 @@ impl __sdk::DbUpdate for DbUpdate { &self.public_work_play_daily_stat, ) .with_updates_by_pk(|row| &row.stat_id); - diff.puzzle_agent_message = cache - .apply_diff_to_table::( - "puzzle_agent_message", - &self.puzzle_agent_message, - ) - .with_updates_by_pk(|row| &row.message_id); - diff.puzzle_agent_session = cache - .apply_diff_to_table::( - "puzzle_agent_session", - &self.puzzle_agent_session, - ) - .with_updates_by_pk(|row| &row.session_id); - diff.puzzle_background_compile_task = cache - .apply_diff_to_table::( - "puzzle_background_compile_task", - &self.puzzle_background_compile_task, - ) - .with_updates_by_pk(|row| &row.task_id); - diff.puzzle_clear_agent_session = cache - .apply_diff_to_table::( - "puzzle_clear_agent_session", - &self.puzzle_clear_agent_session, - ) - .with_updates_by_pk(|row| &row.session_id); - diff.puzzle_clear_event = cache - .apply_diff_to_table::( - "puzzle_clear_event", - &self.puzzle_clear_event, - ) - .with_updates_by_pk(|row| &row.event_id); - diff.puzzle_clear_runtime_run = cache - .apply_diff_to_table::( - "puzzle_clear_runtime_run", - &self.puzzle_clear_runtime_run, - ) - .with_updates_by_pk(|row| &row.run_id); - diff.puzzle_clear_work_profile = cache - .apply_diff_to_table::( - "puzzle_clear_work_profile", - &self.puzzle_clear_work_profile, - ) - .with_updates_by_pk(|row| &row.profile_id); - diff.puzzle_event = self.puzzle_event.into_event_diff(); - diff.puzzle_leaderboard_entry = cache - .apply_diff_to_table::( - "puzzle_leaderboard_entry", - &self.puzzle_leaderboard_entry, - ) - .with_updates_by_pk(|row| &row.entry_id); - diff.puzzle_runtime_run = cache - .apply_diff_to_table::( - "puzzle_runtime_run", - &self.puzzle_runtime_run, - ) - .with_updates_by_pk(|row| &row.run_id); - diff.puzzle_work_profile = cache - .apply_diff_to_table::( - "puzzle_work_profile", - &self.puzzle_work_profile, - ) - .with_updates_by_pk(|row| &row.profile_id); - diff.quest_log = cache - .apply_diff_to_table::("quest_log", &self.quest_log) - .with_updates_by_pk(|row| &row.log_id); - diff.quest_record = cache - .apply_diff_to_table::("quest_record", &self.quest_record) - .with_updates_by_pk(|row| &row.quest_id); diff.refresh_session = cache .apply_diff_to_table::("refresh_session", &self.refresh_session) .with_updates_by_pk(|row| &row.session_id); @@ -3390,36 +2509,6 @@ impl __sdk::DbUpdate for DbUpdate { diff.runtime_snapshot = cache .apply_diff_to_table::("runtime_snapshot", &self.runtime_snapshot) .with_updates_by_pk(|row| &row.user_id); - diff.square_hole_agent_message = cache - .apply_diff_to_table::( - "square_hole_agent_message", - &self.square_hole_agent_message, - ) - .with_updates_by_pk(|row| &row.message_id); - diff.square_hole_agent_session = cache - .apply_diff_to_table::( - "square_hole_agent_session", - &self.square_hole_agent_session, - ) - .with_updates_by_pk(|row| &row.session_id); - diff.square_hole_runtime_run = cache - .apply_diff_to_table::( - "square_hole_runtime_run", - &self.square_hole_runtime_run, - ) - .with_updates_by_pk(|row| &row.run_id); - diff.square_hole_work_profile = cache - .apply_diff_to_table::( - "square_hole_work_profile", - &self.square_hole_work_profile, - ) - .with_updates_by_pk(|row| &row.profile_id); - diff.story_event = cache - .apply_diff_to_table::("story_event", &self.story_event) - .with_updates_by_pk(|row| &row.event_id); - diff.story_session = cache - .apply_diff_to_table::("story_session", &self.story_session) - .with_updates_by_pk(|row| &row.story_session_id); diff.tracking_daily_stat = cache .apply_diff_to_table::( "tracking_daily_stat", @@ -3429,9 +2518,6 @@ impl __sdk::DbUpdate for DbUpdate { diff.tracking_event = cache .apply_diff_to_table::("tracking_event", &self.tracking_event) .with_updates_by_pk(|row| &row.event_id); - diff.treasure_record = cache - .apply_diff_to_table::("treasure_record", &self.treasure_record) - .with_updates_by_pk(|row| &row.treasure_record_id); diff.user_account = cache .apply_diff_to_table::("user_account", &self.user_account) .with_updates_by_pk(|row| &row.user_id); @@ -3441,58 +2527,6 @@ impl __sdk::DbUpdate for DbUpdate { &self.user_browse_history, ) .with_updates_by_pk(|row| &row.browse_history_id); - diff.visual_novel_agent_message = cache - .apply_diff_to_table::( - "visual_novel_agent_message", - &self.visual_novel_agent_message, - ) - .with_updates_by_pk(|row| &row.message_id); - diff.visual_novel_agent_session = cache - .apply_diff_to_table::( - "visual_novel_agent_session", - &self.visual_novel_agent_session, - ) - .with_updates_by_pk(|row| &row.session_id); - diff.visual_novel_runtime_event = self.visual_novel_runtime_event.into_event_diff(); - diff.visual_novel_runtime_history_entry = cache - .apply_diff_to_table::( - "visual_novel_runtime_history_entry", - &self.visual_novel_runtime_history_entry, - ) - .with_updates_by_pk(|row| &row.entry_id); - diff.visual_novel_runtime_run = cache - .apply_diff_to_table::( - "visual_novel_runtime_run", - &self.visual_novel_runtime_run, - ) - .with_updates_by_pk(|row| &row.run_id); - diff.visual_novel_work_profile = cache - .apply_diff_to_table::( - "visual_novel_work_profile", - &self.visual_novel_work_profile, - ) - .with_updates_by_pk(|row| &row.profile_id); - diff.wooden_fish_agent_session = cache - .apply_diff_to_table::( - "wooden_fish_agent_session", - &self.wooden_fish_agent_session, - ) - .with_updates_by_pk(|row| &row.session_id); - diff.wooden_fish_event = cache - .apply_diff_to_table::("wooden_fish_event", &self.wooden_fish_event) - .with_updates_by_pk(|row| &row.event_id); - diff.wooden_fish_runtime_run = cache - .apply_diff_to_table::( - "wooden_fish_runtime_run", - &self.wooden_fish_runtime_run, - ) - .with_updates_by_pk(|row| &row.run_id); - diff.wooden_fish_work_profile = cache - .apply_diff_to_table::( - "wooden_fish_work_profile", - &self.wooden_fish_work_profile, - ) - .with_updates_by_pk(|row| &row.profile_id); diff } @@ -3506,6 +2540,9 @@ impl __sdk::DbUpdate for DbUpdate { "agc_model_catalog" => db_update .agc_model_catalog .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), + "agc_tracking_event" => db_update + .agc_tracking_event + .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "ai_result_reference" => db_update .ai_result_reference .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), @@ -3542,75 +2579,12 @@ impl __sdk::DbUpdate for DbUpdate { "auth_store_projection_meta" => db_update .auth_store_projection_meta .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "bark_battle_draft_config" => db_update - .bark_battle_draft_config - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "bark_battle_leaderboard_entry" => db_update - .bark_battle_leaderboard_entry - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "bark_battle_personal_best_projection" => db_update - .bark_battle_personal_best_projection - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "bark_battle_published_config" => db_update - .bark_battle_published_config - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "bark_battle_runtime_run" => db_update - .bark_battle_runtime_run - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "bark_battle_score_record" => db_update - .bark_battle_score_record - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "bark_battle_work_stats_projection" => db_update - .bark_battle_work_stats_projection - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "battle_state" => db_update - .battle_state - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "big_fish_agent_message" => db_update - .big_fish_agent_message - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "big_fish_asset_slot" => db_update - .big_fish_asset_slot - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "big_fish_creation_session" => db_update - .big_fish_creation_session - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "big_fish_event" => db_update - .big_fish_event - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "big_fish_runtime_run" => db_update - .big_fish_runtime_run - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "chapter_progression" => db_update - .chapter_progression - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "creation_entry_config" => db_update .creation_entry_config .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "creation_entry_type_config" => db_update .creation_entry_type_config .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "custom_world_agent_message" => db_update - .custom_world_agent_message - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "custom_world_agent_operation" => db_update - .custom_world_agent_operation - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "custom_world_agent_session" => db_update - .custom_world_agent_session - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "custom_world_draft_card" => db_update - .custom_world_draft_card - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "custom_world_gallery_entry" => db_update - .custom_world_gallery_entry - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "custom_world_profile" => db_update - .custom_world_profile - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "custom_world_session" => db_update - .custom_world_session - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "database_migration_import_chunk" => db_update .database_migration_import_chunk .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), @@ -3698,48 +2672,12 @@ impl __sdk::DbUpdate for DbUpdate { "game_distribution_version" => db_update .game_distribution_version .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "inventory_slot" => db_update - .inventory_slot - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "jump_hop_agent_session" => db_update - .jump_hop_agent_session - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "jump_hop_event" => db_update - .jump_hop_event - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "jump_hop_leaderboard_entry" => db_update - .jump_hop_leaderboard_entry - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "jump_hop_runtime_run" => db_update - .jump_hop_runtime_run - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "jump_hop_work_profile" => db_update - .jump_hop_work_profile - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "llm_router_account" => db_update .llm_router_account .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "llm_router_billing_checkpoint" => db_update .llm_router_billing_checkpoint .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "match_3_d_agent_message" => db_update - .match_3_d_agent_message - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "match_3_d_agent_session" => db_update - .match_3_d_agent_session - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "match_3_d_runtime_run" => db_update - .match_3_d_runtime_run - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "match_3_d_work_profile" => db_update - .match_3_d_work_profile - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "npc_state" => db_update - .npc_state - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "player_progression" => db_update - .player_progression - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "profile_code_operation" => db_update .profile_code_operation .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), @@ -3830,45 +2768,6 @@ impl __sdk::DbUpdate for DbUpdate { "public_work_play_daily_stat" => db_update .public_work_play_daily_stat .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "puzzle_agent_message" => db_update - .puzzle_agent_message - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "puzzle_agent_session" => db_update - .puzzle_agent_session - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "puzzle_background_compile_task" => db_update - .puzzle_background_compile_task - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "puzzle_clear_agent_session" => db_update - .puzzle_clear_agent_session - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "puzzle_clear_event" => db_update - .puzzle_clear_event - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "puzzle_clear_runtime_run" => db_update - .puzzle_clear_runtime_run - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "puzzle_clear_work_profile" => db_update - .puzzle_clear_work_profile - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "puzzle_event" => db_update - .puzzle_event - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "puzzle_leaderboard_entry" => db_update - .puzzle_leaderboard_entry - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "puzzle_runtime_run" => db_update - .puzzle_runtime_run - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "puzzle_work_profile" => db_update - .puzzle_work_profile - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "quest_log" => db_update - .quest_log - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "quest_record" => db_update - .quest_record - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "refresh_session" => db_update .refresh_session .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), @@ -3878,69 +2777,18 @@ impl __sdk::DbUpdate for DbUpdate { "runtime_snapshot" => db_update .runtime_snapshot .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "square_hole_agent_message" => db_update - .square_hole_agent_message - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "square_hole_agent_session" => db_update - .square_hole_agent_session - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "square_hole_runtime_run" => db_update - .square_hole_runtime_run - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "square_hole_work_profile" => db_update - .square_hole_work_profile - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "story_event" => db_update - .story_event - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "story_session" => db_update - .story_session - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "tracking_daily_stat" => db_update .tracking_daily_stat .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "tracking_event" => db_update .tracking_event .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "treasure_record" => db_update - .treasure_record - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "user_account" => db_update .user_account .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "user_browse_history" => db_update .user_browse_history .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "visual_novel_agent_message" => db_update - .visual_novel_agent_message - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "visual_novel_agent_session" => db_update - .visual_novel_agent_session - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "visual_novel_runtime_event" => db_update - .visual_novel_runtime_event - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "visual_novel_runtime_history_entry" => db_update - .visual_novel_runtime_history_entry - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "visual_novel_runtime_run" => db_update - .visual_novel_runtime_run - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "visual_novel_work_profile" => db_update - .visual_novel_work_profile - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "wooden_fish_agent_session" => db_update - .wooden_fish_agent_session - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "wooden_fish_event" => db_update - .wooden_fish_event - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "wooden_fish_runtime_run" => db_update - .wooden_fish_runtime_run - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "wooden_fish_work_profile" => db_update - .wooden_fish_work_profile - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), unknown => { return Err( __sdk::InternalError::unknown_name("table", unknown, "QueryRows").into(), @@ -3960,6 +2808,9 @@ impl __sdk::DbUpdate for DbUpdate { "agc_model_catalog" => db_update .agc_model_catalog .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), + "agc_tracking_event" => db_update + .agc_tracking_event + .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "ai_result_reference" => db_update .ai_result_reference .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), @@ -3996,75 +2847,12 @@ impl __sdk::DbUpdate for DbUpdate { "auth_store_projection_meta" => db_update .auth_store_projection_meta .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "bark_battle_draft_config" => db_update - .bark_battle_draft_config - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "bark_battle_leaderboard_entry" => db_update - .bark_battle_leaderboard_entry - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "bark_battle_personal_best_projection" => db_update - .bark_battle_personal_best_projection - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "bark_battle_published_config" => db_update - .bark_battle_published_config - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "bark_battle_runtime_run" => db_update - .bark_battle_runtime_run - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "bark_battle_score_record" => db_update - .bark_battle_score_record - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "bark_battle_work_stats_projection" => db_update - .bark_battle_work_stats_projection - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "battle_state" => db_update - .battle_state - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "big_fish_agent_message" => db_update - .big_fish_agent_message - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "big_fish_asset_slot" => db_update - .big_fish_asset_slot - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "big_fish_creation_session" => db_update - .big_fish_creation_session - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "big_fish_event" => db_update - .big_fish_event - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "big_fish_runtime_run" => db_update - .big_fish_runtime_run - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "chapter_progression" => db_update - .chapter_progression - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "creation_entry_config" => db_update .creation_entry_config .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "creation_entry_type_config" => db_update .creation_entry_type_config .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "custom_world_agent_message" => db_update - .custom_world_agent_message - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "custom_world_agent_operation" => db_update - .custom_world_agent_operation - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "custom_world_agent_session" => db_update - .custom_world_agent_session - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "custom_world_draft_card" => db_update - .custom_world_draft_card - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "custom_world_gallery_entry" => db_update - .custom_world_gallery_entry - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "custom_world_profile" => db_update - .custom_world_profile - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "custom_world_session" => db_update - .custom_world_session - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "database_migration_import_chunk" => db_update .database_migration_import_chunk .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), @@ -4152,48 +2940,12 @@ impl __sdk::DbUpdate for DbUpdate { "game_distribution_version" => db_update .game_distribution_version .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "inventory_slot" => db_update - .inventory_slot - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "jump_hop_agent_session" => db_update - .jump_hop_agent_session - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "jump_hop_event" => db_update - .jump_hop_event - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "jump_hop_leaderboard_entry" => db_update - .jump_hop_leaderboard_entry - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "jump_hop_runtime_run" => db_update - .jump_hop_runtime_run - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "jump_hop_work_profile" => db_update - .jump_hop_work_profile - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "llm_router_account" => db_update .llm_router_account .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "llm_router_billing_checkpoint" => db_update .llm_router_billing_checkpoint .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "match_3_d_agent_message" => db_update - .match_3_d_agent_message - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "match_3_d_agent_session" => db_update - .match_3_d_agent_session - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "match_3_d_runtime_run" => db_update - .match_3_d_runtime_run - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "match_3_d_work_profile" => db_update - .match_3_d_work_profile - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "npc_state" => db_update - .npc_state - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "player_progression" => db_update - .player_progression - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "profile_code_operation" => db_update .profile_code_operation .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), @@ -4284,45 +3036,6 @@ impl __sdk::DbUpdate for DbUpdate { "public_work_play_daily_stat" => db_update .public_work_play_daily_stat .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "puzzle_agent_message" => db_update - .puzzle_agent_message - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "puzzle_agent_session" => db_update - .puzzle_agent_session - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "puzzle_background_compile_task" => db_update - .puzzle_background_compile_task - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "puzzle_clear_agent_session" => db_update - .puzzle_clear_agent_session - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "puzzle_clear_event" => db_update - .puzzle_clear_event - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "puzzle_clear_runtime_run" => db_update - .puzzle_clear_runtime_run - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "puzzle_clear_work_profile" => db_update - .puzzle_clear_work_profile - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "puzzle_event" => db_update - .puzzle_event - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "puzzle_leaderboard_entry" => db_update - .puzzle_leaderboard_entry - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "puzzle_runtime_run" => db_update - .puzzle_runtime_run - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "puzzle_work_profile" => db_update - .puzzle_work_profile - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "quest_log" => db_update - .quest_log - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "quest_record" => db_update - .quest_record - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "refresh_session" => db_update .refresh_session .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), @@ -4332,69 +3045,18 @@ impl __sdk::DbUpdate for DbUpdate { "runtime_snapshot" => db_update .runtime_snapshot .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "square_hole_agent_message" => db_update - .square_hole_agent_message - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "square_hole_agent_session" => db_update - .square_hole_agent_session - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "square_hole_runtime_run" => db_update - .square_hole_runtime_run - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "square_hole_work_profile" => db_update - .square_hole_work_profile - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "story_event" => db_update - .story_event - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "story_session" => db_update - .story_session - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "tracking_daily_stat" => db_update .tracking_daily_stat .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "tracking_event" => db_update .tracking_event .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "treasure_record" => db_update - .treasure_record - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "user_account" => db_update .user_account .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "user_browse_history" => db_update .user_browse_history .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "visual_novel_agent_message" => db_update - .visual_novel_agent_message - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "visual_novel_agent_session" => db_update - .visual_novel_agent_session - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "visual_novel_runtime_event" => db_update - .visual_novel_runtime_event - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "visual_novel_runtime_history_entry" => db_update - .visual_novel_runtime_history_entry - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "visual_novel_runtime_run" => db_update - .visual_novel_runtime_run - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "visual_novel_work_profile" => db_update - .visual_novel_work_profile - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "wooden_fish_agent_session" => db_update - .wooden_fish_agent_session - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "wooden_fish_event" => db_update - .wooden_fish_event - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "wooden_fish_runtime_run" => db_update - .wooden_fish_runtime_run - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "wooden_fish_work_profile" => db_update - .wooden_fish_work_profile - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), unknown => { return Err( __sdk::InternalError::unknown_name("table", unknown, "QueryRows").into(), @@ -4412,6 +3074,7 @@ impl __sdk::DbUpdate for DbUpdate { pub struct AppliedDiff<'r> { admin_account: __sdk::TableAppliedDiff<'r, AdminAccount>, agc_model_catalog: __sdk::TableAppliedDiff<'r, AgcModelCatalogRow>, + agc_tracking_event: __sdk::TableAppliedDiff<'r, AgcTrackingEvent>, ai_result_reference: __sdk::TableAppliedDiff<'r, AiResultReference>, ai_task: __sdk::TableAppliedDiff<'r, AiTask>, ai_task_event: __sdk::TableAppliedDiff<'r, AiTaskEvent>, @@ -4424,31 +3087,8 @@ pub struct AppliedDiff<'r> { asset_operation_wallet_settlement: __sdk::TableAppliedDiff<'r, AssetOperationWalletSettlement>, auth_identity: __sdk::TableAppliedDiff<'r, AuthIdentity>, auth_store_projection_meta: __sdk::TableAppliedDiff<'r, AuthStoreProjectionMeta>, - bark_battle_draft_config: __sdk::TableAppliedDiff<'r, BarkBattleDraftConfigRow>, - bark_battle_leaderboard_entry: __sdk::TableAppliedDiff<'r, BarkBattleLeaderboardEntryRow>, - bark_battle_personal_best_projection: - __sdk::TableAppliedDiff<'r, BarkBattlePersonalBestProjectionRow>, - bark_battle_published_config: __sdk::TableAppliedDiff<'r, BarkBattlePublishedConfigRow>, - bark_battle_runtime_run: __sdk::TableAppliedDiff<'r, BarkBattleRuntimeRunRow>, - bark_battle_score_record: __sdk::TableAppliedDiff<'r, BarkBattleScoreRecordRow>, - bark_battle_work_stats_projection: - __sdk::TableAppliedDiff<'r, BarkBattleWorkStatsProjectionRow>, - battle_state: __sdk::TableAppliedDiff<'r, BattleState>, - big_fish_agent_message: __sdk::TableAppliedDiff<'r, BigFishAgentMessage>, - big_fish_asset_slot: __sdk::TableAppliedDiff<'r, BigFishAssetSlot>, - big_fish_creation_session: __sdk::TableAppliedDiff<'r, BigFishCreationSession>, - big_fish_event: __sdk::TableAppliedDiff<'r, BigFishEvent>, - big_fish_runtime_run: __sdk::TableAppliedDiff<'r, BigFishRuntimeRun>, - chapter_progression: __sdk::TableAppliedDiff<'r, ChapterProgression>, creation_entry_config: __sdk::TableAppliedDiff<'r, CreationEntryConfig>, creation_entry_type_config: __sdk::TableAppliedDiff<'r, CreationEntryTypeConfig>, - custom_world_agent_message: __sdk::TableAppliedDiff<'r, CustomWorldAgentMessage>, - custom_world_agent_operation: __sdk::TableAppliedDiff<'r, CustomWorldAgentOperation>, - custom_world_agent_session: __sdk::TableAppliedDiff<'r, CustomWorldAgentSession>, - custom_world_draft_card: __sdk::TableAppliedDiff<'r, CustomWorldDraftCard>, - custom_world_gallery_entry: __sdk::TableAppliedDiff<'r, CustomWorldGalleryEntry>, - custom_world_profile: __sdk::TableAppliedDiff<'r, CustomWorldProfile>, - custom_world_session: __sdk::TableAppliedDiff<'r, CustomWorldSession>, database_migration_import_chunk: __sdk::TableAppliedDiff<'r, DatabaseMigrationImportChunk>, database_migration_operator: __sdk::TableAppliedDiff<'r, DatabaseMigrationOperator>, editor_agent_conversation: __sdk::TableAppliedDiff<'r, EditorAgentConversation>, @@ -4481,20 +3121,8 @@ pub struct AppliedDiff<'r> { game_distribution_idempotency_receipt: __sdk::TableAppliedDiff<'r, GameDistributionIdempotencyReceipt>, game_distribution_version: __sdk::TableAppliedDiff<'r, GameDistributionVersion>, - inventory_slot: __sdk::TableAppliedDiff<'r, InventorySlot>, - jump_hop_agent_session: __sdk::TableAppliedDiff<'r, JumpHopAgentSessionRow>, - jump_hop_event: __sdk::TableAppliedDiff<'r, JumpHopEventRow>, - jump_hop_leaderboard_entry: __sdk::TableAppliedDiff<'r, JumpHopLeaderboardEntryRow>, - jump_hop_runtime_run: __sdk::TableAppliedDiff<'r, JumpHopRuntimeRunRow>, - jump_hop_work_profile: __sdk::TableAppliedDiff<'r, JumpHopWorkProfileRow>, llm_router_account: __sdk::TableAppliedDiff<'r, LlmRouterAccount>, llm_router_billing_checkpoint: __sdk::TableAppliedDiff<'r, LlmRouterBillingCheckpoint>, - match_3_d_agent_message: __sdk::TableAppliedDiff<'r, Match3DAgentMessageRow>, - match_3_d_agent_session: __sdk::TableAppliedDiff<'r, Match3DAgentSessionRow>, - match_3_d_runtime_run: __sdk::TableAppliedDiff<'r, Match3DRuntimeRunRow>, - match_3_d_work_profile: __sdk::TableAppliedDiff<'r, Match3DWorkProfileRow>, - npc_state: __sdk::TableAppliedDiff<'r, NpcState>, - player_progression: __sdk::TableAppliedDiff<'r, PlayerProgression>, profile_code_operation: __sdk::TableAppliedDiff<'r, ProfileCodeOperation>, profile_daily_free_points: __sdk::TableAppliedDiff<'r, ProfileDailyFreePoints>, profile_dashboard_state: __sdk::TableAppliedDiff<'r, ProfileDashboardState>, @@ -4530,44 +3158,13 @@ pub struct AppliedDiff<'r> { profile_wallet_refund_outbox: __sdk::TableAppliedDiff<'r, ProfileWalletRefundOutbox>, public_work_like: __sdk::TableAppliedDiff<'r, PublicWorkLike>, public_work_play_daily_stat: __sdk::TableAppliedDiff<'r, PublicWorkPlayDailyStat>, - puzzle_agent_message: __sdk::TableAppliedDiff<'r, PuzzleAgentMessageRow>, - puzzle_agent_session: __sdk::TableAppliedDiff<'r, PuzzleAgentSessionRow>, - puzzle_background_compile_task: __sdk::TableAppliedDiff<'r, PuzzleBackgroundCompileTaskRow>, - puzzle_clear_agent_session: __sdk::TableAppliedDiff<'r, PuzzleClearAgentSessionRow>, - puzzle_clear_event: __sdk::TableAppliedDiff<'r, PuzzleClearEventRow>, - puzzle_clear_runtime_run: __sdk::TableAppliedDiff<'r, PuzzleClearRuntimeRunRow>, - puzzle_clear_work_profile: __sdk::TableAppliedDiff<'r, PuzzleClearWorkProfileRow>, - puzzle_event: __sdk::TableAppliedDiff<'r, PuzzleEvent>, - puzzle_leaderboard_entry: __sdk::TableAppliedDiff<'r, PuzzleLeaderboardEntryRow>, - puzzle_runtime_run: __sdk::TableAppliedDiff<'r, PuzzleRuntimeRunRow>, - puzzle_work_profile: __sdk::TableAppliedDiff<'r, PuzzleWorkProfileRow>, - quest_log: __sdk::TableAppliedDiff<'r, QuestLog>, - quest_record: __sdk::TableAppliedDiff<'r, QuestRecord>, refresh_session: __sdk::TableAppliedDiff<'r, RefreshSession>, runtime_setting: __sdk::TableAppliedDiff<'r, RuntimeSetting>, runtime_snapshot: __sdk::TableAppliedDiff<'r, RuntimeSnapshotRow>, - square_hole_agent_message: __sdk::TableAppliedDiff<'r, SquareHoleAgentMessageRow>, - square_hole_agent_session: __sdk::TableAppliedDiff<'r, SquareHoleAgentSessionRow>, - square_hole_runtime_run: __sdk::TableAppliedDiff<'r, SquareHoleRuntimeRunRow>, - square_hole_work_profile: __sdk::TableAppliedDiff<'r, SquareHoleWorkProfileRow>, - story_event: __sdk::TableAppliedDiff<'r, StoryEvent>, - story_session: __sdk::TableAppliedDiff<'r, StorySession>, tracking_daily_stat: __sdk::TableAppliedDiff<'r, TrackingDailyStat>, tracking_event: __sdk::TableAppliedDiff<'r, TrackingEvent>, - treasure_record: __sdk::TableAppliedDiff<'r, TreasureRecord>, user_account: __sdk::TableAppliedDiff<'r, UserAccount>, user_browse_history: __sdk::TableAppliedDiff<'r, UserBrowseHistory>, - visual_novel_agent_message: __sdk::TableAppliedDiff<'r, VisualNovelAgentMessageRow>, - visual_novel_agent_session: __sdk::TableAppliedDiff<'r, VisualNovelAgentSessionRow>, - visual_novel_runtime_event: __sdk::TableAppliedDiff<'r, VisualNovelRuntimeEvent>, - visual_novel_runtime_history_entry: - __sdk::TableAppliedDiff<'r, VisualNovelRuntimeHistoryEntryRow>, - visual_novel_runtime_run: __sdk::TableAppliedDiff<'r, VisualNovelRuntimeRunRow>, - visual_novel_work_profile: __sdk::TableAppliedDiff<'r, VisualNovelWorkProfileRow>, - wooden_fish_agent_session: __sdk::TableAppliedDiff<'r, WoodenFishAgentSessionRow>, - wooden_fish_event: __sdk::TableAppliedDiff<'r, WoodenFishEventRow>, - wooden_fish_runtime_run: __sdk::TableAppliedDiff<'r, WoodenFishRuntimeRunRow>, - wooden_fish_work_profile: __sdk::TableAppliedDiff<'r, WoodenFishWorkProfileRow>, __unused: std::marker::PhantomData<&'r ()>, } @@ -4591,6 +3188,11 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> { &self.agc_model_catalog, event, ); + callbacks.invoke_table_row_callbacks::( + "agc_tracking_event", + &self.agc_tracking_event, + event, + ); callbacks.invoke_table_row_callbacks::( "ai_result_reference", &self.ai_result_reference, @@ -4643,76 +3245,6 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> { &self.auth_store_projection_meta, event, ); - callbacks.invoke_table_row_callbacks::( - "bark_battle_draft_config", - &self.bark_battle_draft_config, - event, - ); - callbacks.invoke_table_row_callbacks::( - "bark_battle_leaderboard_entry", - &self.bark_battle_leaderboard_entry, - event, - ); - callbacks.invoke_table_row_callbacks::( - "bark_battle_personal_best_projection", - &self.bark_battle_personal_best_projection, - event, - ); - callbacks.invoke_table_row_callbacks::( - "bark_battle_published_config", - &self.bark_battle_published_config, - event, - ); - callbacks.invoke_table_row_callbacks::( - "bark_battle_runtime_run", - &self.bark_battle_runtime_run, - event, - ); - callbacks.invoke_table_row_callbacks::( - "bark_battle_score_record", - &self.bark_battle_score_record, - event, - ); - callbacks.invoke_table_row_callbacks::( - "bark_battle_work_stats_projection", - &self.bark_battle_work_stats_projection, - event, - ); - callbacks.invoke_table_row_callbacks::( - "battle_state", - &self.battle_state, - event, - ); - callbacks.invoke_table_row_callbacks::( - "big_fish_agent_message", - &self.big_fish_agent_message, - event, - ); - callbacks.invoke_table_row_callbacks::( - "big_fish_asset_slot", - &self.big_fish_asset_slot, - event, - ); - callbacks.invoke_table_row_callbacks::( - "big_fish_creation_session", - &self.big_fish_creation_session, - event, - ); - callbacks.invoke_table_row_callbacks::( - "big_fish_event", - &self.big_fish_event, - event, - ); - callbacks.invoke_table_row_callbacks::( - "big_fish_runtime_run", - &self.big_fish_runtime_run, - event, - ); - callbacks.invoke_table_row_callbacks::( - "chapter_progression", - &self.chapter_progression, - event, - ); callbacks.invoke_table_row_callbacks::( "creation_entry_config", &self.creation_entry_config, @@ -4723,41 +3255,6 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> { &self.creation_entry_type_config, event, ); - callbacks.invoke_table_row_callbacks::( - "custom_world_agent_message", - &self.custom_world_agent_message, - event, - ); - callbacks.invoke_table_row_callbacks::( - "custom_world_agent_operation", - &self.custom_world_agent_operation, - event, - ); - callbacks.invoke_table_row_callbacks::( - "custom_world_agent_session", - &self.custom_world_agent_session, - event, - ); - callbacks.invoke_table_row_callbacks::( - "custom_world_draft_card", - &self.custom_world_draft_card, - event, - ); - callbacks.invoke_table_row_callbacks::( - "custom_world_gallery_entry", - &self.custom_world_gallery_entry, - event, - ); - callbacks.invoke_table_row_callbacks::( - "custom_world_profile", - &self.custom_world_profile, - event, - ); - callbacks.invoke_table_row_callbacks::( - "custom_world_session", - &self.custom_world_session, - event, - ); callbacks.invoke_table_row_callbacks::( "database_migration_import_chunk", &self.database_migration_import_chunk, @@ -4903,36 +3400,6 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> { &self.game_distribution_version, event, ); - callbacks.invoke_table_row_callbacks::( - "inventory_slot", - &self.inventory_slot, - event, - ); - callbacks.invoke_table_row_callbacks::( - "jump_hop_agent_session", - &self.jump_hop_agent_session, - event, - ); - callbacks.invoke_table_row_callbacks::( - "jump_hop_event", - &self.jump_hop_event, - event, - ); - callbacks.invoke_table_row_callbacks::( - "jump_hop_leaderboard_entry", - &self.jump_hop_leaderboard_entry, - event, - ); - callbacks.invoke_table_row_callbacks::( - "jump_hop_runtime_run", - &self.jump_hop_runtime_run, - event, - ); - callbacks.invoke_table_row_callbacks::( - "jump_hop_work_profile", - &self.jump_hop_work_profile, - event, - ); callbacks.invoke_table_row_callbacks::( "llm_router_account", &self.llm_router_account, @@ -4943,32 +3410,6 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> { &self.llm_router_billing_checkpoint, event, ); - callbacks.invoke_table_row_callbacks::( - "match_3_d_agent_message", - &self.match_3_d_agent_message, - event, - ); - callbacks.invoke_table_row_callbacks::( - "match_3_d_agent_session", - &self.match_3_d_agent_session, - event, - ); - callbacks.invoke_table_row_callbacks::( - "match_3_d_runtime_run", - &self.match_3_d_runtime_run, - event, - ); - callbacks.invoke_table_row_callbacks::( - "match_3_d_work_profile", - &self.match_3_d_work_profile, - event, - ); - callbacks.invoke_table_row_callbacks::("npc_state", &self.npc_state, event); - callbacks.invoke_table_row_callbacks::( - "player_progression", - &self.player_progression, - event, - ); callbacks.invoke_table_row_callbacks::( "profile_code_operation", &self.profile_code_operation, @@ -5119,67 +3560,6 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> { &self.public_work_play_daily_stat, event, ); - callbacks.invoke_table_row_callbacks::( - "puzzle_agent_message", - &self.puzzle_agent_message, - event, - ); - callbacks.invoke_table_row_callbacks::( - "puzzle_agent_session", - &self.puzzle_agent_session, - event, - ); - callbacks.invoke_table_row_callbacks::( - "puzzle_background_compile_task", - &self.puzzle_background_compile_task, - event, - ); - callbacks.invoke_table_row_callbacks::( - "puzzle_clear_agent_session", - &self.puzzle_clear_agent_session, - event, - ); - callbacks.invoke_table_row_callbacks::( - "puzzle_clear_event", - &self.puzzle_clear_event, - event, - ); - callbacks.invoke_table_row_callbacks::( - "puzzle_clear_runtime_run", - &self.puzzle_clear_runtime_run, - event, - ); - callbacks.invoke_table_row_callbacks::( - "puzzle_clear_work_profile", - &self.puzzle_clear_work_profile, - event, - ); - callbacks.invoke_table_row_callbacks::( - "puzzle_event", - &self.puzzle_event, - event, - ); - callbacks.invoke_table_row_callbacks::( - "puzzle_leaderboard_entry", - &self.puzzle_leaderboard_entry, - event, - ); - callbacks.invoke_table_row_callbacks::( - "puzzle_runtime_run", - &self.puzzle_runtime_run, - event, - ); - callbacks.invoke_table_row_callbacks::( - "puzzle_work_profile", - &self.puzzle_work_profile, - event, - ); - callbacks.invoke_table_row_callbacks::("quest_log", &self.quest_log, event); - callbacks.invoke_table_row_callbacks::( - "quest_record", - &self.quest_record, - event, - ); callbacks.invoke_table_row_callbacks::( "refresh_session", &self.refresh_session, @@ -5195,32 +3575,6 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> { &self.runtime_snapshot, event, ); - callbacks.invoke_table_row_callbacks::( - "square_hole_agent_message", - &self.square_hole_agent_message, - event, - ); - callbacks.invoke_table_row_callbacks::( - "square_hole_agent_session", - &self.square_hole_agent_session, - event, - ); - callbacks.invoke_table_row_callbacks::( - "square_hole_runtime_run", - &self.square_hole_runtime_run, - event, - ); - callbacks.invoke_table_row_callbacks::( - "square_hole_work_profile", - &self.square_hole_work_profile, - event, - ); - callbacks.invoke_table_row_callbacks::("story_event", &self.story_event, event); - callbacks.invoke_table_row_callbacks::( - "story_session", - &self.story_session, - event, - ); callbacks.invoke_table_row_callbacks::( "tracking_daily_stat", &self.tracking_daily_stat, @@ -5231,11 +3585,6 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> { &self.tracking_event, event, ); - callbacks.invoke_table_row_callbacks::( - "treasure_record", - &self.treasure_record, - event, - ); callbacks.invoke_table_row_callbacks::( "user_account", &self.user_account, @@ -5246,56 +3595,6 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> { &self.user_browse_history, event, ); - callbacks.invoke_table_row_callbacks::( - "visual_novel_agent_message", - &self.visual_novel_agent_message, - event, - ); - callbacks.invoke_table_row_callbacks::( - "visual_novel_agent_session", - &self.visual_novel_agent_session, - event, - ); - callbacks.invoke_table_row_callbacks::( - "visual_novel_runtime_event", - &self.visual_novel_runtime_event, - event, - ); - callbacks.invoke_table_row_callbacks::( - "visual_novel_runtime_history_entry", - &self.visual_novel_runtime_history_entry, - event, - ); - callbacks.invoke_table_row_callbacks::( - "visual_novel_runtime_run", - &self.visual_novel_runtime_run, - event, - ); - callbacks.invoke_table_row_callbacks::( - "visual_novel_work_profile", - &self.visual_novel_work_profile, - event, - ); - callbacks.invoke_table_row_callbacks::( - "wooden_fish_agent_session", - &self.wooden_fish_agent_session, - event, - ); - callbacks.invoke_table_row_callbacks::( - "wooden_fish_event", - &self.wooden_fish_event, - event, - ); - callbacks.invoke_table_row_callbacks::( - "wooden_fish_runtime_run", - &self.wooden_fish_runtime_run, - event, - ); - callbacks.invoke_table_row_callbacks::( - "wooden_fish_work_profile", - &self.wooden_fish_work_profile, - event, - ); } } @@ -5551,19 +3850,19 @@ impl __sdk::SubscriptionHandle for SubscriptionHandle { /// either a [`DbConnection`] or an [`EventContext`] and operate on either. pub trait RemoteDbContext: __sdk::DbContext< - DbView = RemoteTables, - Reducers = RemoteReducers, - SubscriptionBuilder = __sdk::SubscriptionBuilder, -> + DbView = RemoteTables, + Reducers = RemoteReducers, + SubscriptionBuilder = __sdk::SubscriptionBuilder, + > { } impl< - Ctx: __sdk::DbContext< + Ctx: __sdk::DbContext< DbView = RemoteTables, Reducers = RemoteReducers, SubscriptionBuilder = __sdk::SubscriptionBuilder, >, - > RemoteDbContext for Ctx +> RemoteDbContext for Ctx { } @@ -5958,6 +4257,7 @@ impl __sdk::SpacetimeModule for RemoteModule { fn register_tables(client_cache: &mut __sdk::ClientCache) { admin_account_table::register_table(client_cache); agc_model_catalog_table::register_table(client_cache); + agc_tracking_event_table::register_table(client_cache); ai_result_reference_table::register_table(client_cache); ai_task_table::register_table(client_cache); ai_task_event_table::register_table(client_cache); @@ -5970,29 +4270,8 @@ impl __sdk::SpacetimeModule for RemoteModule { asset_operation_wallet_settlement_table::register_table(client_cache); auth_identity_table::register_table(client_cache); auth_store_projection_meta_table::register_table(client_cache); - bark_battle_draft_config_table::register_table(client_cache); - bark_battle_leaderboard_entry_table::register_table(client_cache); - bark_battle_personal_best_projection_table::register_table(client_cache); - bark_battle_published_config_table::register_table(client_cache); - bark_battle_runtime_run_table::register_table(client_cache); - bark_battle_score_record_table::register_table(client_cache); - bark_battle_work_stats_projection_table::register_table(client_cache); - battle_state_table::register_table(client_cache); - big_fish_agent_message_table::register_table(client_cache); - big_fish_asset_slot_table::register_table(client_cache); - big_fish_creation_session_table::register_table(client_cache); - big_fish_event_table::register_table(client_cache); - big_fish_runtime_run_table::register_table(client_cache); - chapter_progression_table::register_table(client_cache); creation_entry_config_table::register_table(client_cache); creation_entry_type_config_table::register_table(client_cache); - custom_world_agent_message_table::register_table(client_cache); - custom_world_agent_operation_table::register_table(client_cache); - custom_world_agent_session_table::register_table(client_cache); - custom_world_draft_card_table::register_table(client_cache); - custom_world_gallery_entry_table::register_table(client_cache); - custom_world_profile_table::register_table(client_cache); - custom_world_session_table::register_table(client_cache); database_migration_import_chunk_table::register_table(client_cache); database_migration_operator_table::register_table(client_cache); editor_agent_conversation_table::register_table(client_cache); @@ -6022,20 +4301,8 @@ impl __sdk::SpacetimeModule for RemoteModule { game_distribution_game_table::register_table(client_cache); game_distribution_idempotency_receipt_table::register_table(client_cache); game_distribution_version_table::register_table(client_cache); - inventory_slot_table::register_table(client_cache); - jump_hop_agent_session_table::register_table(client_cache); - jump_hop_event_table::register_table(client_cache); - jump_hop_leaderboard_entry_table::register_table(client_cache); - jump_hop_runtime_run_table::register_table(client_cache); - jump_hop_work_profile_table::register_table(client_cache); llm_router_account_table::register_table(client_cache); llm_router_billing_checkpoint_table::register_table(client_cache); - match_3_d_agent_message_table::register_table(client_cache); - match_3_d_agent_session_table::register_table(client_cache); - match_3_d_runtime_run_table::register_table(client_cache); - match_3_d_work_profile_table::register_table(client_cache); - npc_state_table::register_table(client_cache); - player_progression_table::register_table(client_cache); profile_code_operation_table::register_table(client_cache); profile_daily_free_points_table::register_table(client_cache); profile_dashboard_state_table::register_table(client_cache); @@ -6066,47 +4333,18 @@ impl __sdk::SpacetimeModule for RemoteModule { profile_wallet_refund_outbox_table::register_table(client_cache); public_work_like_table::register_table(client_cache); public_work_play_daily_stat_table::register_table(client_cache); - puzzle_agent_message_table::register_table(client_cache); - puzzle_agent_session_table::register_table(client_cache); - puzzle_background_compile_task_table::register_table(client_cache); - puzzle_clear_agent_session_table::register_table(client_cache); - puzzle_clear_event_table::register_table(client_cache); - puzzle_clear_runtime_run_table::register_table(client_cache); - puzzle_clear_work_profile_table::register_table(client_cache); - puzzle_event_table::register_table(client_cache); - puzzle_leaderboard_entry_table::register_table(client_cache); - puzzle_runtime_run_table::register_table(client_cache); - puzzle_work_profile_table::register_table(client_cache); - quest_log_table::register_table(client_cache); - quest_record_table::register_table(client_cache); refresh_session_table::register_table(client_cache); runtime_setting_table::register_table(client_cache); runtime_snapshot_table::register_table(client_cache); - square_hole_agent_message_table::register_table(client_cache); - square_hole_agent_session_table::register_table(client_cache); - square_hole_runtime_run_table::register_table(client_cache); - square_hole_work_profile_table::register_table(client_cache); - story_event_table::register_table(client_cache); - story_session_table::register_table(client_cache); tracking_daily_stat_table::register_table(client_cache); tracking_event_table::register_table(client_cache); - treasure_record_table::register_table(client_cache); user_account_table::register_table(client_cache); user_browse_history_table::register_table(client_cache); - visual_novel_agent_message_table::register_table(client_cache); - visual_novel_agent_session_table::register_table(client_cache); - visual_novel_runtime_event_table::register_table(client_cache); - visual_novel_runtime_history_entry_table::register_table(client_cache); - visual_novel_runtime_run_table::register_table(client_cache); - visual_novel_work_profile_table::register_table(client_cache); - wooden_fish_agent_session_table::register_table(client_cache); - wooden_fish_event_table::register_table(client_cache); - wooden_fish_runtime_run_table::register_table(client_cache); - wooden_fish_work_profile_table::register_table(client_cache); } const ALL_TABLE_NAMES: &'static [&'static str] = &[ "admin_account", "agc_model_catalog", + "agc_tracking_event", "ai_result_reference", "ai_task", "ai_task_event", @@ -6119,29 +4357,8 @@ impl __sdk::SpacetimeModule for RemoteModule { "asset_operation_wallet_settlement", "auth_identity", "auth_store_projection_meta", - "bark_battle_draft_config", - "bark_battle_leaderboard_entry", - "bark_battle_personal_best_projection", - "bark_battle_published_config", - "bark_battle_runtime_run", - "bark_battle_score_record", - "bark_battle_work_stats_projection", - "battle_state", - "big_fish_agent_message", - "big_fish_asset_slot", - "big_fish_creation_session", - "big_fish_event", - "big_fish_runtime_run", - "chapter_progression", "creation_entry_config", "creation_entry_type_config", - "custom_world_agent_message", - "custom_world_agent_operation", - "custom_world_agent_session", - "custom_world_draft_card", - "custom_world_gallery_entry", - "custom_world_profile", - "custom_world_session", "database_migration_import_chunk", "database_migration_operator", "editor_agent_conversation", @@ -6171,20 +4388,8 @@ impl __sdk::SpacetimeModule for RemoteModule { "game_distribution_game", "game_distribution_idempotency_receipt", "game_distribution_version", - "inventory_slot", - "jump_hop_agent_session", - "jump_hop_event", - "jump_hop_leaderboard_entry", - "jump_hop_runtime_run", - "jump_hop_work_profile", "llm_router_account", "llm_router_billing_checkpoint", - "match_3_d_agent_message", - "match_3_d_agent_session", - "match_3_d_runtime_run", - "match_3_d_work_profile", - "npc_state", - "player_progression", "profile_code_operation", "profile_daily_free_points", "profile_dashboard_state", @@ -6215,42 +4420,12 @@ impl __sdk::SpacetimeModule for RemoteModule { "profile_wallet_refund_outbox", "public_work_like", "public_work_play_daily_stat", - "puzzle_agent_message", - "puzzle_agent_session", - "puzzle_background_compile_task", - "puzzle_clear_agent_session", - "puzzle_clear_event", - "puzzle_clear_runtime_run", - "puzzle_clear_work_profile", - "puzzle_event", - "puzzle_leaderboard_entry", - "puzzle_runtime_run", - "puzzle_work_profile", - "quest_log", - "quest_record", "refresh_session", "runtime_setting", "runtime_snapshot", - "square_hole_agent_message", - "square_hole_agent_session", - "square_hole_runtime_run", - "square_hole_work_profile", - "story_event", - "story_session", "tracking_daily_stat", "tracking_event", - "treasure_record", "user_account", "user_browse_history", - "visual_novel_agent_message", - "visual_novel_agent_session", - "visual_novel_runtime_event", - "visual_novel_runtime_history_entry", - "visual_novel_runtime_run", - "visual_novel_work_profile", - "wooden_fish_agent_session", - "wooden_fish_event", - "wooden_fish_runtime_run", - "wooden_fish_work_profile", ]; } diff --git a/server-rs/crates/spacetime-client/src/module_bindings/acknowledge_external_generation_job_summaries_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/acknowledge_external_generation_job_summaries_and_return_procedure.rs index 48ec50384..5ef0251b0 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/acknowledge_external_generation_job_summaries_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/acknowledge_external_generation_job_summaries_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait acknowledge_external_generation_job_summaries_and_return { input: ExternalGenerationJobAcknowledgeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl acknowledge_external_generation_job_summaries_and_return for super::RemoteP input: ExternalGenerationJobAcknowledgeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ExternalGenerationJobSummaryProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/acknowledge_external_generation_jobs_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/acknowledge_external_generation_jobs_and_return_procedure.rs index 4c83af9ca..e9b1c18fe 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/acknowledge_external_generation_jobs_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/acknowledge_external_generation_jobs_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait acknowledge_external_generation_jobs_and_return { input: ExternalGenerationJobAcknowledgeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl acknowledge_external_generation_jobs_and_return for super::RemoteProcedures input: ExternalGenerationJobAcknowledgeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ExternalGenerationJobProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/activate_editor_canvas_layout_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/activate_editor_canvas_layout_and_return_procedure.rs index a92a1ed66..b9c3aa0ba 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/activate_editor_canvas_layout_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/activate_editor_canvas_layout_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait activate_editor_canvas_layout_and_return { input: EditorCanvasLayoutMigrationInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl activate_editor_canvas_layout_and_return for super::RemoteProcedures { input: EditorCanvasLayoutMigrationInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorCanvasLayoutMigrationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_disable_profile_redeem_code_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_disable_profile_redeem_code_procedure.rs index 9865ace59..bbdaab4f3 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_disable_profile_redeem_code_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_disable_profile_redeem_code_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_disable_profile_redeem_code { input: RuntimeProfileRedeemCodeAdminDisableInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_disable_profile_redeem_code for super::RemoteProcedures { input: RuntimeProfileRedeemCodeAdminDisableInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRedeemCodeAdminProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_disable_profile_task_config_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_disable_profile_task_config_procedure.rs index 0417bd2e9..c968f950d 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_disable_profile_task_config_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_disable_profile_task_config_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_disable_profile_task_config { input: RuntimeProfileTaskConfigAdminDisableInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_disable_profile_task_config for super::RemoteProcedures { input: RuntimeProfileTaskConfigAdminDisableInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileTaskConfigAdminProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_get_profile_wallet_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_get_profile_wallet_and_return_procedure.rs index 782d73f58..b482cdd15 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_get_profile_wallet_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_get_profile_wallet_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_get_profile_wallet_and_return { input: RuntimeProfileAdminWalletGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_get_profile_wallet_and_return for super::RemoteProcedures { input: RuntimeProfileAdminWalletGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileAdminWalletProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_get_profile_wallet_config_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_get_profile_wallet_config_procedure.rs index 1f48e0770..c7c836f1b 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_get_profile_wallet_config_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_get_profile_wallet_config_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_get_profile_wallet_config { input: RuntimeProfileWalletConfigAdminGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_get_profile_wallet_config for super::RemoteProcedures { input: RuntimeProfileWalletConfigAdminGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileWalletConfigAdminProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_get_profile_wallet_detail_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_get_profile_wallet_detail_and_return_procedure.rs index bacc1bbb4..95f78510c 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_get_profile_wallet_detail_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_get_profile_wallet_detail_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_get_profile_wallet_detail_and_return { input: RuntimeProfileAdminWalletGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_get_profile_wallet_detail_and_return for super::RemoteProcedures { input: RuntimeProfileAdminWalletGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileAdminWalletDetailProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_initialize_profile_wallet_consumption_projections_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_initialize_profile_wallet_consumption_projections_and_return_procedure.rs index 9c5414c9c..02fa9d1f6 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_initialize_profile_wallet_consumption_projections_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_initialize_profile_wallet_consumption_projections_and_return_procedure.rs @@ -37,13 +37,13 @@ pub trait admin_initialize_profile_wallet_consumption_projections_and_return { input: RuntimeProfileWalletConsumptionProjectionInitializeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result< - RuntimeProfileWalletConsumptionProjectionInitializeProcedureResult, - __sdk::InternalError, - >, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result< + RuntimeProfileWalletConsumptionProjectionInitializeProcedureResult, + __sdk::InternalError, + >, + ) + Send + + 'static, ); } @@ -55,13 +55,13 @@ impl admin_initialize_profile_wallet_consumption_projections_and_return input: RuntimeProfileWalletConsumptionProjectionInitializeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result< - RuntimeProfileWalletConsumptionProjectionInitializeProcedureResult, - __sdk::InternalError, - >, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result< + RuntimeProfileWalletConsumptionProjectionInitializeProcedureResult, + __sdk::InternalError, + >, + ) + Send + + 'static, ) { self.imp.invoke_procedure_with_callback::<_, RuntimeProfileWalletConsumptionProjectionInitializeProcedureResult>( "admin_initialize_profile_wallet_consumption_projections_and_return", diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_editor_assets_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_editor_assets_and_return_procedure.rs index 8e3589adb..cc3c8ecd6 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_editor_assets_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_editor_assets_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_list_editor_assets_and_return { input: AdminEditorAssetListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_list_editor_assets_and_return for super::RemoteProcedures { input: AdminEditorAssetListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AdminEditorAssetListProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_editor_showcase_assets_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_editor_showcase_assets_and_return_procedure.rs index a740930a7..69ce4beca 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_editor_showcase_assets_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_editor_showcase_assets_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait admin_list_editor_showcase_assets_and_return { input: EditorShowcaseAssetAdminListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl admin_list_editor_showcase_assets_and_return for super::RemoteProcedures { input: EditorShowcaseAssetAdminListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorShowcaseAssetListProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_invite_codes_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_invite_codes_procedure.rs index 96d2350f5..cdfa27d91 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_invite_codes_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_invite_codes_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_list_profile_invite_codes { input: RuntimeProfileInviteCodeAdminListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_list_profile_invite_codes for super::RemoteProcedures { input: RuntimeProfileInviteCodeAdminListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileInviteCodeAdminListProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_recharge_orders_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_recharge_orders_and_return_procedure.rs index f0238f7a0..d0c49b1a7 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_recharge_orders_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_recharge_orders_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait admin_list_profile_recharge_orders_and_return { input: RuntimeProfileRechargeOrderAdminListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl admin_list_profile_recharge_orders_and_return for super::RemoteProcedures { input: RuntimeProfileRechargeOrderAdminListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp.invoke_procedure_with_callback::<_, RuntimeProfileRechargeOrderAdminListProcedureResult>( "admin_list_profile_recharge_orders_and_return", diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_recharge_products_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_recharge_products_procedure.rs index a1deed886..e84d4ec62 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_recharge_products_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_recharge_products_procedure.rs @@ -34,10 +34,10 @@ pub trait admin_list_profile_recharge_products { input: RuntimeProfileRechargeProductAdminListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl admin_list_profile_recharge_products for super::RemoteProcedures { input: RuntimeProfileRechargeProductAdminListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp.invoke_procedure_with_callback::<_, RuntimeProfileRechargeProductAdminListProcedureResult>( "admin_list_profile_recharge_products", diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_redeem_codes_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_redeem_codes_procedure.rs index c7d6a78e8..2c9b9dd73 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_redeem_codes_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_redeem_codes_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_list_profile_redeem_codes { input: RuntimeProfileRedeemCodeAdminListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_list_profile_redeem_codes for super::RemoteProcedures { input: RuntimeProfileRedeemCodeAdminListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRedeemCodeAdminListProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_task_configs_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_task_configs_procedure.rs index a152116df..88ca28d55 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_task_configs_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_task_configs_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_list_profile_task_configs { input: RuntimeProfileTaskConfigAdminListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_list_profile_task_configs for super::RemoteProcedures { input: RuntimeProfileTaskConfigAdminListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileTaskConfigAdminListProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_reconcile_profile_wallet_consumption_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_reconcile_profile_wallet_consumption_and_return_procedure.rs index 1002fcc4e..f267d78af 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_reconcile_profile_wallet_consumption_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_reconcile_profile_wallet_consumption_and_return_procedure.rs @@ -34,10 +34,13 @@ pub trait admin_reconcile_profile_wallet_consumption_and_return { input: RuntimeProfileWalletConsumptionReconcileInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result< + RuntimeProfileWalletConsumptionReconcileProcedureResult, + __sdk::InternalError, + >, + ) + Send + + 'static, ); } @@ -47,10 +50,13 @@ impl admin_reconcile_profile_wallet_consumption_and_return for super::RemoteProc input: RuntimeProfileWalletConsumptionReconcileInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result< + RuntimeProfileWalletConsumptionReconcileProcedureResult, + __sdk::InternalError, + >, + ) + Send + + 'static, ) { self.imp.invoke_procedure_with_callback::<_, RuntimeProfileWalletConsumptionReconcileProcedureResult>( "admin_reconcile_profile_wallet_consumption_and_return", diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_review_editor_showcase_asset_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_review_editor_showcase_asset_and_return_procedure.rs index 71334fc07..29b2ecf60 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_review_editor_showcase_asset_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_review_editor_showcase_asset_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait admin_review_editor_showcase_asset_and_return { input: EditorShowcaseAssetAdminReviewInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl admin_review_editor_showcase_asset_and_return for super::RemoteProcedures { input: EditorShowcaseAssetAdminReviewInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorShowcaseAssetProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_invite_code_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_invite_code_procedure.rs index 2411092d2..3601be97f 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_invite_code_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_invite_code_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_upsert_profile_invite_code { input: RuntimeProfileInviteCodeAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_upsert_profile_invite_code for super::RemoteProcedures { input: RuntimeProfileInviteCodeAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileInviteCodeAdminProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_recharge_product_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_recharge_product_procedure.rs index 83941b836..e3f42278b 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_recharge_product_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_recharge_product_procedure.rs @@ -34,10 +34,10 @@ pub trait admin_upsert_profile_recharge_product { input: RuntimeProfileRechargeProductAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl admin_upsert_profile_recharge_product for super::RemoteProcedures { input: RuntimeProfileRechargeProductAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRechargeProductAdminProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_redeem_code_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_redeem_code_procedure.rs index 9c7ae92f1..7e918220f 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_redeem_code_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_redeem_code_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_upsert_profile_redeem_code { input: RuntimeProfileRedeemCodeAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_upsert_profile_redeem_code for super::RemoteProcedures { input: RuntimeProfileRedeemCodeAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRedeemCodeAdminProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_task_config_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_task_config_procedure.rs index b441a8084..a3d3e11a4 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_task_config_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_task_config_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_upsert_profile_task_config { input: RuntimeProfileTaskConfigAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_upsert_profile_task_config for super::RemoteProcedures { input: RuntimeProfileTaskConfigAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileTaskConfigAdminProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_wallet_config_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_wallet_config_procedure.rs index 46814d669..b87b6506d 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_wallet_config_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_wallet_config_procedure.rs @@ -34,10 +34,10 @@ pub trait admin_upsert_profile_wallet_config { input: RuntimeProfileWalletConfigAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl admin_upsert_profile_wallet_config for super::RemoteProcedures { input: RuntimeProfileWalletConfigAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileWalletConfigAdminProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_wallet_manual_restriction_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_wallet_manual_restriction_and_return_procedure.rs index c313d2d44..54786f87a 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_wallet_manual_restriction_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_wallet_manual_restriction_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait admin_upsert_profile_wallet_manual_restriction_and_return { input: RuntimeProfileWalletManualRestrictionUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl admin_upsert_profile_wallet_manual_restriction_and_return for super::Remote input: RuntimeProfileWalletManualRestrictionUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileAdminWalletProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/advance_profile_recharge_refund_bill_checkpoint_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/advance_profile_recharge_refund_bill_checkpoint_and_return_procedure.rs index 06631fcfe..064148be6 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/advance_profile_recharge_refund_bill_checkpoint_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/advance_profile_recharge_refund_bill_checkpoint_and_return_procedure.rs @@ -34,10 +34,13 @@ pub trait advance_profile_recharge_refund_bill_checkpoint_and_return { input: RuntimeProfileRechargeRefundBillCheckpointAdvanceInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result< + RuntimeProfileRechargeRefundBillCheckpointProcedureResult, + __sdk::InternalError, + >, + ) + Send + + 'static, ); } @@ -47,10 +50,13 @@ impl advance_profile_recharge_refund_bill_checkpoint_and_return for super::Remot input: RuntimeProfileRechargeRefundBillCheckpointAdvanceInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result< + RuntimeProfileRechargeRefundBillCheckpointProcedureResult, + __sdk::InternalError, + >, + ) + Send + + 'static, ) { self.imp.invoke_procedure_with_callback::<_, RuntimeProfileRechargeRefundBillCheckpointProcedureResult>( "advance_profile_recharge_refund_bill_checkpoint_and_return", diff --git a/server-rs/crates/spacetime-client/src/module_bindings/agc_tracking_event_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/agc_tracking_event_table.rs new file mode 100644 index 000000000..2c3712e0f --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/agc_tracking_event_table.rs @@ -0,0 +1,228 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use super::agc_tracking_event_type::AgcTrackingEvent; +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +/// Table handle for the table `agc_tracking_event`. +/// +/// Obtain a handle from the [`AgcTrackingEventTableAccess::agc_tracking_event`] method on [`super::RemoteTables`], +/// like `ctx.db.agc_tracking_event()`. +/// +/// Users are encouraged not to explicitly reference this type, +/// but to directly chain method calls, +/// like `ctx.db.agc_tracking_event().on_insert(...)`. +pub struct AgcTrackingEventTableHandle<'ctx> { + imp: __sdk::TableHandle, + ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, +} + +/// Lifetime-aware accessor marker for the table `agc_tracking_event`. +pub struct AgcTrackingEventTableAccessor; + +impl __sdk::TableAccessor for AgcTrackingEventTableAccessor { + type Row = AgcTrackingEvent; + type Handle<'db> = AgcTrackingEventTableHandle<'db>; + + fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { + db.agc_tracking_event() + } +} + +#[allow(non_camel_case_types)] +/// Extension trait for access to the table `agc_tracking_event`. +/// +/// Implemented for [`super::RemoteTables`]. +pub trait AgcTrackingEventTableAccess { + #[allow(non_snake_case)] + /// Obtain a [`AgcTrackingEventTableHandle`], which mediates access to the table `agc_tracking_event`. + fn agc_tracking_event(&self) -> AgcTrackingEventTableHandle<'_>; +} + +impl AgcTrackingEventTableAccess for super::RemoteTables { + fn agc_tracking_event(&self) -> AgcTrackingEventTableHandle<'_> { + AgcTrackingEventTableHandle { + imp: self.imp.get_table::("agc_tracking_event"), + ctx: std::marker::PhantomData, + } + } +} + +pub struct AgcTrackingEventInsertCallbackId(__sdk::CallbackId); +pub struct AgcTrackingEventDeleteCallbackId(__sdk::CallbackId); + +impl<'ctx> __sdk::TableLike for AgcTrackingEventTableHandle<'ctx> { + type Row = AgcTrackingEvent; + type EventContext = super::EventContext; + + fn count(&self) -> u64 { + self.imp.count() + } + fn iter(&self) -> impl Iterator + '_ { + self.imp.iter() + } +} + +impl<'ctx> __sdk::Table for AgcTrackingEventTableHandle<'ctx> { + type Row = AgcTrackingEvent; + type EventContext = super::EventContext; + + fn count(&self) -> u64 { + self.imp.count() + } + fn iter(&self) -> impl Iterator + '_ { + self.imp.iter() + } + + type InsertCallbackId = AgcTrackingEventInsertCallbackId; + + fn on_insert( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> AgcTrackingEventInsertCallbackId { + AgcTrackingEventInsertCallbackId(self.imp.on_insert(Box::new(callback))) + } + + fn remove_on_insert(&self, callback: AgcTrackingEventInsertCallbackId) { + self.imp.remove_on_insert(callback.0) + } + + type DeleteCallbackId = AgcTrackingEventDeleteCallbackId; + + fn on_delete( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> AgcTrackingEventDeleteCallbackId { + AgcTrackingEventDeleteCallbackId(self.imp.on_delete(Box::new(callback))) + } + + fn remove_on_delete(&self, callback: AgcTrackingEventDeleteCallbackId) { + self.imp.remove_on_delete(callback.0) + } +} + +impl<'ctx> __sdk::WithInsert for AgcTrackingEventTableHandle<'ctx> { + type InsertCallbackId = AgcTrackingEventInsertCallbackId; + + fn on_insert( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> AgcTrackingEventInsertCallbackId { + AgcTrackingEventInsertCallbackId(self.imp.on_insert(Box::new(callback))) + } + + fn remove_on_insert(&self, callback: AgcTrackingEventInsertCallbackId) { + self.imp.remove_on_insert(callback.0) + } +} + +impl<'ctx> __sdk::WithDelete for AgcTrackingEventTableHandle<'ctx> { + type DeleteCallbackId = AgcTrackingEventDeleteCallbackId; + + fn on_delete( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> AgcTrackingEventDeleteCallbackId { + AgcTrackingEventDeleteCallbackId(self.imp.on_delete(Box::new(callback))) + } + + fn remove_on_delete(&self, callback: AgcTrackingEventDeleteCallbackId) { + self.imp.remove_on_delete(callback.0) + } +} + +pub struct AgcTrackingEventUpdateCallbackId(__sdk::CallbackId); + +impl<'ctx> __sdk::TableWithPrimaryKey for AgcTrackingEventTableHandle<'ctx> { + type UpdateCallbackId = AgcTrackingEventUpdateCallbackId; + + fn on_update( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, + ) -> AgcTrackingEventUpdateCallbackId { + AgcTrackingEventUpdateCallbackId(self.imp.on_update(Box::new(callback))) + } + + fn remove_on_update(&self, callback: AgcTrackingEventUpdateCallbackId) { + self.imp.remove_on_update(callback.0) + } +} + +impl<'ctx> __sdk::WithUpdate for AgcTrackingEventTableHandle<'ctx> { + type UpdateCallbackId = AgcTrackingEventUpdateCallbackId; + + fn on_update( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, + ) -> AgcTrackingEventUpdateCallbackId { + AgcTrackingEventUpdateCallbackId(self.imp.on_update(Box::new(callback))) + } + + fn remove_on_update(&self, callback: AgcTrackingEventUpdateCallbackId) { + self.imp.remove_on_update(callback.0) + } +} + +/// Access to the `event_id` unique index on the table `agc_tracking_event`, +/// which allows point queries on the field of the same name +/// via the [`AgcTrackingEventEventIdUnique::find`] method. +/// +/// Users are encouraged not to explicitly reference this type, +/// but to directly chain method calls, +/// like `ctx.db.agc_tracking_event().event_id().find(...)`. +pub struct AgcTrackingEventEventIdUnique<'ctx> { + imp: __sdk::UniqueConstraintHandle, + phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, +} + +impl<'ctx> AgcTrackingEventTableHandle<'ctx> { + /// Get a handle on the `event_id` unique index on the table `agc_tracking_event`. + pub fn event_id(&self) -> AgcTrackingEventEventIdUnique<'ctx> { + AgcTrackingEventEventIdUnique { + imp: self.imp.get_unique_constraint::("event_id"), + phantom: std::marker::PhantomData, + } + } +} + +impl<'ctx> AgcTrackingEventEventIdUnique<'ctx> { + /// Find the subscribed row whose `event_id` column value is equal to `col_val`, + /// if such a row is present in the client cache. + pub fn find(&self, col_val: &String) -> Option { + self.imp.find(col_val) + } +} + +#[doc(hidden)] +pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { + let _table = client_cache.get_or_make_table::("agc_tracking_event"); + _table.add_unique_constraint::("event_id", |row| &row.event_id); +} + +#[doc(hidden)] +pub(super) fn parse_table_update( + raw_updates: __ws::v2::TableUpdate, +) -> __sdk::Result<__sdk::TableUpdate> { + __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { + __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") + .with_cause(e) + .into() + }) +} + +#[allow(non_camel_case_types)] +/// Extension trait for query builder access to the table `AgcTrackingEvent`. +/// +/// Implemented for [`__sdk::QueryTableAccessor`]. +pub trait agc_tracking_eventQueryTableAccess { + #[allow(non_snake_case)] + /// Get a query builder for the table `AgcTrackingEvent`. + fn agc_tracking_event(&self) -> __sdk::__query_builder::Table; +} + +impl agc_tracking_eventQueryTableAccess for __sdk::QueryTableAccessor { + fn agc_tracking_event(&self) -> __sdk::__query_builder::Table { + __sdk::__query_builder::Table::new("agc_tracking_event") + } +} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/agc_tracking_event_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/agc_tracking_event_type.rs new file mode 100644 index 000000000..750fe691f --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/agc_tracking_event_type.rs @@ -0,0 +1,99 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub struct AgcTrackingEvent { + pub event_id: String, + pub schema_version: u32, + pub event_name: String, + pub event_time: __sdk::Timestamp, + pub user_id: String, + pub editor_session_id: String, + pub project_id: Option, + pub creative_task_id: Option, + pub agent_run_id: Option, + pub agent_turn_id: Option, + pub status: Option, + pub error_code: Option, + pub source: String, + pub client_version: String, + pub properties_json: String, + pub batch_id: String, + pub received_at: __sdk::Timestamp, +} + +impl __sdk::InModule for AgcTrackingEvent { + type Module = super::RemoteModule; +} + +/// Column accessor struct for the table `AgcTrackingEvent`. +/// +/// Provides typed access to columns for query building. +pub struct AgcTrackingEventCols { + pub event_id: __sdk::__query_builder::Col, + pub schema_version: __sdk::__query_builder::Col, + pub event_name: __sdk::__query_builder::Col, + pub event_time: __sdk::__query_builder::Col, + pub user_id: __sdk::__query_builder::Col, + pub editor_session_id: __sdk::__query_builder::Col, + pub project_id: __sdk::__query_builder::Col>, + pub creative_task_id: __sdk::__query_builder::Col>, + pub agent_run_id: __sdk::__query_builder::Col>, + pub agent_turn_id: __sdk::__query_builder::Col>, + pub status: __sdk::__query_builder::Col>, + pub error_code: __sdk::__query_builder::Col>, + pub source: __sdk::__query_builder::Col, + pub client_version: __sdk::__query_builder::Col, + pub properties_json: __sdk::__query_builder::Col, + pub batch_id: __sdk::__query_builder::Col, + pub received_at: __sdk::__query_builder::Col, +} + +impl __sdk::__query_builder::HasCols for AgcTrackingEvent { + type Cols = AgcTrackingEventCols; + fn cols(table_name: &'static str) -> Self::Cols { + AgcTrackingEventCols { + event_id: __sdk::__query_builder::Col::new(table_name, "event_id"), + schema_version: __sdk::__query_builder::Col::new(table_name, "schema_version"), + event_name: __sdk::__query_builder::Col::new(table_name, "event_name"), + event_time: __sdk::__query_builder::Col::new(table_name, "event_time"), + user_id: __sdk::__query_builder::Col::new(table_name, "user_id"), + editor_session_id: __sdk::__query_builder::Col::new(table_name, "editor_session_id"), + project_id: __sdk::__query_builder::Col::new(table_name, "project_id"), + creative_task_id: __sdk::__query_builder::Col::new(table_name, "creative_task_id"), + agent_run_id: __sdk::__query_builder::Col::new(table_name, "agent_run_id"), + agent_turn_id: __sdk::__query_builder::Col::new(table_name, "agent_turn_id"), + status: __sdk::__query_builder::Col::new(table_name, "status"), + error_code: __sdk::__query_builder::Col::new(table_name, "error_code"), + source: __sdk::__query_builder::Col::new(table_name, "source"), + client_version: __sdk::__query_builder::Col::new(table_name, "client_version"), + properties_json: __sdk::__query_builder::Col::new(table_name, "properties_json"), + batch_id: __sdk::__query_builder::Col::new(table_name, "batch_id"), + received_at: __sdk::__query_builder::Col::new(table_name, "received_at"), + } + } +} + +/// Indexed column accessor struct for the table `AgcTrackingEvent`. +/// +/// Provides typed access to indexed columns for query building. +pub struct AgcTrackingEventIxCols { + pub event_id: __sdk::__query_builder::IxCol, + pub received_at: __sdk::__query_builder::IxCol, +} + +impl __sdk::__query_builder::HasIxCols for AgcTrackingEvent { + type IxCols = AgcTrackingEventIxCols; + fn ix_cols(table_name: &'static str) -> Self::IxCols { + AgcTrackingEventIxCols { + event_id: __sdk::__query_builder::IxCol::new(table_name, "event_id"), + received_at: __sdk::__query_builder::IxCol::new(table_name, "received_at"), + } + } +} + +impl __sdk::__query_builder::CanBeLookupTable for AgcTrackingEvent {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/append_ai_text_chunk_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/append_ai_text_chunk_and_return_procedure.rs index 191e2ea7c..11323392d 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/append_ai_text_chunk_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/append_ai_text_chunk_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait append_ai_text_chunk_and_return { input: AiTextChunkAppendInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl append_ai_text_chunk_and_return for super::RemoteProcedures { input: AiTextChunkAppendInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AiTaskProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/attach_ai_result_reference_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/attach_ai_result_reference_and_return_procedure.rs index 94d418502..2f3edbe2a 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/attach_ai_result_reference_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/attach_ai_result_reference_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait attach_ai_result_reference_and_return { input: AiResultReferenceInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl attach_ai_result_reference_and_return for super::RemoteProcedures { input: AiResultReferenceInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AiTaskProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/authenticate_external_api_key_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/authenticate_external_api_key_and_return_procedure.rs index 279534f41..4c3aec34c 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/authenticate_external_api_key_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/authenticate_external_api_key_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait authenticate_external_api_key_and_return { input: ExternalApiKeyAuthenticateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl authenticate_external_api_key_and_return for super::RemoteProcedures { input: ExternalApiKeyAuthenticateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ExternalApiKeyProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/authorize_database_migration_operator_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/authorize_database_migration_operator_procedure.rs index ac77f7e80..b58850228 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/authorize_database_migration_operator_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/authorize_database_migration_operator_procedure.rs @@ -34,10 +34,10 @@ pub trait authorize_database_migration_operator { input: DatabaseMigrationAuthorizeOperatorInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl authorize_database_migration_operator for super::RemoteProcedures { input: DatabaseMigrationAuthorizeOperatorInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, DatabaseMigrationOperatorProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/backfill_editor_canvas_layout_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/backfill_editor_canvas_layout_and_return_procedure.rs index 714b64947..9af4d59d3 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/backfill_editor_canvas_layout_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/backfill_editor_canvas_layout_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait backfill_editor_canvas_layout_and_return { input: EditorCanvasLayoutMigrationInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl backfill_editor_canvas_layout_and_return for super::RemoteProcedures { input: EditorCanvasLayoutMigrationInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorCanvasLayoutMigrationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/backfill_external_generation_job_summaries_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/backfill_external_generation_job_summaries_and_return_procedure.rs index 315b908ab..8636a1587 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/backfill_external_generation_job_summaries_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/backfill_external_generation_job_summaries_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait backfill_external_generation_job_summaries_and_return { input: ExternalGenerationJobSummaryBackfillInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl backfill_external_generation_job_summaries_and_return for super::RemoteProc input: ExternalGenerationJobSummaryBackfillInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp.invoke_procedure_with_callback::<_, ExternalGenerationJobSummaryBackfillProcedureResult>( "backfill_external_generation_job_summaries_and_return", diff --git a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_draft_config_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_draft_config_row_type.rs deleted file mode 100644 index 37494c810..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_draft_config_row_type.rs +++ /dev/null @@ -1,86 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct BarkBattleDraftConfigRow { - pub draft_id: String, - pub owner_user_id: String, - pub work_id: String, - pub config_version: u64, - pub ruleset_version: String, - pub difficulty_preset: String, - pub leaderboard_enabled: bool, - pub config_json: String, - pub editor_state_json: String, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for BarkBattleDraftConfigRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `BarkBattleDraftConfigRow`. -/// -/// Provides typed access to columns for query building. -pub struct BarkBattleDraftConfigRowCols { - pub draft_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub work_id: __sdk::__query_builder::Col, - pub config_version: __sdk::__query_builder::Col, - pub ruleset_version: __sdk::__query_builder::Col, - pub difficulty_preset: __sdk::__query_builder::Col, - pub leaderboard_enabled: __sdk::__query_builder::Col, - pub config_json: __sdk::__query_builder::Col, - pub editor_state_json: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for BarkBattleDraftConfigRow { - type Cols = BarkBattleDraftConfigRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - BarkBattleDraftConfigRowCols { - draft_id: __sdk::__query_builder::Col::new(table_name, "draft_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - work_id: __sdk::__query_builder::Col::new(table_name, "work_id"), - config_version: __sdk::__query_builder::Col::new(table_name, "config_version"), - ruleset_version: __sdk::__query_builder::Col::new(table_name, "ruleset_version"), - difficulty_preset: __sdk::__query_builder::Col::new(table_name, "difficulty_preset"), - leaderboard_enabled: __sdk::__query_builder::Col::new( - table_name, - "leaderboard_enabled", - ), - config_json: __sdk::__query_builder::Col::new(table_name, "config_json"), - editor_state_json: __sdk::__query_builder::Col::new(table_name, "editor_state_json"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `BarkBattleDraftConfigRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct BarkBattleDraftConfigRowIxCols { - pub draft_id: __sdk::__query_builder::IxCol, - pub owner_user_id: __sdk::__query_builder::IxCol, - pub work_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for BarkBattleDraftConfigRow { - type IxCols = BarkBattleDraftConfigRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - BarkBattleDraftConfigRowIxCols { - draft_id: __sdk::__query_builder::IxCol::new(table_name, "draft_id"), - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - work_id: __sdk::__query_builder::IxCol::new(table_name, "work_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for BarkBattleDraftConfigRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_draft_config_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_draft_config_table.rs deleted file mode 100644 index 4675aace0..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_draft_config_table.rs +++ /dev/null @@ -1,231 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::bark_battle_draft_config_row_type::BarkBattleDraftConfigRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `bark_battle_draft_config`. -/// -/// Obtain a handle from the [`BarkBattleDraftConfigTableAccess::bark_battle_draft_config`] method on [`super::RemoteTables`], -/// like `ctx.db.bark_battle_draft_config()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.bark_battle_draft_config().on_insert(...)`. -pub struct BarkBattleDraftConfigTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `bark_battle_draft_config`. -pub struct BarkBattleDraftConfigTableAccessor; - -impl __sdk::TableAccessor for BarkBattleDraftConfigTableAccessor { - type Row = BarkBattleDraftConfigRow; - type Handle<'db> = BarkBattleDraftConfigTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.bark_battle_draft_config() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `bark_battle_draft_config`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait BarkBattleDraftConfigTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`BarkBattleDraftConfigTableHandle`], which mediates access to the table `bark_battle_draft_config`. - fn bark_battle_draft_config(&self) -> BarkBattleDraftConfigTableHandle<'_>; -} - -impl BarkBattleDraftConfigTableAccess for super::RemoteTables { - fn bark_battle_draft_config(&self) -> BarkBattleDraftConfigTableHandle<'_> { - BarkBattleDraftConfigTableHandle { - imp: self - .imp - .get_table::("bark_battle_draft_config"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct BarkBattleDraftConfigInsertCallbackId(__sdk::CallbackId); -pub struct BarkBattleDraftConfigDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for BarkBattleDraftConfigTableHandle<'ctx> { - type Row = BarkBattleDraftConfigRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for BarkBattleDraftConfigTableHandle<'ctx> { - type Row = BarkBattleDraftConfigRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = BarkBattleDraftConfigInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattleDraftConfigInsertCallbackId { - BarkBattleDraftConfigInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BarkBattleDraftConfigInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = BarkBattleDraftConfigDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattleDraftConfigDeleteCallbackId { - BarkBattleDraftConfigDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BarkBattleDraftConfigDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for BarkBattleDraftConfigTableHandle<'ctx> { - type InsertCallbackId = BarkBattleDraftConfigInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattleDraftConfigInsertCallbackId { - BarkBattleDraftConfigInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BarkBattleDraftConfigInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for BarkBattleDraftConfigTableHandle<'ctx> { - type DeleteCallbackId = BarkBattleDraftConfigDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattleDraftConfigDeleteCallbackId { - BarkBattleDraftConfigDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BarkBattleDraftConfigDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct BarkBattleDraftConfigUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for BarkBattleDraftConfigTableHandle<'ctx> { - type UpdateCallbackId = BarkBattleDraftConfigUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BarkBattleDraftConfigUpdateCallbackId { - BarkBattleDraftConfigUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BarkBattleDraftConfigUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for BarkBattleDraftConfigTableHandle<'ctx> { - type UpdateCallbackId = BarkBattleDraftConfigUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BarkBattleDraftConfigUpdateCallbackId { - BarkBattleDraftConfigUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BarkBattleDraftConfigUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `draft_id` unique index on the table `bark_battle_draft_config`, -/// which allows point queries on the field of the same name -/// via the [`BarkBattleDraftConfigDraftIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.bark_battle_draft_config().draft_id().find(...)`. -pub struct BarkBattleDraftConfigDraftIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> BarkBattleDraftConfigTableHandle<'ctx> { - /// Get a handle on the `draft_id` unique index on the table `bark_battle_draft_config`. - pub fn draft_id(&self) -> BarkBattleDraftConfigDraftIdUnique<'ctx> { - BarkBattleDraftConfigDraftIdUnique { - imp: self.imp.get_unique_constraint::("draft_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> BarkBattleDraftConfigDraftIdUnique<'ctx> { - /// Find the subscribed row whose `draft_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("bark_battle_draft_config"); - _table.add_unique_constraint::("draft_id", |row| &row.draft_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `BarkBattleDraftConfigRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait bark_battle_draft_configQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `BarkBattleDraftConfigRow`. - fn bark_battle_draft_config(&self) -> __sdk::__query_builder::Table; -} - -impl bark_battle_draft_configQueryTableAccess for __sdk::QueryTableAccessor { - fn bark_battle_draft_config(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("bark_battle_draft_config") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_leaderboard_entry_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_leaderboard_entry_row_type.rs deleted file mode 100644 index c23b8e6da..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_leaderboard_entry_row_type.rs +++ /dev/null @@ -1,94 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct BarkBattleLeaderboardEntryRow { - pub leaderboard_entry_id: String, - pub work_id: String, - pub owner_user_id: String, - pub run_id: String, - pub score_id: String, - pub leaderboard_score: u64, - pub final_energy: f32, - pub trigger_count: u64, - pub max_volume: f32, - pub duration_closeness_ms: u64, - pub finished_at_micros: i64, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for BarkBattleLeaderboardEntryRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `BarkBattleLeaderboardEntryRow`. -/// -/// Provides typed access to columns for query building. -pub struct BarkBattleLeaderboardEntryRowCols { - pub leaderboard_entry_id: __sdk::__query_builder::Col, - pub work_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub run_id: __sdk::__query_builder::Col, - pub score_id: __sdk::__query_builder::Col, - pub leaderboard_score: __sdk::__query_builder::Col, - pub final_energy: __sdk::__query_builder::Col, - pub trigger_count: __sdk::__query_builder::Col, - pub max_volume: __sdk::__query_builder::Col, - pub duration_closeness_ms: __sdk::__query_builder::Col, - pub finished_at_micros: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for BarkBattleLeaderboardEntryRow { - type Cols = BarkBattleLeaderboardEntryRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - BarkBattleLeaderboardEntryRowCols { - leaderboard_entry_id: __sdk::__query_builder::Col::new( - table_name, - "leaderboard_entry_id", - ), - work_id: __sdk::__query_builder::Col::new(table_name, "work_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - run_id: __sdk::__query_builder::Col::new(table_name, "run_id"), - score_id: __sdk::__query_builder::Col::new(table_name, "score_id"), - leaderboard_score: __sdk::__query_builder::Col::new(table_name, "leaderboard_score"), - final_energy: __sdk::__query_builder::Col::new(table_name, "final_energy"), - trigger_count: __sdk::__query_builder::Col::new(table_name, "trigger_count"), - max_volume: __sdk::__query_builder::Col::new(table_name, "max_volume"), - duration_closeness_ms: __sdk::__query_builder::Col::new( - table_name, - "duration_closeness_ms", - ), - finished_at_micros: __sdk::__query_builder::Col::new(table_name, "finished_at_micros"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `BarkBattleLeaderboardEntryRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct BarkBattleLeaderboardEntryRowIxCols { - pub leaderboard_entry_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for BarkBattleLeaderboardEntryRow { - type IxCols = BarkBattleLeaderboardEntryRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - BarkBattleLeaderboardEntryRowIxCols { - leaderboard_entry_id: __sdk::__query_builder::IxCol::new( - table_name, - "leaderboard_entry_id", - ), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for BarkBattleLeaderboardEntryRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_leaderboard_entry_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_leaderboard_entry_table.rs deleted file mode 100644 index ae1423815..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_leaderboard_entry_table.rs +++ /dev/null @@ -1,240 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::bark_battle_leaderboard_entry_row_type::BarkBattleLeaderboardEntryRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `bark_battle_leaderboard_entry`. -/// -/// Obtain a handle from the [`BarkBattleLeaderboardEntryTableAccess::bark_battle_leaderboard_entry`] method on [`super::RemoteTables`], -/// like `ctx.db.bark_battle_leaderboard_entry()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.bark_battle_leaderboard_entry().on_insert(...)`. -pub struct BarkBattleLeaderboardEntryTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `bark_battle_leaderboard_entry`. -pub struct BarkBattleLeaderboardEntryTableAccessor; - -impl __sdk::TableAccessor for BarkBattleLeaderboardEntryTableAccessor { - type Row = BarkBattleLeaderboardEntryRow; - type Handle<'db> = BarkBattleLeaderboardEntryTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.bark_battle_leaderboard_entry() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `bark_battle_leaderboard_entry`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait BarkBattleLeaderboardEntryTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`BarkBattleLeaderboardEntryTableHandle`], which mediates access to the table `bark_battle_leaderboard_entry`. - fn bark_battle_leaderboard_entry(&self) -> BarkBattleLeaderboardEntryTableHandle<'_>; -} - -impl BarkBattleLeaderboardEntryTableAccess for super::RemoteTables { - fn bark_battle_leaderboard_entry(&self) -> BarkBattleLeaderboardEntryTableHandle<'_> { - BarkBattleLeaderboardEntryTableHandle { - imp: self - .imp - .get_table::("bark_battle_leaderboard_entry"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct BarkBattleLeaderboardEntryInsertCallbackId(__sdk::CallbackId); -pub struct BarkBattleLeaderboardEntryDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for BarkBattleLeaderboardEntryTableHandle<'ctx> { - type Row = BarkBattleLeaderboardEntryRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for BarkBattleLeaderboardEntryTableHandle<'ctx> { - type Row = BarkBattleLeaderboardEntryRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = BarkBattleLeaderboardEntryInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattleLeaderboardEntryInsertCallbackId { - BarkBattleLeaderboardEntryInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BarkBattleLeaderboardEntryInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = BarkBattleLeaderboardEntryDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattleLeaderboardEntryDeleteCallbackId { - BarkBattleLeaderboardEntryDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BarkBattleLeaderboardEntryDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for BarkBattleLeaderboardEntryTableHandle<'ctx> { - type InsertCallbackId = BarkBattleLeaderboardEntryInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattleLeaderboardEntryInsertCallbackId { - BarkBattleLeaderboardEntryInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BarkBattleLeaderboardEntryInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for BarkBattleLeaderboardEntryTableHandle<'ctx> { - type DeleteCallbackId = BarkBattleLeaderboardEntryDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattleLeaderboardEntryDeleteCallbackId { - BarkBattleLeaderboardEntryDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BarkBattleLeaderboardEntryDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct BarkBattleLeaderboardEntryUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for BarkBattleLeaderboardEntryTableHandle<'ctx> { - type UpdateCallbackId = BarkBattleLeaderboardEntryUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BarkBattleLeaderboardEntryUpdateCallbackId { - BarkBattleLeaderboardEntryUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BarkBattleLeaderboardEntryUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for BarkBattleLeaderboardEntryTableHandle<'ctx> { - type UpdateCallbackId = BarkBattleLeaderboardEntryUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BarkBattleLeaderboardEntryUpdateCallbackId { - BarkBattleLeaderboardEntryUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BarkBattleLeaderboardEntryUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `leaderboard_entry_id` unique index on the table `bark_battle_leaderboard_entry`, -/// which allows point queries on the field of the same name -/// via the [`BarkBattleLeaderboardEntryLeaderboardEntryIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.bark_battle_leaderboard_entry().leaderboard_entry_id().find(...)`. -pub struct BarkBattleLeaderboardEntryLeaderboardEntryIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> BarkBattleLeaderboardEntryTableHandle<'ctx> { - /// Get a handle on the `leaderboard_entry_id` unique index on the table `bark_battle_leaderboard_entry`. - pub fn leaderboard_entry_id(&self) -> BarkBattleLeaderboardEntryLeaderboardEntryIdUnique<'ctx> { - BarkBattleLeaderboardEntryLeaderboardEntryIdUnique { - imp: self - .imp - .get_unique_constraint::("leaderboard_entry_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> BarkBattleLeaderboardEntryLeaderboardEntryIdUnique<'ctx> { - /// Find the subscribed row whose `leaderboard_entry_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache - .get_or_make_table::("bark_battle_leaderboard_entry"); - _table.add_unique_constraint::("leaderboard_entry_id", |row| &row.leaderboard_entry_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse( - "TableUpdate", - "TableUpdate", - ) - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `BarkBattleLeaderboardEntryRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait bark_battle_leaderboard_entryQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `BarkBattleLeaderboardEntryRow`. - fn bark_battle_leaderboard_entry( - &self, - ) -> __sdk::__query_builder::Table; -} - -impl bark_battle_leaderboard_entryQueryTableAccess for __sdk::QueryTableAccessor { - fn bark_battle_leaderboard_entry( - &self, - ) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("bark_battle_leaderboard_entry") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_personal_best_projection_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_personal_best_projection_row_type.rs deleted file mode 100644 index e7a882839..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_personal_best_projection_row_type.rs +++ /dev/null @@ -1,107 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct BarkBattlePersonalBestProjectionRow { - pub personal_best_id: String, - pub owner_user_id: String, - pub work_id: String, - pub run_id: String, - pub score_id: String, - pub leaderboard_entry_id: Option, - pub leaderboard_score: Option, - pub final_energy: f32, - pub trigger_count: u64, - pub max_volume: f32, - pub duration_closeness_ms: u64, - pub server_result: String, - pub validation_status: String, - pub finished_at_micros: i64, - pub summary_json: String, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for BarkBattlePersonalBestProjectionRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `BarkBattlePersonalBestProjectionRow`. -/// -/// Provides typed access to columns for query building. -pub struct BarkBattlePersonalBestProjectionRowCols { - pub personal_best_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub work_id: __sdk::__query_builder::Col, - pub run_id: __sdk::__query_builder::Col, - pub score_id: __sdk::__query_builder::Col, - pub leaderboard_entry_id: - __sdk::__query_builder::Col>, - pub leaderboard_score: - __sdk::__query_builder::Col>, - pub final_energy: __sdk::__query_builder::Col, - pub trigger_count: __sdk::__query_builder::Col, - pub max_volume: __sdk::__query_builder::Col, - pub duration_closeness_ms: - __sdk::__query_builder::Col, - pub server_result: __sdk::__query_builder::Col, - pub validation_status: __sdk::__query_builder::Col, - pub finished_at_micros: __sdk::__query_builder::Col, - pub summary_json: __sdk::__query_builder::Col, - pub updated_at: - __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for BarkBattlePersonalBestProjectionRow { - type Cols = BarkBattlePersonalBestProjectionRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - BarkBattlePersonalBestProjectionRowCols { - personal_best_id: __sdk::__query_builder::Col::new(table_name, "personal_best_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - work_id: __sdk::__query_builder::Col::new(table_name, "work_id"), - run_id: __sdk::__query_builder::Col::new(table_name, "run_id"), - score_id: __sdk::__query_builder::Col::new(table_name, "score_id"), - leaderboard_entry_id: __sdk::__query_builder::Col::new( - table_name, - "leaderboard_entry_id", - ), - leaderboard_score: __sdk::__query_builder::Col::new(table_name, "leaderboard_score"), - final_energy: __sdk::__query_builder::Col::new(table_name, "final_energy"), - trigger_count: __sdk::__query_builder::Col::new(table_name, "trigger_count"), - max_volume: __sdk::__query_builder::Col::new(table_name, "max_volume"), - duration_closeness_ms: __sdk::__query_builder::Col::new( - table_name, - "duration_closeness_ms", - ), - server_result: __sdk::__query_builder::Col::new(table_name, "server_result"), - validation_status: __sdk::__query_builder::Col::new(table_name, "validation_status"), - finished_at_micros: __sdk::__query_builder::Col::new(table_name, "finished_at_micros"), - summary_json: __sdk::__query_builder::Col::new(table_name, "summary_json"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `BarkBattlePersonalBestProjectionRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct BarkBattlePersonalBestProjectionRowIxCols { - pub personal_best_id: - __sdk::__query_builder::IxCol, - pub work_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for BarkBattlePersonalBestProjectionRow { - type IxCols = BarkBattlePersonalBestProjectionRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - BarkBattlePersonalBestProjectionRowIxCols { - personal_best_id: __sdk::__query_builder::IxCol::new(table_name, "personal_best_id"), - work_id: __sdk::__query_builder::IxCol::new(table_name, "work_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for BarkBattlePersonalBestProjectionRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_personal_best_projection_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_personal_best_projection_table.rs deleted file mode 100644 index 7c1080cb1..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_personal_best_projection_table.rs +++ /dev/null @@ -1,243 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::bark_battle_personal_best_projection_row_type::BarkBattlePersonalBestProjectionRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `bark_battle_personal_best_projection`. -/// -/// Obtain a handle from the [`BarkBattlePersonalBestProjectionTableAccess::bark_battle_personal_best_projection`] method on [`super::RemoteTables`], -/// like `ctx.db.bark_battle_personal_best_projection()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.bark_battle_personal_best_projection().on_insert(...)`. -pub struct BarkBattlePersonalBestProjectionTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `bark_battle_personal_best_projection`. -pub struct BarkBattlePersonalBestProjectionTableAccessor; - -impl __sdk::TableAccessor for BarkBattlePersonalBestProjectionTableAccessor { - type Row = BarkBattlePersonalBestProjectionRow; - type Handle<'db> = BarkBattlePersonalBestProjectionTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.bark_battle_personal_best_projection() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `bark_battle_personal_best_projection`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait BarkBattlePersonalBestProjectionTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`BarkBattlePersonalBestProjectionTableHandle`], which mediates access to the table `bark_battle_personal_best_projection`. - fn bark_battle_personal_best_projection( - &self, - ) -> BarkBattlePersonalBestProjectionTableHandle<'_>; -} - -impl BarkBattlePersonalBestProjectionTableAccess for super::RemoteTables { - fn bark_battle_personal_best_projection( - &self, - ) -> BarkBattlePersonalBestProjectionTableHandle<'_> { - BarkBattlePersonalBestProjectionTableHandle { - imp: self.imp.get_table::( - "bark_battle_personal_best_projection", - ), - ctx: std::marker::PhantomData, - } - } -} - -pub struct BarkBattlePersonalBestProjectionInsertCallbackId(__sdk::CallbackId); -pub struct BarkBattlePersonalBestProjectionDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for BarkBattlePersonalBestProjectionTableHandle<'ctx> { - type Row = BarkBattlePersonalBestProjectionRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for BarkBattlePersonalBestProjectionTableHandle<'ctx> { - type Row = BarkBattlePersonalBestProjectionRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = BarkBattlePersonalBestProjectionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattlePersonalBestProjectionInsertCallbackId { - BarkBattlePersonalBestProjectionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BarkBattlePersonalBestProjectionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = BarkBattlePersonalBestProjectionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattlePersonalBestProjectionDeleteCallbackId { - BarkBattlePersonalBestProjectionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BarkBattlePersonalBestProjectionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for BarkBattlePersonalBestProjectionTableHandle<'ctx> { - type InsertCallbackId = BarkBattlePersonalBestProjectionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattlePersonalBestProjectionInsertCallbackId { - BarkBattlePersonalBestProjectionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BarkBattlePersonalBestProjectionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for BarkBattlePersonalBestProjectionTableHandle<'ctx> { - type DeleteCallbackId = BarkBattlePersonalBestProjectionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattlePersonalBestProjectionDeleteCallbackId { - BarkBattlePersonalBestProjectionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BarkBattlePersonalBestProjectionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct BarkBattlePersonalBestProjectionUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for BarkBattlePersonalBestProjectionTableHandle<'ctx> { - type UpdateCallbackId = BarkBattlePersonalBestProjectionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BarkBattlePersonalBestProjectionUpdateCallbackId { - BarkBattlePersonalBestProjectionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BarkBattlePersonalBestProjectionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for BarkBattlePersonalBestProjectionTableHandle<'ctx> { - type UpdateCallbackId = BarkBattlePersonalBestProjectionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BarkBattlePersonalBestProjectionUpdateCallbackId { - BarkBattlePersonalBestProjectionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BarkBattlePersonalBestProjectionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `personal_best_id` unique index on the table `bark_battle_personal_best_projection`, -/// which allows point queries on the field of the same name -/// via the [`BarkBattlePersonalBestProjectionPersonalBestIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.bark_battle_personal_best_projection().personal_best_id().find(...)`. -pub struct BarkBattlePersonalBestProjectionPersonalBestIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> BarkBattlePersonalBestProjectionTableHandle<'ctx> { - /// Get a handle on the `personal_best_id` unique index on the table `bark_battle_personal_best_projection`. - pub fn personal_best_id(&self) -> BarkBattlePersonalBestProjectionPersonalBestIdUnique<'ctx> { - BarkBattlePersonalBestProjectionPersonalBestIdUnique { - imp: self.imp.get_unique_constraint::("personal_best_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> BarkBattlePersonalBestProjectionPersonalBestIdUnique<'ctx> { - /// Find the subscribed row whose `personal_best_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::( - "bark_battle_personal_best_projection", - ); - _table.add_unique_constraint::("personal_best_id", |row| &row.personal_best_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse( - "TableUpdate", - "TableUpdate", - ) - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `BarkBattlePersonalBestProjectionRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait bark_battle_personal_best_projectionQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `BarkBattlePersonalBestProjectionRow`. - fn bark_battle_personal_best_projection( - &self, - ) -> __sdk::__query_builder::Table; -} - -impl bark_battle_personal_best_projectionQueryTableAccess for __sdk::QueryTableAccessor { - fn bark_battle_personal_best_projection( - &self, - ) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("bark_battle_personal_best_projection") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_published_config_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_published_config_row_type.rs deleted file mode 100644 index 64f11bacc..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_published_config_row_type.rs +++ /dev/null @@ -1,93 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct BarkBattlePublishedConfigRow { - pub work_id: String, - pub owner_user_id: String, - pub source_draft_id: Option, - pub config_version: u64, - pub ruleset_version: String, - pub difficulty_preset: String, - pub leaderboard_enabled: bool, - pub config_json: String, - pub published_snapshot_json: String, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, - pub published_at: __sdk::Timestamp, - pub visible: bool, -} - -impl __sdk::InModule for BarkBattlePublishedConfigRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `BarkBattlePublishedConfigRow`. -/// -/// Provides typed access to columns for query building. -pub struct BarkBattlePublishedConfigRowCols { - pub work_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub source_draft_id: __sdk::__query_builder::Col>, - pub config_version: __sdk::__query_builder::Col, - pub ruleset_version: __sdk::__query_builder::Col, - pub difficulty_preset: __sdk::__query_builder::Col, - pub leaderboard_enabled: __sdk::__query_builder::Col, - pub config_json: __sdk::__query_builder::Col, - pub published_snapshot_json: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, - pub published_at: __sdk::__query_builder::Col, - pub visible: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for BarkBattlePublishedConfigRow { - type Cols = BarkBattlePublishedConfigRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - BarkBattlePublishedConfigRowCols { - work_id: __sdk::__query_builder::Col::new(table_name, "work_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - source_draft_id: __sdk::__query_builder::Col::new(table_name, "source_draft_id"), - config_version: __sdk::__query_builder::Col::new(table_name, "config_version"), - ruleset_version: __sdk::__query_builder::Col::new(table_name, "ruleset_version"), - difficulty_preset: __sdk::__query_builder::Col::new(table_name, "difficulty_preset"), - leaderboard_enabled: __sdk::__query_builder::Col::new( - table_name, - "leaderboard_enabled", - ), - config_json: __sdk::__query_builder::Col::new(table_name, "config_json"), - published_snapshot_json: __sdk::__query_builder::Col::new( - table_name, - "published_snapshot_json", - ), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - published_at: __sdk::__query_builder::Col::new(table_name, "published_at"), - visible: __sdk::__query_builder::Col::new(table_name, "visible"), - } - } -} - -/// Indexed column accessor struct for the table `BarkBattlePublishedConfigRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct BarkBattlePublishedConfigRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub work_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for BarkBattlePublishedConfigRow { - type IxCols = BarkBattlePublishedConfigRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - BarkBattlePublishedConfigRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - work_id: __sdk::__query_builder::IxCol::new(table_name, "work_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for BarkBattlePublishedConfigRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_published_config_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_published_config_table.rs deleted file mode 100644 index 0f61595ce..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_published_config_table.rs +++ /dev/null @@ -1,238 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::bark_battle_published_config_row_type::BarkBattlePublishedConfigRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `bark_battle_published_config`. -/// -/// Obtain a handle from the [`BarkBattlePublishedConfigTableAccess::bark_battle_published_config`] method on [`super::RemoteTables`], -/// like `ctx.db.bark_battle_published_config()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.bark_battle_published_config().on_insert(...)`. -pub struct BarkBattlePublishedConfigTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `bark_battle_published_config`. -pub struct BarkBattlePublishedConfigTableAccessor; - -impl __sdk::TableAccessor for BarkBattlePublishedConfigTableAccessor { - type Row = BarkBattlePublishedConfigRow; - type Handle<'db> = BarkBattlePublishedConfigTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.bark_battle_published_config() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `bark_battle_published_config`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait BarkBattlePublishedConfigTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`BarkBattlePublishedConfigTableHandle`], which mediates access to the table `bark_battle_published_config`. - fn bark_battle_published_config(&self) -> BarkBattlePublishedConfigTableHandle<'_>; -} - -impl BarkBattlePublishedConfigTableAccess for super::RemoteTables { - fn bark_battle_published_config(&self) -> BarkBattlePublishedConfigTableHandle<'_> { - BarkBattlePublishedConfigTableHandle { - imp: self - .imp - .get_table::("bark_battle_published_config"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct BarkBattlePublishedConfigInsertCallbackId(__sdk::CallbackId); -pub struct BarkBattlePublishedConfigDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for BarkBattlePublishedConfigTableHandle<'ctx> { - type Row = BarkBattlePublishedConfigRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for BarkBattlePublishedConfigTableHandle<'ctx> { - type Row = BarkBattlePublishedConfigRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = BarkBattlePublishedConfigInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattlePublishedConfigInsertCallbackId { - BarkBattlePublishedConfigInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BarkBattlePublishedConfigInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = BarkBattlePublishedConfigDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattlePublishedConfigDeleteCallbackId { - BarkBattlePublishedConfigDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BarkBattlePublishedConfigDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for BarkBattlePublishedConfigTableHandle<'ctx> { - type InsertCallbackId = BarkBattlePublishedConfigInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattlePublishedConfigInsertCallbackId { - BarkBattlePublishedConfigInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BarkBattlePublishedConfigInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for BarkBattlePublishedConfigTableHandle<'ctx> { - type DeleteCallbackId = BarkBattlePublishedConfigDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattlePublishedConfigDeleteCallbackId { - BarkBattlePublishedConfigDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BarkBattlePublishedConfigDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct BarkBattlePublishedConfigUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for BarkBattlePublishedConfigTableHandle<'ctx> { - type UpdateCallbackId = BarkBattlePublishedConfigUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BarkBattlePublishedConfigUpdateCallbackId { - BarkBattlePublishedConfigUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BarkBattlePublishedConfigUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for BarkBattlePublishedConfigTableHandle<'ctx> { - type UpdateCallbackId = BarkBattlePublishedConfigUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BarkBattlePublishedConfigUpdateCallbackId { - BarkBattlePublishedConfigUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BarkBattlePublishedConfigUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `work_id` unique index on the table `bark_battle_published_config`, -/// which allows point queries on the field of the same name -/// via the [`BarkBattlePublishedConfigWorkIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.bark_battle_published_config().work_id().find(...)`. -pub struct BarkBattlePublishedConfigWorkIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> BarkBattlePublishedConfigTableHandle<'ctx> { - /// Get a handle on the `work_id` unique index on the table `bark_battle_published_config`. - pub fn work_id(&self) -> BarkBattlePublishedConfigWorkIdUnique<'ctx> { - BarkBattlePublishedConfigWorkIdUnique { - imp: self.imp.get_unique_constraint::("work_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> BarkBattlePublishedConfigWorkIdUnique<'ctx> { - /// Find the subscribed row whose `work_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache - .get_or_make_table::("bark_battle_published_config"); - _table.add_unique_constraint::("work_id", |row| &row.work_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse( - "TableUpdate", - "TableUpdate", - ) - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `BarkBattlePublishedConfigRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait bark_battle_published_configQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `BarkBattlePublishedConfigRow`. - fn bark_battle_published_config( - &self, - ) -> __sdk::__query_builder::Table; -} - -impl bark_battle_published_configQueryTableAccess for __sdk::QueryTableAccessor { - fn bark_battle_published_config( - &self, - ) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("bark_battle_published_config") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_runtime_run_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_runtime_run_row_type.rs deleted file mode 100644 index 24edf9c6b..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_runtime_run_row_type.rs +++ /dev/null @@ -1,127 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct BarkBattleRuntimeRunRow { - pub run_id: String, - pub run_token_hash: String, - pub owner_user_id: String, - pub work_id: String, - pub config_version: u64, - pub ruleset_version: String, - pub difficulty_preset: String, - pub leaderboard_enabled: bool, - pub status: String, - pub client_started_at_micros: i64, - pub server_started_at: __sdk::Timestamp, - pub client_finished_at_micros: Option, - pub server_finished_at: Option<__sdk::Timestamp>, - pub metrics_json: String, - pub server_result: Option, - pub validation_status: String, - pub anti_cheat_flags_json: String, - pub leaderboard_score: Option, - pub score_id: Option, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for BarkBattleRuntimeRunRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `BarkBattleRuntimeRunRow`. -/// -/// Provides typed access to columns for query building. -pub struct BarkBattleRuntimeRunRowCols { - pub run_id: __sdk::__query_builder::Col, - pub run_token_hash: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub work_id: __sdk::__query_builder::Col, - pub config_version: __sdk::__query_builder::Col, - pub ruleset_version: __sdk::__query_builder::Col, - pub difficulty_preset: __sdk::__query_builder::Col, - pub leaderboard_enabled: __sdk::__query_builder::Col, - pub status: __sdk::__query_builder::Col, - pub client_started_at_micros: __sdk::__query_builder::Col, - pub server_started_at: __sdk::__query_builder::Col, - pub client_finished_at_micros: - __sdk::__query_builder::Col>, - pub server_finished_at: - __sdk::__query_builder::Col>, - pub metrics_json: __sdk::__query_builder::Col, - pub server_result: __sdk::__query_builder::Col>, - pub validation_status: __sdk::__query_builder::Col, - pub anti_cheat_flags_json: __sdk::__query_builder::Col, - pub leaderboard_score: __sdk::__query_builder::Col>, - pub score_id: __sdk::__query_builder::Col>, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for BarkBattleRuntimeRunRow { - type Cols = BarkBattleRuntimeRunRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - BarkBattleRuntimeRunRowCols { - run_id: __sdk::__query_builder::Col::new(table_name, "run_id"), - run_token_hash: __sdk::__query_builder::Col::new(table_name, "run_token_hash"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - work_id: __sdk::__query_builder::Col::new(table_name, "work_id"), - config_version: __sdk::__query_builder::Col::new(table_name, "config_version"), - ruleset_version: __sdk::__query_builder::Col::new(table_name, "ruleset_version"), - difficulty_preset: __sdk::__query_builder::Col::new(table_name, "difficulty_preset"), - leaderboard_enabled: __sdk::__query_builder::Col::new( - table_name, - "leaderboard_enabled", - ), - status: __sdk::__query_builder::Col::new(table_name, "status"), - client_started_at_micros: __sdk::__query_builder::Col::new( - table_name, - "client_started_at_micros", - ), - server_started_at: __sdk::__query_builder::Col::new(table_name, "server_started_at"), - client_finished_at_micros: __sdk::__query_builder::Col::new( - table_name, - "client_finished_at_micros", - ), - server_finished_at: __sdk::__query_builder::Col::new(table_name, "server_finished_at"), - metrics_json: __sdk::__query_builder::Col::new(table_name, "metrics_json"), - server_result: __sdk::__query_builder::Col::new(table_name, "server_result"), - validation_status: __sdk::__query_builder::Col::new(table_name, "validation_status"), - anti_cheat_flags_json: __sdk::__query_builder::Col::new( - table_name, - "anti_cheat_flags_json", - ), - leaderboard_score: __sdk::__query_builder::Col::new(table_name, "leaderboard_score"), - score_id: __sdk::__query_builder::Col::new(table_name, "score_id"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `BarkBattleRuntimeRunRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct BarkBattleRuntimeRunRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub run_id: __sdk::__query_builder::IxCol, - pub work_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for BarkBattleRuntimeRunRow { - type IxCols = BarkBattleRuntimeRunRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - BarkBattleRuntimeRunRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - run_id: __sdk::__query_builder::IxCol::new(table_name, "run_id"), - work_id: __sdk::__query_builder::IxCol::new(table_name, "work_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for BarkBattleRuntimeRunRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_runtime_run_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_runtime_run_table.rs deleted file mode 100644 index e1ce7b5db..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_runtime_run_table.rs +++ /dev/null @@ -1,231 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::bark_battle_runtime_run_row_type::BarkBattleRuntimeRunRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `bark_battle_runtime_run`. -/// -/// Obtain a handle from the [`BarkBattleRuntimeRunTableAccess::bark_battle_runtime_run`] method on [`super::RemoteTables`], -/// like `ctx.db.bark_battle_runtime_run()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.bark_battle_runtime_run().on_insert(...)`. -pub struct BarkBattleRuntimeRunTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `bark_battle_runtime_run`. -pub struct BarkBattleRuntimeRunTableAccessor; - -impl __sdk::TableAccessor for BarkBattleRuntimeRunTableAccessor { - type Row = BarkBattleRuntimeRunRow; - type Handle<'db> = BarkBattleRuntimeRunTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.bark_battle_runtime_run() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `bark_battle_runtime_run`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait BarkBattleRuntimeRunTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`BarkBattleRuntimeRunTableHandle`], which mediates access to the table `bark_battle_runtime_run`. - fn bark_battle_runtime_run(&self) -> BarkBattleRuntimeRunTableHandle<'_>; -} - -impl BarkBattleRuntimeRunTableAccess for super::RemoteTables { - fn bark_battle_runtime_run(&self) -> BarkBattleRuntimeRunTableHandle<'_> { - BarkBattleRuntimeRunTableHandle { - imp: self - .imp - .get_table::("bark_battle_runtime_run"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct BarkBattleRuntimeRunInsertCallbackId(__sdk::CallbackId); -pub struct BarkBattleRuntimeRunDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for BarkBattleRuntimeRunTableHandle<'ctx> { - type Row = BarkBattleRuntimeRunRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for BarkBattleRuntimeRunTableHandle<'ctx> { - type Row = BarkBattleRuntimeRunRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = BarkBattleRuntimeRunInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattleRuntimeRunInsertCallbackId { - BarkBattleRuntimeRunInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BarkBattleRuntimeRunInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = BarkBattleRuntimeRunDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattleRuntimeRunDeleteCallbackId { - BarkBattleRuntimeRunDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BarkBattleRuntimeRunDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for BarkBattleRuntimeRunTableHandle<'ctx> { - type InsertCallbackId = BarkBattleRuntimeRunInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattleRuntimeRunInsertCallbackId { - BarkBattleRuntimeRunInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BarkBattleRuntimeRunInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for BarkBattleRuntimeRunTableHandle<'ctx> { - type DeleteCallbackId = BarkBattleRuntimeRunDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattleRuntimeRunDeleteCallbackId { - BarkBattleRuntimeRunDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BarkBattleRuntimeRunDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct BarkBattleRuntimeRunUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for BarkBattleRuntimeRunTableHandle<'ctx> { - type UpdateCallbackId = BarkBattleRuntimeRunUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BarkBattleRuntimeRunUpdateCallbackId { - BarkBattleRuntimeRunUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BarkBattleRuntimeRunUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for BarkBattleRuntimeRunTableHandle<'ctx> { - type UpdateCallbackId = BarkBattleRuntimeRunUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BarkBattleRuntimeRunUpdateCallbackId { - BarkBattleRuntimeRunUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BarkBattleRuntimeRunUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `run_id` unique index on the table `bark_battle_runtime_run`, -/// which allows point queries on the field of the same name -/// via the [`BarkBattleRuntimeRunRunIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.bark_battle_runtime_run().run_id().find(...)`. -pub struct BarkBattleRuntimeRunRunIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> BarkBattleRuntimeRunTableHandle<'ctx> { - /// Get a handle on the `run_id` unique index on the table `bark_battle_runtime_run`. - pub fn run_id(&self) -> BarkBattleRuntimeRunRunIdUnique<'ctx> { - BarkBattleRuntimeRunRunIdUnique { - imp: self.imp.get_unique_constraint::("run_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> BarkBattleRuntimeRunRunIdUnique<'ctx> { - /// Find the subscribed row whose `run_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("bark_battle_runtime_run"); - _table.add_unique_constraint::("run_id", |row| &row.run_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `BarkBattleRuntimeRunRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait bark_battle_runtime_runQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `BarkBattleRuntimeRunRow`. - fn bark_battle_runtime_run(&self) -> __sdk::__query_builder::Table; -} - -impl bark_battle_runtime_runQueryTableAccess for __sdk::QueryTableAccessor { - fn bark_battle_runtime_run(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("bark_battle_runtime_run") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_score_record_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_score_record_row_type.rs deleted file mode 100644 index 8c8703b4b..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_score_record_row_type.rs +++ /dev/null @@ -1,106 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct BarkBattleScoreRecordRow { - pub score_id: String, - pub owner_user_id: String, - pub work_id: String, - pub run_id: String, - pub config_version: u64, - pub ruleset_version: String, - pub difficulty_preset: String, - pub leaderboard_enabled: bool, - pub metrics_json: String, - pub derived_metrics_json: String, - pub server_result: String, - pub validation_status: String, - pub anti_cheat_flags_json: String, - pub leaderboard_score: Option, - pub recorded_at: __sdk::Timestamp, -} - -impl __sdk::InModule for BarkBattleScoreRecordRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `BarkBattleScoreRecordRow`. -/// -/// Provides typed access to columns for query building. -pub struct BarkBattleScoreRecordRowCols { - pub score_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub work_id: __sdk::__query_builder::Col, - pub run_id: __sdk::__query_builder::Col, - pub config_version: __sdk::__query_builder::Col, - pub ruleset_version: __sdk::__query_builder::Col, - pub difficulty_preset: __sdk::__query_builder::Col, - pub leaderboard_enabled: __sdk::__query_builder::Col, - pub metrics_json: __sdk::__query_builder::Col, - pub derived_metrics_json: __sdk::__query_builder::Col, - pub server_result: __sdk::__query_builder::Col, - pub validation_status: __sdk::__query_builder::Col, - pub anti_cheat_flags_json: __sdk::__query_builder::Col, - pub leaderboard_score: __sdk::__query_builder::Col>, - pub recorded_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for BarkBattleScoreRecordRow { - type Cols = BarkBattleScoreRecordRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - BarkBattleScoreRecordRowCols { - score_id: __sdk::__query_builder::Col::new(table_name, "score_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - work_id: __sdk::__query_builder::Col::new(table_name, "work_id"), - run_id: __sdk::__query_builder::Col::new(table_name, "run_id"), - config_version: __sdk::__query_builder::Col::new(table_name, "config_version"), - ruleset_version: __sdk::__query_builder::Col::new(table_name, "ruleset_version"), - difficulty_preset: __sdk::__query_builder::Col::new(table_name, "difficulty_preset"), - leaderboard_enabled: __sdk::__query_builder::Col::new( - table_name, - "leaderboard_enabled", - ), - metrics_json: __sdk::__query_builder::Col::new(table_name, "metrics_json"), - derived_metrics_json: __sdk::__query_builder::Col::new( - table_name, - "derived_metrics_json", - ), - server_result: __sdk::__query_builder::Col::new(table_name, "server_result"), - validation_status: __sdk::__query_builder::Col::new(table_name, "validation_status"), - anti_cheat_flags_json: __sdk::__query_builder::Col::new( - table_name, - "anti_cheat_flags_json", - ), - leaderboard_score: __sdk::__query_builder::Col::new(table_name, "leaderboard_score"), - recorded_at: __sdk::__query_builder::Col::new(table_name, "recorded_at"), - } - } -} - -/// Indexed column accessor struct for the table `BarkBattleScoreRecordRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct BarkBattleScoreRecordRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub run_id: __sdk::__query_builder::IxCol, - pub score_id: __sdk::__query_builder::IxCol, - pub work_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for BarkBattleScoreRecordRow { - type IxCols = BarkBattleScoreRecordRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - BarkBattleScoreRecordRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - run_id: __sdk::__query_builder::IxCol::new(table_name, "run_id"), - score_id: __sdk::__query_builder::IxCol::new(table_name, "score_id"), - work_id: __sdk::__query_builder::IxCol::new(table_name, "work_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for BarkBattleScoreRecordRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_score_record_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_score_record_table.rs deleted file mode 100644 index c466c9d1a..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_score_record_table.rs +++ /dev/null @@ -1,231 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::bark_battle_score_record_row_type::BarkBattleScoreRecordRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `bark_battle_score_record`. -/// -/// Obtain a handle from the [`BarkBattleScoreRecordTableAccess::bark_battle_score_record`] method on [`super::RemoteTables`], -/// like `ctx.db.bark_battle_score_record()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.bark_battle_score_record().on_insert(...)`. -pub struct BarkBattleScoreRecordTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `bark_battle_score_record`. -pub struct BarkBattleScoreRecordTableAccessor; - -impl __sdk::TableAccessor for BarkBattleScoreRecordTableAccessor { - type Row = BarkBattleScoreRecordRow; - type Handle<'db> = BarkBattleScoreRecordTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.bark_battle_score_record() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `bark_battle_score_record`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait BarkBattleScoreRecordTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`BarkBattleScoreRecordTableHandle`], which mediates access to the table `bark_battle_score_record`. - fn bark_battle_score_record(&self) -> BarkBattleScoreRecordTableHandle<'_>; -} - -impl BarkBattleScoreRecordTableAccess for super::RemoteTables { - fn bark_battle_score_record(&self) -> BarkBattleScoreRecordTableHandle<'_> { - BarkBattleScoreRecordTableHandle { - imp: self - .imp - .get_table::("bark_battle_score_record"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct BarkBattleScoreRecordInsertCallbackId(__sdk::CallbackId); -pub struct BarkBattleScoreRecordDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for BarkBattleScoreRecordTableHandle<'ctx> { - type Row = BarkBattleScoreRecordRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for BarkBattleScoreRecordTableHandle<'ctx> { - type Row = BarkBattleScoreRecordRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = BarkBattleScoreRecordInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattleScoreRecordInsertCallbackId { - BarkBattleScoreRecordInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BarkBattleScoreRecordInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = BarkBattleScoreRecordDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattleScoreRecordDeleteCallbackId { - BarkBattleScoreRecordDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BarkBattleScoreRecordDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for BarkBattleScoreRecordTableHandle<'ctx> { - type InsertCallbackId = BarkBattleScoreRecordInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattleScoreRecordInsertCallbackId { - BarkBattleScoreRecordInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BarkBattleScoreRecordInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for BarkBattleScoreRecordTableHandle<'ctx> { - type DeleteCallbackId = BarkBattleScoreRecordDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattleScoreRecordDeleteCallbackId { - BarkBattleScoreRecordDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BarkBattleScoreRecordDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct BarkBattleScoreRecordUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for BarkBattleScoreRecordTableHandle<'ctx> { - type UpdateCallbackId = BarkBattleScoreRecordUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BarkBattleScoreRecordUpdateCallbackId { - BarkBattleScoreRecordUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BarkBattleScoreRecordUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for BarkBattleScoreRecordTableHandle<'ctx> { - type UpdateCallbackId = BarkBattleScoreRecordUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BarkBattleScoreRecordUpdateCallbackId { - BarkBattleScoreRecordUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BarkBattleScoreRecordUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `score_id` unique index on the table `bark_battle_score_record`, -/// which allows point queries on the field of the same name -/// via the [`BarkBattleScoreRecordScoreIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.bark_battle_score_record().score_id().find(...)`. -pub struct BarkBattleScoreRecordScoreIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> BarkBattleScoreRecordTableHandle<'ctx> { - /// Get a handle on the `score_id` unique index on the table `bark_battle_score_record`. - pub fn score_id(&self) -> BarkBattleScoreRecordScoreIdUnique<'ctx> { - BarkBattleScoreRecordScoreIdUnique { - imp: self.imp.get_unique_constraint::("score_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> BarkBattleScoreRecordScoreIdUnique<'ctx> { - /// Find the subscribed row whose `score_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("bark_battle_score_record"); - _table.add_unique_constraint::("score_id", |row| &row.score_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `BarkBattleScoreRecordRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait bark_battle_score_recordQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `BarkBattleScoreRecordRow`. - fn bark_battle_score_record(&self) -> __sdk::__query_builder::Table; -} - -impl bark_battle_score_recordQueryTableAccess for __sdk::QueryTableAccessor { - fn bark_battle_score_record(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("bark_battle_score_record") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_work_stats_projection_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_work_stats_projection_row_type.rs deleted file mode 100644 index 2d1163957..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_work_stats_projection_row_type.rs +++ /dev/null @@ -1,111 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct BarkBattleWorkStatsProjectionRow { - pub work_id: String, - pub owner_user_id: String, - pub play_count: u64, - pub finished_count: u64, - pub accepted_score_count: u64, - pub leaderboard_entry_count: u64, - pub best_leaderboard_score: Option, - pub best_score_id: Option, - pub best_run_id: Option, - pub average_final_energy: f32, - pub average_trigger_count: f32, - pub last_finished_at_micros: Option, - pub stats_json: String, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for BarkBattleWorkStatsProjectionRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `BarkBattleWorkStatsProjectionRow`. -/// -/// Provides typed access to columns for query building. -pub struct BarkBattleWorkStatsProjectionRowCols { - pub work_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub play_count: __sdk::__query_builder::Col, - pub finished_count: __sdk::__query_builder::Col, - pub accepted_score_count: __sdk::__query_builder::Col, - pub leaderboard_entry_count: __sdk::__query_builder::Col, - pub best_leaderboard_score: - __sdk::__query_builder::Col>, - pub best_score_id: - __sdk::__query_builder::Col>, - pub best_run_id: __sdk::__query_builder::Col>, - pub average_final_energy: __sdk::__query_builder::Col, - pub average_trigger_count: __sdk::__query_builder::Col, - pub last_finished_at_micros: - __sdk::__query_builder::Col>, - pub stats_json: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for BarkBattleWorkStatsProjectionRow { - type Cols = BarkBattleWorkStatsProjectionRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - BarkBattleWorkStatsProjectionRowCols { - work_id: __sdk::__query_builder::Col::new(table_name, "work_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - play_count: __sdk::__query_builder::Col::new(table_name, "play_count"), - finished_count: __sdk::__query_builder::Col::new(table_name, "finished_count"), - accepted_score_count: __sdk::__query_builder::Col::new( - table_name, - "accepted_score_count", - ), - leaderboard_entry_count: __sdk::__query_builder::Col::new( - table_name, - "leaderboard_entry_count", - ), - best_leaderboard_score: __sdk::__query_builder::Col::new( - table_name, - "best_leaderboard_score", - ), - best_score_id: __sdk::__query_builder::Col::new(table_name, "best_score_id"), - best_run_id: __sdk::__query_builder::Col::new(table_name, "best_run_id"), - average_final_energy: __sdk::__query_builder::Col::new( - table_name, - "average_final_energy", - ), - average_trigger_count: __sdk::__query_builder::Col::new( - table_name, - "average_trigger_count", - ), - last_finished_at_micros: __sdk::__query_builder::Col::new( - table_name, - "last_finished_at_micros", - ), - stats_json: __sdk::__query_builder::Col::new(table_name, "stats_json"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `BarkBattleWorkStatsProjectionRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct BarkBattleWorkStatsProjectionRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub work_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for BarkBattleWorkStatsProjectionRow { - type IxCols = BarkBattleWorkStatsProjectionRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - BarkBattleWorkStatsProjectionRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - work_id: __sdk::__query_builder::IxCol::new(table_name, "work_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for BarkBattleWorkStatsProjectionRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_work_stats_projection_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_work_stats_projection_table.rs deleted file mode 100644 index bc6346f76..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/bark_battle_work_stats_projection_table.rs +++ /dev/null @@ -1,238 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::bark_battle_work_stats_projection_row_type::BarkBattleWorkStatsProjectionRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `bark_battle_work_stats_projection`. -/// -/// Obtain a handle from the [`BarkBattleWorkStatsProjectionTableAccess::bark_battle_work_stats_projection`] method on [`super::RemoteTables`], -/// like `ctx.db.bark_battle_work_stats_projection()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.bark_battle_work_stats_projection().on_insert(...)`. -pub struct BarkBattleWorkStatsProjectionTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `bark_battle_work_stats_projection`. -pub struct BarkBattleWorkStatsProjectionTableAccessor; - -impl __sdk::TableAccessor for BarkBattleWorkStatsProjectionTableAccessor { - type Row = BarkBattleWorkStatsProjectionRow; - type Handle<'db> = BarkBattleWorkStatsProjectionTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.bark_battle_work_stats_projection() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `bark_battle_work_stats_projection`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait BarkBattleWorkStatsProjectionTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`BarkBattleWorkStatsProjectionTableHandle`], which mediates access to the table `bark_battle_work_stats_projection`. - fn bark_battle_work_stats_projection(&self) -> BarkBattleWorkStatsProjectionTableHandle<'_>; -} - -impl BarkBattleWorkStatsProjectionTableAccess for super::RemoteTables { - fn bark_battle_work_stats_projection(&self) -> BarkBattleWorkStatsProjectionTableHandle<'_> { - BarkBattleWorkStatsProjectionTableHandle { - imp: self - .imp - .get_table::("bark_battle_work_stats_projection"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct BarkBattleWorkStatsProjectionInsertCallbackId(__sdk::CallbackId); -pub struct BarkBattleWorkStatsProjectionDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for BarkBattleWorkStatsProjectionTableHandle<'ctx> { - type Row = BarkBattleWorkStatsProjectionRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for BarkBattleWorkStatsProjectionTableHandle<'ctx> { - type Row = BarkBattleWorkStatsProjectionRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = BarkBattleWorkStatsProjectionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattleWorkStatsProjectionInsertCallbackId { - BarkBattleWorkStatsProjectionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BarkBattleWorkStatsProjectionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = BarkBattleWorkStatsProjectionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattleWorkStatsProjectionDeleteCallbackId { - BarkBattleWorkStatsProjectionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BarkBattleWorkStatsProjectionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for BarkBattleWorkStatsProjectionTableHandle<'ctx> { - type InsertCallbackId = BarkBattleWorkStatsProjectionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattleWorkStatsProjectionInsertCallbackId { - BarkBattleWorkStatsProjectionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BarkBattleWorkStatsProjectionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for BarkBattleWorkStatsProjectionTableHandle<'ctx> { - type DeleteCallbackId = BarkBattleWorkStatsProjectionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BarkBattleWorkStatsProjectionDeleteCallbackId { - BarkBattleWorkStatsProjectionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BarkBattleWorkStatsProjectionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct BarkBattleWorkStatsProjectionUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for BarkBattleWorkStatsProjectionTableHandle<'ctx> { - type UpdateCallbackId = BarkBattleWorkStatsProjectionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BarkBattleWorkStatsProjectionUpdateCallbackId { - BarkBattleWorkStatsProjectionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BarkBattleWorkStatsProjectionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for BarkBattleWorkStatsProjectionTableHandle<'ctx> { - type UpdateCallbackId = BarkBattleWorkStatsProjectionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BarkBattleWorkStatsProjectionUpdateCallbackId { - BarkBattleWorkStatsProjectionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BarkBattleWorkStatsProjectionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `work_id` unique index on the table `bark_battle_work_stats_projection`, -/// which allows point queries on the field of the same name -/// via the [`BarkBattleWorkStatsProjectionWorkIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.bark_battle_work_stats_projection().work_id().find(...)`. -pub struct BarkBattleWorkStatsProjectionWorkIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> BarkBattleWorkStatsProjectionTableHandle<'ctx> { - /// Get a handle on the `work_id` unique index on the table `bark_battle_work_stats_projection`. - pub fn work_id(&self) -> BarkBattleWorkStatsProjectionWorkIdUnique<'ctx> { - BarkBattleWorkStatsProjectionWorkIdUnique { - imp: self.imp.get_unique_constraint::("work_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> BarkBattleWorkStatsProjectionWorkIdUnique<'ctx> { - /// Find the subscribed row whose `work_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache - .get_or_make_table::("bark_battle_work_stats_projection"); - _table.add_unique_constraint::("work_id", |row| &row.work_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse( - "TableUpdate", - "TableUpdate", - ) - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `BarkBattleWorkStatsProjectionRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait bark_battle_work_stats_projectionQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `BarkBattleWorkStatsProjectionRow`. - fn bark_battle_work_stats_projection( - &self, - ) -> __sdk::__query_builder::Table; -} - -impl bark_battle_work_stats_projectionQueryTableAccess for __sdk::QueryTableAccessor { - fn bark_battle_work_stats_projection( - &self, - ) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("bark_battle_work_stats_projection") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/battle_mode_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/battle_mode_type.rs deleted file mode 100644 index a88c25f4a..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/battle_mode_type.rs +++ /dev/null @@ -1,18 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum BattleMode { - Fight, - - Spar, -} - -impl __sdk::InModule for BattleMode { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/battle_state_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/battle_state_table.rs deleted file mode 100644 index 6b59fb16c..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/battle_state_table.rs +++ /dev/null @@ -1,232 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::battle_mode_type::BattleMode; -use super::battle_state_type::BattleState; -use super::battle_status_type::BattleStatus; -use super::combat_outcome_type::CombatOutcome; -use super::runtime_item_reward_item_snapshot_type::RuntimeItemRewardItemSnapshot; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `battle_state`. -/// -/// Obtain a handle from the [`BattleStateTableAccess::battle_state`] method on [`super::RemoteTables`], -/// like `ctx.db.battle_state()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.battle_state().on_insert(...)`. -pub struct BattleStateTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `battle_state`. -pub struct BattleStateTableAccessor; - -impl __sdk::TableAccessor for BattleStateTableAccessor { - type Row = BattleState; - type Handle<'db> = BattleStateTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.battle_state() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `battle_state`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait BattleStateTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`BattleStateTableHandle`], which mediates access to the table `battle_state`. - fn battle_state(&self) -> BattleStateTableHandle<'_>; -} - -impl BattleStateTableAccess for super::RemoteTables { - fn battle_state(&self) -> BattleStateTableHandle<'_> { - BattleStateTableHandle { - imp: self.imp.get_table::("battle_state"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct BattleStateInsertCallbackId(__sdk::CallbackId); -pub struct BattleStateDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for BattleStateTableHandle<'ctx> { - type Row = BattleState; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for BattleStateTableHandle<'ctx> { - type Row = BattleState; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = BattleStateInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BattleStateInsertCallbackId { - BattleStateInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BattleStateInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = BattleStateDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BattleStateDeleteCallbackId { - BattleStateDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BattleStateDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for BattleStateTableHandle<'ctx> { - type InsertCallbackId = BattleStateInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BattleStateInsertCallbackId { - BattleStateInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BattleStateInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for BattleStateTableHandle<'ctx> { - type DeleteCallbackId = BattleStateDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BattleStateDeleteCallbackId { - BattleStateDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BattleStateDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct BattleStateUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for BattleStateTableHandle<'ctx> { - type UpdateCallbackId = BattleStateUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BattleStateUpdateCallbackId { - BattleStateUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BattleStateUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for BattleStateTableHandle<'ctx> { - type UpdateCallbackId = BattleStateUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BattleStateUpdateCallbackId { - BattleStateUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BattleStateUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `battle_state_id` unique index on the table `battle_state`, -/// which allows point queries on the field of the same name -/// via the [`BattleStateBattleStateIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.battle_state().battle_state_id().find(...)`. -pub struct BattleStateBattleStateIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> BattleStateTableHandle<'ctx> { - /// Get a handle on the `battle_state_id` unique index on the table `battle_state`. - pub fn battle_state_id(&self) -> BattleStateBattleStateIdUnique<'ctx> { - BattleStateBattleStateIdUnique { - imp: self.imp.get_unique_constraint::("battle_state_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> BattleStateBattleStateIdUnique<'ctx> { - /// Find the subscribed row whose `battle_state_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("battle_state"); - _table.add_unique_constraint::("battle_state_id", |row| &row.battle_state_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `BattleState`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait battle_stateQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `BattleState`. - fn battle_state(&self) -> __sdk::__query_builder::Table; -} - -impl battle_stateQueryTableAccess for __sdk::QueryTableAccessor { - fn battle_state(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("battle_state") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/battle_state_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/battle_state_type.rs deleted file mode 100644 index 9d9b852ff..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/battle_state_type.rs +++ /dev/null @@ -1,144 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::battle_mode_type::BattleMode; -use super::battle_status_type::BattleStatus; -use super::combat_outcome_type::CombatOutcome; -use super::runtime_item_reward_item_snapshot_type::RuntimeItemRewardItemSnapshot; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct BattleState { - pub battle_state_id: String, - pub story_session_id: String, - pub runtime_session_id: String, - pub actor_user_id: String, - pub chapter_id: Option, - pub target_npc_id: String, - pub target_name: String, - pub battle_mode: BattleMode, - pub status: BattleStatus, - pub player_hp: i32, - pub player_max_hp: i32, - pub player_mana: i32, - pub player_max_mana: i32, - pub target_hp: i32, - pub target_max_hp: i32, - pub experience_reward: u32, - pub reward_items: Vec, - pub turn_index: u32, - pub last_action_function_id: Option, - pub last_action_text: Option, - pub last_result_text: Option, - pub last_damage_dealt: i32, - pub last_damage_taken: i32, - pub last_outcome: CombatOutcome, - pub version: u32, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for BattleState { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `BattleState`. -/// -/// Provides typed access to columns for query building. -pub struct BattleStateCols { - pub battle_state_id: __sdk::__query_builder::Col, - pub story_session_id: __sdk::__query_builder::Col, - pub runtime_session_id: __sdk::__query_builder::Col, - pub actor_user_id: __sdk::__query_builder::Col, - pub chapter_id: __sdk::__query_builder::Col>, - pub target_npc_id: __sdk::__query_builder::Col, - pub target_name: __sdk::__query_builder::Col, - pub battle_mode: __sdk::__query_builder::Col, - pub status: __sdk::__query_builder::Col, - pub player_hp: __sdk::__query_builder::Col, - pub player_max_hp: __sdk::__query_builder::Col, - pub player_mana: __sdk::__query_builder::Col, - pub player_max_mana: __sdk::__query_builder::Col, - pub target_hp: __sdk::__query_builder::Col, - pub target_max_hp: __sdk::__query_builder::Col, - pub experience_reward: __sdk::__query_builder::Col, - pub reward_items: __sdk::__query_builder::Col>, - pub turn_index: __sdk::__query_builder::Col, - pub last_action_function_id: __sdk::__query_builder::Col>, - pub last_action_text: __sdk::__query_builder::Col>, - pub last_result_text: __sdk::__query_builder::Col>, - pub last_damage_dealt: __sdk::__query_builder::Col, - pub last_damage_taken: __sdk::__query_builder::Col, - pub last_outcome: __sdk::__query_builder::Col, - pub version: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for BattleState { - type Cols = BattleStateCols; - fn cols(table_name: &'static str) -> Self::Cols { - BattleStateCols { - battle_state_id: __sdk::__query_builder::Col::new(table_name, "battle_state_id"), - story_session_id: __sdk::__query_builder::Col::new(table_name, "story_session_id"), - runtime_session_id: __sdk::__query_builder::Col::new(table_name, "runtime_session_id"), - actor_user_id: __sdk::__query_builder::Col::new(table_name, "actor_user_id"), - chapter_id: __sdk::__query_builder::Col::new(table_name, "chapter_id"), - target_npc_id: __sdk::__query_builder::Col::new(table_name, "target_npc_id"), - target_name: __sdk::__query_builder::Col::new(table_name, "target_name"), - battle_mode: __sdk::__query_builder::Col::new(table_name, "battle_mode"), - status: __sdk::__query_builder::Col::new(table_name, "status"), - player_hp: __sdk::__query_builder::Col::new(table_name, "player_hp"), - player_max_hp: __sdk::__query_builder::Col::new(table_name, "player_max_hp"), - player_mana: __sdk::__query_builder::Col::new(table_name, "player_mana"), - player_max_mana: __sdk::__query_builder::Col::new(table_name, "player_max_mana"), - target_hp: __sdk::__query_builder::Col::new(table_name, "target_hp"), - target_max_hp: __sdk::__query_builder::Col::new(table_name, "target_max_hp"), - experience_reward: __sdk::__query_builder::Col::new(table_name, "experience_reward"), - reward_items: __sdk::__query_builder::Col::new(table_name, "reward_items"), - turn_index: __sdk::__query_builder::Col::new(table_name, "turn_index"), - last_action_function_id: __sdk::__query_builder::Col::new( - table_name, - "last_action_function_id", - ), - last_action_text: __sdk::__query_builder::Col::new(table_name, "last_action_text"), - last_result_text: __sdk::__query_builder::Col::new(table_name, "last_result_text"), - last_damage_dealt: __sdk::__query_builder::Col::new(table_name, "last_damage_dealt"), - last_damage_taken: __sdk::__query_builder::Col::new(table_name, "last_damage_taken"), - last_outcome: __sdk::__query_builder::Col::new(table_name, "last_outcome"), - version: __sdk::__query_builder::Col::new(table_name, "version"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `BattleState`. -/// -/// Provides typed access to indexed columns for query building. -pub struct BattleStateIxCols { - pub actor_user_id: __sdk::__query_builder::IxCol, - pub battle_state_id: __sdk::__query_builder::IxCol, - pub runtime_session_id: __sdk::__query_builder::IxCol, - pub story_session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for BattleState { - type IxCols = BattleStateIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - BattleStateIxCols { - actor_user_id: __sdk::__query_builder::IxCol::new(table_name, "actor_user_id"), - battle_state_id: __sdk::__query_builder::IxCol::new(table_name, "battle_state_id"), - runtime_session_id: __sdk::__query_builder::IxCol::new( - table_name, - "runtime_session_id", - ), - story_session_id: __sdk::__query_builder::IxCol::new(table_name, "story_session_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for BattleState {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/battle_status_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/battle_status_type.rs deleted file mode 100644 index 0aba4f432..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/battle_status_type.rs +++ /dev/null @@ -1,20 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum BattleStatus { - Ongoing, - - Resolved, - - Aborted, -} - -impl __sdk::InModule for BattleStatus { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_agent_message_kind_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_agent_message_kind_type.rs deleted file mode 100644 index 00f36e4ef..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_agent_message_kind_type.rs +++ /dev/null @@ -1,22 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum BigFishAgentMessageKind { - Chat, - - Summary, - - ActionResult, - - Warning, -} - -impl __sdk::InModule for BigFishAgentMessageKind { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_agent_message_role_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_agent_message_role_type.rs deleted file mode 100644 index d8a1a82c3..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_agent_message_role_type.rs +++ /dev/null @@ -1,20 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum BigFishAgentMessageRole { - User, - - Assistant, - - System, -} - -impl __sdk::InModule for BigFishAgentMessageRole { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_agent_message_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_agent_message_table.rs deleted file mode 100644 index 51683b3d3..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_agent_message_table.rs +++ /dev/null @@ -1,232 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::big_fish_agent_message_kind_type::BigFishAgentMessageKind; -use super::big_fish_agent_message_role_type::BigFishAgentMessageRole; -use super::big_fish_agent_message_type::BigFishAgentMessage; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `big_fish_agent_message`. -/// -/// Obtain a handle from the [`BigFishAgentMessageTableAccess::big_fish_agent_message`] method on [`super::RemoteTables`], -/// like `ctx.db.big_fish_agent_message()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.big_fish_agent_message().on_insert(...)`. -pub struct BigFishAgentMessageTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `big_fish_agent_message`. -pub struct BigFishAgentMessageTableAccessor; - -impl __sdk::TableAccessor for BigFishAgentMessageTableAccessor { - type Row = BigFishAgentMessage; - type Handle<'db> = BigFishAgentMessageTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.big_fish_agent_message() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `big_fish_agent_message`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait BigFishAgentMessageTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`BigFishAgentMessageTableHandle`], which mediates access to the table `big_fish_agent_message`. - fn big_fish_agent_message(&self) -> BigFishAgentMessageTableHandle<'_>; -} - -impl BigFishAgentMessageTableAccess for super::RemoteTables { - fn big_fish_agent_message(&self) -> BigFishAgentMessageTableHandle<'_> { - BigFishAgentMessageTableHandle { - imp: self - .imp - .get_table::("big_fish_agent_message"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct BigFishAgentMessageInsertCallbackId(__sdk::CallbackId); -pub struct BigFishAgentMessageDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for BigFishAgentMessageTableHandle<'ctx> { - type Row = BigFishAgentMessage; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for BigFishAgentMessageTableHandle<'ctx> { - type Row = BigFishAgentMessage; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = BigFishAgentMessageInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BigFishAgentMessageInsertCallbackId { - BigFishAgentMessageInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BigFishAgentMessageInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = BigFishAgentMessageDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BigFishAgentMessageDeleteCallbackId { - BigFishAgentMessageDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BigFishAgentMessageDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for BigFishAgentMessageTableHandle<'ctx> { - type InsertCallbackId = BigFishAgentMessageInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BigFishAgentMessageInsertCallbackId { - BigFishAgentMessageInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BigFishAgentMessageInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for BigFishAgentMessageTableHandle<'ctx> { - type DeleteCallbackId = BigFishAgentMessageDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BigFishAgentMessageDeleteCallbackId { - BigFishAgentMessageDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BigFishAgentMessageDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct BigFishAgentMessageUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for BigFishAgentMessageTableHandle<'ctx> { - type UpdateCallbackId = BigFishAgentMessageUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BigFishAgentMessageUpdateCallbackId { - BigFishAgentMessageUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BigFishAgentMessageUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for BigFishAgentMessageTableHandle<'ctx> { - type UpdateCallbackId = BigFishAgentMessageUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BigFishAgentMessageUpdateCallbackId { - BigFishAgentMessageUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BigFishAgentMessageUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `message_id` unique index on the table `big_fish_agent_message`, -/// which allows point queries on the field of the same name -/// via the [`BigFishAgentMessageMessageIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.big_fish_agent_message().message_id().find(...)`. -pub struct BigFishAgentMessageMessageIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> BigFishAgentMessageTableHandle<'ctx> { - /// Get a handle on the `message_id` unique index on the table `big_fish_agent_message`. - pub fn message_id(&self) -> BigFishAgentMessageMessageIdUnique<'ctx> { - BigFishAgentMessageMessageIdUnique { - imp: self.imp.get_unique_constraint::("message_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> BigFishAgentMessageMessageIdUnique<'ctx> { - /// Find the subscribed row whose `message_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("big_fish_agent_message"); - _table.add_unique_constraint::("message_id", |row| &row.message_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `BigFishAgentMessage`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait big_fish_agent_messageQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `BigFishAgentMessage`. - fn big_fish_agent_message(&self) -> __sdk::__query_builder::Table; -} - -impl big_fish_agent_messageQueryTableAccess for __sdk::QueryTableAccessor { - fn big_fish_agent_message(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("big_fish_agent_message") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_agent_message_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_agent_message_type.rs deleted file mode 100644 index a5e70272d..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_agent_message_type.rs +++ /dev/null @@ -1,69 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::big_fish_agent_message_kind_type::BigFishAgentMessageKind; -use super::big_fish_agent_message_role_type::BigFishAgentMessageRole; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct BigFishAgentMessage { - pub message_id: String, - pub session_id: String, - pub role: BigFishAgentMessageRole, - pub kind: BigFishAgentMessageKind, - pub text: String, - pub created_at: __sdk::Timestamp, -} - -impl __sdk::InModule for BigFishAgentMessage { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `BigFishAgentMessage`. -/// -/// Provides typed access to columns for query building. -pub struct BigFishAgentMessageCols { - pub message_id: __sdk::__query_builder::Col, - pub session_id: __sdk::__query_builder::Col, - pub role: __sdk::__query_builder::Col, - pub kind: __sdk::__query_builder::Col, - pub text: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for BigFishAgentMessage { - type Cols = BigFishAgentMessageCols; - fn cols(table_name: &'static str) -> Self::Cols { - BigFishAgentMessageCols { - message_id: __sdk::__query_builder::Col::new(table_name, "message_id"), - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - role: __sdk::__query_builder::Col::new(table_name, "role"), - kind: __sdk::__query_builder::Col::new(table_name, "kind"), - text: __sdk::__query_builder::Col::new(table_name, "text"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - } - } -} - -/// Indexed column accessor struct for the table `BigFishAgentMessage`. -/// -/// Provides typed access to indexed columns for query building. -pub struct BigFishAgentMessageIxCols { - pub message_id: __sdk::__query_builder::IxCol, - pub session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for BigFishAgentMessage { - type IxCols = BigFishAgentMessageIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - BigFishAgentMessageIxCols { - message_id: __sdk::__query_builder::IxCol::new(table_name, "message_id"), - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for BigFishAgentMessage {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_asset_kind_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_asset_kind_type.rs deleted file mode 100644 index b4c9dcd1f..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_asset_kind_type.rs +++ /dev/null @@ -1,20 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum BigFishAssetKind { - LevelMainImage, - - LevelMotion, - - StageBackground, -} - -impl __sdk::InModule for BigFishAssetKind { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_asset_slot_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_asset_slot_table.rs deleted file mode 100644 index 1cc8b52cc..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_asset_slot_table.rs +++ /dev/null @@ -1,232 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::big_fish_asset_kind_type::BigFishAssetKind; -use super::big_fish_asset_slot_type::BigFishAssetSlot; -use super::big_fish_asset_status_type::BigFishAssetStatus; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `big_fish_asset_slot`. -/// -/// Obtain a handle from the [`BigFishAssetSlotTableAccess::big_fish_asset_slot`] method on [`super::RemoteTables`], -/// like `ctx.db.big_fish_asset_slot()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.big_fish_asset_slot().on_insert(...)`. -pub struct BigFishAssetSlotTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `big_fish_asset_slot`. -pub struct BigFishAssetSlotTableAccessor; - -impl __sdk::TableAccessor for BigFishAssetSlotTableAccessor { - type Row = BigFishAssetSlot; - type Handle<'db> = BigFishAssetSlotTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.big_fish_asset_slot() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `big_fish_asset_slot`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait BigFishAssetSlotTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`BigFishAssetSlotTableHandle`], which mediates access to the table `big_fish_asset_slot`. - fn big_fish_asset_slot(&self) -> BigFishAssetSlotTableHandle<'_>; -} - -impl BigFishAssetSlotTableAccess for super::RemoteTables { - fn big_fish_asset_slot(&self) -> BigFishAssetSlotTableHandle<'_> { - BigFishAssetSlotTableHandle { - imp: self - .imp - .get_table::("big_fish_asset_slot"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct BigFishAssetSlotInsertCallbackId(__sdk::CallbackId); -pub struct BigFishAssetSlotDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for BigFishAssetSlotTableHandle<'ctx> { - type Row = BigFishAssetSlot; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for BigFishAssetSlotTableHandle<'ctx> { - type Row = BigFishAssetSlot; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = BigFishAssetSlotInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BigFishAssetSlotInsertCallbackId { - BigFishAssetSlotInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BigFishAssetSlotInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = BigFishAssetSlotDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BigFishAssetSlotDeleteCallbackId { - BigFishAssetSlotDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BigFishAssetSlotDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for BigFishAssetSlotTableHandle<'ctx> { - type InsertCallbackId = BigFishAssetSlotInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BigFishAssetSlotInsertCallbackId { - BigFishAssetSlotInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BigFishAssetSlotInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for BigFishAssetSlotTableHandle<'ctx> { - type DeleteCallbackId = BigFishAssetSlotDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BigFishAssetSlotDeleteCallbackId { - BigFishAssetSlotDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BigFishAssetSlotDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct BigFishAssetSlotUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for BigFishAssetSlotTableHandle<'ctx> { - type UpdateCallbackId = BigFishAssetSlotUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BigFishAssetSlotUpdateCallbackId { - BigFishAssetSlotUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BigFishAssetSlotUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for BigFishAssetSlotTableHandle<'ctx> { - type UpdateCallbackId = BigFishAssetSlotUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BigFishAssetSlotUpdateCallbackId { - BigFishAssetSlotUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BigFishAssetSlotUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `slot_id` unique index on the table `big_fish_asset_slot`, -/// which allows point queries on the field of the same name -/// via the [`BigFishAssetSlotSlotIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.big_fish_asset_slot().slot_id().find(...)`. -pub struct BigFishAssetSlotSlotIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> BigFishAssetSlotTableHandle<'ctx> { - /// Get a handle on the `slot_id` unique index on the table `big_fish_asset_slot`. - pub fn slot_id(&self) -> BigFishAssetSlotSlotIdUnique<'ctx> { - BigFishAssetSlotSlotIdUnique { - imp: self.imp.get_unique_constraint::("slot_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> BigFishAssetSlotSlotIdUnique<'ctx> { - /// Find the subscribed row whose `slot_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("big_fish_asset_slot"); - _table.add_unique_constraint::("slot_id", |row| &row.slot_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `BigFishAssetSlot`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait big_fish_asset_slotQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `BigFishAssetSlot`. - fn big_fish_asset_slot(&self) -> __sdk::__query_builder::Table; -} - -impl big_fish_asset_slotQueryTableAccess for __sdk::QueryTableAccessor { - fn big_fish_asset_slot(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("big_fish_asset_slot") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_asset_slot_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_asset_slot_type.rs deleted file mode 100644 index 406c151d0..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_asset_slot_type.rs +++ /dev/null @@ -1,78 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::big_fish_asset_kind_type::BigFishAssetKind; -use super::big_fish_asset_status_type::BigFishAssetStatus; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct BigFishAssetSlot { - pub slot_id: String, - pub session_id: String, - pub asset_kind: BigFishAssetKind, - pub level: Option, - pub motion_key: Option, - pub status: BigFishAssetStatus, - pub asset_url: Option, - pub prompt_snapshot: String, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for BigFishAssetSlot { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `BigFishAssetSlot`. -/// -/// Provides typed access to columns for query building. -pub struct BigFishAssetSlotCols { - pub slot_id: __sdk::__query_builder::Col, - pub session_id: __sdk::__query_builder::Col, - pub asset_kind: __sdk::__query_builder::Col, - pub level: __sdk::__query_builder::Col>, - pub motion_key: __sdk::__query_builder::Col>, - pub status: __sdk::__query_builder::Col, - pub asset_url: __sdk::__query_builder::Col>, - pub prompt_snapshot: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for BigFishAssetSlot { - type Cols = BigFishAssetSlotCols; - fn cols(table_name: &'static str) -> Self::Cols { - BigFishAssetSlotCols { - slot_id: __sdk::__query_builder::Col::new(table_name, "slot_id"), - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - asset_kind: __sdk::__query_builder::Col::new(table_name, "asset_kind"), - level: __sdk::__query_builder::Col::new(table_name, "level"), - motion_key: __sdk::__query_builder::Col::new(table_name, "motion_key"), - status: __sdk::__query_builder::Col::new(table_name, "status"), - asset_url: __sdk::__query_builder::Col::new(table_name, "asset_url"), - prompt_snapshot: __sdk::__query_builder::Col::new(table_name, "prompt_snapshot"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `BigFishAssetSlot`. -/// -/// Provides typed access to indexed columns for query building. -pub struct BigFishAssetSlotIxCols { - pub session_id: __sdk::__query_builder::IxCol, - pub slot_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for BigFishAssetSlot { - type IxCols = BigFishAssetSlotIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - BigFishAssetSlotIxCols { - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - slot_id: __sdk::__query_builder::IxCol::new(table_name, "slot_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for BigFishAssetSlot {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_asset_status_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_asset_status_type.rs deleted file mode 100644 index c673f0f33..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_asset_status_type.rs +++ /dev/null @@ -1,18 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum BigFishAssetStatus { - Missing, - - Ready, -} - -impl __sdk::InModule for BigFishAssetStatus { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_creation_session_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_creation_session_table.rs deleted file mode 100644 index 62451f321..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_creation_session_table.rs +++ /dev/null @@ -1,232 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::big_fish_creation_session_type::BigFishCreationSession; -use super::big_fish_creation_stage_type::BigFishCreationStage; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `big_fish_creation_session`. -/// -/// Obtain a handle from the [`BigFishCreationSessionTableAccess::big_fish_creation_session`] method on [`super::RemoteTables`], -/// like `ctx.db.big_fish_creation_session()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.big_fish_creation_session().on_insert(...)`. -pub struct BigFishCreationSessionTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `big_fish_creation_session`. -pub struct BigFishCreationSessionTableAccessor; - -impl __sdk::TableAccessor for BigFishCreationSessionTableAccessor { - type Row = BigFishCreationSession; - type Handle<'db> = BigFishCreationSessionTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.big_fish_creation_session() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `big_fish_creation_session`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait BigFishCreationSessionTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`BigFishCreationSessionTableHandle`], which mediates access to the table `big_fish_creation_session`. - fn big_fish_creation_session(&self) -> BigFishCreationSessionTableHandle<'_>; -} - -impl BigFishCreationSessionTableAccess for super::RemoteTables { - fn big_fish_creation_session(&self) -> BigFishCreationSessionTableHandle<'_> { - BigFishCreationSessionTableHandle { - imp: self - .imp - .get_table::("big_fish_creation_session"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct BigFishCreationSessionInsertCallbackId(__sdk::CallbackId); -pub struct BigFishCreationSessionDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for BigFishCreationSessionTableHandle<'ctx> { - type Row = BigFishCreationSession; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for BigFishCreationSessionTableHandle<'ctx> { - type Row = BigFishCreationSession; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = BigFishCreationSessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BigFishCreationSessionInsertCallbackId { - BigFishCreationSessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BigFishCreationSessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = BigFishCreationSessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BigFishCreationSessionDeleteCallbackId { - BigFishCreationSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BigFishCreationSessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for BigFishCreationSessionTableHandle<'ctx> { - type InsertCallbackId = BigFishCreationSessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BigFishCreationSessionInsertCallbackId { - BigFishCreationSessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BigFishCreationSessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for BigFishCreationSessionTableHandle<'ctx> { - type DeleteCallbackId = BigFishCreationSessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BigFishCreationSessionDeleteCallbackId { - BigFishCreationSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BigFishCreationSessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct BigFishCreationSessionUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for BigFishCreationSessionTableHandle<'ctx> { - type UpdateCallbackId = BigFishCreationSessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BigFishCreationSessionUpdateCallbackId { - BigFishCreationSessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BigFishCreationSessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for BigFishCreationSessionTableHandle<'ctx> { - type UpdateCallbackId = BigFishCreationSessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BigFishCreationSessionUpdateCallbackId { - BigFishCreationSessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BigFishCreationSessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `session_id` unique index on the table `big_fish_creation_session`, -/// which allows point queries on the field of the same name -/// via the [`BigFishCreationSessionSessionIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.big_fish_creation_session().session_id().find(...)`. -pub struct BigFishCreationSessionSessionIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> BigFishCreationSessionTableHandle<'ctx> { - /// Get a handle on the `session_id` unique index on the table `big_fish_creation_session`. - pub fn session_id(&self) -> BigFishCreationSessionSessionIdUnique<'ctx> { - BigFishCreationSessionSessionIdUnique { - imp: self.imp.get_unique_constraint::("session_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> BigFishCreationSessionSessionIdUnique<'ctx> { - /// Find the subscribed row whose `session_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("big_fish_creation_session"); - _table.add_unique_constraint::("session_id", |row| &row.session_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `BigFishCreationSession`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait big_fish_creation_sessionQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `BigFishCreationSession`. - fn big_fish_creation_session(&self) -> __sdk::__query_builder::Table; -} - -impl big_fish_creation_sessionQueryTableAccess for __sdk::QueryTableAccessor { - fn big_fish_creation_session(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("big_fish_creation_session") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_creation_session_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_creation_session_type.rs deleted file mode 100644 index 25aaff8c8..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_creation_session_type.rs +++ /dev/null @@ -1,112 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::big_fish_creation_stage_type::BigFishCreationStage; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct BigFishCreationSession { - pub session_id: String, - pub owner_user_id: String, - pub seed_text: String, - pub current_turn: u32, - pub progress_percent: u32, - pub stage: BigFishCreationStage, - pub anchor_pack_json: String, - pub draft_json: Option, - pub asset_coverage_json: String, - pub last_assistant_reply: Option, - pub publish_ready: bool, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, - pub play_count: u32, - pub remix_count: u32, - pub like_count: u32, - pub published_at: Option<__sdk::Timestamp>, - pub visible: bool, -} - -impl __sdk::InModule for BigFishCreationSession { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `BigFishCreationSession`. -/// -/// Provides typed access to columns for query building. -pub struct BigFishCreationSessionCols { - pub session_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub seed_text: __sdk::__query_builder::Col, - pub current_turn: __sdk::__query_builder::Col, - pub progress_percent: __sdk::__query_builder::Col, - pub stage: __sdk::__query_builder::Col, - pub anchor_pack_json: __sdk::__query_builder::Col, - pub draft_json: __sdk::__query_builder::Col>, - pub asset_coverage_json: __sdk::__query_builder::Col, - pub last_assistant_reply: __sdk::__query_builder::Col>, - pub publish_ready: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, - pub play_count: __sdk::__query_builder::Col, - pub remix_count: __sdk::__query_builder::Col, - pub like_count: __sdk::__query_builder::Col, - pub published_at: __sdk::__query_builder::Col>, - pub visible: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for BigFishCreationSession { - type Cols = BigFishCreationSessionCols; - fn cols(table_name: &'static str) -> Self::Cols { - BigFishCreationSessionCols { - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - seed_text: __sdk::__query_builder::Col::new(table_name, "seed_text"), - current_turn: __sdk::__query_builder::Col::new(table_name, "current_turn"), - progress_percent: __sdk::__query_builder::Col::new(table_name, "progress_percent"), - stage: __sdk::__query_builder::Col::new(table_name, "stage"), - anchor_pack_json: __sdk::__query_builder::Col::new(table_name, "anchor_pack_json"), - draft_json: __sdk::__query_builder::Col::new(table_name, "draft_json"), - asset_coverage_json: __sdk::__query_builder::Col::new( - table_name, - "asset_coverage_json", - ), - last_assistant_reply: __sdk::__query_builder::Col::new( - table_name, - "last_assistant_reply", - ), - publish_ready: __sdk::__query_builder::Col::new(table_name, "publish_ready"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - play_count: __sdk::__query_builder::Col::new(table_name, "play_count"), - remix_count: __sdk::__query_builder::Col::new(table_name, "remix_count"), - like_count: __sdk::__query_builder::Col::new(table_name, "like_count"), - published_at: __sdk::__query_builder::Col::new(table_name, "published_at"), - visible: __sdk::__query_builder::Col::new(table_name, "visible"), - } - } -} - -/// Indexed column accessor struct for the table `BigFishCreationSession`. -/// -/// Provides typed access to indexed columns for query building. -pub struct BigFishCreationSessionIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub session_id: __sdk::__query_builder::IxCol, - pub stage: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for BigFishCreationSession { - type IxCols = BigFishCreationSessionIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - BigFishCreationSessionIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - stage: __sdk::__query_builder::IxCol::new(table_name, "stage"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for BigFishCreationSession {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_creation_stage_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_creation_stage_type.rs deleted file mode 100644 index c878d467a..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_creation_stage_type.rs +++ /dev/null @@ -1,24 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum BigFishCreationStage { - CollectingAnchors, - - DraftReady, - - AssetRefining, - - ReadyToPublish, - - Published, -} - -impl __sdk::InModule for BigFishCreationStage { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_event_kind_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_event_kind_type.rs deleted file mode 100644 index d033e0265..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_event_kind_type.rs +++ /dev/null @@ -1,16 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum BigFishEventKind { - PublishReadinessEvaluated, -} - -impl __sdk::InModule for BigFishEventKind { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_event_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_event_table.rs deleted file mode 100644 index 1999f9fa9..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_event_table.rs +++ /dev/null @@ -1,138 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::big_fish_event_kind_type::BigFishEventKind; -use super::big_fish_event_type::BigFishEvent; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `big_fish_event`. -/// -/// Obtain a handle from the [`BigFishEventTableAccess::big_fish_event`] method on [`super::RemoteTables`], -/// like `ctx.db.big_fish_event()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.big_fish_event().on_insert(...)`. -pub struct BigFishEventTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `big_fish_event`. -pub struct BigFishEventTableAccessor; - -impl __sdk::TableAccessor for BigFishEventTableAccessor { - type Row = BigFishEvent; - type Handle<'db> = BigFishEventTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.big_fish_event() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `big_fish_event`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait BigFishEventTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`BigFishEventTableHandle`], which mediates access to the table `big_fish_event`. - fn big_fish_event(&self) -> BigFishEventTableHandle<'_>; -} - -impl BigFishEventTableAccess for super::RemoteTables { - fn big_fish_event(&self) -> BigFishEventTableHandle<'_> { - BigFishEventTableHandle { - imp: self.imp.get_table::("big_fish_event"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct BigFishEventInsertCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for BigFishEventTableHandle<'ctx> { - type Row = BigFishEvent; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::EventTable for BigFishEventTableHandle<'ctx> { - type Row = BigFishEvent; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = BigFishEventInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BigFishEventInsertCallbackId { - BigFishEventInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BigFishEventInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for BigFishEventTableHandle<'ctx> { - type InsertCallbackId = BigFishEventInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BigFishEventInsertCallbackId { - BigFishEventInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BigFishEventInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("big_fish_event"); - _table.add_unique_constraint::("event_id", |row| &row.event_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `BigFishEvent`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait big_fish_eventQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `BigFishEvent`. - fn big_fish_event(&self) -> __sdk::__query_builder::Table; -} - -impl big_fish_eventQueryTableAccess for __sdk::QueryTableAccessor { - fn big_fish_event(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("big_fish_event") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_event_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_event_type.rs deleted file mode 100644 index d5fd1db54..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_event_type.rs +++ /dev/null @@ -1,71 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::big_fish_event_kind_type::BigFishEventKind; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct BigFishEvent { - pub event_id: String, - pub session_id: String, - pub owner_user_id: String, - pub event_kind: BigFishEventKind, - pub publish_ready: bool, - pub blockers_json: String, - pub occurred_at: __sdk::Timestamp, -} - -impl __sdk::InModule for BigFishEvent { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `BigFishEvent`. -/// -/// Provides typed access to columns for query building. -pub struct BigFishEventCols { - pub event_id: __sdk::__query_builder::Col, - pub session_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub event_kind: __sdk::__query_builder::Col, - pub publish_ready: __sdk::__query_builder::Col, - pub blockers_json: __sdk::__query_builder::Col, - pub occurred_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for BigFishEvent { - type Cols = BigFishEventCols; - fn cols(table_name: &'static str) -> Self::Cols { - BigFishEventCols { - event_id: __sdk::__query_builder::Col::new(table_name, "event_id"), - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - event_kind: __sdk::__query_builder::Col::new(table_name, "event_kind"), - publish_ready: __sdk::__query_builder::Col::new(table_name, "publish_ready"), - blockers_json: __sdk::__query_builder::Col::new(table_name, "blockers_json"), - occurred_at: __sdk::__query_builder::Col::new(table_name, "occurred_at"), - } - } -} - -/// Indexed column accessor struct for the table `BigFishEvent`. -/// -/// Provides typed access to indexed columns for query building. -pub struct BigFishEventIxCols { - pub event_id: __sdk::__query_builder::IxCol, - pub owner_user_id: __sdk::__query_builder::IxCol, - pub session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for BigFishEvent { - type IxCols = BigFishEventIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - BigFishEventIxCols { - event_id: __sdk::__query_builder::IxCol::new(table_name, "event_id"), - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - } - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_run_status_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_run_status_type.rs deleted file mode 100644 index 6bb94f360..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_run_status_type.rs +++ /dev/null @@ -1,20 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum BigFishRunStatus { - Running, - - Won, - - Failed, -} - -impl __sdk::InModule for BigFishRunStatus { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_runtime_run_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_runtime_run_table.rs deleted file mode 100644 index 1b037679a..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_runtime_run_table.rs +++ /dev/null @@ -1,231 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::big_fish_run_status_type::BigFishRunStatus; -use super::big_fish_runtime_run_type::BigFishRuntimeRun; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `big_fish_runtime_run`. -/// -/// Obtain a handle from the [`BigFishRuntimeRunTableAccess::big_fish_runtime_run`] method on [`super::RemoteTables`], -/// like `ctx.db.big_fish_runtime_run()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.big_fish_runtime_run().on_insert(...)`. -pub struct BigFishRuntimeRunTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `big_fish_runtime_run`. -pub struct BigFishRuntimeRunTableAccessor; - -impl __sdk::TableAccessor for BigFishRuntimeRunTableAccessor { - type Row = BigFishRuntimeRun; - type Handle<'db> = BigFishRuntimeRunTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.big_fish_runtime_run() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `big_fish_runtime_run`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait BigFishRuntimeRunTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`BigFishRuntimeRunTableHandle`], which mediates access to the table `big_fish_runtime_run`. - fn big_fish_runtime_run(&self) -> BigFishRuntimeRunTableHandle<'_>; -} - -impl BigFishRuntimeRunTableAccess for super::RemoteTables { - fn big_fish_runtime_run(&self) -> BigFishRuntimeRunTableHandle<'_> { - BigFishRuntimeRunTableHandle { - imp: self - .imp - .get_table::("big_fish_runtime_run"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct BigFishRuntimeRunInsertCallbackId(__sdk::CallbackId); -pub struct BigFishRuntimeRunDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for BigFishRuntimeRunTableHandle<'ctx> { - type Row = BigFishRuntimeRun; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for BigFishRuntimeRunTableHandle<'ctx> { - type Row = BigFishRuntimeRun; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = BigFishRuntimeRunInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BigFishRuntimeRunInsertCallbackId { - BigFishRuntimeRunInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BigFishRuntimeRunInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = BigFishRuntimeRunDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BigFishRuntimeRunDeleteCallbackId { - BigFishRuntimeRunDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BigFishRuntimeRunDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for BigFishRuntimeRunTableHandle<'ctx> { - type InsertCallbackId = BigFishRuntimeRunInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BigFishRuntimeRunInsertCallbackId { - BigFishRuntimeRunInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: BigFishRuntimeRunInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for BigFishRuntimeRunTableHandle<'ctx> { - type DeleteCallbackId = BigFishRuntimeRunDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> BigFishRuntimeRunDeleteCallbackId { - BigFishRuntimeRunDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: BigFishRuntimeRunDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct BigFishRuntimeRunUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for BigFishRuntimeRunTableHandle<'ctx> { - type UpdateCallbackId = BigFishRuntimeRunUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BigFishRuntimeRunUpdateCallbackId { - BigFishRuntimeRunUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BigFishRuntimeRunUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for BigFishRuntimeRunTableHandle<'ctx> { - type UpdateCallbackId = BigFishRuntimeRunUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> BigFishRuntimeRunUpdateCallbackId { - BigFishRuntimeRunUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: BigFishRuntimeRunUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `run_id` unique index on the table `big_fish_runtime_run`, -/// which allows point queries on the field of the same name -/// via the [`BigFishRuntimeRunRunIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.big_fish_runtime_run().run_id().find(...)`. -pub struct BigFishRuntimeRunRunIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> BigFishRuntimeRunTableHandle<'ctx> { - /// Get a handle on the `run_id` unique index on the table `big_fish_runtime_run`. - pub fn run_id(&self) -> BigFishRuntimeRunRunIdUnique<'ctx> { - BigFishRuntimeRunRunIdUnique { - imp: self.imp.get_unique_constraint::("run_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> BigFishRuntimeRunRunIdUnique<'ctx> { - /// Find the subscribed row whose `run_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("big_fish_runtime_run"); - _table.add_unique_constraint::("run_id", |row| &row.run_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `BigFishRuntimeRun`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait big_fish_runtime_runQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `BigFishRuntimeRun`. - fn big_fish_runtime_run(&self) -> __sdk::__query_builder::Table; -} - -impl big_fish_runtime_runQueryTableAccess for __sdk::QueryTableAccessor { - fn big_fish_runtime_run(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("big_fish_runtime_run") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_runtime_run_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_runtime_run_type.rs deleted file mode 100644 index 01852b9cc..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_runtime_run_type.rs +++ /dev/null @@ -1,82 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::big_fish_run_status_type::BigFishRunStatus; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct BigFishRuntimeRun { - pub run_id: String, - pub session_id: String, - pub owner_user_id: String, - pub status: BigFishRunStatus, - pub snapshot_json: String, - pub last_input_x: f32, - pub last_input_y: f32, - pub tick: u64, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for BigFishRuntimeRun { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `BigFishRuntimeRun`. -/// -/// Provides typed access to columns for query building. -pub struct BigFishRuntimeRunCols { - pub run_id: __sdk::__query_builder::Col, - pub session_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub status: __sdk::__query_builder::Col, - pub snapshot_json: __sdk::__query_builder::Col, - pub last_input_x: __sdk::__query_builder::Col, - pub last_input_y: __sdk::__query_builder::Col, - pub tick: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for BigFishRuntimeRun { - type Cols = BigFishRuntimeRunCols; - fn cols(table_name: &'static str) -> Self::Cols { - BigFishRuntimeRunCols { - run_id: __sdk::__query_builder::Col::new(table_name, "run_id"), - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - status: __sdk::__query_builder::Col::new(table_name, "status"), - snapshot_json: __sdk::__query_builder::Col::new(table_name, "snapshot_json"), - last_input_x: __sdk::__query_builder::Col::new(table_name, "last_input_x"), - last_input_y: __sdk::__query_builder::Col::new(table_name, "last_input_y"), - tick: __sdk::__query_builder::Col::new(table_name, "tick"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `BigFishRuntimeRun`. -/// -/// Provides typed access to indexed columns for query building. -pub struct BigFishRuntimeRunIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub run_id: __sdk::__query_builder::IxCol, - pub session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for BigFishRuntimeRun { - type IxCols = BigFishRuntimeRunIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - BigFishRuntimeRunIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - run_id: __sdk::__query_builder::IxCol::new(table_name, "run_id"), - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for BigFishRuntimeRun {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/bind_asset_object_to_entity_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/bind_asset_object_to_entity_and_return_procedure.rs index 78c80aee5..b709d5c2f 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/bind_asset_object_to_entity_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/bind_asset_object_to_entity_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait bind_asset_object_to_entity_and_return { input: AssetEntityBindingInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl bind_asset_object_to_entity_and_return for super::RemoteProcedures { input: AssetEntityBindingInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AssetEntityBindingProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/bind_asset_object_to_entity_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/bind_asset_object_to_entity_reducer.rs index caf48b269..b20bc5b23 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/bind_asset_object_to_entity_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/bind_asset_object_to_entity_reducer.rs @@ -47,11 +47,9 @@ pub trait bind_asset_object_to_entity { &self, input: AssetEntityBindingInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl bind_asset_object_to_entity for super::RemoteReducers { &self, input: AssetEntityBindingInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(BindAssetObjectToEntityArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/cancel_ai_task_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/cancel_ai_task_and_return_procedure.rs index 0c5dc3eb4..b239e0600 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/cancel_ai_task_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/cancel_ai_task_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait cancel_ai_task_and_return { input: AiTaskCancelInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl cancel_ai_task_and_return for super::RemoteProcedures { input: AiTaskCancelInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AiTaskProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/chapter_pace_band_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/chapter_pace_band_type.rs deleted file mode 100644 index effbeb9d4..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/chapter_pace_band_type.rs +++ /dev/null @@ -1,22 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum ChapterPaceBand { - OpeningFast, - - Steady, - - Pressure, - - FinaleDense, -} - -impl __sdk::InModule for ChapterPaceBand { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/chapter_progression_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/chapter_progression_table.rs deleted file mode 100644 index 2072a6a90..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/chapter_progression_table.rs +++ /dev/null @@ -1,235 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::chapter_pace_band_type::ChapterPaceBand; -use super::chapter_progression_type::ChapterProgression; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `chapter_progression`. -/// -/// Obtain a handle from the [`ChapterProgressionTableAccess::chapter_progression`] method on [`super::RemoteTables`], -/// like `ctx.db.chapter_progression()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.chapter_progression().on_insert(...)`. -pub struct ChapterProgressionTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `chapter_progression`. -pub struct ChapterProgressionTableAccessor; - -impl __sdk::TableAccessor for ChapterProgressionTableAccessor { - type Row = ChapterProgression; - type Handle<'db> = ChapterProgressionTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.chapter_progression() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `chapter_progression`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait ChapterProgressionTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`ChapterProgressionTableHandle`], which mediates access to the table `chapter_progression`. - fn chapter_progression(&self) -> ChapterProgressionTableHandle<'_>; -} - -impl ChapterProgressionTableAccess for super::RemoteTables { - fn chapter_progression(&self) -> ChapterProgressionTableHandle<'_> { - ChapterProgressionTableHandle { - imp: self - .imp - .get_table::("chapter_progression"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct ChapterProgressionInsertCallbackId(__sdk::CallbackId); -pub struct ChapterProgressionDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for ChapterProgressionTableHandle<'ctx> { - type Row = ChapterProgression; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for ChapterProgressionTableHandle<'ctx> { - type Row = ChapterProgression; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = ChapterProgressionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> ChapterProgressionInsertCallbackId { - ChapterProgressionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: ChapterProgressionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = ChapterProgressionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> ChapterProgressionDeleteCallbackId { - ChapterProgressionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: ChapterProgressionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for ChapterProgressionTableHandle<'ctx> { - type InsertCallbackId = ChapterProgressionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> ChapterProgressionInsertCallbackId { - ChapterProgressionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: ChapterProgressionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for ChapterProgressionTableHandle<'ctx> { - type DeleteCallbackId = ChapterProgressionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> ChapterProgressionDeleteCallbackId { - ChapterProgressionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: ChapterProgressionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct ChapterProgressionUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for ChapterProgressionTableHandle<'ctx> { - type UpdateCallbackId = ChapterProgressionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> ChapterProgressionUpdateCallbackId { - ChapterProgressionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: ChapterProgressionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for ChapterProgressionTableHandle<'ctx> { - type UpdateCallbackId = ChapterProgressionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> ChapterProgressionUpdateCallbackId { - ChapterProgressionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: ChapterProgressionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `chapter_progression_id` unique index on the table `chapter_progression`, -/// which allows point queries on the field of the same name -/// via the [`ChapterProgressionChapterProgressionIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.chapter_progression().chapter_progression_id().find(...)`. -pub struct ChapterProgressionChapterProgressionIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> ChapterProgressionTableHandle<'ctx> { - /// Get a handle on the `chapter_progression_id` unique index on the table `chapter_progression`. - pub fn chapter_progression_id(&self) -> ChapterProgressionChapterProgressionIdUnique<'ctx> { - ChapterProgressionChapterProgressionIdUnique { - imp: self - .imp - .get_unique_constraint::("chapter_progression_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> ChapterProgressionChapterProgressionIdUnique<'ctx> { - /// Find the subscribed row whose `chapter_progression_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("chapter_progression"); - _table.add_unique_constraint::("chapter_progression_id", |row| { - &row.chapter_progression_id - }); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `ChapterProgression`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait chapter_progressionQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `ChapterProgression`. - fn chapter_progression(&self) -> __sdk::__query_builder::Table; -} - -impl chapter_progressionQueryTableAccess for __sdk::QueryTableAccessor { - fn chapter_progression(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("chapter_progression") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/chapter_progression_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/chapter_progression_type.rs deleted file mode 100644 index c94a7196d..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/chapter_progression_type.rs +++ /dev/null @@ -1,133 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::chapter_pace_band_type::ChapterPaceBand; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct ChapterProgression { - pub chapter_progression_id: String, - pub user_id: String, - pub chapter_id: String, - pub chapter_index: u32, - pub total_chapters: u32, - pub entry_pseudo_level_millis: u32, - pub exit_pseudo_level_millis: u32, - pub entry_level: u32, - pub exit_level: u32, - pub planned_total_xp: u32, - pub planned_quest_xp: u32, - pub planned_hostile_xp: u32, - pub actual_quest_xp: u32, - pub actual_hostile_xp: u32, - pub expected_hostile_defeat_count: u32, - pub actual_hostile_defeat_count: u32, - pub level_at_entry: u32, - pub level_at_exit: Option, - pub pace_band: ChapterPaceBand, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for ChapterProgression { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `ChapterProgression`. -/// -/// Provides typed access to columns for query building. -pub struct ChapterProgressionCols { - pub chapter_progression_id: __sdk::__query_builder::Col, - pub user_id: __sdk::__query_builder::Col, - pub chapter_id: __sdk::__query_builder::Col, - pub chapter_index: __sdk::__query_builder::Col, - pub total_chapters: __sdk::__query_builder::Col, - pub entry_pseudo_level_millis: __sdk::__query_builder::Col, - pub exit_pseudo_level_millis: __sdk::__query_builder::Col, - pub entry_level: __sdk::__query_builder::Col, - pub exit_level: __sdk::__query_builder::Col, - pub planned_total_xp: __sdk::__query_builder::Col, - pub planned_quest_xp: __sdk::__query_builder::Col, - pub planned_hostile_xp: __sdk::__query_builder::Col, - pub actual_quest_xp: __sdk::__query_builder::Col, - pub actual_hostile_xp: __sdk::__query_builder::Col, - pub expected_hostile_defeat_count: __sdk::__query_builder::Col, - pub actual_hostile_defeat_count: __sdk::__query_builder::Col, - pub level_at_entry: __sdk::__query_builder::Col, - pub level_at_exit: __sdk::__query_builder::Col>, - pub pace_band: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for ChapterProgression { - type Cols = ChapterProgressionCols; - fn cols(table_name: &'static str) -> Self::Cols { - ChapterProgressionCols { - chapter_progression_id: __sdk::__query_builder::Col::new( - table_name, - "chapter_progression_id", - ), - user_id: __sdk::__query_builder::Col::new(table_name, "user_id"), - chapter_id: __sdk::__query_builder::Col::new(table_name, "chapter_id"), - chapter_index: __sdk::__query_builder::Col::new(table_name, "chapter_index"), - total_chapters: __sdk::__query_builder::Col::new(table_name, "total_chapters"), - entry_pseudo_level_millis: __sdk::__query_builder::Col::new( - table_name, - "entry_pseudo_level_millis", - ), - exit_pseudo_level_millis: __sdk::__query_builder::Col::new( - table_name, - "exit_pseudo_level_millis", - ), - entry_level: __sdk::__query_builder::Col::new(table_name, "entry_level"), - exit_level: __sdk::__query_builder::Col::new(table_name, "exit_level"), - planned_total_xp: __sdk::__query_builder::Col::new(table_name, "planned_total_xp"), - planned_quest_xp: __sdk::__query_builder::Col::new(table_name, "planned_quest_xp"), - planned_hostile_xp: __sdk::__query_builder::Col::new(table_name, "planned_hostile_xp"), - actual_quest_xp: __sdk::__query_builder::Col::new(table_name, "actual_quest_xp"), - actual_hostile_xp: __sdk::__query_builder::Col::new(table_name, "actual_hostile_xp"), - expected_hostile_defeat_count: __sdk::__query_builder::Col::new( - table_name, - "expected_hostile_defeat_count", - ), - actual_hostile_defeat_count: __sdk::__query_builder::Col::new( - table_name, - "actual_hostile_defeat_count", - ), - level_at_entry: __sdk::__query_builder::Col::new(table_name, "level_at_entry"), - level_at_exit: __sdk::__query_builder::Col::new(table_name, "level_at_exit"), - pace_band: __sdk::__query_builder::Col::new(table_name, "pace_band"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `ChapterProgression`. -/// -/// Provides typed access to indexed columns for query building. -pub struct ChapterProgressionIxCols { - pub chapter_id: __sdk::__query_builder::IxCol, - pub chapter_progression_id: __sdk::__query_builder::IxCol, - pub user_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for ChapterProgression { - type IxCols = ChapterProgressionIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - ChapterProgressionIxCols { - chapter_id: __sdk::__query_builder::IxCol::new(table_name, "chapter_id"), - chapter_progression_id: __sdk::__query_builder::IxCol::new( - table_name, - "chapter_progression_id", - ), - user_id: __sdk::__query_builder::IxCol::new(table_name, "user_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for ChapterProgression {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/claim_external_generation_jobs_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/claim_external_generation_jobs_and_return_procedure.rs index 979ea56cc..6455c7b2e 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/claim_external_generation_jobs_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/claim_external_generation_jobs_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait claim_external_generation_jobs_and_return { input: ExternalGenerationJobClaimInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl claim_external_generation_jobs_and_return for super::RemoteProcedures { input: ExternalGenerationJobClaimInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ExternalGenerationJobProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/claim_profile_recharge_order_expiration_schedule_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/claim_profile_recharge_order_expiration_schedule_and_return_procedure.rs index 93d75e737..93a626b00 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/claim_profile_recharge_order_expiration_schedule_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/claim_profile_recharge_order_expiration_schedule_and_return_procedure.rs @@ -34,10 +34,13 @@ pub trait claim_profile_recharge_order_expiration_schedule_and_return { input: RuntimeProfileRechargeOrderExpirationClaimInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result< + RuntimeProfileRechargeOrderExpirationClaimProcedureResult, + __sdk::InternalError, + >, + ) + Send + + 'static, ); } @@ -47,10 +50,13 @@ impl claim_profile_recharge_order_expiration_schedule_and_return for super::Remo input: RuntimeProfileRechargeOrderExpirationClaimInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result< + RuntimeProfileRechargeOrderExpirationClaimProcedureResult, + __sdk::InternalError, + >, + ) + Send + + 'static, ) { self.imp.invoke_procedure_with_callback::<_, RuntimeProfileRechargeOrderExpirationClaimProcedureResult>( "claim_profile_recharge_order_expiration_schedule_and_return", diff --git a/server-rs/crates/spacetime-client/src/module_bindings/claim_profile_task_reward_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/claim_profile_task_reward_and_return_procedure.rs index ea5010707..5a386f3cd 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/claim_profile_task_reward_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/claim_profile_task_reward_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait claim_profile_task_reward_and_return { input: RuntimeProfileTaskClaimInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl claim_profile_task_reward_and_return for super::RemoteProcedures { input: RuntimeProfileTaskClaimInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileTaskClaimProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/clean_editor_image_asset_kind_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/clean_editor_image_asset_kind_and_return_procedure.rs index a32372261..1241d9343 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/clean_editor_image_asset_kind_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/clean_editor_image_asset_kind_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait clean_editor_image_asset_kind_and_return { input: EditorImageAssetKindCleanupInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl clean_editor_image_asset_kind_and_return for super::RemoteProcedures { input: EditorImageAssetKindCleanupInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorImageAssetKindCleanupProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/clear_database_migration_import_chunks_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/clear_database_migration_import_chunks_procedure.rs index d05fcdf27..51146e998 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/clear_database_migration_import_chunks_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/clear_database_migration_import_chunks_procedure.rs @@ -34,10 +34,10 @@ pub trait clear_database_migration_import_chunks { input: DatabaseMigrationImportChunksClearInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl clear_database_migration_import_chunks for super::RemoteProcedures { input: DatabaseMigrationImportChunksClearInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, DatabaseMigrationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/clear_retired_database_tables_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/clear_retired_database_tables_procedure.rs deleted file mode 100644 index 3d7e1b5d6..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/clear_retired_database_tables_procedure.rs +++ /dev/null @@ -1,59 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::database_migration_clear_retired_tables_input_type::DatabaseMigrationClearRetiredTablesInput; -use super::database_migration_clear_retired_tables_result_type::DatabaseMigrationClearRetiredTablesResult; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -struct ClearRetiredDatabaseTablesArgs { - pub input: DatabaseMigrationClearRetiredTablesInput, -} - -impl __sdk::InModule for ClearRetiredDatabaseTablesArgs { - type Module = super::RemoteModule; -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the procedure `clear_retired_database_tables`. -/// -/// Implemented for [`super::RemoteProcedures`]. -pub trait clear_retired_database_tables { - fn clear_retired_database_tables(&self, input: DatabaseMigrationClearRetiredTablesInput) { - self.clear_retired_database_tables_then(input, |_, _| {}); - } - - fn clear_retired_database_tables_then( - &self, - input: DatabaseMigrationClearRetiredTablesInput, - - __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, - ); -} - -impl clear_retired_database_tables for super::RemoteProcedures { - fn clear_retired_database_tables_then( - &self, - input: DatabaseMigrationClearRetiredTablesInput, - - __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, - ) { - self.imp - .invoke_procedure_with_callback::<_, DatabaseMigrationClearRetiredTablesResult>( - "clear_retired_database_tables", - ClearRetiredDatabaseTablesArgs { input }, - __callback, - ); - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/close_profile_recharge_order_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/close_profile_recharge_order_and_return_procedure.rs index 984e99294..461f43399 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/close_profile_recharge_order_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/close_profile_recharge_order_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait close_profile_recharge_order_and_return { input: RuntimeProfileRechargeOrderCloseInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl close_profile_recharge_order_and_return for super::RemoteProcedures { input: RuntimeProfileRechargeOrderCloseInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRechargeCenterProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/combat_outcome_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/combat_outcome_type.rs deleted file mode 100644 index 731563dd5..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/combat_outcome_type.rs +++ /dev/null @@ -1,22 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum CombatOutcome { - Ongoing, - - Victory, - - SparComplete, - - Escaped, -} - -impl __sdk::InModule for CombatOutcome { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/compact_external_generation_job_payloads_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/compact_external_generation_job_payloads_and_return_procedure.rs index e98609333..416c06161 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/compact_external_generation_job_payloads_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/compact_external_generation_job_payloads_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait compact_external_generation_job_payloads_and_return { input: ExternalGenerationJobPayloadCompactionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl compact_external_generation_job_payloads_and_return for super::RemoteProced input: ExternalGenerationJobPayloadCompactionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp.invoke_procedure_with_callback::<_, ExternalGenerationJobPayloadCompactionProcedureResult>( "compact_external_generation_job_payloads_and_return", diff --git a/server-rs/crates/spacetime-client/src/module_bindings/complete_ai_stage_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/complete_ai_stage_and_return_procedure.rs index e59ab8f0e..51375935c 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/complete_ai_stage_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/complete_ai_stage_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait complete_ai_stage_and_return { input: AiStageCompletionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl complete_ai_stage_and_return for super::RemoteProcedures { input: AiStageCompletionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AiTaskProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/complete_ai_task_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/complete_ai_task_and_return_procedure.rs index ca7eab9f8..040af6392 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/complete_ai_task_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/complete_ai_task_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait complete_ai_task_and_return { input: AiTaskFinishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl complete_ai_task_and_return for super::RemoteProcedures { input: AiTaskFinishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AiTaskProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/complete_editor_asset_group_cohort_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/complete_editor_asset_group_cohort_and_return_procedure.rs index 7b2a74f89..189f54bd5 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/complete_editor_asset_group_cohort_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/complete_editor_asset_group_cohort_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait complete_editor_asset_group_cohort_and_return { input: EditorAssetGroupCohortCompleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl complete_editor_asset_group_cohort_and_return for super::RemoteProcedures { input: EditorAssetGroupCohortCompleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorAssetProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/complete_external_generation_job_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/complete_external_generation_job_and_return_procedure.rs index cebd89edd..9c923b968 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/complete_external_generation_job_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/complete_external_generation_job_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait complete_external_generation_job_and_return { input: ExternalGenerationJobCompleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl complete_external_generation_job_and_return for super::RemoteProcedures { input: ExternalGenerationJobCompleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ExternalGenerationJobProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/complete_profile_recharge_order_expiration_schedule_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/complete_profile_recharge_order_expiration_schedule_and_return_procedure.rs index 64040eb0e..b3c8a39e2 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/complete_profile_recharge_order_expiration_schedule_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/complete_profile_recharge_order_expiration_schedule_and_return_procedure.rs @@ -34,13 +34,13 @@ pub trait complete_profile_recharge_order_expiration_schedule_and_return { input: RuntimeProfileRechargeOrderExpirationCompleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result< - RuntimeProfileRechargeOrderExpirationCompleteProcedureResult, - __sdk::InternalError, - >, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result< + RuntimeProfileRechargeOrderExpirationCompleteProcedureResult, + __sdk::InternalError, + >, + ) + Send + + 'static, ); } @@ -50,13 +50,13 @@ impl complete_profile_recharge_order_expiration_schedule_and_return for super::R input: RuntimeProfileRechargeOrderExpirationCompleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result< - RuntimeProfileRechargeOrderExpirationCompleteProcedureResult, - __sdk::InternalError, - >, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result< + RuntimeProfileRechargeOrderExpirationCompleteProcedureResult, + __sdk::InternalError, + >, + ) + Send + + 'static, ) { self.imp.invoke_procedure_with_callback::<_, RuntimeProfileRechargeOrderExpirationCompleteProcedureResult>( "complete_profile_recharge_order_expiration_schedule_and_return", diff --git a/server-rs/crates/spacetime-client/src/module_bindings/confirm_asset_object_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/confirm_asset_object_and_return_procedure.rs index cc65f7445..0b4f26b2b 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/confirm_asset_object_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/confirm_asset_object_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait confirm_asset_object_and_return { input: AssetObjectUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl confirm_asset_object_and_return for super::RemoteProcedures { input: AssetObjectUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AssetObjectProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/confirm_asset_object_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/confirm_asset_object_reducer.rs index f5edb63a4..183c2efa8 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/confirm_asset_object_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/confirm_asset_object_reducer.rs @@ -47,11 +47,9 @@ pub trait confirm_asset_object { &self, input: AssetObjectUpsertInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl confirm_asset_object for super::RemoteReducers { &self, input: AssetObjectUpsertInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(ConfirmAssetObjectArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/consume_profile_wallet_points_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/consume_profile_wallet_points_and_return_procedure.rs index 11394b665..3d3e47a20 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/consume_profile_wallet_points_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/consume_profile_wallet_points_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait consume_profile_wallet_points_and_return { input: RuntimeProfileWalletAdjustmentInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl consume_profile_wallet_points_and_return for super::RemoteProcedures { input: RuntimeProfileWalletAdjustmentInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileWalletAdjustmentProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_admin_account_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_admin_account_and_return_procedure.rs index dc9f883ec..0271d730c 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_admin_account_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_admin_account_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait create_admin_account_and_return { input: AdminAccountCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl create_admin_account_and_return for super::RemoteProcedures { input: AdminAccountCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AdminAccountProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_ai_task_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_ai_task_and_return_procedure.rs index a2f40fd06..20d8ceee1 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_ai_task_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_ai_task_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait create_ai_task_and_return { input: AiTaskCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl create_ai_task_and_return for super::RemoteProcedures { input: AiTaskCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AiTaskProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_ai_task_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_ai_task_reducer.rs index b87207f02..213f28e58 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_ai_task_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_ai_task_reducer.rs @@ -47,11 +47,9 @@ pub trait create_ai_task { &self, input: AiTaskCreateInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl create_ai_task for super::RemoteReducers { &self, input: AiTaskCreateInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(CreateAiTaskArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_editor_agent_conversation_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_editor_agent_conversation_and_return_procedure.rs index 6e45ee7c2..0317b0856 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_editor_agent_conversation_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_editor_agent_conversation_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait create_editor_agent_conversation_and_return { input: EditorAgentConversationCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl create_editor_agent_conversation_and_return for super::RemoteProcedures { input: EditorAgentConversationCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorAgentConversationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_editor_asset_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_editor_asset_and_return_procedure.rs index e1926a0ef..8ca475434 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_editor_asset_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_editor_asset_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait create_editor_asset_and_return { input: EditorAssetCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl create_editor_asset_and_return for super::RemoteProcedures { input: EditorAssetCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorAssetProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_editor_asset_folder_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_editor_asset_folder_and_return_procedure.rs index e45dcf833..33ec7f85c 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_editor_asset_folder_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_editor_asset_folder_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait create_editor_asset_folder_and_return { input: EditorAssetFolderCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl create_editor_asset_folder_and_return for super::RemoteProcedures { input: EditorAssetFolderCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorAssetFolderProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_editor_project_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_editor_project_and_return_procedure.rs index 7c305c26e..7340d97d3 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_editor_project_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_editor_project_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait create_editor_project_and_return { input: EditorProjectCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl create_editor_project_and_return for super::RemoteProcedures { input: EditorProjectCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorProjectProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_editor_project_resource_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_editor_project_resource_and_return_procedure.rs index 957e3aff0..649d2a3e0 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_editor_project_resource_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_editor_project_resource_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait create_editor_project_resource_and_return { input: EditorProjectResourceCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl create_editor_project_resource_and_return for super::RemoteProcedures { input: EditorProjectResourceCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorProjectResourceProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_external_api_key_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_external_api_key_and_return_procedure.rs index 7dc438368..daf4a676f 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_external_api_key_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_external_api_key_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait create_external_api_key_and_return { input: ExternalApiKeyCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl create_external_api_key_and_return for super::RemoteProcedures { input: ExternalApiKeyCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ExternalApiKeyProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_profile_recharge_order_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_profile_recharge_order_and_return_procedure.rs index 1c53f6aea..893fbdf68 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_profile_recharge_order_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_profile_recharge_order_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait create_profile_recharge_order_and_return { input: RuntimeProfileRechargeOrderCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl create_profile_recharge_order_and_return for super::RemoteProcedures { input: RuntimeProfileRechargeOrderCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRechargeCenterProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_agent_message_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/custom_world_agent_message_table.rs deleted file mode 100644 index df529c284..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_agent_message_table.rs +++ /dev/null @@ -1,233 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::custom_world_agent_message_type::CustomWorldAgentMessage; -use super::rpg_agent_message_kind_type::RpgAgentMessageKind; -use super::rpg_agent_message_role_type::RpgAgentMessageRole; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `custom_world_agent_message`. -/// -/// Obtain a handle from the [`CustomWorldAgentMessageTableAccess::custom_world_agent_message`] method on [`super::RemoteTables`], -/// like `ctx.db.custom_world_agent_message()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.custom_world_agent_message().on_insert(...)`. -pub struct CustomWorldAgentMessageTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `custom_world_agent_message`. -pub struct CustomWorldAgentMessageTableAccessor; - -impl __sdk::TableAccessor for CustomWorldAgentMessageTableAccessor { - type Row = CustomWorldAgentMessage; - type Handle<'db> = CustomWorldAgentMessageTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.custom_world_agent_message() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `custom_world_agent_message`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait CustomWorldAgentMessageTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`CustomWorldAgentMessageTableHandle`], which mediates access to the table `custom_world_agent_message`. - fn custom_world_agent_message(&self) -> CustomWorldAgentMessageTableHandle<'_>; -} - -impl CustomWorldAgentMessageTableAccess for super::RemoteTables { - fn custom_world_agent_message(&self) -> CustomWorldAgentMessageTableHandle<'_> { - CustomWorldAgentMessageTableHandle { - imp: self - .imp - .get_table::("custom_world_agent_message"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct CustomWorldAgentMessageInsertCallbackId(__sdk::CallbackId); -pub struct CustomWorldAgentMessageDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for CustomWorldAgentMessageTableHandle<'ctx> { - type Row = CustomWorldAgentMessage; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for CustomWorldAgentMessageTableHandle<'ctx> { - type Row = CustomWorldAgentMessage; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = CustomWorldAgentMessageInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldAgentMessageInsertCallbackId { - CustomWorldAgentMessageInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: CustomWorldAgentMessageInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = CustomWorldAgentMessageDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldAgentMessageDeleteCallbackId { - CustomWorldAgentMessageDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: CustomWorldAgentMessageDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for CustomWorldAgentMessageTableHandle<'ctx> { - type InsertCallbackId = CustomWorldAgentMessageInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldAgentMessageInsertCallbackId { - CustomWorldAgentMessageInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: CustomWorldAgentMessageInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for CustomWorldAgentMessageTableHandle<'ctx> { - type DeleteCallbackId = CustomWorldAgentMessageDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldAgentMessageDeleteCallbackId { - CustomWorldAgentMessageDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: CustomWorldAgentMessageDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct CustomWorldAgentMessageUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for CustomWorldAgentMessageTableHandle<'ctx> { - type UpdateCallbackId = CustomWorldAgentMessageUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> CustomWorldAgentMessageUpdateCallbackId { - CustomWorldAgentMessageUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: CustomWorldAgentMessageUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for CustomWorldAgentMessageTableHandle<'ctx> { - type UpdateCallbackId = CustomWorldAgentMessageUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> CustomWorldAgentMessageUpdateCallbackId { - CustomWorldAgentMessageUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: CustomWorldAgentMessageUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `message_id` unique index on the table `custom_world_agent_message`, -/// which allows point queries on the field of the same name -/// via the [`CustomWorldAgentMessageMessageIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.custom_world_agent_message().message_id().find(...)`. -pub struct CustomWorldAgentMessageMessageIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> CustomWorldAgentMessageTableHandle<'ctx> { - /// Get a handle on the `message_id` unique index on the table `custom_world_agent_message`. - pub fn message_id(&self) -> CustomWorldAgentMessageMessageIdUnique<'ctx> { - CustomWorldAgentMessageMessageIdUnique { - imp: self.imp.get_unique_constraint::("message_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> CustomWorldAgentMessageMessageIdUnique<'ctx> { - /// Find the subscribed row whose `message_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("custom_world_agent_message"); - _table.add_unique_constraint::("message_id", |row| &row.message_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `CustomWorldAgentMessage`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait custom_world_agent_messageQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `CustomWorldAgentMessage`. - fn custom_world_agent_message(&self) -> __sdk::__query_builder::Table; -} - -impl custom_world_agent_messageQueryTableAccess for __sdk::QueryTableAccessor { - fn custom_world_agent_message(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("custom_world_agent_message") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_agent_message_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/custom_world_agent_message_type.rs deleted file mode 100644 index 751108606..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_agent_message_type.rs +++ /dev/null @@ -1,75 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::rpg_agent_message_kind_type::RpgAgentMessageKind; -use super::rpg_agent_message_role_type::RpgAgentMessageRole; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct CustomWorldAgentMessage { - pub message_id: String, - pub session_id: String, - pub role: RpgAgentMessageRole, - pub kind: RpgAgentMessageKind, - pub text: String, - pub related_operation_id: Option, - pub created_at: __sdk::Timestamp, -} - -impl __sdk::InModule for CustomWorldAgentMessage { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `CustomWorldAgentMessage`. -/// -/// Provides typed access to columns for query building. -pub struct CustomWorldAgentMessageCols { - pub message_id: __sdk::__query_builder::Col, - pub session_id: __sdk::__query_builder::Col, - pub role: __sdk::__query_builder::Col, - pub kind: __sdk::__query_builder::Col, - pub text: __sdk::__query_builder::Col, - pub related_operation_id: __sdk::__query_builder::Col>, - pub created_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for CustomWorldAgentMessage { - type Cols = CustomWorldAgentMessageCols; - fn cols(table_name: &'static str) -> Self::Cols { - CustomWorldAgentMessageCols { - message_id: __sdk::__query_builder::Col::new(table_name, "message_id"), - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - role: __sdk::__query_builder::Col::new(table_name, "role"), - kind: __sdk::__query_builder::Col::new(table_name, "kind"), - text: __sdk::__query_builder::Col::new(table_name, "text"), - related_operation_id: __sdk::__query_builder::Col::new( - table_name, - "related_operation_id", - ), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - } - } -} - -/// Indexed column accessor struct for the table `CustomWorldAgentMessage`. -/// -/// Provides typed access to indexed columns for query building. -pub struct CustomWorldAgentMessageIxCols { - pub message_id: __sdk::__query_builder::IxCol, - pub session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for CustomWorldAgentMessage { - type IxCols = CustomWorldAgentMessageIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - CustomWorldAgentMessageIxCols { - message_id: __sdk::__query_builder::IxCol::new(table_name, "message_id"), - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for CustomWorldAgentMessage {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_agent_operation_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/custom_world_agent_operation_table.rs deleted file mode 100644 index e7eec6e80..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_agent_operation_table.rs +++ /dev/null @@ -1,237 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::custom_world_agent_operation_type::CustomWorldAgentOperation; -use super::rpg_agent_operation_status_type::RpgAgentOperationStatus; -use super::rpg_agent_operation_type_type::RpgAgentOperationType; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `custom_world_agent_operation`. -/// -/// Obtain a handle from the [`CustomWorldAgentOperationTableAccess::custom_world_agent_operation`] method on [`super::RemoteTables`], -/// like `ctx.db.custom_world_agent_operation()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.custom_world_agent_operation().on_insert(...)`. -pub struct CustomWorldAgentOperationTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `custom_world_agent_operation`. -pub struct CustomWorldAgentOperationTableAccessor; - -impl __sdk::TableAccessor for CustomWorldAgentOperationTableAccessor { - type Row = CustomWorldAgentOperation; - type Handle<'db> = CustomWorldAgentOperationTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.custom_world_agent_operation() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `custom_world_agent_operation`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait CustomWorldAgentOperationTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`CustomWorldAgentOperationTableHandle`], which mediates access to the table `custom_world_agent_operation`. - fn custom_world_agent_operation(&self) -> CustomWorldAgentOperationTableHandle<'_>; -} - -impl CustomWorldAgentOperationTableAccess for super::RemoteTables { - fn custom_world_agent_operation(&self) -> CustomWorldAgentOperationTableHandle<'_> { - CustomWorldAgentOperationTableHandle { - imp: self - .imp - .get_table::("custom_world_agent_operation"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct CustomWorldAgentOperationInsertCallbackId(__sdk::CallbackId); -pub struct CustomWorldAgentOperationDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for CustomWorldAgentOperationTableHandle<'ctx> { - type Row = CustomWorldAgentOperation; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for CustomWorldAgentOperationTableHandle<'ctx> { - type Row = CustomWorldAgentOperation; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = CustomWorldAgentOperationInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldAgentOperationInsertCallbackId { - CustomWorldAgentOperationInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: CustomWorldAgentOperationInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = CustomWorldAgentOperationDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldAgentOperationDeleteCallbackId { - CustomWorldAgentOperationDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: CustomWorldAgentOperationDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for CustomWorldAgentOperationTableHandle<'ctx> { - type InsertCallbackId = CustomWorldAgentOperationInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldAgentOperationInsertCallbackId { - CustomWorldAgentOperationInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: CustomWorldAgentOperationInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for CustomWorldAgentOperationTableHandle<'ctx> { - type DeleteCallbackId = CustomWorldAgentOperationDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldAgentOperationDeleteCallbackId { - CustomWorldAgentOperationDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: CustomWorldAgentOperationDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct CustomWorldAgentOperationUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for CustomWorldAgentOperationTableHandle<'ctx> { - type UpdateCallbackId = CustomWorldAgentOperationUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> CustomWorldAgentOperationUpdateCallbackId { - CustomWorldAgentOperationUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: CustomWorldAgentOperationUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for CustomWorldAgentOperationTableHandle<'ctx> { - type UpdateCallbackId = CustomWorldAgentOperationUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> CustomWorldAgentOperationUpdateCallbackId { - CustomWorldAgentOperationUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: CustomWorldAgentOperationUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `operation_id` unique index on the table `custom_world_agent_operation`, -/// which allows point queries on the field of the same name -/// via the [`CustomWorldAgentOperationOperationIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.custom_world_agent_operation().operation_id().find(...)`. -pub struct CustomWorldAgentOperationOperationIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> CustomWorldAgentOperationTableHandle<'ctx> { - /// Get a handle on the `operation_id` unique index on the table `custom_world_agent_operation`. - pub fn operation_id(&self) -> CustomWorldAgentOperationOperationIdUnique<'ctx> { - CustomWorldAgentOperationOperationIdUnique { - imp: self.imp.get_unique_constraint::("operation_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> CustomWorldAgentOperationOperationIdUnique<'ctx> { - /// Find the subscribed row whose `operation_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("custom_world_agent_operation"); - _table.add_unique_constraint::("operation_id", |row| &row.operation_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `CustomWorldAgentOperation`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait custom_world_agent_operationQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `CustomWorldAgentOperation`. - fn custom_world_agent_operation( - &self, - ) -> __sdk::__query_builder::Table; -} - -impl custom_world_agent_operationQueryTableAccess for __sdk::QueryTableAccessor { - fn custom_world_agent_operation( - &self, - ) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("custom_world_agent_operation") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_agent_operation_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/custom_world_agent_operation_type.rs deleted file mode 100644 index 41957317f..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_agent_operation_type.rs +++ /dev/null @@ -1,82 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::rpg_agent_operation_status_type::RpgAgentOperationStatus; -use super::rpg_agent_operation_type_type::RpgAgentOperationType; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct CustomWorldAgentOperation { - pub operation_id: String, - pub session_id: String, - pub operation_type: RpgAgentOperationType, - pub status: RpgAgentOperationStatus, - pub phase_label: String, - pub phase_detail: String, - pub progress: u32, - pub error_message: Option, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for CustomWorldAgentOperation { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `CustomWorldAgentOperation`. -/// -/// Provides typed access to columns for query building. -pub struct CustomWorldAgentOperationCols { - pub operation_id: __sdk::__query_builder::Col, - pub session_id: __sdk::__query_builder::Col, - pub operation_type: - __sdk::__query_builder::Col, - pub status: __sdk::__query_builder::Col, - pub phase_label: __sdk::__query_builder::Col, - pub phase_detail: __sdk::__query_builder::Col, - pub progress: __sdk::__query_builder::Col, - pub error_message: __sdk::__query_builder::Col>, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for CustomWorldAgentOperation { - type Cols = CustomWorldAgentOperationCols; - fn cols(table_name: &'static str) -> Self::Cols { - CustomWorldAgentOperationCols { - operation_id: __sdk::__query_builder::Col::new(table_name, "operation_id"), - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - operation_type: __sdk::__query_builder::Col::new(table_name, "operation_type"), - status: __sdk::__query_builder::Col::new(table_name, "status"), - phase_label: __sdk::__query_builder::Col::new(table_name, "phase_label"), - phase_detail: __sdk::__query_builder::Col::new(table_name, "phase_detail"), - progress: __sdk::__query_builder::Col::new(table_name, "progress"), - error_message: __sdk::__query_builder::Col::new(table_name, "error_message"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `CustomWorldAgentOperation`. -/// -/// Provides typed access to indexed columns for query building. -pub struct CustomWorldAgentOperationIxCols { - pub operation_id: __sdk::__query_builder::IxCol, - pub session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for CustomWorldAgentOperation { - type IxCols = CustomWorldAgentOperationIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - CustomWorldAgentOperationIxCols { - operation_id: __sdk::__query_builder::IxCol::new(table_name, "operation_id"), - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for CustomWorldAgentOperation {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_agent_session_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/custom_world_agent_session_table.rs deleted file mode 100644 index 30a77d90c..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_agent_session_table.rs +++ /dev/null @@ -1,232 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::custom_world_agent_session_type::CustomWorldAgentSession; -use super::rpg_agent_stage_type::RpgAgentStage; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `custom_world_agent_session`. -/// -/// Obtain a handle from the [`CustomWorldAgentSessionTableAccess::custom_world_agent_session`] method on [`super::RemoteTables`], -/// like `ctx.db.custom_world_agent_session()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.custom_world_agent_session().on_insert(...)`. -pub struct CustomWorldAgentSessionTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `custom_world_agent_session`. -pub struct CustomWorldAgentSessionTableAccessor; - -impl __sdk::TableAccessor for CustomWorldAgentSessionTableAccessor { - type Row = CustomWorldAgentSession; - type Handle<'db> = CustomWorldAgentSessionTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.custom_world_agent_session() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `custom_world_agent_session`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait CustomWorldAgentSessionTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`CustomWorldAgentSessionTableHandle`], which mediates access to the table `custom_world_agent_session`. - fn custom_world_agent_session(&self) -> CustomWorldAgentSessionTableHandle<'_>; -} - -impl CustomWorldAgentSessionTableAccess for super::RemoteTables { - fn custom_world_agent_session(&self) -> CustomWorldAgentSessionTableHandle<'_> { - CustomWorldAgentSessionTableHandle { - imp: self - .imp - .get_table::("custom_world_agent_session"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct CustomWorldAgentSessionInsertCallbackId(__sdk::CallbackId); -pub struct CustomWorldAgentSessionDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for CustomWorldAgentSessionTableHandle<'ctx> { - type Row = CustomWorldAgentSession; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for CustomWorldAgentSessionTableHandle<'ctx> { - type Row = CustomWorldAgentSession; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = CustomWorldAgentSessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldAgentSessionInsertCallbackId { - CustomWorldAgentSessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: CustomWorldAgentSessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = CustomWorldAgentSessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldAgentSessionDeleteCallbackId { - CustomWorldAgentSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: CustomWorldAgentSessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for CustomWorldAgentSessionTableHandle<'ctx> { - type InsertCallbackId = CustomWorldAgentSessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldAgentSessionInsertCallbackId { - CustomWorldAgentSessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: CustomWorldAgentSessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for CustomWorldAgentSessionTableHandle<'ctx> { - type DeleteCallbackId = CustomWorldAgentSessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldAgentSessionDeleteCallbackId { - CustomWorldAgentSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: CustomWorldAgentSessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct CustomWorldAgentSessionUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for CustomWorldAgentSessionTableHandle<'ctx> { - type UpdateCallbackId = CustomWorldAgentSessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> CustomWorldAgentSessionUpdateCallbackId { - CustomWorldAgentSessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: CustomWorldAgentSessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for CustomWorldAgentSessionTableHandle<'ctx> { - type UpdateCallbackId = CustomWorldAgentSessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> CustomWorldAgentSessionUpdateCallbackId { - CustomWorldAgentSessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: CustomWorldAgentSessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `session_id` unique index on the table `custom_world_agent_session`, -/// which allows point queries on the field of the same name -/// via the [`CustomWorldAgentSessionSessionIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.custom_world_agent_session().session_id().find(...)`. -pub struct CustomWorldAgentSessionSessionIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> CustomWorldAgentSessionTableHandle<'ctx> { - /// Get a handle on the `session_id` unique index on the table `custom_world_agent_session`. - pub fn session_id(&self) -> CustomWorldAgentSessionSessionIdUnique<'ctx> { - CustomWorldAgentSessionSessionIdUnique { - imp: self.imp.get_unique_constraint::("session_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> CustomWorldAgentSessionSessionIdUnique<'ctx> { - /// Find the subscribed row whose `session_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("custom_world_agent_session"); - _table.add_unique_constraint::("session_id", |row| &row.session_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `CustomWorldAgentSession`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait custom_world_agent_sessionQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `CustomWorldAgentSession`. - fn custom_world_agent_session(&self) -> __sdk::__query_builder::Table; -} - -impl custom_world_agent_sessionQueryTableAccess for __sdk::QueryTableAccessor { - fn custom_world_agent_session(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("custom_world_agent_session") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_agent_session_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/custom_world_agent_session_type.rs deleted file mode 100644 index 105bc9247..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_agent_session_type.rs +++ /dev/null @@ -1,154 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::rpg_agent_stage_type::RpgAgentStage; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct CustomWorldAgentSession { - pub session_id: String, - pub owner_user_id: String, - pub seed_text: String, - pub current_turn: u32, - pub progress_percent: u32, - pub stage: RpgAgentStage, - pub focus_card_id: Option, - pub anchor_content_json: String, - pub creator_intent_json: Option, - pub creator_intent_readiness_json: String, - pub anchor_pack_json: Option, - pub lock_state_json: Option, - pub draft_profile_json: Option, - pub last_assistant_reply: Option, - pub publish_gate_json: Option, - pub result_preview_json: Option, - pub pending_clarifications_json: String, - pub quality_findings_json: String, - pub suggested_actions_json: String, - pub recommended_replies_json: String, - pub asset_coverage_json: String, - pub checkpoints_json: String, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for CustomWorldAgentSession { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `CustomWorldAgentSession`. -/// -/// Provides typed access to columns for query building. -pub struct CustomWorldAgentSessionCols { - pub session_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub seed_text: __sdk::__query_builder::Col, - pub current_turn: __sdk::__query_builder::Col, - pub progress_percent: __sdk::__query_builder::Col, - pub stage: __sdk::__query_builder::Col, - pub focus_card_id: __sdk::__query_builder::Col>, - pub anchor_content_json: __sdk::__query_builder::Col, - pub creator_intent_json: __sdk::__query_builder::Col>, - pub creator_intent_readiness_json: __sdk::__query_builder::Col, - pub anchor_pack_json: __sdk::__query_builder::Col>, - pub lock_state_json: __sdk::__query_builder::Col>, - pub draft_profile_json: __sdk::__query_builder::Col>, - pub last_assistant_reply: __sdk::__query_builder::Col>, - pub publish_gate_json: __sdk::__query_builder::Col>, - pub result_preview_json: __sdk::__query_builder::Col>, - pub pending_clarifications_json: __sdk::__query_builder::Col, - pub quality_findings_json: __sdk::__query_builder::Col, - pub suggested_actions_json: __sdk::__query_builder::Col, - pub recommended_replies_json: __sdk::__query_builder::Col, - pub asset_coverage_json: __sdk::__query_builder::Col, - pub checkpoints_json: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for CustomWorldAgentSession { - type Cols = CustomWorldAgentSessionCols; - fn cols(table_name: &'static str) -> Self::Cols { - CustomWorldAgentSessionCols { - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - seed_text: __sdk::__query_builder::Col::new(table_name, "seed_text"), - current_turn: __sdk::__query_builder::Col::new(table_name, "current_turn"), - progress_percent: __sdk::__query_builder::Col::new(table_name, "progress_percent"), - stage: __sdk::__query_builder::Col::new(table_name, "stage"), - focus_card_id: __sdk::__query_builder::Col::new(table_name, "focus_card_id"), - anchor_content_json: __sdk::__query_builder::Col::new( - table_name, - "anchor_content_json", - ), - creator_intent_json: __sdk::__query_builder::Col::new( - table_name, - "creator_intent_json", - ), - creator_intent_readiness_json: __sdk::__query_builder::Col::new( - table_name, - "creator_intent_readiness_json", - ), - anchor_pack_json: __sdk::__query_builder::Col::new(table_name, "anchor_pack_json"), - lock_state_json: __sdk::__query_builder::Col::new(table_name, "lock_state_json"), - draft_profile_json: __sdk::__query_builder::Col::new(table_name, "draft_profile_json"), - last_assistant_reply: __sdk::__query_builder::Col::new( - table_name, - "last_assistant_reply", - ), - publish_gate_json: __sdk::__query_builder::Col::new(table_name, "publish_gate_json"), - result_preview_json: __sdk::__query_builder::Col::new( - table_name, - "result_preview_json", - ), - pending_clarifications_json: __sdk::__query_builder::Col::new( - table_name, - "pending_clarifications_json", - ), - quality_findings_json: __sdk::__query_builder::Col::new( - table_name, - "quality_findings_json", - ), - suggested_actions_json: __sdk::__query_builder::Col::new( - table_name, - "suggested_actions_json", - ), - recommended_replies_json: __sdk::__query_builder::Col::new( - table_name, - "recommended_replies_json", - ), - asset_coverage_json: __sdk::__query_builder::Col::new( - table_name, - "asset_coverage_json", - ), - checkpoints_json: __sdk::__query_builder::Col::new(table_name, "checkpoints_json"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `CustomWorldAgentSession`. -/// -/// Provides typed access to indexed columns for query building. -pub struct CustomWorldAgentSessionIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub session_id: __sdk::__query_builder::IxCol, - pub stage: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for CustomWorldAgentSession { - type IxCols = CustomWorldAgentSessionIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - CustomWorldAgentSessionIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - stage: __sdk::__query_builder::IxCol::new(table_name, "stage"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for CustomWorldAgentSession {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_draft_card_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/custom_world_draft_card_table.rs deleted file mode 100644 index 45c003c5e..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_draft_card_table.rs +++ /dev/null @@ -1,233 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::custom_world_draft_card_type::CustomWorldDraftCard; -use super::custom_world_role_asset_status_type::CustomWorldRoleAssetStatus; -use super::rpg_agent_draft_card_kind_type::RpgAgentDraftCardKind; -use super::rpg_agent_draft_card_status_type::RpgAgentDraftCardStatus; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `custom_world_draft_card`. -/// -/// Obtain a handle from the [`CustomWorldDraftCardTableAccess::custom_world_draft_card`] method on [`super::RemoteTables`], -/// like `ctx.db.custom_world_draft_card()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.custom_world_draft_card().on_insert(...)`. -pub struct CustomWorldDraftCardTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `custom_world_draft_card`. -pub struct CustomWorldDraftCardTableAccessor; - -impl __sdk::TableAccessor for CustomWorldDraftCardTableAccessor { - type Row = CustomWorldDraftCard; - type Handle<'db> = CustomWorldDraftCardTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.custom_world_draft_card() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `custom_world_draft_card`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait CustomWorldDraftCardTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`CustomWorldDraftCardTableHandle`], which mediates access to the table `custom_world_draft_card`. - fn custom_world_draft_card(&self) -> CustomWorldDraftCardTableHandle<'_>; -} - -impl CustomWorldDraftCardTableAccess for super::RemoteTables { - fn custom_world_draft_card(&self) -> CustomWorldDraftCardTableHandle<'_> { - CustomWorldDraftCardTableHandle { - imp: self - .imp - .get_table::("custom_world_draft_card"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct CustomWorldDraftCardInsertCallbackId(__sdk::CallbackId); -pub struct CustomWorldDraftCardDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for CustomWorldDraftCardTableHandle<'ctx> { - type Row = CustomWorldDraftCard; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for CustomWorldDraftCardTableHandle<'ctx> { - type Row = CustomWorldDraftCard; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = CustomWorldDraftCardInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldDraftCardInsertCallbackId { - CustomWorldDraftCardInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: CustomWorldDraftCardInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = CustomWorldDraftCardDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldDraftCardDeleteCallbackId { - CustomWorldDraftCardDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: CustomWorldDraftCardDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for CustomWorldDraftCardTableHandle<'ctx> { - type InsertCallbackId = CustomWorldDraftCardInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldDraftCardInsertCallbackId { - CustomWorldDraftCardInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: CustomWorldDraftCardInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for CustomWorldDraftCardTableHandle<'ctx> { - type DeleteCallbackId = CustomWorldDraftCardDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldDraftCardDeleteCallbackId { - CustomWorldDraftCardDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: CustomWorldDraftCardDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct CustomWorldDraftCardUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for CustomWorldDraftCardTableHandle<'ctx> { - type UpdateCallbackId = CustomWorldDraftCardUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> CustomWorldDraftCardUpdateCallbackId { - CustomWorldDraftCardUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: CustomWorldDraftCardUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for CustomWorldDraftCardTableHandle<'ctx> { - type UpdateCallbackId = CustomWorldDraftCardUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> CustomWorldDraftCardUpdateCallbackId { - CustomWorldDraftCardUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: CustomWorldDraftCardUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `card_id` unique index on the table `custom_world_draft_card`, -/// which allows point queries on the field of the same name -/// via the [`CustomWorldDraftCardCardIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.custom_world_draft_card().card_id().find(...)`. -pub struct CustomWorldDraftCardCardIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> CustomWorldDraftCardTableHandle<'ctx> { - /// Get a handle on the `card_id` unique index on the table `custom_world_draft_card`. - pub fn card_id(&self) -> CustomWorldDraftCardCardIdUnique<'ctx> { - CustomWorldDraftCardCardIdUnique { - imp: self.imp.get_unique_constraint::("card_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> CustomWorldDraftCardCardIdUnique<'ctx> { - /// Find the subscribed row whose `card_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("custom_world_draft_card"); - _table.add_unique_constraint::("card_id", |row| &row.card_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `CustomWorldDraftCard`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait custom_world_draft_cardQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `CustomWorldDraftCard`. - fn custom_world_draft_card(&self) -> __sdk::__query_builder::Table; -} - -impl custom_world_draft_cardQueryTableAccess for __sdk::QueryTableAccessor { - fn custom_world_draft_card(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("custom_world_draft_card") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_draft_card_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/custom_world_draft_card_type.rs deleted file mode 100644 index 600c1f310..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_draft_card_type.rs +++ /dev/null @@ -1,100 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::custom_world_role_asset_status_type::CustomWorldRoleAssetStatus; -use super::rpg_agent_draft_card_kind_type::RpgAgentDraftCardKind; -use super::rpg_agent_draft_card_status_type::RpgAgentDraftCardStatus; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct CustomWorldDraftCard { - pub card_id: String, - pub session_id: String, - pub kind: RpgAgentDraftCardKind, - pub status: RpgAgentDraftCardStatus, - pub title: String, - pub subtitle: String, - pub summary: String, - pub linked_ids_json: String, - pub warning_count: u32, - pub asset_status: Option, - pub asset_status_label: Option, - pub detail_payload_json: Option, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for CustomWorldDraftCard { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `CustomWorldDraftCard`. -/// -/// Provides typed access to columns for query building. -pub struct CustomWorldDraftCardCols { - pub card_id: __sdk::__query_builder::Col, - pub session_id: __sdk::__query_builder::Col, - pub kind: __sdk::__query_builder::Col, - pub status: __sdk::__query_builder::Col, - pub title: __sdk::__query_builder::Col, - pub subtitle: __sdk::__query_builder::Col, - pub summary: __sdk::__query_builder::Col, - pub linked_ids_json: __sdk::__query_builder::Col, - pub warning_count: __sdk::__query_builder::Col, - pub asset_status: - __sdk::__query_builder::Col>, - pub asset_status_label: __sdk::__query_builder::Col>, - pub detail_payload_json: __sdk::__query_builder::Col>, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for CustomWorldDraftCard { - type Cols = CustomWorldDraftCardCols; - fn cols(table_name: &'static str) -> Self::Cols { - CustomWorldDraftCardCols { - card_id: __sdk::__query_builder::Col::new(table_name, "card_id"), - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - kind: __sdk::__query_builder::Col::new(table_name, "kind"), - status: __sdk::__query_builder::Col::new(table_name, "status"), - title: __sdk::__query_builder::Col::new(table_name, "title"), - subtitle: __sdk::__query_builder::Col::new(table_name, "subtitle"), - summary: __sdk::__query_builder::Col::new(table_name, "summary"), - linked_ids_json: __sdk::__query_builder::Col::new(table_name, "linked_ids_json"), - warning_count: __sdk::__query_builder::Col::new(table_name, "warning_count"), - asset_status: __sdk::__query_builder::Col::new(table_name, "asset_status"), - asset_status_label: __sdk::__query_builder::Col::new(table_name, "asset_status_label"), - detail_payload_json: __sdk::__query_builder::Col::new( - table_name, - "detail_payload_json", - ), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `CustomWorldDraftCard`. -/// -/// Provides typed access to indexed columns for query building. -pub struct CustomWorldDraftCardIxCols { - pub card_id: __sdk::__query_builder::IxCol, - pub kind: __sdk::__query_builder::IxCol, - pub session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for CustomWorldDraftCard { - type IxCols = CustomWorldDraftCardIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - CustomWorldDraftCardIxCols { - card_id: __sdk::__query_builder::IxCol::new(table_name, "card_id"), - kind: __sdk::__query_builder::IxCol::new(table_name, "kind"), - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for CustomWorldDraftCard {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_gallery_entry_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/custom_world_gallery_entry_table.rs deleted file mode 100644 index 293f489fe..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_gallery_entry_table.rs +++ /dev/null @@ -1,232 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::custom_world_gallery_entry_type::CustomWorldGalleryEntry; -use super::custom_world_theme_mode_type::CustomWorldThemeMode; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `custom_world_gallery_entry`. -/// -/// Obtain a handle from the [`CustomWorldGalleryEntryTableAccess::custom_world_gallery_entry`] method on [`super::RemoteTables`], -/// like `ctx.db.custom_world_gallery_entry()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.custom_world_gallery_entry().on_insert(...)`. -pub struct CustomWorldGalleryEntryTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `custom_world_gallery_entry`. -pub struct CustomWorldGalleryEntryTableAccessor; - -impl __sdk::TableAccessor for CustomWorldGalleryEntryTableAccessor { - type Row = CustomWorldGalleryEntry; - type Handle<'db> = CustomWorldGalleryEntryTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.custom_world_gallery_entry() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `custom_world_gallery_entry`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait CustomWorldGalleryEntryTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`CustomWorldGalleryEntryTableHandle`], which mediates access to the table `custom_world_gallery_entry`. - fn custom_world_gallery_entry(&self) -> CustomWorldGalleryEntryTableHandle<'_>; -} - -impl CustomWorldGalleryEntryTableAccess for super::RemoteTables { - fn custom_world_gallery_entry(&self) -> CustomWorldGalleryEntryTableHandle<'_> { - CustomWorldGalleryEntryTableHandle { - imp: self - .imp - .get_table::("custom_world_gallery_entry"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct CustomWorldGalleryEntryInsertCallbackId(__sdk::CallbackId); -pub struct CustomWorldGalleryEntryDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for CustomWorldGalleryEntryTableHandle<'ctx> { - type Row = CustomWorldGalleryEntry; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for CustomWorldGalleryEntryTableHandle<'ctx> { - type Row = CustomWorldGalleryEntry; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = CustomWorldGalleryEntryInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldGalleryEntryInsertCallbackId { - CustomWorldGalleryEntryInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: CustomWorldGalleryEntryInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = CustomWorldGalleryEntryDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldGalleryEntryDeleteCallbackId { - CustomWorldGalleryEntryDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: CustomWorldGalleryEntryDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for CustomWorldGalleryEntryTableHandle<'ctx> { - type InsertCallbackId = CustomWorldGalleryEntryInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldGalleryEntryInsertCallbackId { - CustomWorldGalleryEntryInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: CustomWorldGalleryEntryInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for CustomWorldGalleryEntryTableHandle<'ctx> { - type DeleteCallbackId = CustomWorldGalleryEntryDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldGalleryEntryDeleteCallbackId { - CustomWorldGalleryEntryDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: CustomWorldGalleryEntryDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct CustomWorldGalleryEntryUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for CustomWorldGalleryEntryTableHandle<'ctx> { - type UpdateCallbackId = CustomWorldGalleryEntryUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> CustomWorldGalleryEntryUpdateCallbackId { - CustomWorldGalleryEntryUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: CustomWorldGalleryEntryUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for CustomWorldGalleryEntryTableHandle<'ctx> { - type UpdateCallbackId = CustomWorldGalleryEntryUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> CustomWorldGalleryEntryUpdateCallbackId { - CustomWorldGalleryEntryUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: CustomWorldGalleryEntryUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `profile_id` unique index on the table `custom_world_gallery_entry`, -/// which allows point queries on the field of the same name -/// via the [`CustomWorldGalleryEntryProfileIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.custom_world_gallery_entry().profile_id().find(...)`. -pub struct CustomWorldGalleryEntryProfileIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> CustomWorldGalleryEntryTableHandle<'ctx> { - /// Get a handle on the `profile_id` unique index on the table `custom_world_gallery_entry`. - pub fn profile_id(&self) -> CustomWorldGalleryEntryProfileIdUnique<'ctx> { - CustomWorldGalleryEntryProfileIdUnique { - imp: self.imp.get_unique_constraint::("profile_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> CustomWorldGalleryEntryProfileIdUnique<'ctx> { - /// Find the subscribed row whose `profile_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("custom_world_gallery_entry"); - _table.add_unique_constraint::("profile_id", |row| &row.profile_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `CustomWorldGalleryEntry`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait custom_world_gallery_entryQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `CustomWorldGalleryEntry`. - fn custom_world_gallery_entry(&self) -> __sdk::__query_builder::Table; -} - -impl custom_world_gallery_entryQueryTableAccess for __sdk::QueryTableAccessor { - fn custom_world_gallery_entry(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("custom_world_gallery_entry") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_gallery_entry_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/custom_world_gallery_entry_type.rs deleted file mode 100644 index 4e8a9b2aa..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_gallery_entry_type.rs +++ /dev/null @@ -1,114 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::custom_world_theme_mode_type::CustomWorldThemeMode; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct CustomWorldGalleryEntry { - pub profile_id: String, - pub owner_user_id: String, - pub public_work_code: String, - pub author_public_user_code: String, - pub author_display_name: String, - pub world_name: String, - pub subtitle: String, - pub summary_text: String, - pub cover_image_src: Option, - pub theme_mode: CustomWorldThemeMode, - pub playable_npc_count: u32, - pub landmark_count: u32, - pub play_count: u32, - pub remix_count: u32, - pub like_count: u32, - pub published_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, - pub visible: bool, -} - -impl __sdk::InModule for CustomWorldGalleryEntry { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `CustomWorldGalleryEntry`. -/// -/// Provides typed access to columns for query building. -pub struct CustomWorldGalleryEntryCols { - pub profile_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub public_work_code: __sdk::__query_builder::Col, - pub author_public_user_code: __sdk::__query_builder::Col, - pub author_display_name: __sdk::__query_builder::Col, - pub world_name: __sdk::__query_builder::Col, - pub subtitle: __sdk::__query_builder::Col, - pub summary_text: __sdk::__query_builder::Col, - pub cover_image_src: __sdk::__query_builder::Col>, - pub theme_mode: __sdk::__query_builder::Col, - pub playable_npc_count: __sdk::__query_builder::Col, - pub landmark_count: __sdk::__query_builder::Col, - pub play_count: __sdk::__query_builder::Col, - pub remix_count: __sdk::__query_builder::Col, - pub like_count: __sdk::__query_builder::Col, - pub published_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, - pub visible: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for CustomWorldGalleryEntry { - type Cols = CustomWorldGalleryEntryCols; - fn cols(table_name: &'static str) -> Self::Cols { - CustomWorldGalleryEntryCols { - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - public_work_code: __sdk::__query_builder::Col::new(table_name, "public_work_code"), - author_public_user_code: __sdk::__query_builder::Col::new( - table_name, - "author_public_user_code", - ), - author_display_name: __sdk::__query_builder::Col::new( - table_name, - "author_display_name", - ), - world_name: __sdk::__query_builder::Col::new(table_name, "world_name"), - subtitle: __sdk::__query_builder::Col::new(table_name, "subtitle"), - summary_text: __sdk::__query_builder::Col::new(table_name, "summary_text"), - cover_image_src: __sdk::__query_builder::Col::new(table_name, "cover_image_src"), - theme_mode: __sdk::__query_builder::Col::new(table_name, "theme_mode"), - playable_npc_count: __sdk::__query_builder::Col::new(table_name, "playable_npc_count"), - landmark_count: __sdk::__query_builder::Col::new(table_name, "landmark_count"), - play_count: __sdk::__query_builder::Col::new(table_name, "play_count"), - remix_count: __sdk::__query_builder::Col::new(table_name, "remix_count"), - like_count: __sdk::__query_builder::Col::new(table_name, "like_count"), - published_at: __sdk::__query_builder::Col::new(table_name, "published_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - visible: __sdk::__query_builder::Col::new(table_name, "visible"), - } - } -} - -/// Indexed column accessor struct for the table `CustomWorldGalleryEntry`. -/// -/// Provides typed access to indexed columns for query building. -pub struct CustomWorldGalleryEntryIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub profile_id: __sdk::__query_builder::IxCol, - pub public_work_code: __sdk::__query_builder::IxCol, - pub theme_mode: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for CustomWorldGalleryEntry { - type IxCols = CustomWorldGalleryEntryIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - CustomWorldGalleryEntryIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::IxCol::new(table_name, "profile_id"), - public_work_code: __sdk::__query_builder::IxCol::new(table_name, "public_work_code"), - theme_mode: __sdk::__query_builder::IxCol::new(table_name, "theme_mode"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for CustomWorldGalleryEntry {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_generation_mode_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/custom_world_generation_mode_type.rs deleted file mode 100644 index 8b424a9a7..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_generation_mode_type.rs +++ /dev/null @@ -1,18 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum CustomWorldGenerationMode { - Fast, - - Full, -} - -impl __sdk::InModule for CustomWorldGenerationMode { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_profile_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/custom_world_profile_table.rs deleted file mode 100644 index 963f9cb0a..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_profile_table.rs +++ /dev/null @@ -1,232 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::custom_world_profile_type::CustomWorldProfile; -use super::custom_world_publication_status_type::CustomWorldPublicationStatus; -use super::custom_world_theme_mode_type::CustomWorldThemeMode; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `custom_world_profile`. -/// -/// Obtain a handle from the [`CustomWorldProfileTableAccess::custom_world_profile`] method on [`super::RemoteTables`], -/// like `ctx.db.custom_world_profile()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.custom_world_profile().on_insert(...)`. -pub struct CustomWorldProfileTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `custom_world_profile`. -pub struct CustomWorldProfileTableAccessor; - -impl __sdk::TableAccessor for CustomWorldProfileTableAccessor { - type Row = CustomWorldProfile; - type Handle<'db> = CustomWorldProfileTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.custom_world_profile() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `custom_world_profile`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait CustomWorldProfileTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`CustomWorldProfileTableHandle`], which mediates access to the table `custom_world_profile`. - fn custom_world_profile(&self) -> CustomWorldProfileTableHandle<'_>; -} - -impl CustomWorldProfileTableAccess for super::RemoteTables { - fn custom_world_profile(&self) -> CustomWorldProfileTableHandle<'_> { - CustomWorldProfileTableHandle { - imp: self - .imp - .get_table::("custom_world_profile"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct CustomWorldProfileInsertCallbackId(__sdk::CallbackId); -pub struct CustomWorldProfileDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for CustomWorldProfileTableHandle<'ctx> { - type Row = CustomWorldProfile; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for CustomWorldProfileTableHandle<'ctx> { - type Row = CustomWorldProfile; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = CustomWorldProfileInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldProfileInsertCallbackId { - CustomWorldProfileInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: CustomWorldProfileInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = CustomWorldProfileDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldProfileDeleteCallbackId { - CustomWorldProfileDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: CustomWorldProfileDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for CustomWorldProfileTableHandle<'ctx> { - type InsertCallbackId = CustomWorldProfileInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldProfileInsertCallbackId { - CustomWorldProfileInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: CustomWorldProfileInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for CustomWorldProfileTableHandle<'ctx> { - type DeleteCallbackId = CustomWorldProfileDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldProfileDeleteCallbackId { - CustomWorldProfileDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: CustomWorldProfileDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct CustomWorldProfileUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for CustomWorldProfileTableHandle<'ctx> { - type UpdateCallbackId = CustomWorldProfileUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> CustomWorldProfileUpdateCallbackId { - CustomWorldProfileUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: CustomWorldProfileUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for CustomWorldProfileTableHandle<'ctx> { - type UpdateCallbackId = CustomWorldProfileUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> CustomWorldProfileUpdateCallbackId { - CustomWorldProfileUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: CustomWorldProfileUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `profile_id` unique index on the table `custom_world_profile`, -/// which allows point queries on the field of the same name -/// via the [`CustomWorldProfileProfileIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.custom_world_profile().profile_id().find(...)`. -pub struct CustomWorldProfileProfileIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> CustomWorldProfileTableHandle<'ctx> { - /// Get a handle on the `profile_id` unique index on the table `custom_world_profile`. - pub fn profile_id(&self) -> CustomWorldProfileProfileIdUnique<'ctx> { - CustomWorldProfileProfileIdUnique { - imp: self.imp.get_unique_constraint::("profile_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> CustomWorldProfileProfileIdUnique<'ctx> { - /// Find the subscribed row whose `profile_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("custom_world_profile"); - _table.add_unique_constraint::("profile_id", |row| &row.profile_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `CustomWorldProfile`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait custom_world_profileQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `CustomWorldProfile`. - fn custom_world_profile(&self) -> __sdk::__query_builder::Table; -} - -impl custom_world_profileQueryTableAccess for __sdk::QueryTableAccessor { - fn custom_world_profile(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("custom_world_profile") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_profile_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/custom_world_profile_type.rs deleted file mode 100644 index bbed3f0da..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_profile_type.rs +++ /dev/null @@ -1,139 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::custom_world_publication_status_type::CustomWorldPublicationStatus; -use super::custom_world_theme_mode_type::CustomWorldThemeMode; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct CustomWorldProfile { - pub profile_id: String, - pub owner_user_id: String, - pub public_work_code: Option, - pub author_public_user_code: Option, - pub source_agent_session_id: Option, - pub publication_status: CustomWorldPublicationStatus, - pub world_name: String, - pub subtitle: String, - pub summary_text: String, - pub theme_mode: CustomWorldThemeMode, - pub cover_image_src: Option, - pub profile_payload_json: String, - pub playable_npc_count: u32, - pub landmark_count: u32, - pub play_count: u32, - pub remix_count: u32, - pub like_count: u32, - pub author_display_name: String, - pub published_at: Option<__sdk::Timestamp>, - pub deleted_at: Option<__sdk::Timestamp>, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, - pub visible: bool, -} - -impl __sdk::InModule for CustomWorldProfile { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `CustomWorldProfile`. -/// -/// Provides typed access to columns for query building. -pub struct CustomWorldProfileCols { - pub profile_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub public_work_code: __sdk::__query_builder::Col>, - pub author_public_user_code: __sdk::__query_builder::Col>, - pub source_agent_session_id: __sdk::__query_builder::Col>, - pub publication_status: - __sdk::__query_builder::Col, - pub world_name: __sdk::__query_builder::Col, - pub subtitle: __sdk::__query_builder::Col, - pub summary_text: __sdk::__query_builder::Col, - pub theme_mode: __sdk::__query_builder::Col, - pub cover_image_src: __sdk::__query_builder::Col>, - pub profile_payload_json: __sdk::__query_builder::Col, - pub playable_npc_count: __sdk::__query_builder::Col, - pub landmark_count: __sdk::__query_builder::Col, - pub play_count: __sdk::__query_builder::Col, - pub remix_count: __sdk::__query_builder::Col, - pub like_count: __sdk::__query_builder::Col, - pub author_display_name: __sdk::__query_builder::Col, - pub published_at: __sdk::__query_builder::Col>, - pub deleted_at: __sdk::__query_builder::Col>, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, - pub visible: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for CustomWorldProfile { - type Cols = CustomWorldProfileCols; - fn cols(table_name: &'static str) -> Self::Cols { - CustomWorldProfileCols { - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - public_work_code: __sdk::__query_builder::Col::new(table_name, "public_work_code"), - author_public_user_code: __sdk::__query_builder::Col::new( - table_name, - "author_public_user_code", - ), - source_agent_session_id: __sdk::__query_builder::Col::new( - table_name, - "source_agent_session_id", - ), - publication_status: __sdk::__query_builder::Col::new(table_name, "publication_status"), - world_name: __sdk::__query_builder::Col::new(table_name, "world_name"), - subtitle: __sdk::__query_builder::Col::new(table_name, "subtitle"), - summary_text: __sdk::__query_builder::Col::new(table_name, "summary_text"), - theme_mode: __sdk::__query_builder::Col::new(table_name, "theme_mode"), - cover_image_src: __sdk::__query_builder::Col::new(table_name, "cover_image_src"), - profile_payload_json: __sdk::__query_builder::Col::new( - table_name, - "profile_payload_json", - ), - playable_npc_count: __sdk::__query_builder::Col::new(table_name, "playable_npc_count"), - landmark_count: __sdk::__query_builder::Col::new(table_name, "landmark_count"), - play_count: __sdk::__query_builder::Col::new(table_name, "play_count"), - remix_count: __sdk::__query_builder::Col::new(table_name, "remix_count"), - like_count: __sdk::__query_builder::Col::new(table_name, "like_count"), - author_display_name: __sdk::__query_builder::Col::new( - table_name, - "author_display_name", - ), - published_at: __sdk::__query_builder::Col::new(table_name, "published_at"), - deleted_at: __sdk::__query_builder::Col::new(table_name, "deleted_at"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - visible: __sdk::__query_builder::Col::new(table_name, "visible"), - } - } -} - -/// Indexed column accessor struct for the table `CustomWorldProfile`. -/// -/// Provides typed access to indexed columns for query building. -pub struct CustomWorldProfileIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub profile_id: __sdk::__query_builder::IxCol, - pub publication_status: - __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for CustomWorldProfile { - type IxCols = CustomWorldProfileIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - CustomWorldProfileIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::IxCol::new(table_name, "profile_id"), - publication_status: __sdk::__query_builder::IxCol::new( - table_name, - "publication_status", - ), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for CustomWorldProfile {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_publication_status_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/custom_world_publication_status_type.rs deleted file mode 100644 index f21186ff6..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_publication_status_type.rs +++ /dev/null @@ -1,18 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum CustomWorldPublicationStatus { - Draft, - - Published, -} - -impl __sdk::InModule for CustomWorldPublicationStatus { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_role_asset_status_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/custom_world_role_asset_status_type.rs deleted file mode 100644 index 1ab238e93..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_role_asset_status_type.rs +++ /dev/null @@ -1,22 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum CustomWorldRoleAssetStatus { - Missing, - - VisualReady, - - AnimationsReady, - - Complete, -} - -impl __sdk::InModule for CustomWorldRoleAssetStatus { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_session_status_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/custom_world_session_status_type.rs deleted file mode 100644 index 9b640e4ff..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_session_status_type.rs +++ /dev/null @@ -1,24 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum CustomWorldSessionStatus { - Clarifying, - - ReadyToGenerate, - - Generating, - - Completed, - - GenerationError, -} - -impl __sdk::InModule for CustomWorldSessionStatus { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_session_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/custom_world_session_table.rs deleted file mode 100644 index 52d89b600..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_session_table.rs +++ /dev/null @@ -1,232 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::custom_world_generation_mode_type::CustomWorldGenerationMode; -use super::custom_world_session_status_type::CustomWorldSessionStatus; -use super::custom_world_session_type::CustomWorldSession; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `custom_world_session`. -/// -/// Obtain a handle from the [`CustomWorldSessionTableAccess::custom_world_session`] method on [`super::RemoteTables`], -/// like `ctx.db.custom_world_session()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.custom_world_session().on_insert(...)`. -pub struct CustomWorldSessionTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `custom_world_session`. -pub struct CustomWorldSessionTableAccessor; - -impl __sdk::TableAccessor for CustomWorldSessionTableAccessor { - type Row = CustomWorldSession; - type Handle<'db> = CustomWorldSessionTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.custom_world_session() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `custom_world_session`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait CustomWorldSessionTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`CustomWorldSessionTableHandle`], which mediates access to the table `custom_world_session`. - fn custom_world_session(&self) -> CustomWorldSessionTableHandle<'_>; -} - -impl CustomWorldSessionTableAccess for super::RemoteTables { - fn custom_world_session(&self) -> CustomWorldSessionTableHandle<'_> { - CustomWorldSessionTableHandle { - imp: self - .imp - .get_table::("custom_world_session"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct CustomWorldSessionInsertCallbackId(__sdk::CallbackId); -pub struct CustomWorldSessionDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for CustomWorldSessionTableHandle<'ctx> { - type Row = CustomWorldSession; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for CustomWorldSessionTableHandle<'ctx> { - type Row = CustomWorldSession; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = CustomWorldSessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldSessionInsertCallbackId { - CustomWorldSessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: CustomWorldSessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = CustomWorldSessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldSessionDeleteCallbackId { - CustomWorldSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: CustomWorldSessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for CustomWorldSessionTableHandle<'ctx> { - type InsertCallbackId = CustomWorldSessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldSessionInsertCallbackId { - CustomWorldSessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: CustomWorldSessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for CustomWorldSessionTableHandle<'ctx> { - type DeleteCallbackId = CustomWorldSessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> CustomWorldSessionDeleteCallbackId { - CustomWorldSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: CustomWorldSessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct CustomWorldSessionUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for CustomWorldSessionTableHandle<'ctx> { - type UpdateCallbackId = CustomWorldSessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> CustomWorldSessionUpdateCallbackId { - CustomWorldSessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: CustomWorldSessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for CustomWorldSessionTableHandle<'ctx> { - type UpdateCallbackId = CustomWorldSessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> CustomWorldSessionUpdateCallbackId { - CustomWorldSessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: CustomWorldSessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `session_id` unique index on the table `custom_world_session`, -/// which allows point queries on the field of the same name -/// via the [`CustomWorldSessionSessionIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.custom_world_session().session_id().find(...)`. -pub struct CustomWorldSessionSessionIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> CustomWorldSessionTableHandle<'ctx> { - /// Get a handle on the `session_id` unique index on the table `custom_world_session`. - pub fn session_id(&self) -> CustomWorldSessionSessionIdUnique<'ctx> { - CustomWorldSessionSessionIdUnique { - imp: self.imp.get_unique_constraint::("session_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> CustomWorldSessionSessionIdUnique<'ctx> { - /// Find the subscribed row whose `session_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("custom_world_session"); - _table.add_unique_constraint::("session_id", |row| &row.session_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `CustomWorldSession`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait custom_world_sessionQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `CustomWorldSession`. - fn custom_world_session(&self) -> __sdk::__query_builder::Table; -} - -impl custom_world_sessionQueryTableAccess for __sdk::QueryTableAccessor { - fn custom_world_session(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("custom_world_session") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_session_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/custom_world_session_type.rs deleted file mode 100644 index 58e9f40cc..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_session_type.rs +++ /dev/null @@ -1,93 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::custom_world_generation_mode_type::CustomWorldGenerationMode; -use super::custom_world_session_status_type::CustomWorldSessionStatus; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct CustomWorldSession { - pub session_id: String, - pub owner_user_id: String, - pub generation_mode: CustomWorldGenerationMode, - pub status: CustomWorldSessionStatus, - pub setting_text: String, - pub creator_intent_json: Option, - pub question_snapshot_json: String, - pub result_payload_json: Option, - pub last_error_message: Option, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for CustomWorldSession { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `CustomWorldSession`. -/// -/// Provides typed access to columns for query building. -pub struct CustomWorldSessionCols { - pub session_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub generation_mode: __sdk::__query_builder::Col, - pub status: __sdk::__query_builder::Col, - pub setting_text: __sdk::__query_builder::Col, - pub creator_intent_json: __sdk::__query_builder::Col>, - pub question_snapshot_json: __sdk::__query_builder::Col, - pub result_payload_json: __sdk::__query_builder::Col>, - pub last_error_message: __sdk::__query_builder::Col>, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for CustomWorldSession { - type Cols = CustomWorldSessionCols; - fn cols(table_name: &'static str) -> Self::Cols { - CustomWorldSessionCols { - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - generation_mode: __sdk::__query_builder::Col::new(table_name, "generation_mode"), - status: __sdk::__query_builder::Col::new(table_name, "status"), - setting_text: __sdk::__query_builder::Col::new(table_name, "setting_text"), - creator_intent_json: __sdk::__query_builder::Col::new( - table_name, - "creator_intent_json", - ), - question_snapshot_json: __sdk::__query_builder::Col::new( - table_name, - "question_snapshot_json", - ), - result_payload_json: __sdk::__query_builder::Col::new( - table_name, - "result_payload_json", - ), - last_error_message: __sdk::__query_builder::Col::new(table_name, "last_error_message"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `CustomWorldSession`. -/// -/// Provides typed access to indexed columns for query building. -pub struct CustomWorldSessionIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for CustomWorldSession { - type IxCols = CustomWorldSessionIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - CustomWorldSessionIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for CustomWorldSession {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_theme_mode_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/custom_world_theme_mode_type.rs deleted file mode 100644 index 2084ea043..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/custom_world_theme_mode_type.rs +++ /dev/null @@ -1,26 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum CustomWorldThemeMode { - Martial, - - Arcane, - - Machina, - - Tide, - - Rift, - - Mythic, -} - -impl __sdk::InModule for CustomWorldThemeMode { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/database_migration_clear_retired_tables_input_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/database_migration_clear_retired_tables_input_type.rs deleted file mode 100644 index 0e8efa42f..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/database_migration_clear_retired_tables_input_type.rs +++ /dev/null @@ -1,15 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct DatabaseMigrationClearRetiredTablesInput { - pub dry_run: bool, -} - -impl __sdk::InModule for DatabaseMigrationClearRetiredTablesInput { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/database_migration_clear_retired_tables_result_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/database_migration_clear_retired_tables_result_type.rs deleted file mode 100644 index 2507b80d2..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/database_migration_clear_retired_tables_result_type.rs +++ /dev/null @@ -1,20 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::database_migration_clear_table_stat_type::DatabaseMigrationClearTableStat; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct DatabaseMigrationClearRetiredTablesResult { - pub ok: bool, - pub dry_run: bool, - pub table_stats: Vec, - pub error_message: Option, -} - -impl __sdk::InModule for DatabaseMigrationClearRetiredTablesResult { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/database_migration_clear_table_stat_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/database_migration_clear_table_stat_type.rs deleted file mode 100644 index 2b83ab354..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/database_migration_clear_table_stat_type.rs +++ /dev/null @@ -1,17 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct DatabaseMigrationClearTableStat { - pub table_name: String, - pub row_count_before: u64, - pub cleared_row_count: u64, -} - -impl __sdk::InModule for DatabaseMigrationClearTableStat { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/delete_editor_agent_conversation_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/delete_editor_agent_conversation_and_return_procedure.rs index e7bf76bfd..95157cf96 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/delete_editor_agent_conversation_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/delete_editor_agent_conversation_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait delete_editor_agent_conversation_and_return { input: EditorAgentConversationDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl delete_editor_agent_conversation_and_return for super::RemoteProcedures { input: EditorAgentConversationDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorAgentConversationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/delete_editor_asset_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/delete_editor_asset_and_return_procedure.rs index a7c50753a..4c71ecd53 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/delete_editor_asset_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/delete_editor_asset_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait delete_editor_asset_and_return { input: EditorAssetDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl delete_editor_asset_and_return for super::RemoteProcedures { input: EditorAssetDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorAssetProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/delete_editor_asset_folder_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/delete_editor_asset_folder_and_return_procedure.rs index 15aae6008..6500a7c79 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/delete_editor_asset_folder_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/delete_editor_asset_folder_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait delete_editor_asset_folder_and_return { input: EditorAssetFolderDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl delete_editor_asset_folder_and_return for super::RemoteProcedures { input: EditorAssetFolderDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorAssetFolderProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/delete_editor_project_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/delete_editor_project_and_return_procedure.rs index 4586a8691..529aec929 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/delete_editor_project_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/delete_editor_project_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait delete_editor_project_and_return { input: EditorProjectDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl delete_editor_project_and_return for super::RemoteProcedures { input: EditorProjectDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorProjectDeleteProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/enqueue_external_generation_job_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/enqueue_external_generation_job_and_return_procedure.rs index e38fdf29d..cd14e1432 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/enqueue_external_generation_job_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/enqueue_external_generation_job_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait enqueue_external_generation_job_and_return { input: ExternalGenerationJobEnqueueInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl enqueue_external_generation_job_and_return for super::RemoteProcedures { input: ExternalGenerationJobEnqueueInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ExternalGenerationJobProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/enqueue_profile_wallet_refund_outbox_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/enqueue_profile_wallet_refund_outbox_and_return_procedure.rs index 2ef1a2997..4f5f28c68 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/enqueue_profile_wallet_refund_outbox_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/enqueue_profile_wallet_refund_outbox_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait enqueue_profile_wallet_refund_outbox_and_return { input: RuntimeProfileWalletRefundOutboxEnqueueInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl enqueue_profile_wallet_refund_outbox_and_return for super::RemoteProcedures input: RuntimeProfileWalletRefundOutboxEnqueueInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileWalletRefundOutboxProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/ensure_analytics_date_dimension_for_date_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/ensure_analytics_date_dimension_for_date_reducer.rs index a6ea3098f..30b9ba357 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/ensure_analytics_date_dimension_for_date_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/ensure_analytics_date_dimension_for_date_reducer.rs @@ -50,11 +50,9 @@ pub trait ensure_analytics_date_dimension_for_date { &self, input: AnalyticsDateDimensionEnsureInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -63,11 +61,9 @@ impl ensure_analytics_date_dimension_for_date for super::RemoteReducers { &self, input: AnalyticsDateDimensionEnsureInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp.invoke_reducer_with_callback( EnsureAnalyticsDateDimensionForDateArgs { input }, diff --git a/server-rs/crates/spacetime-client/src/module_bindings/expire_profile_recharge_order_timer_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/expire_profile_recharge_order_timer_reducer.rs index 4ee98c011..b9e5a5db5 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/expire_profile_recharge_order_timer_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/expire_profile_recharge_order_timer_reducer.rs @@ -50,11 +50,9 @@ pub trait expire_profile_recharge_order_timer { &self, timer: ProfileRechargeOrderExpirationTimer, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -63,11 +61,9 @@ impl expire_profile_recharge_order_timer for super::RemoteReducers { &self, timer: ProfileRechargeOrderExpirationTimer, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(ExpireProfileRechargeOrderTimerArgs { timer }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/export_auth_store_projection_from_tables_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/export_auth_store_projection_from_tables_procedure.rs index 9334aa833..ece547ce8 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/export_auth_store_projection_from_tables_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/export_auth_store_projection_from_tables_procedure.rs @@ -27,10 +27,10 @@ pub trait export_auth_store_projection_from_tables { &self, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -39,10 +39,10 @@ impl export_auth_store_projection_from_tables for super::RemoteProcedures { &self, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AuthStoreProjectionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/export_database_migration_to_file_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/export_database_migration_to_file_procedure.rs index d850737bc..3dfe18f83 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/export_database_migration_to_file_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/export_database_migration_to_file_procedure.rs @@ -31,10 +31,10 @@ pub trait export_database_migration_to_file { input: DatabaseMigrationExportInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl export_database_migration_to_file for super::RemoteProcedures { input: DatabaseMigrationExportInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, DatabaseMigrationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/fail_ai_task_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/fail_ai_task_and_return_procedure.rs index 3194799b9..46090a010 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/fail_ai_task_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/fail_ai_task_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait fail_ai_task_and_return { input: AiTaskFailureInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl fail_ai_task_and_return for super::RemoteProcedures { input: AiTaskFailureInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AiTaskProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/fail_external_generation_job_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/fail_external_generation_job_and_return_procedure.rs index 92be5608f..46c1f8846 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/fail_external_generation_job_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/fail_external_generation_job_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait fail_external_generation_job_and_return { input: ExternalGenerationJobFailInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl fail_external_generation_job_and_return for super::RemoteProcedures { input: ExternalGenerationJobFailInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ExternalGenerationJobProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/find_editor_asset_group_source_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/find_editor_asset_group_source_and_return_procedure.rs index 1c8b4c32a..7b8d7dbd0 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/find_editor_asset_group_source_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/find_editor_asset_group_source_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait find_editor_asset_group_source_and_return { input: EditorAssetGroupSourceLookupInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl find_editor_asset_group_source_and_return for super::RemoteProcedures { input: EditorAssetGroupSourceLookupInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorAssetProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_admin_account_by_id_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_admin_account_by_id_and_return_procedure.rs index f6a70ccf2..7dccc1606 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_admin_account_by_id_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_admin_account_by_id_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait get_admin_account_by_id_and_return { input: AdminAccountGetByIdInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_admin_account_by_id_and_return for super::RemoteProcedures { input: AdminAccountGetByIdInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AdminAccountProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_admin_account_by_username_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_admin_account_by_username_and_return_procedure.rs index 240260454..a441962e4 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_admin_account_by_username_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_admin_account_by_username_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait get_admin_account_by_username_and_return { input: AdminAccountGetByUsernameInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_admin_account_by_username_and_return for super::RemoteProcedures { input: AdminAccountGetByUsernameInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AdminAccountCredentialProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_admin_dashboard_stats_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_admin_dashboard_stats_and_return_procedure.rs index 4fc1f2929..ec663a6d4 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_admin_dashboard_stats_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_admin_dashboard_stats_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait get_admin_dashboard_stats_and_return { input: AdminDashboardStatsInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_admin_dashboard_stats_and_return for super::RemoteProcedures { input: AdminDashboardStatsInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AdminDashboardStatsProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_asset_object_by_id_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_asset_object_by_id_and_return_procedure.rs index edb842e1e..b1d165b00 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_asset_object_by_id_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_asset_object_by_id_and_return_procedure.rs @@ -30,10 +30,10 @@ pub trait get_asset_object_by_id_and_return { asset_object_id: String, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -43,10 +43,10 @@ impl get_asset_object_by_id_and_return for super::RemoteProcedures { asset_object_id: String, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AssetObjectProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_asset_object_by_location_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_asset_object_by_location_and_return_procedure.rs index c7ecc9e73..9254cc5c9 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_asset_object_by_location_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_asset_object_by_location_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait get_asset_object_by_location_and_return { input: AssetObjectLocationInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_asset_object_by_location_and_return for super::RemoteProcedures { input: AssetObjectLocationInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AssetObjectProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_asset_read_access_by_location_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_asset_read_access_by_location_and_return_procedure.rs index c2e89aa8e..bb8314cfa 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_asset_read_access_by_location_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_asset_read_access_by_location_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait get_asset_read_access_by_location_and_return { input: AssetObjectLocationInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_asset_read_access_by_location_and_return for super::RemoteProcedures { input: AssetObjectLocationInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AssetObjectReadAccessProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_editor_agent_conversation_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_editor_agent_conversation_and_return_procedure.rs index e45514af6..79b9f43f1 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_editor_agent_conversation_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_editor_agent_conversation_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait get_editor_agent_conversation_and_return { input: EditorAgentConversationGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_editor_agent_conversation_and_return for super::RemoteProcedures { input: EditorAgentConversationGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorAgentConversationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_editor_asset_library_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_editor_asset_library_and_return_procedure.rs index c1053c14c..dca803bbf 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_editor_asset_library_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_editor_asset_library_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait get_editor_asset_library_and_return { input: EditorAssetLibraryGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_editor_asset_library_and_return for super::RemoteProcedures { input: EditorAssetLibraryGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorAssetLibraryProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_editor_generation_pricing_config_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_editor_generation_pricing_config_and_return_procedure.rs index 33520d813..e64edf0c2 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_editor_generation_pricing_config_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_editor_generation_pricing_config_and_return_procedure.rs @@ -27,10 +27,10 @@ pub trait get_editor_generation_pricing_config_and_return { &self, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -39,10 +39,10 @@ impl get_editor_generation_pricing_config_and_return for super::RemoteProcedures &self, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorGenerationPricingConfigProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_editor_project_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_editor_project_and_return_procedure.rs index f01b87343..07d5c4fe1 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_editor_project_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_editor_project_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait get_editor_project_and_return { input: EditorProjectGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_editor_project_and_return for super::RemoteProcedures { input: EditorProjectGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorProjectProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_editor_showcase_campaign_config_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_editor_showcase_campaign_config_and_return_procedure.rs index 5d7332290..baeb8c837 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_editor_showcase_campaign_config_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_editor_showcase_campaign_config_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait get_editor_showcase_campaign_config_and_return { input: EditorShowcaseCampaignConfigGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl get_editor_showcase_campaign_config_and_return for super::RemoteProcedures input: EditorShowcaseCampaignConfigGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorShowcaseCampaignConfigProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_external_generation_job_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_external_generation_job_and_return_procedure.rs index 51ce17456..e2bc98a33 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_external_generation_job_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_external_generation_job_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait get_external_generation_job_and_return { input: ExternalGenerationJobGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_external_generation_job_and_return for super::RemoteProcedures { input: ExternalGenerationJobGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ExternalGenerationJobProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_external_generation_job_result_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_external_generation_job_result_and_return_procedure.rs index d0ff920cd..367154dfb 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_external_generation_job_result_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_external_generation_job_result_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait get_external_generation_job_result_and_return { input: ExternalGenerationJobGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_external_generation_job_result_and_return for super::RemoteProcedures { input: ExternalGenerationJobGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ExternalGenerationJobResultProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_external_generation_job_summary_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_external_generation_job_summary_and_return_procedure.rs index 2009e65a2..2b5703e72 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_external_generation_job_summary_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_external_generation_job_summary_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait get_external_generation_job_summary_and_return { input: ExternalGenerationJobGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_external_generation_job_summary_and_return for super::RemoteProcedures input: ExternalGenerationJobGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ExternalGenerationJobSummaryProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_external_generation_queue_stats_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_external_generation_queue_stats_and_return_procedure.rs index 429d22f4b..9d7a98a05 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_external_generation_queue_stats_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_external_generation_queue_stats_and_return_procedure.rs @@ -27,10 +27,10 @@ pub trait get_external_generation_queue_stats_and_return { &self, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -39,10 +39,10 @@ impl get_external_generation_queue_stats_and_return for super::RemoteProcedures &self, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ExternalGenerationQueueStatsProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_feature_gate_config_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_feature_gate_config_procedure.rs index ab7b59b18..5e2bb5c7a 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_feature_gate_config_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_feature_gate_config_procedure.rs @@ -27,10 +27,10 @@ pub trait get_feature_gate_config { &self, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -39,10 +39,10 @@ impl get_feature_gate_config for super::RemoteProcedures { &self, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, FeatureGateConfigProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_llm_router_account_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_llm_router_account_and_return_procedure.rs index 71702eee1..be31e0104 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_llm_router_account_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_llm_router_account_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait get_llm_router_account_and_return { input: LlmRouterAccountGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_llm_router_account_and_return for super::RemoteProcedures { input: LlmRouterAccountGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, LlmRouterAccountProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_dashboard_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_dashboard_procedure.rs index 6c48fafb3..38200b75a 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_dashboard_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_dashboard_procedure.rs @@ -31,10 +31,10 @@ pub trait get_profile_dashboard { input: RuntimeProfileDashboardGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_profile_dashboard for super::RemoteProcedures { input: RuntimeProfileDashboardGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileDashboardProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_center_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_center_procedure.rs index 3e42f3d57..bf070c9c8 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_center_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_center_procedure.rs @@ -31,10 +31,10 @@ pub trait get_profile_recharge_center { input: RuntimeProfileRechargeCenterGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_profile_recharge_center for super::RemoteProcedures { input: RuntimeProfileRechargeCenterGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRechargeCenterProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_order_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_order_and_return_procedure.rs index f187bc6fb..437f0048b 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_order_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_order_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait get_profile_recharge_order_and_return { input: RuntimeProfileRechargeOrderGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_profile_recharge_order_and_return for super::RemoteProcedures { input: RuntimeProfileRechargeOrderGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRechargeCenterProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_refund_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_refund_and_return_procedure.rs index 977396098..d1a584f1b 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_refund_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_refund_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait get_profile_recharge_refund_and_return { input: RuntimeProfileRechargeRefundGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_profile_recharge_refund_and_return for super::RemoteProcedures { input: RuntimeProfileRechargeRefundGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRechargeRefundProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_refund_bill_checkpoint_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_refund_bill_checkpoint_and_return_procedure.rs index 2a9b9dcca..9cb29fc5b 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_refund_bill_checkpoint_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_refund_bill_checkpoint_and_return_procedure.rs @@ -34,10 +34,13 @@ pub trait get_profile_recharge_refund_bill_checkpoint_and_return { input: RuntimeProfileRechargeRefundBillCheckpointGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result< + RuntimeProfileRechargeRefundBillCheckpointProcedureResult, + __sdk::InternalError, + >, + ) + Send + + 'static, ); } @@ -47,10 +50,13 @@ impl get_profile_recharge_refund_bill_checkpoint_and_return for super::RemotePro input: RuntimeProfileRechargeRefundBillCheckpointGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result< + RuntimeProfileRechargeRefundBillCheckpointProcedureResult, + __sdk::InternalError, + >, + ) + Send + + 'static, ) { self.imp.invoke_procedure_with_callback::<_, RuntimeProfileRechargeRefundBillCheckpointProcedureResult>( "get_profile_recharge_refund_bill_checkpoint_and_return", diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_referral_invite_center_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_referral_invite_center_procedure.rs index c72214843..2b3dcdadc 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_referral_invite_center_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_referral_invite_center_procedure.rs @@ -31,10 +31,10 @@ pub trait get_profile_referral_invite_center { input: RuntimeReferralInviteCenterGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_profile_referral_invite_center for super::RemoteProcedures { input: RuntimeReferralInviteCenterGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeReferralInviteCenterProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_task_center_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_task_center_procedure.rs index 0aa83260a..105a4f98c 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_task_center_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_task_center_procedure.rs @@ -31,10 +31,10 @@ pub trait get_profile_task_center { input: RuntimeProfileTaskCenterGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_profile_task_center for super::RemoteProcedures { input: RuntimeProfileTaskCenterGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileTaskCenterProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_recent_editor_project_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_recent_editor_project_and_return_procedure.rs index ea9b9720c..b16395853 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_recent_editor_project_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_recent_editor_project_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait get_recent_editor_project_and_return { input: EditorProjectGetRecentInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_recent_editor_project_and_return for super::RemoteProcedures { input: EditorProjectGetRecentInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorProjectProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_runtime_setting_or_default_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_runtime_setting_or_default_procedure.rs index 4ca8b03ea..261caed19 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_runtime_setting_or_default_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_runtime_setting_or_default_procedure.rs @@ -31,10 +31,10 @@ pub trait get_runtime_setting_or_default { input: RuntimeSettingGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_runtime_setting_or_default for super::RemoteProcedures { input: RuntimeSettingGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeSettingProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/grant_new_user_registration_wallet_reward_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/grant_new_user_registration_wallet_reward_procedure.rs index 71e481514..c1d7b6dea 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/grant_new_user_registration_wallet_reward_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/grant_new_user_registration_wallet_reward_procedure.rs @@ -31,10 +31,10 @@ pub trait grant_new_user_registration_wallet_reward { input: RuntimeProfileDashboardGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl grant_new_user_registration_wallet_reward for super::RemoteProcedures { input: RuntimeProfileDashboardGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileWalletAdjustmentProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_from_chunks_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_from_chunks_procedure.rs index 080dda548..731574800 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_from_chunks_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_from_chunks_procedure.rs @@ -31,10 +31,10 @@ pub trait import_database_migration_from_chunks { input: DatabaseMigrationImportChunksInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl import_database_migration_from_chunks for super::RemoteProcedures { input: DatabaseMigrationImportChunksInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, DatabaseMigrationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_from_file_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_from_file_procedure.rs index 2ce4ee2ad..7b2322ee5 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_from_file_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_from_file_procedure.rs @@ -31,10 +31,10 @@ pub trait import_database_migration_from_file { input: DatabaseMigrationImportInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl import_database_migration_from_file for super::RemoteProcedures { input: DatabaseMigrationImportInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, DatabaseMigrationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_incremental_from_chunks_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_incremental_from_chunks_procedure.rs index bbe493578..51ff565c0 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_incremental_from_chunks_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_incremental_from_chunks_procedure.rs @@ -34,10 +34,10 @@ pub trait import_database_migration_incremental_from_chunks { input: DatabaseMigrationImportChunksInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl import_database_migration_incremental_from_chunks for super::RemoteProcedur input: DatabaseMigrationImportChunksInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, DatabaseMigrationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_incremental_from_file_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_incremental_from_file_procedure.rs index f911c87f8..2fc318044 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_incremental_from_file_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_incremental_from_file_procedure.rs @@ -31,10 +31,10 @@ pub trait import_database_migration_incremental_from_file { input: DatabaseMigrationImportInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl import_database_migration_incremental_from_file for super::RemoteProcedures input: DatabaseMigrationImportInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, DatabaseMigrationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/initialize_editor_generation_pricing_config_if_missing_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/initialize_editor_generation_pricing_config_if_missing_and_return_procedure.rs index 841e0298c..cc4468e45 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/initialize_editor_generation_pricing_config_if_missing_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/initialize_editor_generation_pricing_config_if_missing_and_return_procedure.rs @@ -37,10 +37,10 @@ pub trait initialize_editor_generation_pricing_config_if_missing_and_return { input: EditorGenerationPricingConfigUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -50,10 +50,10 @@ impl initialize_editor_generation_pricing_config_if_missing_and_return for super input: EditorGenerationPricingConfigUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorGenerationPricingConfigProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/inventory_container_kind_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/inventory_container_kind_type.rs deleted file mode 100644 index 45522ce74..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/inventory_container_kind_type.rs +++ /dev/null @@ -1,18 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum InventoryContainerKind { - Backpack, - - Equipment, -} - -impl __sdk::InModule for InventoryContainerKind { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/inventory_equipment_slot_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/inventory_equipment_slot_type.rs deleted file mode 100644 index e2055f6af..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/inventory_equipment_slot_type.rs +++ /dev/null @@ -1,20 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum InventoryEquipmentSlot { - Weapon, - - Armor, - - Relic, -} - -impl __sdk::InModule for InventoryEquipmentSlot { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/inventory_item_rarity_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/inventory_item_rarity_type.rs deleted file mode 100644 index 85b460902..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/inventory_item_rarity_type.rs +++ /dev/null @@ -1,24 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum InventoryItemRarity { - Common, - - Uncommon, - - Rare, - - Epic, - - Legendary, -} - -impl __sdk::InModule for InventoryItemRarity { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/inventory_item_source_kind_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/inventory_item_source_kind_type.rs deleted file mode 100644 index 1d3961bc8..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/inventory_item_source_kind_type.rs +++ /dev/null @@ -1,32 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum InventoryItemSourceKind { - StoryReward, - - QuestReward, - - TreasureReward, - - NpcGift, - - NpcTrade, - - CombatDrop, - - ForgeCraft, - - ForgeReforge, - - ManualPatch, -} - -impl __sdk::InModule for InventoryItemSourceKind { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/inventory_slot_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/inventory_slot_table.rs deleted file mode 100644 index 76786f9e1..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/inventory_slot_table.rs +++ /dev/null @@ -1,232 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::inventory_container_kind_type::InventoryContainerKind; -use super::inventory_equipment_slot_type::InventoryEquipmentSlot; -use super::inventory_item_rarity_type::InventoryItemRarity; -use super::inventory_item_source_kind_type::InventoryItemSourceKind; -use super::inventory_slot_type::InventorySlot; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `inventory_slot`. -/// -/// Obtain a handle from the [`InventorySlotTableAccess::inventory_slot`] method on [`super::RemoteTables`], -/// like `ctx.db.inventory_slot()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.inventory_slot().on_insert(...)`. -pub struct InventorySlotTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `inventory_slot`. -pub struct InventorySlotTableAccessor; - -impl __sdk::TableAccessor for InventorySlotTableAccessor { - type Row = InventorySlot; - type Handle<'db> = InventorySlotTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.inventory_slot() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `inventory_slot`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait InventorySlotTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`InventorySlotTableHandle`], which mediates access to the table `inventory_slot`. - fn inventory_slot(&self) -> InventorySlotTableHandle<'_>; -} - -impl InventorySlotTableAccess for super::RemoteTables { - fn inventory_slot(&self) -> InventorySlotTableHandle<'_> { - InventorySlotTableHandle { - imp: self.imp.get_table::("inventory_slot"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct InventorySlotInsertCallbackId(__sdk::CallbackId); -pub struct InventorySlotDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for InventorySlotTableHandle<'ctx> { - type Row = InventorySlot; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for InventorySlotTableHandle<'ctx> { - type Row = InventorySlot; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = InventorySlotInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> InventorySlotInsertCallbackId { - InventorySlotInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: InventorySlotInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = InventorySlotDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> InventorySlotDeleteCallbackId { - InventorySlotDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: InventorySlotDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for InventorySlotTableHandle<'ctx> { - type InsertCallbackId = InventorySlotInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> InventorySlotInsertCallbackId { - InventorySlotInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: InventorySlotInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for InventorySlotTableHandle<'ctx> { - type DeleteCallbackId = InventorySlotDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> InventorySlotDeleteCallbackId { - InventorySlotDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: InventorySlotDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct InventorySlotUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for InventorySlotTableHandle<'ctx> { - type UpdateCallbackId = InventorySlotUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> InventorySlotUpdateCallbackId { - InventorySlotUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: InventorySlotUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for InventorySlotTableHandle<'ctx> { - type UpdateCallbackId = InventorySlotUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> InventorySlotUpdateCallbackId { - InventorySlotUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: InventorySlotUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `slot_id` unique index on the table `inventory_slot`, -/// which allows point queries on the field of the same name -/// via the [`InventorySlotSlotIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.inventory_slot().slot_id().find(...)`. -pub struct InventorySlotSlotIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> InventorySlotTableHandle<'ctx> { - /// Get a handle on the `slot_id` unique index on the table `inventory_slot`. - pub fn slot_id(&self) -> InventorySlotSlotIdUnique<'ctx> { - InventorySlotSlotIdUnique { - imp: self.imp.get_unique_constraint::("slot_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> InventorySlotSlotIdUnique<'ctx> { - /// Find the subscribed row whose `slot_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("inventory_slot"); - _table.add_unique_constraint::("slot_id", |row| &row.slot_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `InventorySlot`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait inventory_slotQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `InventorySlot`. - fn inventory_slot(&self) -> __sdk::__query_builder::Table; -} - -impl inventory_slotQueryTableAccess for __sdk::QueryTableAccessor { - fn inventory_slot(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("inventory_slot") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/inventory_slot_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/inventory_slot_type.rs deleted file mode 100644 index fcfbab6a8..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/inventory_slot_type.rs +++ /dev/null @@ -1,124 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::inventory_container_kind_type::InventoryContainerKind; -use super::inventory_equipment_slot_type::InventoryEquipmentSlot; -use super::inventory_item_rarity_type::InventoryItemRarity; -use super::inventory_item_source_kind_type::InventoryItemSourceKind; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct InventorySlot { - pub slot_id: String, - pub runtime_session_id: String, - pub story_session_id: Option, - pub actor_user_id: String, - pub container_kind: InventoryContainerKind, - pub slot_key: String, - pub item_id: String, - pub category: String, - pub name: String, - pub description: Option, - pub quantity: u32, - pub rarity: InventoryItemRarity, - pub tags: Vec, - pub stackable: bool, - pub stack_key: String, - pub equipment_slot_id: Option, - pub source_kind: InventoryItemSourceKind, - pub source_reference_id: Option, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for InventorySlot { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `InventorySlot`. -/// -/// Provides typed access to columns for query building. -pub struct InventorySlotCols { - pub slot_id: __sdk::__query_builder::Col, - pub runtime_session_id: __sdk::__query_builder::Col, - pub story_session_id: __sdk::__query_builder::Col>, - pub actor_user_id: __sdk::__query_builder::Col, - pub container_kind: __sdk::__query_builder::Col, - pub slot_key: __sdk::__query_builder::Col, - pub item_id: __sdk::__query_builder::Col, - pub category: __sdk::__query_builder::Col, - pub name: __sdk::__query_builder::Col, - pub description: __sdk::__query_builder::Col>, - pub quantity: __sdk::__query_builder::Col, - pub rarity: __sdk::__query_builder::Col, - pub tags: __sdk::__query_builder::Col>, - pub stackable: __sdk::__query_builder::Col, - pub stack_key: __sdk::__query_builder::Col, - pub equipment_slot_id: - __sdk::__query_builder::Col>, - pub source_kind: __sdk::__query_builder::Col, - pub source_reference_id: __sdk::__query_builder::Col>, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for InventorySlot { - type Cols = InventorySlotCols; - fn cols(table_name: &'static str) -> Self::Cols { - InventorySlotCols { - slot_id: __sdk::__query_builder::Col::new(table_name, "slot_id"), - runtime_session_id: __sdk::__query_builder::Col::new(table_name, "runtime_session_id"), - story_session_id: __sdk::__query_builder::Col::new(table_name, "story_session_id"), - actor_user_id: __sdk::__query_builder::Col::new(table_name, "actor_user_id"), - container_kind: __sdk::__query_builder::Col::new(table_name, "container_kind"), - slot_key: __sdk::__query_builder::Col::new(table_name, "slot_key"), - item_id: __sdk::__query_builder::Col::new(table_name, "item_id"), - category: __sdk::__query_builder::Col::new(table_name, "category"), - name: __sdk::__query_builder::Col::new(table_name, "name"), - description: __sdk::__query_builder::Col::new(table_name, "description"), - quantity: __sdk::__query_builder::Col::new(table_name, "quantity"), - rarity: __sdk::__query_builder::Col::new(table_name, "rarity"), - tags: __sdk::__query_builder::Col::new(table_name, "tags"), - stackable: __sdk::__query_builder::Col::new(table_name, "stackable"), - stack_key: __sdk::__query_builder::Col::new(table_name, "stack_key"), - equipment_slot_id: __sdk::__query_builder::Col::new(table_name, "equipment_slot_id"), - source_kind: __sdk::__query_builder::Col::new(table_name, "source_kind"), - source_reference_id: __sdk::__query_builder::Col::new( - table_name, - "source_reference_id", - ), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `InventorySlot`. -/// -/// Provides typed access to indexed columns for query building. -pub struct InventorySlotIxCols { - pub actor_user_id: __sdk::__query_builder::IxCol, - pub item_id: __sdk::__query_builder::IxCol, - pub runtime_session_id: __sdk::__query_builder::IxCol, - pub slot_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for InventorySlot { - type IxCols = InventorySlotIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - InventorySlotIxCols { - actor_user_id: __sdk::__query_builder::IxCol::new(table_name, "actor_user_id"), - item_id: __sdk::__query_builder::IxCol::new(table_name, "item_id"), - runtime_session_id: __sdk::__query_builder::IxCol::new( - table_name, - "runtime_session_id", - ), - slot_id: __sdk::__query_builder::IxCol::new(table_name, "slot_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for InventorySlot {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_agent_session_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_agent_session_row_type.rs deleted file mode 100644 index 9783325ff..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_agent_session_row_type.rs +++ /dev/null @@ -1,90 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct JumpHopAgentSessionRow { - pub session_id: String, - pub owner_user_id: String, - pub seed_text: String, - pub current_turn: u32, - pub progress_percent: u32, - pub stage: String, - pub config_json: String, - pub draft_json: String, - pub last_assistant_reply: String, - pub published_profile_id: String, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for JumpHopAgentSessionRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `JumpHopAgentSessionRow`. -/// -/// Provides typed access to columns for query building. -pub struct JumpHopAgentSessionRowCols { - pub session_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub seed_text: __sdk::__query_builder::Col, - pub current_turn: __sdk::__query_builder::Col, - pub progress_percent: __sdk::__query_builder::Col, - pub stage: __sdk::__query_builder::Col, - pub config_json: __sdk::__query_builder::Col, - pub draft_json: __sdk::__query_builder::Col, - pub last_assistant_reply: __sdk::__query_builder::Col, - pub published_profile_id: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for JumpHopAgentSessionRow { - type Cols = JumpHopAgentSessionRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - JumpHopAgentSessionRowCols { - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - seed_text: __sdk::__query_builder::Col::new(table_name, "seed_text"), - current_turn: __sdk::__query_builder::Col::new(table_name, "current_turn"), - progress_percent: __sdk::__query_builder::Col::new(table_name, "progress_percent"), - stage: __sdk::__query_builder::Col::new(table_name, "stage"), - config_json: __sdk::__query_builder::Col::new(table_name, "config_json"), - draft_json: __sdk::__query_builder::Col::new(table_name, "draft_json"), - last_assistant_reply: __sdk::__query_builder::Col::new( - table_name, - "last_assistant_reply", - ), - published_profile_id: __sdk::__query_builder::Col::new( - table_name, - "published_profile_id", - ), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `JumpHopAgentSessionRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct JumpHopAgentSessionRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for JumpHopAgentSessionRow { - type IxCols = JumpHopAgentSessionRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - JumpHopAgentSessionRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for JumpHopAgentSessionRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_agent_session_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_agent_session_table.rs deleted file mode 100644 index 62ca0e530..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_agent_session_table.rs +++ /dev/null @@ -1,230 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::jump_hop_agent_session_row_type::JumpHopAgentSessionRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `jump_hop_agent_session`. -/// -/// Obtain a handle from the [`JumpHopAgentSessionTableAccess::jump_hop_agent_session`] method on [`super::RemoteTables`], -/// like `ctx.db.jump_hop_agent_session()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.jump_hop_agent_session().on_insert(...)`. -pub struct JumpHopAgentSessionTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `jump_hop_agent_session`. -pub struct JumpHopAgentSessionTableAccessor; - -impl __sdk::TableAccessor for JumpHopAgentSessionTableAccessor { - type Row = JumpHopAgentSessionRow; - type Handle<'db> = JumpHopAgentSessionTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.jump_hop_agent_session() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `jump_hop_agent_session`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait JumpHopAgentSessionTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`JumpHopAgentSessionTableHandle`], which mediates access to the table `jump_hop_agent_session`. - fn jump_hop_agent_session(&self) -> JumpHopAgentSessionTableHandle<'_>; -} - -impl JumpHopAgentSessionTableAccess for super::RemoteTables { - fn jump_hop_agent_session(&self) -> JumpHopAgentSessionTableHandle<'_> { - JumpHopAgentSessionTableHandle { - imp: self - .imp - .get_table::("jump_hop_agent_session"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct JumpHopAgentSessionInsertCallbackId(__sdk::CallbackId); -pub struct JumpHopAgentSessionDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for JumpHopAgentSessionTableHandle<'ctx> { - type Row = JumpHopAgentSessionRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for JumpHopAgentSessionTableHandle<'ctx> { - type Row = JumpHopAgentSessionRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = JumpHopAgentSessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> JumpHopAgentSessionInsertCallbackId { - JumpHopAgentSessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: JumpHopAgentSessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = JumpHopAgentSessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> JumpHopAgentSessionDeleteCallbackId { - JumpHopAgentSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: JumpHopAgentSessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for JumpHopAgentSessionTableHandle<'ctx> { - type InsertCallbackId = JumpHopAgentSessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> JumpHopAgentSessionInsertCallbackId { - JumpHopAgentSessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: JumpHopAgentSessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for JumpHopAgentSessionTableHandle<'ctx> { - type DeleteCallbackId = JumpHopAgentSessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> JumpHopAgentSessionDeleteCallbackId { - JumpHopAgentSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: JumpHopAgentSessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct JumpHopAgentSessionUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for JumpHopAgentSessionTableHandle<'ctx> { - type UpdateCallbackId = JumpHopAgentSessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> JumpHopAgentSessionUpdateCallbackId { - JumpHopAgentSessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: JumpHopAgentSessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for JumpHopAgentSessionTableHandle<'ctx> { - type UpdateCallbackId = JumpHopAgentSessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> JumpHopAgentSessionUpdateCallbackId { - JumpHopAgentSessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: JumpHopAgentSessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `session_id` unique index on the table `jump_hop_agent_session`, -/// which allows point queries on the field of the same name -/// via the [`JumpHopAgentSessionSessionIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.jump_hop_agent_session().session_id().find(...)`. -pub struct JumpHopAgentSessionSessionIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> JumpHopAgentSessionTableHandle<'ctx> { - /// Get a handle on the `session_id` unique index on the table `jump_hop_agent_session`. - pub fn session_id(&self) -> JumpHopAgentSessionSessionIdUnique<'ctx> { - JumpHopAgentSessionSessionIdUnique { - imp: self.imp.get_unique_constraint::("session_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> JumpHopAgentSessionSessionIdUnique<'ctx> { - /// Find the subscribed row whose `session_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("jump_hop_agent_session"); - _table.add_unique_constraint::("session_id", |row| &row.session_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `JumpHopAgentSessionRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait jump_hop_agent_sessionQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `JumpHopAgentSessionRow`. - fn jump_hop_agent_session(&self) -> __sdk::__query_builder::Table; -} - -impl jump_hop_agent_sessionQueryTableAccess for __sdk::QueryTableAccessor { - fn jump_hop_agent_session(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("jump_hop_agent_session") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_event_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_event_row_type.rs deleted file mode 100644 index 6e0fe7e2d..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_event_row_type.rs +++ /dev/null @@ -1,71 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct JumpHopEventRow { - pub event_id: String, - pub owner_user_id: String, - pub profile_id: String, - pub run_id: String, - pub event_type: String, - pub result: String, - pub occurred_at: __sdk::Timestamp, -} - -impl __sdk::InModule for JumpHopEventRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `JumpHopEventRow`. -/// -/// Provides typed access to columns for query building. -pub struct JumpHopEventRowCols { - pub event_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub profile_id: __sdk::__query_builder::Col, - pub run_id: __sdk::__query_builder::Col, - pub event_type: __sdk::__query_builder::Col, - pub result: __sdk::__query_builder::Col, - pub occurred_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for JumpHopEventRow { - type Cols = JumpHopEventRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - JumpHopEventRowCols { - event_id: __sdk::__query_builder::Col::new(table_name, "event_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - run_id: __sdk::__query_builder::Col::new(table_name, "run_id"), - event_type: __sdk::__query_builder::Col::new(table_name, "event_type"), - result: __sdk::__query_builder::Col::new(table_name, "result"), - occurred_at: __sdk::__query_builder::Col::new(table_name, "occurred_at"), - } - } -} - -/// Indexed column accessor struct for the table `JumpHopEventRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct JumpHopEventRowIxCols { - pub event_id: __sdk::__query_builder::IxCol, - pub profile_id: __sdk::__query_builder::IxCol, - pub run_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for JumpHopEventRow { - type IxCols = JumpHopEventRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - JumpHopEventRowIxCols { - event_id: __sdk::__query_builder::IxCol::new(table_name, "event_id"), - profile_id: __sdk::__query_builder::IxCol::new(table_name, "profile_id"), - run_id: __sdk::__query_builder::IxCol::new(table_name, "run_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for JumpHopEventRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_event_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_event_table.rs deleted file mode 100644 index 5690cfc9a..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_event_table.rs +++ /dev/null @@ -1,228 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::jump_hop_event_row_type::JumpHopEventRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `jump_hop_event`. -/// -/// Obtain a handle from the [`JumpHopEventTableAccess::jump_hop_event`] method on [`super::RemoteTables`], -/// like `ctx.db.jump_hop_event()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.jump_hop_event().on_insert(...)`. -pub struct JumpHopEventTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `jump_hop_event`. -pub struct JumpHopEventTableAccessor; - -impl __sdk::TableAccessor for JumpHopEventTableAccessor { - type Row = JumpHopEventRow; - type Handle<'db> = JumpHopEventTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.jump_hop_event() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `jump_hop_event`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait JumpHopEventTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`JumpHopEventTableHandle`], which mediates access to the table `jump_hop_event`. - fn jump_hop_event(&self) -> JumpHopEventTableHandle<'_>; -} - -impl JumpHopEventTableAccess for super::RemoteTables { - fn jump_hop_event(&self) -> JumpHopEventTableHandle<'_> { - JumpHopEventTableHandle { - imp: self.imp.get_table::("jump_hop_event"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct JumpHopEventInsertCallbackId(__sdk::CallbackId); -pub struct JumpHopEventDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for JumpHopEventTableHandle<'ctx> { - type Row = JumpHopEventRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for JumpHopEventTableHandle<'ctx> { - type Row = JumpHopEventRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = JumpHopEventInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> JumpHopEventInsertCallbackId { - JumpHopEventInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: JumpHopEventInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = JumpHopEventDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> JumpHopEventDeleteCallbackId { - JumpHopEventDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: JumpHopEventDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for JumpHopEventTableHandle<'ctx> { - type InsertCallbackId = JumpHopEventInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> JumpHopEventInsertCallbackId { - JumpHopEventInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: JumpHopEventInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for JumpHopEventTableHandle<'ctx> { - type DeleteCallbackId = JumpHopEventDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> JumpHopEventDeleteCallbackId { - JumpHopEventDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: JumpHopEventDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct JumpHopEventUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for JumpHopEventTableHandle<'ctx> { - type UpdateCallbackId = JumpHopEventUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> JumpHopEventUpdateCallbackId { - JumpHopEventUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: JumpHopEventUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for JumpHopEventTableHandle<'ctx> { - type UpdateCallbackId = JumpHopEventUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> JumpHopEventUpdateCallbackId { - JumpHopEventUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: JumpHopEventUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `event_id` unique index on the table `jump_hop_event`, -/// which allows point queries on the field of the same name -/// via the [`JumpHopEventEventIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.jump_hop_event().event_id().find(...)`. -pub struct JumpHopEventEventIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> JumpHopEventTableHandle<'ctx> { - /// Get a handle on the `event_id` unique index on the table `jump_hop_event`. - pub fn event_id(&self) -> JumpHopEventEventIdUnique<'ctx> { - JumpHopEventEventIdUnique { - imp: self.imp.get_unique_constraint::("event_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> JumpHopEventEventIdUnique<'ctx> { - /// Find the subscribed row whose `event_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("jump_hop_event"); - _table.add_unique_constraint::("event_id", |row| &row.event_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `JumpHopEventRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait jump_hop_eventQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `JumpHopEventRow`. - fn jump_hop_event(&self) -> __sdk::__query_builder::Table; -} - -impl jump_hop_eventQueryTableAccess for __sdk::QueryTableAccessor { - fn jump_hop_event(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("jump_hop_event") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_leaderboard_entry_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_leaderboard_entry_row_type.rs deleted file mode 100644 index 369cbcce7..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_leaderboard_entry_row_type.rs +++ /dev/null @@ -1,72 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct JumpHopLeaderboardEntryRow { - pub entry_id: String, - pub profile_id: String, - pub player_id: String, - pub successful_jump_count: u32, - pub duration_ms: u64, - pub run_id: String, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for JumpHopLeaderboardEntryRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `JumpHopLeaderboardEntryRow`. -/// -/// Provides typed access to columns for query building. -pub struct JumpHopLeaderboardEntryRowCols { - pub entry_id: __sdk::__query_builder::Col, - pub profile_id: __sdk::__query_builder::Col, - pub player_id: __sdk::__query_builder::Col, - pub successful_jump_count: __sdk::__query_builder::Col, - pub duration_ms: __sdk::__query_builder::Col, - pub run_id: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for JumpHopLeaderboardEntryRow { - type Cols = JumpHopLeaderboardEntryRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - JumpHopLeaderboardEntryRowCols { - entry_id: __sdk::__query_builder::Col::new(table_name, "entry_id"), - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - player_id: __sdk::__query_builder::Col::new(table_name, "player_id"), - successful_jump_count: __sdk::__query_builder::Col::new( - table_name, - "successful_jump_count", - ), - duration_ms: __sdk::__query_builder::Col::new(table_name, "duration_ms"), - run_id: __sdk::__query_builder::Col::new(table_name, "run_id"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `JumpHopLeaderboardEntryRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct JumpHopLeaderboardEntryRowIxCols { - pub entry_id: __sdk::__query_builder::IxCol, - pub profile_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for JumpHopLeaderboardEntryRow { - type IxCols = JumpHopLeaderboardEntryRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - JumpHopLeaderboardEntryRowIxCols { - entry_id: __sdk::__query_builder::IxCol::new(table_name, "entry_id"), - profile_id: __sdk::__query_builder::IxCol::new(table_name, "profile_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for JumpHopLeaderboardEntryRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_leaderboard_entry_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_leaderboard_entry_table.rs deleted file mode 100644 index 960cb02a2..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_leaderboard_entry_table.rs +++ /dev/null @@ -1,235 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::jump_hop_leaderboard_entry_row_type::JumpHopLeaderboardEntryRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `jump_hop_leaderboard_entry`. -/// -/// Obtain a handle from the [`JumpHopLeaderboardEntryTableAccess::jump_hop_leaderboard_entry`] method on [`super::RemoteTables`], -/// like `ctx.db.jump_hop_leaderboard_entry()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.jump_hop_leaderboard_entry().on_insert(...)`. -pub struct JumpHopLeaderboardEntryTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `jump_hop_leaderboard_entry`. -pub struct JumpHopLeaderboardEntryTableAccessor; - -impl __sdk::TableAccessor for JumpHopLeaderboardEntryTableAccessor { - type Row = JumpHopLeaderboardEntryRow; - type Handle<'db> = JumpHopLeaderboardEntryTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.jump_hop_leaderboard_entry() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `jump_hop_leaderboard_entry`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait JumpHopLeaderboardEntryTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`JumpHopLeaderboardEntryTableHandle`], which mediates access to the table `jump_hop_leaderboard_entry`. - fn jump_hop_leaderboard_entry(&self) -> JumpHopLeaderboardEntryTableHandle<'_>; -} - -impl JumpHopLeaderboardEntryTableAccess for super::RemoteTables { - fn jump_hop_leaderboard_entry(&self) -> JumpHopLeaderboardEntryTableHandle<'_> { - JumpHopLeaderboardEntryTableHandle { - imp: self - .imp - .get_table::("jump_hop_leaderboard_entry"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct JumpHopLeaderboardEntryInsertCallbackId(__sdk::CallbackId); -pub struct JumpHopLeaderboardEntryDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for JumpHopLeaderboardEntryTableHandle<'ctx> { - type Row = JumpHopLeaderboardEntryRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for JumpHopLeaderboardEntryTableHandle<'ctx> { - type Row = JumpHopLeaderboardEntryRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = JumpHopLeaderboardEntryInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> JumpHopLeaderboardEntryInsertCallbackId { - JumpHopLeaderboardEntryInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: JumpHopLeaderboardEntryInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = JumpHopLeaderboardEntryDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> JumpHopLeaderboardEntryDeleteCallbackId { - JumpHopLeaderboardEntryDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: JumpHopLeaderboardEntryDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for JumpHopLeaderboardEntryTableHandle<'ctx> { - type InsertCallbackId = JumpHopLeaderboardEntryInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> JumpHopLeaderboardEntryInsertCallbackId { - JumpHopLeaderboardEntryInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: JumpHopLeaderboardEntryInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for JumpHopLeaderboardEntryTableHandle<'ctx> { - type DeleteCallbackId = JumpHopLeaderboardEntryDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> JumpHopLeaderboardEntryDeleteCallbackId { - JumpHopLeaderboardEntryDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: JumpHopLeaderboardEntryDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct JumpHopLeaderboardEntryUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for JumpHopLeaderboardEntryTableHandle<'ctx> { - type UpdateCallbackId = JumpHopLeaderboardEntryUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> JumpHopLeaderboardEntryUpdateCallbackId { - JumpHopLeaderboardEntryUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: JumpHopLeaderboardEntryUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for JumpHopLeaderboardEntryTableHandle<'ctx> { - type UpdateCallbackId = JumpHopLeaderboardEntryUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> JumpHopLeaderboardEntryUpdateCallbackId { - JumpHopLeaderboardEntryUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: JumpHopLeaderboardEntryUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `entry_id` unique index on the table `jump_hop_leaderboard_entry`, -/// which allows point queries on the field of the same name -/// via the [`JumpHopLeaderboardEntryEntryIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.jump_hop_leaderboard_entry().entry_id().find(...)`. -pub struct JumpHopLeaderboardEntryEntryIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> JumpHopLeaderboardEntryTableHandle<'ctx> { - /// Get a handle on the `entry_id` unique index on the table `jump_hop_leaderboard_entry`. - pub fn entry_id(&self) -> JumpHopLeaderboardEntryEntryIdUnique<'ctx> { - JumpHopLeaderboardEntryEntryIdUnique { - imp: self.imp.get_unique_constraint::("entry_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> JumpHopLeaderboardEntryEntryIdUnique<'ctx> { - /// Find the subscribed row whose `entry_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("jump_hop_leaderboard_entry"); - _table.add_unique_constraint::("entry_id", |row| &row.entry_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `JumpHopLeaderboardEntryRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait jump_hop_leaderboard_entryQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `JumpHopLeaderboardEntryRow`. - fn jump_hop_leaderboard_entry( - &self, - ) -> __sdk::__query_builder::Table; -} - -impl jump_hop_leaderboard_entryQueryTableAccess for __sdk::QueryTableAccessor { - fn jump_hop_leaderboard_entry( - &self, - ) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("jump_hop_leaderboard_entry") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_runtime_run_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_runtime_run_row_type.rs deleted file mode 100644 index 1a78cae3d..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_runtime_run_row_type.rs +++ /dev/null @@ -1,92 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct JumpHopRuntimeRunRow { - pub run_id: String, - pub owner_user_id: String, - pub profile_id: String, - pub status: String, - pub started_at_ms: i64, - pub finished_at_ms: i64, - pub current_platform_index: u32, - pub score: u32, - pub combo: u32, - pub snapshot_json: String, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, - pub runtime_mode: Option, -} - -impl __sdk::InModule for JumpHopRuntimeRunRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `JumpHopRuntimeRunRow`. -/// -/// Provides typed access to columns for query building. -pub struct JumpHopRuntimeRunRowCols { - pub run_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub profile_id: __sdk::__query_builder::Col, - pub status: __sdk::__query_builder::Col, - pub started_at_ms: __sdk::__query_builder::Col, - pub finished_at_ms: __sdk::__query_builder::Col, - pub current_platform_index: __sdk::__query_builder::Col, - pub score: __sdk::__query_builder::Col, - pub combo: __sdk::__query_builder::Col, - pub snapshot_json: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, - pub runtime_mode: __sdk::__query_builder::Col>, -} - -impl __sdk::__query_builder::HasCols for JumpHopRuntimeRunRow { - type Cols = JumpHopRuntimeRunRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - JumpHopRuntimeRunRowCols { - run_id: __sdk::__query_builder::Col::new(table_name, "run_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - status: __sdk::__query_builder::Col::new(table_name, "status"), - started_at_ms: __sdk::__query_builder::Col::new(table_name, "started_at_ms"), - finished_at_ms: __sdk::__query_builder::Col::new(table_name, "finished_at_ms"), - current_platform_index: __sdk::__query_builder::Col::new( - table_name, - "current_platform_index", - ), - score: __sdk::__query_builder::Col::new(table_name, "score"), - combo: __sdk::__query_builder::Col::new(table_name, "combo"), - snapshot_json: __sdk::__query_builder::Col::new(table_name, "snapshot_json"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - runtime_mode: __sdk::__query_builder::Col::new(table_name, "runtime_mode"), - } - } -} - -/// Indexed column accessor struct for the table `JumpHopRuntimeRunRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct JumpHopRuntimeRunRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub profile_id: __sdk::__query_builder::IxCol, - pub run_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for JumpHopRuntimeRunRow { - type IxCols = JumpHopRuntimeRunRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - JumpHopRuntimeRunRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::IxCol::new(table_name, "profile_id"), - run_id: __sdk::__query_builder::IxCol::new(table_name, "run_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for JumpHopRuntimeRunRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_runtime_run_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_runtime_run_table.rs deleted file mode 100644 index 64e23a7ee..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_runtime_run_table.rs +++ /dev/null @@ -1,230 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::jump_hop_runtime_run_row_type::JumpHopRuntimeRunRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `jump_hop_runtime_run`. -/// -/// Obtain a handle from the [`JumpHopRuntimeRunTableAccess::jump_hop_runtime_run`] method on [`super::RemoteTables`], -/// like `ctx.db.jump_hop_runtime_run()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.jump_hop_runtime_run().on_insert(...)`. -pub struct JumpHopRuntimeRunTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `jump_hop_runtime_run`. -pub struct JumpHopRuntimeRunTableAccessor; - -impl __sdk::TableAccessor for JumpHopRuntimeRunTableAccessor { - type Row = JumpHopRuntimeRunRow; - type Handle<'db> = JumpHopRuntimeRunTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.jump_hop_runtime_run() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `jump_hop_runtime_run`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait JumpHopRuntimeRunTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`JumpHopRuntimeRunTableHandle`], which mediates access to the table `jump_hop_runtime_run`. - fn jump_hop_runtime_run(&self) -> JumpHopRuntimeRunTableHandle<'_>; -} - -impl JumpHopRuntimeRunTableAccess for super::RemoteTables { - fn jump_hop_runtime_run(&self) -> JumpHopRuntimeRunTableHandle<'_> { - JumpHopRuntimeRunTableHandle { - imp: self - .imp - .get_table::("jump_hop_runtime_run"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct JumpHopRuntimeRunInsertCallbackId(__sdk::CallbackId); -pub struct JumpHopRuntimeRunDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for JumpHopRuntimeRunTableHandle<'ctx> { - type Row = JumpHopRuntimeRunRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for JumpHopRuntimeRunTableHandle<'ctx> { - type Row = JumpHopRuntimeRunRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = JumpHopRuntimeRunInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> JumpHopRuntimeRunInsertCallbackId { - JumpHopRuntimeRunInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: JumpHopRuntimeRunInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = JumpHopRuntimeRunDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> JumpHopRuntimeRunDeleteCallbackId { - JumpHopRuntimeRunDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: JumpHopRuntimeRunDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for JumpHopRuntimeRunTableHandle<'ctx> { - type InsertCallbackId = JumpHopRuntimeRunInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> JumpHopRuntimeRunInsertCallbackId { - JumpHopRuntimeRunInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: JumpHopRuntimeRunInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for JumpHopRuntimeRunTableHandle<'ctx> { - type DeleteCallbackId = JumpHopRuntimeRunDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> JumpHopRuntimeRunDeleteCallbackId { - JumpHopRuntimeRunDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: JumpHopRuntimeRunDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct JumpHopRuntimeRunUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for JumpHopRuntimeRunTableHandle<'ctx> { - type UpdateCallbackId = JumpHopRuntimeRunUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> JumpHopRuntimeRunUpdateCallbackId { - JumpHopRuntimeRunUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: JumpHopRuntimeRunUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for JumpHopRuntimeRunTableHandle<'ctx> { - type UpdateCallbackId = JumpHopRuntimeRunUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> JumpHopRuntimeRunUpdateCallbackId { - JumpHopRuntimeRunUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: JumpHopRuntimeRunUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `run_id` unique index on the table `jump_hop_runtime_run`, -/// which allows point queries on the field of the same name -/// via the [`JumpHopRuntimeRunRunIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.jump_hop_runtime_run().run_id().find(...)`. -pub struct JumpHopRuntimeRunRunIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> JumpHopRuntimeRunTableHandle<'ctx> { - /// Get a handle on the `run_id` unique index on the table `jump_hop_runtime_run`. - pub fn run_id(&self) -> JumpHopRuntimeRunRunIdUnique<'ctx> { - JumpHopRuntimeRunRunIdUnique { - imp: self.imp.get_unique_constraint::("run_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> JumpHopRuntimeRunRunIdUnique<'ctx> { - /// Find the subscribed row whose `run_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("jump_hop_runtime_run"); - _table.add_unique_constraint::("run_id", |row| &row.run_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `JumpHopRuntimeRunRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait jump_hop_runtime_runQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `JumpHopRuntimeRunRow`. - fn jump_hop_runtime_run(&self) -> __sdk::__query_builder::Table; -} - -impl jump_hop_runtime_runQueryTableAccess for __sdk::QueryTableAccessor { - fn jump_hop_runtime_run(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("jump_hop_runtime_run") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_work_profile_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_work_profile_row_type.rs deleted file mode 100644 index 3a8b9e689..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_work_profile_row_type.rs +++ /dev/null @@ -1,146 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct JumpHopWorkProfileRow { - pub profile_id: String, - pub work_id: String, - pub owner_user_id: String, - pub source_session_id: String, - pub author_display_name: String, - pub work_title: String, - pub work_description: String, - pub theme_tags_json: String, - pub difficulty: String, - pub style_preset: String, - pub character_prompt: String, - pub tile_prompt: String, - pub end_mood_prompt: String, - pub character_asset_json: String, - pub tile_atlas_asset_json: String, - pub tile_assets_json: String, - pub path_json: String, - pub cover_image_src: String, - pub cover_composite: String, - pub generation_status: String, - pub publication_status: String, - pub play_count: u32, - pub updated_at: __sdk::Timestamp, - pub published_at: Option<__sdk::Timestamp>, - pub visible: bool, - pub theme_text: Option, - pub back_button_asset_json: Option, -} - -impl __sdk::InModule for JumpHopWorkProfileRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `JumpHopWorkProfileRow`. -/// -/// Provides typed access to columns for query building. -pub struct JumpHopWorkProfileRowCols { - pub profile_id: __sdk::__query_builder::Col, - pub work_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub source_session_id: __sdk::__query_builder::Col, - pub author_display_name: __sdk::__query_builder::Col, - pub work_title: __sdk::__query_builder::Col, - pub work_description: __sdk::__query_builder::Col, - pub theme_tags_json: __sdk::__query_builder::Col, - pub difficulty: __sdk::__query_builder::Col, - pub style_preset: __sdk::__query_builder::Col, - pub character_prompt: __sdk::__query_builder::Col, - pub tile_prompt: __sdk::__query_builder::Col, - pub end_mood_prompt: __sdk::__query_builder::Col, - pub character_asset_json: __sdk::__query_builder::Col, - pub tile_atlas_asset_json: __sdk::__query_builder::Col, - pub tile_assets_json: __sdk::__query_builder::Col, - pub path_json: __sdk::__query_builder::Col, - pub cover_image_src: __sdk::__query_builder::Col, - pub cover_composite: __sdk::__query_builder::Col, - pub generation_status: __sdk::__query_builder::Col, - pub publication_status: __sdk::__query_builder::Col, - pub play_count: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, - pub published_at: __sdk::__query_builder::Col>, - pub visible: __sdk::__query_builder::Col, - pub theme_text: __sdk::__query_builder::Col>, - pub back_button_asset_json: __sdk::__query_builder::Col>, -} - -impl __sdk::__query_builder::HasCols for JumpHopWorkProfileRow { - type Cols = JumpHopWorkProfileRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - JumpHopWorkProfileRowCols { - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - work_id: __sdk::__query_builder::Col::new(table_name, "work_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - source_session_id: __sdk::__query_builder::Col::new(table_name, "source_session_id"), - author_display_name: __sdk::__query_builder::Col::new( - table_name, - "author_display_name", - ), - work_title: __sdk::__query_builder::Col::new(table_name, "work_title"), - work_description: __sdk::__query_builder::Col::new(table_name, "work_description"), - theme_tags_json: __sdk::__query_builder::Col::new(table_name, "theme_tags_json"), - difficulty: __sdk::__query_builder::Col::new(table_name, "difficulty"), - style_preset: __sdk::__query_builder::Col::new(table_name, "style_preset"), - character_prompt: __sdk::__query_builder::Col::new(table_name, "character_prompt"), - tile_prompt: __sdk::__query_builder::Col::new(table_name, "tile_prompt"), - end_mood_prompt: __sdk::__query_builder::Col::new(table_name, "end_mood_prompt"), - character_asset_json: __sdk::__query_builder::Col::new( - table_name, - "character_asset_json", - ), - tile_atlas_asset_json: __sdk::__query_builder::Col::new( - table_name, - "tile_atlas_asset_json", - ), - tile_assets_json: __sdk::__query_builder::Col::new(table_name, "tile_assets_json"), - path_json: __sdk::__query_builder::Col::new(table_name, "path_json"), - cover_image_src: __sdk::__query_builder::Col::new(table_name, "cover_image_src"), - cover_composite: __sdk::__query_builder::Col::new(table_name, "cover_composite"), - generation_status: __sdk::__query_builder::Col::new(table_name, "generation_status"), - publication_status: __sdk::__query_builder::Col::new(table_name, "publication_status"), - play_count: __sdk::__query_builder::Col::new(table_name, "play_count"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - published_at: __sdk::__query_builder::Col::new(table_name, "published_at"), - visible: __sdk::__query_builder::Col::new(table_name, "visible"), - theme_text: __sdk::__query_builder::Col::new(table_name, "theme_text"), - back_button_asset_json: __sdk::__query_builder::Col::new( - table_name, - "back_button_asset_json", - ), - } - } -} - -/// Indexed column accessor struct for the table `JumpHopWorkProfileRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct JumpHopWorkProfileRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub profile_id: __sdk::__query_builder::IxCol, - pub publication_status: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for JumpHopWorkProfileRow { - type IxCols = JumpHopWorkProfileRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - JumpHopWorkProfileRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::IxCol::new(table_name, "profile_id"), - publication_status: __sdk::__query_builder::IxCol::new( - table_name, - "publication_status", - ), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for JumpHopWorkProfileRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_work_profile_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_work_profile_table.rs deleted file mode 100644 index aca645f75..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_work_profile_table.rs +++ /dev/null @@ -1,230 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::jump_hop_work_profile_row_type::JumpHopWorkProfileRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `jump_hop_work_profile`. -/// -/// Obtain a handle from the [`JumpHopWorkProfileTableAccess::jump_hop_work_profile`] method on [`super::RemoteTables`], -/// like `ctx.db.jump_hop_work_profile()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.jump_hop_work_profile().on_insert(...)`. -pub struct JumpHopWorkProfileTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `jump_hop_work_profile`. -pub struct JumpHopWorkProfileTableAccessor; - -impl __sdk::TableAccessor for JumpHopWorkProfileTableAccessor { - type Row = JumpHopWorkProfileRow; - type Handle<'db> = JumpHopWorkProfileTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.jump_hop_work_profile() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `jump_hop_work_profile`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait JumpHopWorkProfileTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`JumpHopWorkProfileTableHandle`], which mediates access to the table `jump_hop_work_profile`. - fn jump_hop_work_profile(&self) -> JumpHopWorkProfileTableHandle<'_>; -} - -impl JumpHopWorkProfileTableAccess for super::RemoteTables { - fn jump_hop_work_profile(&self) -> JumpHopWorkProfileTableHandle<'_> { - JumpHopWorkProfileTableHandle { - imp: self - .imp - .get_table::("jump_hop_work_profile"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct JumpHopWorkProfileInsertCallbackId(__sdk::CallbackId); -pub struct JumpHopWorkProfileDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for JumpHopWorkProfileTableHandle<'ctx> { - type Row = JumpHopWorkProfileRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for JumpHopWorkProfileTableHandle<'ctx> { - type Row = JumpHopWorkProfileRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = JumpHopWorkProfileInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> JumpHopWorkProfileInsertCallbackId { - JumpHopWorkProfileInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: JumpHopWorkProfileInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = JumpHopWorkProfileDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> JumpHopWorkProfileDeleteCallbackId { - JumpHopWorkProfileDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: JumpHopWorkProfileDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for JumpHopWorkProfileTableHandle<'ctx> { - type InsertCallbackId = JumpHopWorkProfileInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> JumpHopWorkProfileInsertCallbackId { - JumpHopWorkProfileInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: JumpHopWorkProfileInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for JumpHopWorkProfileTableHandle<'ctx> { - type DeleteCallbackId = JumpHopWorkProfileDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> JumpHopWorkProfileDeleteCallbackId { - JumpHopWorkProfileDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: JumpHopWorkProfileDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct JumpHopWorkProfileUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for JumpHopWorkProfileTableHandle<'ctx> { - type UpdateCallbackId = JumpHopWorkProfileUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> JumpHopWorkProfileUpdateCallbackId { - JumpHopWorkProfileUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: JumpHopWorkProfileUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for JumpHopWorkProfileTableHandle<'ctx> { - type UpdateCallbackId = JumpHopWorkProfileUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> JumpHopWorkProfileUpdateCallbackId { - JumpHopWorkProfileUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: JumpHopWorkProfileUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `profile_id` unique index on the table `jump_hop_work_profile`, -/// which allows point queries on the field of the same name -/// via the [`JumpHopWorkProfileProfileIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.jump_hop_work_profile().profile_id().find(...)`. -pub struct JumpHopWorkProfileProfileIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> JumpHopWorkProfileTableHandle<'ctx> { - /// Get a handle on the `profile_id` unique index on the table `jump_hop_work_profile`. - pub fn profile_id(&self) -> JumpHopWorkProfileProfileIdUnique<'ctx> { - JumpHopWorkProfileProfileIdUnique { - imp: self.imp.get_unique_constraint::("profile_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> JumpHopWorkProfileProfileIdUnique<'ctx> { - /// Find the subscribed row whose `profile_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("jump_hop_work_profile"); - _table.add_unique_constraint::("profile_id", |row| &row.profile_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `JumpHopWorkProfileRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait jump_hop_work_profileQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `JumpHopWorkProfileRow`. - fn jump_hop_work_profile(&self) -> __sdk::__query_builder::Table; -} - -impl jump_hop_work_profileQueryTableAccess for __sdk::QueryTableAccessor { - fn jump_hop_work_profile(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("jump_hop_work_profile") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_admin_accounts_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_admin_accounts_and_return_procedure.rs index 8258f63a2..0594f17b3 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_admin_accounts_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_admin_accounts_and_return_procedure.rs @@ -27,10 +27,10 @@ pub trait list_admin_accounts_and_return { &self, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -39,10 +39,10 @@ impl list_admin_accounts_and_return for super::RemoteProcedures { &self, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AdminAccountProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_agc_tracking_events_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_agc_tracking_events_procedure.rs new file mode 100644 index 000000000..6244fd337 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_agc_tracking_events_procedure.rs @@ -0,0 +1,56 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +struct ListAgcTrackingEventsArgs { + pub query_json: String, +} + +impl __sdk::InModule for ListAgcTrackingEventsArgs { + type Module = super::RemoteModule; +} + +#[allow(non_camel_case_types)] +/// Extension trait for access to the procedure `list_agc_tracking_events`. +/// +/// Implemented for [`super::RemoteProcedures`]. +pub trait list_agc_tracking_events { + fn list_agc_tracking_events(&self, query_json: String) { + self.list_agc_tracking_events_then(query_json, |_, _| {}); + } + + fn list_agc_tracking_events_then( + &self, + query_json: String, + + __callback: impl FnOnce( + &super::ProcedureEventContext, + Result, __sdk::InternalError>, + ) + Send + + 'static, + ); +} + +impl list_agc_tracking_events for super::RemoteProcedures { + fn list_agc_tracking_events_then( + &self, + query_json: String, + + __callback: impl FnOnce( + &super::ProcedureEventContext, + Result, __sdk::InternalError>, + ) + Send + + 'static, + ) { + self.imp + .invoke_procedure_with_callback::<_, Result>( + "list_agc_tracking_events", + ListAgcTrackingEventsArgs { query_json }, + __callback, + ); + } +} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_asset_history_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_asset_history_and_return_procedure.rs index ea689b101..bcc2a742c 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_asset_history_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_asset_history_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait list_asset_history_and_return { input: AssetHistoryListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl list_asset_history_and_return for super::RemoteProcedures { input: AssetHistoryListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AssetHistoryListResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_editor_agent_conversations_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_editor_agent_conversations_and_return_procedure.rs index b1f34b959..148f968cf 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_editor_agent_conversations_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_editor_agent_conversations_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait list_editor_agent_conversations_and_return { input: EditorAgentConversationListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl list_editor_agent_conversations_and_return for super::RemoteProcedures { input: EditorAgentConversationListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorAgentConversationListProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_editor_projects_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_editor_projects_and_return_procedure.rs index c0181cff2..fca9595d0 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_editor_projects_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_editor_projects_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait list_editor_projects_and_return { input: EditorProjectListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl list_editor_projects_and_return for super::RemoteProcedures { input: EditorProjectListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorProjectListProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_external_api_keys_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_external_api_keys_and_return_procedure.rs index d0ab651fb..ca827a562 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_external_api_keys_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_external_api_keys_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait list_external_api_keys_and_return { input: ExternalApiKeyListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl list_external_api_keys_and_return for super::RemoteProcedures { input: ExternalApiKeyListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ExternalApiKeyProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_external_generation_job_summaries_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_external_generation_job_summaries_and_return_procedure.rs index e6aa64d34..47e617b0d 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_external_generation_job_summaries_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_external_generation_job_summaries_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait list_external_generation_job_summaries_and_return { input: ExternalGenerationJobListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl list_external_generation_job_summaries_and_return for super::RemoteProcedur input: ExternalGenerationJobListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ExternalGenerationJobSummaryProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_external_generation_jobs_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_external_generation_jobs_and_return_procedure.rs index 5164ba9c7..05f3b53ef 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_external_generation_jobs_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_external_generation_jobs_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait list_external_generation_jobs_and_return { input: ExternalGenerationJobListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl list_external_generation_jobs_and_return for super::RemoteProcedures { input: ExternalGenerationJobListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ExternalGenerationJobProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_profile_recharge_refund_holds_for_reconciliation_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_profile_recharge_refund_holds_for_reconciliation_procedure.rs index c8d5ee7e8..6bcdf41c3 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_profile_recharge_refund_holds_for_reconciliation_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_profile_recharge_refund_holds_for_reconciliation_procedure.rs @@ -34,10 +34,10 @@ pub trait list_profile_recharge_refund_holds_for_reconciliation { input: RuntimeProfileRechargeRefundHoldListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl list_profile_recharge_refund_holds_for_reconciliation for super::RemoteProc input: RuntimeProfileRechargeRefundHoldListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp.invoke_procedure_with_callback::<_, RuntimeProfileRechargeRefundHoldListProcedureResult>( "list_profile_recharge_refund_holds_for_reconciliation", diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_profile_recharge_refunds_for_reconciliation_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_profile_recharge_refunds_for_reconciliation_procedure.rs index 9d089bdc8..0a77320bf 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_profile_recharge_refunds_for_reconciliation_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_profile_recharge_refunds_for_reconciliation_procedure.rs @@ -34,10 +34,10 @@ pub trait list_profile_recharge_refunds_for_reconciliation { input: RuntimeProfileRechargeRefundReconciliationListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl list_profile_recharge_refunds_for_reconciliation for super::RemoteProcedure input: RuntimeProfileRechargeRefundReconciliationListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRechargeRefundListProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_profile_wallet_ledger_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_profile_wallet_ledger_procedure.rs index d51f0df2d..23496701a 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_profile_wallet_ledger_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_profile_wallet_ledger_procedure.rs @@ -31,10 +31,10 @@ pub trait list_profile_wallet_ledger { input: RuntimeProfileWalletLedgerListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl list_profile_wallet_ledger for super::RemoteProcedures { input: RuntimeProfileWalletLedgerListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileWalletLedgerProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_public_editor_project_resources_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_public_editor_project_resources_and_return_procedure.rs index b594fe7ff..70b2895cf 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_public_editor_project_resources_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_public_editor_project_resources_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait list_public_editor_project_resources_and_return { input: EditorProjectResourcePublicShowcaseListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl list_public_editor_project_resources_and_return for super::RemoteProcedures input: EditorProjectResourcePublicShowcaseListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorProjectResourceListProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_public_editor_showcase_assets_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_public_editor_showcase_assets_and_return_procedure.rs index b6b5ad8b8..9e357db4f 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_public_editor_showcase_assets_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_public_editor_showcase_assets_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait list_public_editor_showcase_assets_and_return { input: EditorShowcaseAssetPublicListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl list_public_editor_showcase_assets_and_return for super::RemoteProcedures { input: EditorShowcaseAssetPublicListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorShowcaseAssetListProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_public_editor_showcase_assets_for_viewer_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_public_editor_showcase_assets_for_viewer_and_return_procedure.rs index 816054c2c..f89fc1ca9 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_public_editor_showcase_assets_for_viewer_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_public_editor_showcase_assets_for_viewer_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait list_public_editor_showcase_assets_for_viewer_and_return { input: EditorShowcaseAssetViewerListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl list_public_editor_showcase_assets_for_viewer_and_return for super::RemoteP input: EditorShowcaseAssetViewerListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorShowcaseAssetViewerListProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_unchecked_expired_profile_recharge_orders_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_unchecked_expired_profile_recharge_orders_procedure.rs index e930565c3..500ca0cf2 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_unchecked_expired_profile_recharge_orders_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_unchecked_expired_profile_recharge_orders_procedure.rs @@ -34,13 +34,13 @@ pub trait list_unchecked_expired_profile_recharge_orders { input: RuntimeProfileRechargeOrderExpirationCheckListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result< - RuntimeProfileRechargeOrderExpirationCheckListProcedureResult, - __sdk::InternalError, - >, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result< + RuntimeProfileRechargeOrderExpirationCheckListProcedureResult, + __sdk::InternalError, + >, + ) + Send + + 'static, ); } @@ -50,13 +50,13 @@ impl list_unchecked_expired_profile_recharge_orders for super::RemoteProcedures input: RuntimeProfileRechargeOrderExpirationCheckListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result< - RuntimeProfileRechargeOrderExpirationCheckListProcedureResult, - __sdk::InternalError, - >, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result< + RuntimeProfileRechargeOrderExpirationCheckListProcedureResult, + __sdk::InternalError, + >, + ) + Send + + 'static, ) { self.imp.invoke_procedure_with_callback::<_, RuntimeProfileRechargeOrderExpirationCheckListProcedureResult>( "list_unchecked_expired_profile_recharge_orders", diff --git a/server-rs/crates/spacetime-client/src/module_bindings/mark_editor_showcase_asset_refunded_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/mark_editor_showcase_asset_refunded_and_return_procedure.rs index a2d7ad962..2da58f2ca 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/mark_editor_showcase_asset_refunded_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/mark_editor_showcase_asset_refunded_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait mark_editor_showcase_asset_refunded_and_return { input: EditorShowcaseAssetRefundMarkInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl mark_editor_showcase_asset_refunded_and_return for super::RemoteProcedures input: EditorShowcaseAssetRefundMarkInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorShowcaseAssetProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/mark_profile_recharge_order_expiration_checked_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/mark_profile_recharge_order_expiration_checked_procedure.rs index 22ec511a5..5eb121685 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/mark_profile_recharge_order_expiration_checked_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/mark_profile_recharge_order_expiration_checked_procedure.rs @@ -34,10 +34,13 @@ pub trait mark_profile_recharge_order_expiration_checked { input: RuntimeProfileRechargeOrderExpirationCheckInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result< + RuntimeProfileRechargeOrderExpirationCheckProcedureResult, + __sdk::InternalError, + >, + ) + Send + + 'static, ); } @@ -47,10 +50,13 @@ impl mark_profile_recharge_order_expiration_checked for super::RemoteProcedures input: RuntimeProfileRechargeOrderExpirationCheckInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result< + RuntimeProfileRechargeOrderExpirationCheckProcedureResult, + __sdk::InternalError, + >, + ) + Send + + 'static, ) { self.imp.invoke_procedure_with_callback::<_, RuntimeProfileRechargeOrderExpirationCheckProcedureResult>( "mark_profile_recharge_order_expiration_checked", diff --git a/server-rs/crates/spacetime-client/src/module_bindings/mark_profile_recharge_order_paid_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/mark_profile_recharge_order_paid_and_return_procedure.rs index f412f184a..09ba81c70 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/mark_profile_recharge_order_paid_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/mark_profile_recharge_order_paid_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait mark_profile_recharge_order_paid_and_return { input: RuntimeProfileRechargeOrderPaidInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl mark_profile_recharge_order_paid_and_return for super::RemoteProcedures { input: RuntimeProfileRechargeOrderPaidInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRechargeCenterProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_agent_message_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_agent_message_row_type.rs deleted file mode 100644 index 691b9f240..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_agent_message_row_type.rs +++ /dev/null @@ -1,66 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct Match3DAgentMessageRow { - pub message_id: String, - pub session_id: String, - pub role: String, - pub kind: String, - pub text: String, - pub created_at: __sdk::Timestamp, -} - -impl __sdk::InModule for Match3DAgentMessageRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `Match3DAgentMessageRow`. -/// -/// Provides typed access to columns for query building. -pub struct Match3DAgentMessageRowCols { - pub message_id: __sdk::__query_builder::Col, - pub session_id: __sdk::__query_builder::Col, - pub role: __sdk::__query_builder::Col, - pub kind: __sdk::__query_builder::Col, - pub text: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for Match3DAgentMessageRow { - type Cols = Match3DAgentMessageRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - Match3DAgentMessageRowCols { - message_id: __sdk::__query_builder::Col::new(table_name, "message_id"), - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - role: __sdk::__query_builder::Col::new(table_name, "role"), - kind: __sdk::__query_builder::Col::new(table_name, "kind"), - text: __sdk::__query_builder::Col::new(table_name, "text"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - } - } -} - -/// Indexed column accessor struct for the table `Match3DAgentMessageRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct Match3DAgentMessageRowIxCols { - pub message_id: __sdk::__query_builder::IxCol, - pub session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for Match3DAgentMessageRow { - type IxCols = Match3DAgentMessageRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - Match3DAgentMessageRowIxCols { - message_id: __sdk::__query_builder::IxCol::new(table_name, "message_id"), - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for Match3DAgentMessageRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_agent_message_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_agent_message_table.rs deleted file mode 100644 index 6842beee7..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_agent_message_table.rs +++ /dev/null @@ -1,231 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::match_3_d_agent_message_row_type::Match3DAgentMessageRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `match_3_d_agent_message`. -/// -/// Obtain a handle from the [`Match3DAgentMessageTableAccess::match_3_d_agent_message`] method on [`super::RemoteTables`], -/// like `ctx.db.match_3_d_agent_message()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.match_3_d_agent_message().on_insert(...)`. -pub struct Match3DAgentMessageTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `match_3_d_agent_message`. -pub struct Match3DAgentMessageTableAccessor; - -impl __sdk::TableAccessor for Match3DAgentMessageTableAccessor { - type Row = Match3DAgentMessageRow; - type Handle<'db> = Match3DAgentMessageTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.match_3_d_agent_message() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `match_3_d_agent_message`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait Match3DAgentMessageTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`Match3DAgentMessageTableHandle`], which mediates access to the table `match_3_d_agent_message`. - fn match_3_d_agent_message(&self) -> Match3DAgentMessageTableHandle<'_>; -} - -impl Match3DAgentMessageTableAccess for super::RemoteTables { - fn match_3_d_agent_message(&self) -> Match3DAgentMessageTableHandle<'_> { - Match3DAgentMessageTableHandle { - imp: self - .imp - .get_table::("match_3_d_agent_message"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct Match3DAgentMessageInsertCallbackId(__sdk::CallbackId); -pub struct Match3DAgentMessageDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for Match3DAgentMessageTableHandle<'ctx> { - type Row = Match3DAgentMessageRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for Match3DAgentMessageTableHandle<'ctx> { - type Row = Match3DAgentMessageRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = Match3DAgentMessageInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> Match3DAgentMessageInsertCallbackId { - Match3DAgentMessageInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: Match3DAgentMessageInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = Match3DAgentMessageDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> Match3DAgentMessageDeleteCallbackId { - Match3DAgentMessageDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: Match3DAgentMessageDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for Match3DAgentMessageTableHandle<'ctx> { - type InsertCallbackId = Match3DAgentMessageInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> Match3DAgentMessageInsertCallbackId { - Match3DAgentMessageInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: Match3DAgentMessageInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for Match3DAgentMessageTableHandle<'ctx> { - type DeleteCallbackId = Match3DAgentMessageDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> Match3DAgentMessageDeleteCallbackId { - Match3DAgentMessageDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: Match3DAgentMessageDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct Match3DAgentMessageUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for Match3DAgentMessageTableHandle<'ctx> { - type UpdateCallbackId = Match3DAgentMessageUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> Match3DAgentMessageUpdateCallbackId { - Match3DAgentMessageUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: Match3DAgentMessageUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for Match3DAgentMessageTableHandle<'ctx> { - type UpdateCallbackId = Match3DAgentMessageUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> Match3DAgentMessageUpdateCallbackId { - Match3DAgentMessageUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: Match3DAgentMessageUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `message_id` unique index on the table `match_3_d_agent_message`, -/// which allows point queries on the field of the same name -/// via the [`Match3DAgentMessageMessageIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.match_3_d_agent_message().message_id().find(...)`. -pub struct Match3DAgentMessageMessageIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> Match3DAgentMessageTableHandle<'ctx> { - /// Get a handle on the `message_id` unique index on the table `match_3_d_agent_message`. - pub fn message_id(&self) -> Match3DAgentMessageMessageIdUnique<'ctx> { - Match3DAgentMessageMessageIdUnique { - imp: self.imp.get_unique_constraint::("message_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> Match3DAgentMessageMessageIdUnique<'ctx> { - /// Find the subscribed row whose `message_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("match_3_d_agent_message"); - _table.add_unique_constraint::("message_id", |row| &row.message_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `Match3DAgentMessageRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait match_3_d_agent_messageQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `Match3DAgentMessageRow`. - fn match_3_d_agent_message(&self) -> __sdk::__query_builder::Table; -} - -impl match_3_d_agent_messageQueryTableAccess for __sdk::QueryTableAccessor { - fn match_3_d_agent_message(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("match_3_d_agent_message") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_agent_session_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_agent_session_row_type.rs deleted file mode 100644 index 49c07da79..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_agent_session_row_type.rs +++ /dev/null @@ -1,90 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct Match3DAgentSessionRow { - pub session_id: String, - pub owner_user_id: String, - pub seed_text: String, - pub current_turn: u32, - pub progress_percent: u32, - pub stage: String, - pub config_json: String, - pub draft_json: String, - pub last_assistant_reply: String, - pub published_profile_id: String, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for Match3DAgentSessionRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `Match3DAgentSessionRow`. -/// -/// Provides typed access to columns for query building. -pub struct Match3DAgentSessionRowCols { - pub session_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub seed_text: __sdk::__query_builder::Col, - pub current_turn: __sdk::__query_builder::Col, - pub progress_percent: __sdk::__query_builder::Col, - pub stage: __sdk::__query_builder::Col, - pub config_json: __sdk::__query_builder::Col, - pub draft_json: __sdk::__query_builder::Col, - pub last_assistant_reply: __sdk::__query_builder::Col, - pub published_profile_id: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for Match3DAgentSessionRow { - type Cols = Match3DAgentSessionRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - Match3DAgentSessionRowCols { - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - seed_text: __sdk::__query_builder::Col::new(table_name, "seed_text"), - current_turn: __sdk::__query_builder::Col::new(table_name, "current_turn"), - progress_percent: __sdk::__query_builder::Col::new(table_name, "progress_percent"), - stage: __sdk::__query_builder::Col::new(table_name, "stage"), - config_json: __sdk::__query_builder::Col::new(table_name, "config_json"), - draft_json: __sdk::__query_builder::Col::new(table_name, "draft_json"), - last_assistant_reply: __sdk::__query_builder::Col::new( - table_name, - "last_assistant_reply", - ), - published_profile_id: __sdk::__query_builder::Col::new( - table_name, - "published_profile_id", - ), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `Match3DAgentSessionRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct Match3DAgentSessionRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for Match3DAgentSessionRow { - type IxCols = Match3DAgentSessionRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - Match3DAgentSessionRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for Match3DAgentSessionRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_agent_session_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_agent_session_table.rs deleted file mode 100644 index 9e2d554a8..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_agent_session_table.rs +++ /dev/null @@ -1,231 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::match_3_d_agent_session_row_type::Match3DAgentSessionRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `match_3_d_agent_session`. -/// -/// Obtain a handle from the [`Match3DAgentSessionTableAccess::match_3_d_agent_session`] method on [`super::RemoteTables`], -/// like `ctx.db.match_3_d_agent_session()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.match_3_d_agent_session().on_insert(...)`. -pub struct Match3DAgentSessionTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `match_3_d_agent_session`. -pub struct Match3DAgentSessionTableAccessor; - -impl __sdk::TableAccessor for Match3DAgentSessionTableAccessor { - type Row = Match3DAgentSessionRow; - type Handle<'db> = Match3DAgentSessionTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.match_3_d_agent_session() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `match_3_d_agent_session`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait Match3DAgentSessionTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`Match3DAgentSessionTableHandle`], which mediates access to the table `match_3_d_agent_session`. - fn match_3_d_agent_session(&self) -> Match3DAgentSessionTableHandle<'_>; -} - -impl Match3DAgentSessionTableAccess for super::RemoteTables { - fn match_3_d_agent_session(&self) -> Match3DAgentSessionTableHandle<'_> { - Match3DAgentSessionTableHandle { - imp: self - .imp - .get_table::("match_3_d_agent_session"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct Match3DAgentSessionInsertCallbackId(__sdk::CallbackId); -pub struct Match3DAgentSessionDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for Match3DAgentSessionTableHandle<'ctx> { - type Row = Match3DAgentSessionRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for Match3DAgentSessionTableHandle<'ctx> { - type Row = Match3DAgentSessionRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = Match3DAgentSessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> Match3DAgentSessionInsertCallbackId { - Match3DAgentSessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: Match3DAgentSessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = Match3DAgentSessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> Match3DAgentSessionDeleteCallbackId { - Match3DAgentSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: Match3DAgentSessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for Match3DAgentSessionTableHandle<'ctx> { - type InsertCallbackId = Match3DAgentSessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> Match3DAgentSessionInsertCallbackId { - Match3DAgentSessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: Match3DAgentSessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for Match3DAgentSessionTableHandle<'ctx> { - type DeleteCallbackId = Match3DAgentSessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> Match3DAgentSessionDeleteCallbackId { - Match3DAgentSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: Match3DAgentSessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct Match3DAgentSessionUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for Match3DAgentSessionTableHandle<'ctx> { - type UpdateCallbackId = Match3DAgentSessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> Match3DAgentSessionUpdateCallbackId { - Match3DAgentSessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: Match3DAgentSessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for Match3DAgentSessionTableHandle<'ctx> { - type UpdateCallbackId = Match3DAgentSessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> Match3DAgentSessionUpdateCallbackId { - Match3DAgentSessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: Match3DAgentSessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `session_id` unique index on the table `match_3_d_agent_session`, -/// which allows point queries on the field of the same name -/// via the [`Match3DAgentSessionSessionIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.match_3_d_agent_session().session_id().find(...)`. -pub struct Match3DAgentSessionSessionIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> Match3DAgentSessionTableHandle<'ctx> { - /// Get a handle on the `session_id` unique index on the table `match_3_d_agent_session`. - pub fn session_id(&self) -> Match3DAgentSessionSessionIdUnique<'ctx> { - Match3DAgentSessionSessionIdUnique { - imp: self.imp.get_unique_constraint::("session_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> Match3DAgentSessionSessionIdUnique<'ctx> { - /// Find the subscribed row whose `session_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("match_3_d_agent_session"); - _table.add_unique_constraint::("session_id", |row| &row.session_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `Match3DAgentSessionRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait match_3_d_agent_sessionQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `Match3DAgentSessionRow`. - fn match_3_d_agent_session(&self) -> __sdk::__query_builder::Table; -} - -impl match_3_d_agent_sessionQueryTableAccess for __sdk::QueryTableAccessor { - fn match_3_d_agent_session(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("match_3_d_agent_session") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_runtime_run_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_runtime_run_row_type.rs deleted file mode 100644 index 66e8d4aa9..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_runtime_run_row_type.rs +++ /dev/null @@ -1,98 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct Match3DRuntimeRunRow { - pub run_id: String, - pub owner_user_id: String, - pub profile_id: String, - pub status: String, - pub snapshot_version: u32, - pub started_at_ms: i64, - pub duration_limit_ms: i64, - pub finished_at_ms: i64, - pub elapsed_ms: i64, - pub clear_count: u32, - pub total_item_count: u32, - pub cleared_item_count: u32, - pub failure_reason: String, - pub snapshot_json: String, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for Match3DRuntimeRunRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `Match3DRuntimeRunRow`. -/// -/// Provides typed access to columns for query building. -pub struct Match3DRuntimeRunRowCols { - pub run_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub profile_id: __sdk::__query_builder::Col, - pub status: __sdk::__query_builder::Col, - pub snapshot_version: __sdk::__query_builder::Col, - pub started_at_ms: __sdk::__query_builder::Col, - pub duration_limit_ms: __sdk::__query_builder::Col, - pub finished_at_ms: __sdk::__query_builder::Col, - pub elapsed_ms: __sdk::__query_builder::Col, - pub clear_count: __sdk::__query_builder::Col, - pub total_item_count: __sdk::__query_builder::Col, - pub cleared_item_count: __sdk::__query_builder::Col, - pub failure_reason: __sdk::__query_builder::Col, - pub snapshot_json: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for Match3DRuntimeRunRow { - type Cols = Match3DRuntimeRunRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - Match3DRuntimeRunRowCols { - run_id: __sdk::__query_builder::Col::new(table_name, "run_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - status: __sdk::__query_builder::Col::new(table_name, "status"), - snapshot_version: __sdk::__query_builder::Col::new(table_name, "snapshot_version"), - started_at_ms: __sdk::__query_builder::Col::new(table_name, "started_at_ms"), - duration_limit_ms: __sdk::__query_builder::Col::new(table_name, "duration_limit_ms"), - finished_at_ms: __sdk::__query_builder::Col::new(table_name, "finished_at_ms"), - elapsed_ms: __sdk::__query_builder::Col::new(table_name, "elapsed_ms"), - clear_count: __sdk::__query_builder::Col::new(table_name, "clear_count"), - total_item_count: __sdk::__query_builder::Col::new(table_name, "total_item_count"), - cleared_item_count: __sdk::__query_builder::Col::new(table_name, "cleared_item_count"), - failure_reason: __sdk::__query_builder::Col::new(table_name, "failure_reason"), - snapshot_json: __sdk::__query_builder::Col::new(table_name, "snapshot_json"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `Match3DRuntimeRunRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct Match3DRuntimeRunRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub profile_id: __sdk::__query_builder::IxCol, - pub run_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for Match3DRuntimeRunRow { - type IxCols = Match3DRuntimeRunRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - Match3DRuntimeRunRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::IxCol::new(table_name, "profile_id"), - run_id: __sdk::__query_builder::IxCol::new(table_name, "run_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for Match3DRuntimeRunRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_runtime_run_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_runtime_run_table.rs deleted file mode 100644 index 3998804da..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_runtime_run_table.rs +++ /dev/null @@ -1,230 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::match_3_d_runtime_run_row_type::Match3DRuntimeRunRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `match_3_d_runtime_run`. -/// -/// Obtain a handle from the [`Match3DRuntimeRunTableAccess::match_3_d_runtime_run`] method on [`super::RemoteTables`], -/// like `ctx.db.match_3_d_runtime_run()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.match_3_d_runtime_run().on_insert(...)`. -pub struct Match3DRuntimeRunTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `match_3_d_runtime_run`. -pub struct Match3DRuntimeRunTableAccessor; - -impl __sdk::TableAccessor for Match3DRuntimeRunTableAccessor { - type Row = Match3DRuntimeRunRow; - type Handle<'db> = Match3DRuntimeRunTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.match_3_d_runtime_run() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `match_3_d_runtime_run`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait Match3DRuntimeRunTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`Match3DRuntimeRunTableHandle`], which mediates access to the table `match_3_d_runtime_run`. - fn match_3_d_runtime_run(&self) -> Match3DRuntimeRunTableHandle<'_>; -} - -impl Match3DRuntimeRunTableAccess for super::RemoteTables { - fn match_3_d_runtime_run(&self) -> Match3DRuntimeRunTableHandle<'_> { - Match3DRuntimeRunTableHandle { - imp: self - .imp - .get_table::("match_3_d_runtime_run"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct Match3DRuntimeRunInsertCallbackId(__sdk::CallbackId); -pub struct Match3DRuntimeRunDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for Match3DRuntimeRunTableHandle<'ctx> { - type Row = Match3DRuntimeRunRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for Match3DRuntimeRunTableHandle<'ctx> { - type Row = Match3DRuntimeRunRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = Match3DRuntimeRunInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> Match3DRuntimeRunInsertCallbackId { - Match3DRuntimeRunInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: Match3DRuntimeRunInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = Match3DRuntimeRunDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> Match3DRuntimeRunDeleteCallbackId { - Match3DRuntimeRunDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: Match3DRuntimeRunDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for Match3DRuntimeRunTableHandle<'ctx> { - type InsertCallbackId = Match3DRuntimeRunInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> Match3DRuntimeRunInsertCallbackId { - Match3DRuntimeRunInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: Match3DRuntimeRunInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for Match3DRuntimeRunTableHandle<'ctx> { - type DeleteCallbackId = Match3DRuntimeRunDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> Match3DRuntimeRunDeleteCallbackId { - Match3DRuntimeRunDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: Match3DRuntimeRunDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct Match3DRuntimeRunUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for Match3DRuntimeRunTableHandle<'ctx> { - type UpdateCallbackId = Match3DRuntimeRunUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> Match3DRuntimeRunUpdateCallbackId { - Match3DRuntimeRunUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: Match3DRuntimeRunUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for Match3DRuntimeRunTableHandle<'ctx> { - type UpdateCallbackId = Match3DRuntimeRunUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> Match3DRuntimeRunUpdateCallbackId { - Match3DRuntimeRunUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: Match3DRuntimeRunUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `run_id` unique index on the table `match_3_d_runtime_run`, -/// which allows point queries on the field of the same name -/// via the [`Match3DRuntimeRunRunIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.match_3_d_runtime_run().run_id().find(...)`. -pub struct Match3DRuntimeRunRunIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> Match3DRuntimeRunTableHandle<'ctx> { - /// Get a handle on the `run_id` unique index on the table `match_3_d_runtime_run`. - pub fn run_id(&self) -> Match3DRuntimeRunRunIdUnique<'ctx> { - Match3DRuntimeRunRunIdUnique { - imp: self.imp.get_unique_constraint::("run_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> Match3DRuntimeRunRunIdUnique<'ctx> { - /// Find the subscribed row whose `run_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("match_3_d_runtime_run"); - _table.add_unique_constraint::("run_id", |row| &row.run_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `Match3DRuntimeRunRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait match_3_d_runtime_runQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `Match3DRuntimeRunRow`. - fn match_3_d_runtime_run(&self) -> __sdk::__query_builder::Table; -} - -impl match_3_d_runtime_runQueryTableAccess for __sdk::QueryTableAccessor { - fn match_3_d_runtime_run(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("match_3_d_runtime_run") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_work_profile_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_work_profile_row_type.rs deleted file mode 100644 index aafe2065a..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_work_profile_row_type.rs +++ /dev/null @@ -1,117 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct Match3DWorkProfileRow { - pub profile_id: String, - pub owner_user_id: String, - pub source_session_id: String, - pub author_display_name: String, - pub game_name: String, - pub theme_text: String, - pub summary_text: String, - pub tags_json: String, - pub cover_image_src: String, - pub cover_asset_id: String, - pub clear_count: u32, - pub difficulty: u32, - pub config_json: String, - pub publication_status: String, - pub play_count: u32, - pub updated_at: __sdk::Timestamp, - pub published_at: Option<__sdk::Timestamp>, - pub generated_item_assets_json: Option, - pub visible: bool, -} - -impl __sdk::InModule for Match3DWorkProfileRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `Match3DWorkProfileRow`. -/// -/// Provides typed access to columns for query building. -pub struct Match3DWorkProfileRowCols { - pub profile_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub source_session_id: __sdk::__query_builder::Col, - pub author_display_name: __sdk::__query_builder::Col, - pub game_name: __sdk::__query_builder::Col, - pub theme_text: __sdk::__query_builder::Col, - pub summary_text: __sdk::__query_builder::Col, - pub tags_json: __sdk::__query_builder::Col, - pub cover_image_src: __sdk::__query_builder::Col, - pub cover_asset_id: __sdk::__query_builder::Col, - pub clear_count: __sdk::__query_builder::Col, - pub difficulty: __sdk::__query_builder::Col, - pub config_json: __sdk::__query_builder::Col, - pub publication_status: __sdk::__query_builder::Col, - pub play_count: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, - pub published_at: __sdk::__query_builder::Col>, - pub generated_item_assets_json: - __sdk::__query_builder::Col>, - pub visible: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for Match3DWorkProfileRow { - type Cols = Match3DWorkProfileRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - Match3DWorkProfileRowCols { - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - source_session_id: __sdk::__query_builder::Col::new(table_name, "source_session_id"), - author_display_name: __sdk::__query_builder::Col::new( - table_name, - "author_display_name", - ), - game_name: __sdk::__query_builder::Col::new(table_name, "game_name"), - theme_text: __sdk::__query_builder::Col::new(table_name, "theme_text"), - summary_text: __sdk::__query_builder::Col::new(table_name, "summary_text"), - tags_json: __sdk::__query_builder::Col::new(table_name, "tags_json"), - cover_image_src: __sdk::__query_builder::Col::new(table_name, "cover_image_src"), - cover_asset_id: __sdk::__query_builder::Col::new(table_name, "cover_asset_id"), - clear_count: __sdk::__query_builder::Col::new(table_name, "clear_count"), - difficulty: __sdk::__query_builder::Col::new(table_name, "difficulty"), - config_json: __sdk::__query_builder::Col::new(table_name, "config_json"), - publication_status: __sdk::__query_builder::Col::new(table_name, "publication_status"), - play_count: __sdk::__query_builder::Col::new(table_name, "play_count"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - published_at: __sdk::__query_builder::Col::new(table_name, "published_at"), - generated_item_assets_json: __sdk::__query_builder::Col::new( - table_name, - "generated_item_assets_json", - ), - visible: __sdk::__query_builder::Col::new(table_name, "visible"), - } - } -} - -/// Indexed column accessor struct for the table `Match3DWorkProfileRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct Match3DWorkProfileRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub profile_id: __sdk::__query_builder::IxCol, - pub publication_status: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for Match3DWorkProfileRow { - type IxCols = Match3DWorkProfileRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - Match3DWorkProfileRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::IxCol::new(table_name, "profile_id"), - publication_status: __sdk::__query_builder::IxCol::new( - table_name, - "publication_status", - ), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for Match3DWorkProfileRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_work_profile_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_work_profile_table.rs deleted file mode 100644 index dc5155c43..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_work_profile_table.rs +++ /dev/null @@ -1,230 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::match_3_d_work_profile_row_type::Match3DWorkProfileRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `match_3_d_work_profile`. -/// -/// Obtain a handle from the [`Match3DWorkProfileTableAccess::match_3_d_work_profile`] method on [`super::RemoteTables`], -/// like `ctx.db.match_3_d_work_profile()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.match_3_d_work_profile().on_insert(...)`. -pub struct Match3DWorkProfileTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `match_3_d_work_profile`. -pub struct Match3DWorkProfileTableAccessor; - -impl __sdk::TableAccessor for Match3DWorkProfileTableAccessor { - type Row = Match3DWorkProfileRow; - type Handle<'db> = Match3DWorkProfileTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.match_3_d_work_profile() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `match_3_d_work_profile`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait Match3DWorkProfileTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`Match3DWorkProfileTableHandle`], which mediates access to the table `match_3_d_work_profile`. - fn match_3_d_work_profile(&self) -> Match3DWorkProfileTableHandle<'_>; -} - -impl Match3DWorkProfileTableAccess for super::RemoteTables { - fn match_3_d_work_profile(&self) -> Match3DWorkProfileTableHandle<'_> { - Match3DWorkProfileTableHandle { - imp: self - .imp - .get_table::("match_3_d_work_profile"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct Match3DWorkProfileInsertCallbackId(__sdk::CallbackId); -pub struct Match3DWorkProfileDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for Match3DWorkProfileTableHandle<'ctx> { - type Row = Match3DWorkProfileRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for Match3DWorkProfileTableHandle<'ctx> { - type Row = Match3DWorkProfileRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = Match3DWorkProfileInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> Match3DWorkProfileInsertCallbackId { - Match3DWorkProfileInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: Match3DWorkProfileInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = Match3DWorkProfileDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> Match3DWorkProfileDeleteCallbackId { - Match3DWorkProfileDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: Match3DWorkProfileDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for Match3DWorkProfileTableHandle<'ctx> { - type InsertCallbackId = Match3DWorkProfileInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> Match3DWorkProfileInsertCallbackId { - Match3DWorkProfileInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: Match3DWorkProfileInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for Match3DWorkProfileTableHandle<'ctx> { - type DeleteCallbackId = Match3DWorkProfileDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> Match3DWorkProfileDeleteCallbackId { - Match3DWorkProfileDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: Match3DWorkProfileDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct Match3DWorkProfileUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for Match3DWorkProfileTableHandle<'ctx> { - type UpdateCallbackId = Match3DWorkProfileUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> Match3DWorkProfileUpdateCallbackId { - Match3DWorkProfileUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: Match3DWorkProfileUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for Match3DWorkProfileTableHandle<'ctx> { - type UpdateCallbackId = Match3DWorkProfileUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> Match3DWorkProfileUpdateCallbackId { - Match3DWorkProfileUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: Match3DWorkProfileUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `profile_id` unique index on the table `match_3_d_work_profile`, -/// which allows point queries on the field of the same name -/// via the [`Match3DWorkProfileProfileIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.match_3_d_work_profile().profile_id().find(...)`. -pub struct Match3DWorkProfileProfileIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> Match3DWorkProfileTableHandle<'ctx> { - /// Get a handle on the `profile_id` unique index on the table `match_3_d_work_profile`. - pub fn profile_id(&self) -> Match3DWorkProfileProfileIdUnique<'ctx> { - Match3DWorkProfileProfileIdUnique { - imp: self.imp.get_unique_constraint::("profile_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> Match3DWorkProfileProfileIdUnique<'ctx> { - /// Find the subscribed row whose `profile_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("match_3_d_work_profile"); - _table.add_unique_constraint::("profile_id", |row| &row.profile_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `Match3DWorkProfileRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait match_3_d_work_profileQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `Match3DWorkProfileRow`. - fn match_3_d_work_profile(&self) -> __sdk::__query_builder::Table; -} - -impl match_3_d_work_profileQueryTableAccess for __sdk::QueryTableAccessor { - fn match_3_d_work_profile(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("match_3_d_work_profile") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/normalize_editor_character_animation_metadata_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/normalize_editor_character_animation_metadata_and_return_procedure.rs index 083ef15b9..68712687d 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/normalize_editor_character_animation_metadata_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/normalize_editor_character_animation_metadata_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait normalize_editor_character_animation_metadata_and_return { input: EditorCharacterAnimationNormalizationInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl normalize_editor_character_animation_metadata_and_return for super::RemoteP input: EditorCharacterAnimationNormalizationInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp.invoke_procedure_with_callback::<_, EditorCharacterAnimationNormalizationProcedureResult>( "normalize_editor_character_animation_metadata_and_return", diff --git a/server-rs/crates/spacetime-client/src/module_bindings/npc_relation_stance_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/npc_relation_stance_type.rs deleted file mode 100644 index 48e8ac700..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/npc_relation_stance_type.rs +++ /dev/null @@ -1,24 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum NpcRelationStance { - Hostile, - - Guarded, - - Neutral, - - Cooperative, - - Bonded, -} - -impl __sdk::InModule for NpcRelationStance { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/npc_relation_state_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/npc_relation_state_type.rs deleted file mode 100644 index b6bbc07d1..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/npc_relation_state_type.rs +++ /dev/null @@ -1,18 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::npc_relation_stance_type::NpcRelationStance; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct NpcRelationState { - pub affinity: i32, - pub stance: NpcRelationStance, -} - -impl __sdk::InModule for NpcRelationState { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/npc_stance_profile_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/npc_stance_profile_type.rs deleted file mode 100644 index 73177673f..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/npc_stance_profile_type.rs +++ /dev/null @@ -1,22 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct NpcStanceProfile { - pub trust: u8, - pub warmth: u8, - pub ideological_fit: u8, - pub fear_or_guard: u8, - pub loyalty: u8, - pub current_conflict_tag: Option, - pub recent_approvals: Vec, - pub recent_disapprovals: Vec, -} - -impl __sdk::InModule for NpcStanceProfile { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/npc_state_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/npc_state_table.rs deleted file mode 100644 index 83c676126..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/npc_state_table.rs +++ /dev/null @@ -1,230 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::npc_relation_state_type::NpcRelationState; -use super::npc_stance_profile_type::NpcStanceProfile; -use super::npc_state_type::NpcState; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `npc_state`. -/// -/// Obtain a handle from the [`NpcStateTableAccess::npc_state`] method on [`super::RemoteTables`], -/// like `ctx.db.npc_state()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.npc_state().on_insert(...)`. -pub struct NpcStateTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `npc_state`. -pub struct NpcStateTableAccessor; - -impl __sdk::TableAccessor for NpcStateTableAccessor { - type Row = NpcState; - type Handle<'db> = NpcStateTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.npc_state() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `npc_state`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait NpcStateTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`NpcStateTableHandle`], which mediates access to the table `npc_state`. - fn npc_state(&self) -> NpcStateTableHandle<'_>; -} - -impl NpcStateTableAccess for super::RemoteTables { - fn npc_state(&self) -> NpcStateTableHandle<'_> { - NpcStateTableHandle { - imp: self.imp.get_table::("npc_state"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct NpcStateInsertCallbackId(__sdk::CallbackId); -pub struct NpcStateDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for NpcStateTableHandle<'ctx> { - type Row = NpcState; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for NpcStateTableHandle<'ctx> { - type Row = NpcState; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = NpcStateInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> NpcStateInsertCallbackId { - NpcStateInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: NpcStateInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = NpcStateDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> NpcStateDeleteCallbackId { - NpcStateDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: NpcStateDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for NpcStateTableHandle<'ctx> { - type InsertCallbackId = NpcStateInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> NpcStateInsertCallbackId { - NpcStateInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: NpcStateInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for NpcStateTableHandle<'ctx> { - type DeleteCallbackId = NpcStateDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> NpcStateDeleteCallbackId { - NpcStateDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: NpcStateDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct NpcStateUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for NpcStateTableHandle<'ctx> { - type UpdateCallbackId = NpcStateUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> NpcStateUpdateCallbackId { - NpcStateUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: NpcStateUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for NpcStateTableHandle<'ctx> { - type UpdateCallbackId = NpcStateUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> NpcStateUpdateCallbackId { - NpcStateUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: NpcStateUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `npc_state_id` unique index on the table `npc_state`, -/// which allows point queries on the field of the same name -/// via the [`NpcStateNpcStateIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.npc_state().npc_state_id().find(...)`. -pub struct NpcStateNpcStateIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> NpcStateTableHandle<'ctx> { - /// Get a handle on the `npc_state_id` unique index on the table `npc_state`. - pub fn npc_state_id(&self) -> NpcStateNpcStateIdUnique<'ctx> { - NpcStateNpcStateIdUnique { - imp: self.imp.get_unique_constraint::("npc_state_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> NpcStateNpcStateIdUnique<'ctx> { - /// Find the subscribed row whose `npc_state_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("npc_state"); - _table.add_unique_constraint::("npc_state_id", |row| &row.npc_state_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `NpcState`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait npc_stateQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `NpcState`. - fn npc_state(&self) -> __sdk::__query_builder::Table; -} - -impl npc_stateQueryTableAccess for __sdk::QueryTableAccessor { - fn npc_state(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("npc_state") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/npc_state_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/npc_state_type.rs deleted file mode 100644 index 1ddeec426..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/npc_state_type.rs +++ /dev/null @@ -1,122 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::npc_relation_state_type::NpcRelationState; -use super::npc_stance_profile_type::NpcStanceProfile; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct NpcState { - pub npc_state_id: String, - pub runtime_session_id: String, - pub npc_id: String, - pub npc_name: String, - pub affinity: i32, - pub relation_state: NpcRelationState, - pub help_used: bool, - pub chatted_count: u32, - pub gifts_given: u32, - pub recruited: bool, - pub trade_stock_signature: Option, - pub revealed_facts: Vec, - pub known_attribute_rumors: Vec, - pub first_meaningful_contact_resolved: bool, - pub seen_backstory_chapter_ids: Vec, - pub stance_profile: NpcStanceProfile, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for NpcState { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `NpcState`. -/// -/// Provides typed access to columns for query building. -pub struct NpcStateCols { - pub npc_state_id: __sdk::__query_builder::Col, - pub runtime_session_id: __sdk::__query_builder::Col, - pub npc_id: __sdk::__query_builder::Col, - pub npc_name: __sdk::__query_builder::Col, - pub affinity: __sdk::__query_builder::Col, - pub relation_state: __sdk::__query_builder::Col, - pub help_used: __sdk::__query_builder::Col, - pub chatted_count: __sdk::__query_builder::Col, - pub gifts_given: __sdk::__query_builder::Col, - pub recruited: __sdk::__query_builder::Col, - pub trade_stock_signature: __sdk::__query_builder::Col>, - pub revealed_facts: __sdk::__query_builder::Col>, - pub known_attribute_rumors: __sdk::__query_builder::Col>, - pub first_meaningful_contact_resolved: __sdk::__query_builder::Col, - pub seen_backstory_chapter_ids: __sdk::__query_builder::Col>, - pub stance_profile: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for NpcState { - type Cols = NpcStateCols; - fn cols(table_name: &'static str) -> Self::Cols { - NpcStateCols { - npc_state_id: __sdk::__query_builder::Col::new(table_name, "npc_state_id"), - runtime_session_id: __sdk::__query_builder::Col::new(table_name, "runtime_session_id"), - npc_id: __sdk::__query_builder::Col::new(table_name, "npc_id"), - npc_name: __sdk::__query_builder::Col::new(table_name, "npc_name"), - affinity: __sdk::__query_builder::Col::new(table_name, "affinity"), - relation_state: __sdk::__query_builder::Col::new(table_name, "relation_state"), - help_used: __sdk::__query_builder::Col::new(table_name, "help_used"), - chatted_count: __sdk::__query_builder::Col::new(table_name, "chatted_count"), - gifts_given: __sdk::__query_builder::Col::new(table_name, "gifts_given"), - recruited: __sdk::__query_builder::Col::new(table_name, "recruited"), - trade_stock_signature: __sdk::__query_builder::Col::new( - table_name, - "trade_stock_signature", - ), - revealed_facts: __sdk::__query_builder::Col::new(table_name, "revealed_facts"), - known_attribute_rumors: __sdk::__query_builder::Col::new( - table_name, - "known_attribute_rumors", - ), - first_meaningful_contact_resolved: __sdk::__query_builder::Col::new( - table_name, - "first_meaningful_contact_resolved", - ), - seen_backstory_chapter_ids: __sdk::__query_builder::Col::new( - table_name, - "seen_backstory_chapter_ids", - ), - stance_profile: __sdk::__query_builder::Col::new(table_name, "stance_profile"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `NpcState`. -/// -/// Provides typed access to indexed columns for query building. -pub struct NpcStateIxCols { - pub npc_id: __sdk::__query_builder::IxCol, - pub npc_state_id: __sdk::__query_builder::IxCol, - pub runtime_session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for NpcState { - type IxCols = NpcStateIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - NpcStateIxCols { - npc_id: __sdk::__query_builder::IxCol::new(table_name, "npc_id"), - npc_state_id: __sdk::__query_builder::IxCol::new(table_name, "npc_state_id"), - runtime_session_id: __sdk::__query_builder::IxCol::new( - table_name, - "runtime_session_id", - ), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for NpcState {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/persist_editor_generation_result_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/persist_editor_generation_result_and_return_procedure.rs index 6e05128b2..17c3468dc 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/persist_editor_generation_result_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/persist_editor_generation_result_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait persist_editor_generation_result_and_return { input: EditorGenerationResultPersistInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl persist_editor_generation_result_and_return for super::RemoteProcedures { input: EditorGenerationResultPersistInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorGenerationResultPersistResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/persist_editor_pixel_art_result_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/persist_editor_pixel_art_result_and_return_procedure.rs index c25ee2e1c..cdccf6f35 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/persist_editor_pixel_art_result_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/persist_editor_pixel_art_result_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait persist_editor_pixel_art_result_and_return { input: EditorPixelArtResultPersistInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl persist_editor_pixel_art_result_and_return for super::RemoteProcedures { input: EditorPixelArtResultPersistInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorPixelArtResultPersistResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/persist_editor_spritesheet_slice_batch_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/persist_editor_spritesheet_slice_batch_and_return_procedure.rs index bbf93f160..5789c1e76 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/persist_editor_spritesheet_slice_batch_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/persist_editor_spritesheet_slice_batch_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait persist_editor_spritesheet_slice_batch_and_return { input: EditorSpritesheetSliceBatchPersistInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl persist_editor_spritesheet_slice_batch_and_return for super::RemoteProcedur input: EditorSpritesheetSliceBatchPersistInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorSpritesheetSliceBatchPersistResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/player_progression_grant_source_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/player_progression_grant_source_type.rs deleted file mode 100644 index bf3ae257f..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/player_progression_grant_source_type.rs +++ /dev/null @@ -1,18 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum PlayerProgressionGrantSource { - Quest, - - HostileNpc, -} - -impl __sdk::InModule for PlayerProgressionGrantSource { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/player_progression_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/player_progression_table.rs deleted file mode 100644 index 12f1cb0db..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/player_progression_table.rs +++ /dev/null @@ -1,231 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::player_progression_grant_source_type::PlayerProgressionGrantSource; -use super::player_progression_type::PlayerProgression; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `player_progression`. -/// -/// Obtain a handle from the [`PlayerProgressionTableAccess::player_progression`] method on [`super::RemoteTables`], -/// like `ctx.db.player_progression()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.player_progression().on_insert(...)`. -pub struct PlayerProgressionTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `player_progression`. -pub struct PlayerProgressionTableAccessor; - -impl __sdk::TableAccessor for PlayerProgressionTableAccessor { - type Row = PlayerProgression; - type Handle<'db> = PlayerProgressionTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.player_progression() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `player_progression`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait PlayerProgressionTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`PlayerProgressionTableHandle`], which mediates access to the table `player_progression`. - fn player_progression(&self) -> PlayerProgressionTableHandle<'_>; -} - -impl PlayerProgressionTableAccess for super::RemoteTables { - fn player_progression(&self) -> PlayerProgressionTableHandle<'_> { - PlayerProgressionTableHandle { - imp: self - .imp - .get_table::("player_progression"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct PlayerProgressionInsertCallbackId(__sdk::CallbackId); -pub struct PlayerProgressionDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for PlayerProgressionTableHandle<'ctx> { - type Row = PlayerProgression; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for PlayerProgressionTableHandle<'ctx> { - type Row = PlayerProgression; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = PlayerProgressionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PlayerProgressionInsertCallbackId { - PlayerProgressionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PlayerProgressionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = PlayerProgressionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PlayerProgressionDeleteCallbackId { - PlayerProgressionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PlayerProgressionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for PlayerProgressionTableHandle<'ctx> { - type InsertCallbackId = PlayerProgressionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PlayerProgressionInsertCallbackId { - PlayerProgressionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PlayerProgressionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for PlayerProgressionTableHandle<'ctx> { - type DeleteCallbackId = PlayerProgressionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PlayerProgressionDeleteCallbackId { - PlayerProgressionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PlayerProgressionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct PlayerProgressionUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for PlayerProgressionTableHandle<'ctx> { - type UpdateCallbackId = PlayerProgressionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PlayerProgressionUpdateCallbackId { - PlayerProgressionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PlayerProgressionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for PlayerProgressionTableHandle<'ctx> { - type UpdateCallbackId = PlayerProgressionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PlayerProgressionUpdateCallbackId { - PlayerProgressionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PlayerProgressionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `user_id` unique index on the table `player_progression`, -/// which allows point queries on the field of the same name -/// via the [`PlayerProgressionUserIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.player_progression().user_id().find(...)`. -pub struct PlayerProgressionUserIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> PlayerProgressionTableHandle<'ctx> { - /// Get a handle on the `user_id` unique index on the table `player_progression`. - pub fn user_id(&self) -> PlayerProgressionUserIdUnique<'ctx> { - PlayerProgressionUserIdUnique { - imp: self.imp.get_unique_constraint::("user_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> PlayerProgressionUserIdUnique<'ctx> { - /// Find the subscribed row whose `user_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("player_progression"); - _table.add_unique_constraint::("user_id", |row| &row.user_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `PlayerProgression`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait player_progressionQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `PlayerProgression`. - fn player_progression(&self) -> __sdk::__query_builder::Table; -} - -impl player_progressionQueryTableAccess for __sdk::QueryTableAccessor { - fn player_progression(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("player_progression") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/player_progression_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/player_progression_type.rs deleted file mode 100644 index c734d1c2f..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/player_progression_type.rs +++ /dev/null @@ -1,79 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::player_progression_grant_source_type::PlayerProgressionGrantSource; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct PlayerProgression { - pub user_id: String, - pub level: u32, - pub current_level_xp: u32, - pub total_xp: u32, - pub xp_to_next_level: u32, - pub pending_level_ups: u32, - pub last_granted_source: Option, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for PlayerProgression { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `PlayerProgression`. -/// -/// Provides typed access to columns for query building. -pub struct PlayerProgressionCols { - pub user_id: __sdk::__query_builder::Col, - pub level: __sdk::__query_builder::Col, - pub current_level_xp: __sdk::__query_builder::Col, - pub total_xp: __sdk::__query_builder::Col, - pub xp_to_next_level: __sdk::__query_builder::Col, - pub pending_level_ups: __sdk::__query_builder::Col, - pub last_granted_source: - __sdk::__query_builder::Col>, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for PlayerProgression { - type Cols = PlayerProgressionCols; - fn cols(table_name: &'static str) -> Self::Cols { - PlayerProgressionCols { - user_id: __sdk::__query_builder::Col::new(table_name, "user_id"), - level: __sdk::__query_builder::Col::new(table_name, "level"), - current_level_xp: __sdk::__query_builder::Col::new(table_name, "current_level_xp"), - total_xp: __sdk::__query_builder::Col::new(table_name, "total_xp"), - xp_to_next_level: __sdk::__query_builder::Col::new(table_name, "xp_to_next_level"), - pending_level_ups: __sdk::__query_builder::Col::new(table_name, "pending_level_ups"), - last_granted_source: __sdk::__query_builder::Col::new( - table_name, - "last_granted_source", - ), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `PlayerProgression`. -/// -/// Provides typed access to indexed columns for query building. -pub struct PlayerProgressionIxCols { - pub user_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for PlayerProgression { - type IxCols = PlayerProgressionIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - PlayerProgressionIxCols { - user_id: __sdk::__query_builder::IxCol::new(table_name, "user_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for PlayerProgression {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/preflight_editor_generation_target_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/preflight_editor_generation_target_and_return_procedure.rs index f2b701d1b..f734a0fdf 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/preflight_editor_generation_target_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/preflight_editor_generation_target_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait preflight_editor_generation_target_and_return { input: EditorGenerationTargetPreflightInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl preflight_editor_generation_target_and_return for super::RemoteProcedures { input: EditorGenerationTargetPreflightInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorGenerationTargetPreflightResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/preflight_editor_pixel_art_result_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/preflight_editor_pixel_art_result_and_return_procedure.rs index f38144b63..e2aa2624a 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/preflight_editor_pixel_art_result_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/preflight_editor_pixel_art_result_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait preflight_editor_pixel_art_result_and_return { input: EditorPixelArtResultPreflightInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl preflight_editor_pixel_art_result_and_return for super::RemoteProcedures { input: EditorPixelArtResultPreflightInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorPixelArtResultPreflightResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/prepare_profile_recharge_refund_hold_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/prepare_profile_recharge_refund_hold_and_return_procedure.rs index 401e46c3b..e23c2e5c3 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/prepare_profile_recharge_refund_hold_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/prepare_profile_recharge_refund_hold_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait prepare_profile_recharge_refund_hold_and_return { input: RuntimeProfileRechargeRefundHoldPrepareInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl prepare_profile_recharge_refund_hold_and_return for super::RemoteProcedures input: RuntimeProfileRechargeRefundHoldPrepareInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRechargeRefundHoldProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/preview_profile_recharge_refund_hold_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/preview_profile_recharge_refund_hold_and_return_procedure.rs index d89f4664c..ac8898bb6 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/preview_profile_recharge_refund_hold_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/preview_profile_recharge_refund_hold_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait preview_profile_recharge_refund_hold_and_return { input: RuntimeProfileRechargeRefundHoldPreviewInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl preview_profile_recharge_refund_hold_and_return for super::RemoteProcedures input: RuntimeProfileRechargeRefundHoldPreviewInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRechargeRefundHoldProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/process_profile_wallet_refund_outbox_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/process_profile_wallet_refund_outbox_and_return_procedure.rs index c7fb461ec..8b6f64ccd 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/process_profile_wallet_refund_outbox_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/process_profile_wallet_refund_outbox_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait process_profile_wallet_refund_outbox_and_return { input: RuntimeProfileWalletRefundOutboxProcessInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl process_profile_wallet_refund_outbox_and_return for super::RemoteProcedures input: RuntimeProfileWalletRefundOutboxProcessInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileWalletRefundOutboxProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/prune_external_generation_job_history_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/prune_external_generation_job_history_and_return_procedure.rs index 37a9d55d5..877d06380 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/prune_external_generation_job_history_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/prune_external_generation_job_history_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait prune_external_generation_job_history_and_return { input: ExternalGenerationJobRetentionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl prune_external_generation_job_history_and_return for super::RemoteProcedure input: ExternalGenerationJobRetentionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ExternalGenerationJobRetentionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/public_work_play_daily_stat_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/public_work_play_daily_stat_table.rs index 5b589fc7a..3117ed994 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/public_work_play_daily_stat_table.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/public_work_play_daily_stat_table.rs @@ -222,7 +222,7 @@ pub trait public_work_play_daily_statQueryTableAccess { #[allow(non_snake_case)] /// Get a query builder for the table `PublicWorkPlayDailyStat`. fn public_work_play_daily_stat(&self) - -> __sdk::__query_builder::Table; + -> __sdk::__query_builder::Table; } impl public_work_play_daily_statQueryTableAccess for __sdk::QueryTableAccessor { diff --git a/server-rs/crates/spacetime-client/src/module_bindings/put_database_migration_import_chunk_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/put_database_migration_import_chunk_procedure.rs index f3776bfdc..597b25119 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/put_database_migration_import_chunk_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/put_database_migration_import_chunk_procedure.rs @@ -31,10 +31,10 @@ pub trait put_database_migration_import_chunk { input: DatabaseMigrationImportChunkInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl put_database_migration_import_chunk for super::RemoteProcedures { input: DatabaseMigrationImportChunkInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, DatabaseMigrationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_agent_message_kind_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_agent_message_kind_type.rs deleted file mode 100644 index ca46edeba..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_agent_message_kind_type.rs +++ /dev/null @@ -1,22 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum PuzzleAgentMessageKind { - Chat, - - Summary, - - ActionResult, - - Warning, -} - -impl __sdk::InModule for PuzzleAgentMessageKind { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_agent_message_role_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_agent_message_role_type.rs deleted file mode 100644 index 5dd7eb511..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_agent_message_role_type.rs +++ /dev/null @@ -1,20 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum PuzzleAgentMessageRole { - User, - - Assistant, - - System, -} - -impl __sdk::InModule for PuzzleAgentMessageRole { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_agent_message_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_agent_message_row_type.rs deleted file mode 100644 index b0bb85f2d..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_agent_message_row_type.rs +++ /dev/null @@ -1,69 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::puzzle_agent_message_kind_type::PuzzleAgentMessageKind; -use super::puzzle_agent_message_role_type::PuzzleAgentMessageRole; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct PuzzleAgentMessageRow { - pub message_id: String, - pub session_id: String, - pub role: PuzzleAgentMessageRole, - pub kind: PuzzleAgentMessageKind, - pub text: String, - pub created_at: __sdk::Timestamp, -} - -impl __sdk::InModule for PuzzleAgentMessageRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `PuzzleAgentMessageRow`. -/// -/// Provides typed access to columns for query building. -pub struct PuzzleAgentMessageRowCols { - pub message_id: __sdk::__query_builder::Col, - pub session_id: __sdk::__query_builder::Col, - pub role: __sdk::__query_builder::Col, - pub kind: __sdk::__query_builder::Col, - pub text: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for PuzzleAgentMessageRow { - type Cols = PuzzleAgentMessageRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - PuzzleAgentMessageRowCols { - message_id: __sdk::__query_builder::Col::new(table_name, "message_id"), - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - role: __sdk::__query_builder::Col::new(table_name, "role"), - kind: __sdk::__query_builder::Col::new(table_name, "kind"), - text: __sdk::__query_builder::Col::new(table_name, "text"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - } - } -} - -/// Indexed column accessor struct for the table `PuzzleAgentMessageRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct PuzzleAgentMessageRowIxCols { - pub message_id: __sdk::__query_builder::IxCol, - pub session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for PuzzleAgentMessageRow { - type IxCols = PuzzleAgentMessageRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - PuzzleAgentMessageRowIxCols { - message_id: __sdk::__query_builder::IxCol::new(table_name, "message_id"), - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for PuzzleAgentMessageRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_agent_message_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_agent_message_table.rs deleted file mode 100644 index eb26ee22d..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_agent_message_table.rs +++ /dev/null @@ -1,232 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::puzzle_agent_message_kind_type::PuzzleAgentMessageKind; -use super::puzzle_agent_message_role_type::PuzzleAgentMessageRole; -use super::puzzle_agent_message_row_type::PuzzleAgentMessageRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `puzzle_agent_message`. -/// -/// Obtain a handle from the [`PuzzleAgentMessageTableAccess::puzzle_agent_message`] method on [`super::RemoteTables`], -/// like `ctx.db.puzzle_agent_message()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.puzzle_agent_message().on_insert(...)`. -pub struct PuzzleAgentMessageTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `puzzle_agent_message`. -pub struct PuzzleAgentMessageTableAccessor; - -impl __sdk::TableAccessor for PuzzleAgentMessageTableAccessor { - type Row = PuzzleAgentMessageRow; - type Handle<'db> = PuzzleAgentMessageTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.puzzle_agent_message() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `puzzle_agent_message`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait PuzzleAgentMessageTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`PuzzleAgentMessageTableHandle`], which mediates access to the table `puzzle_agent_message`. - fn puzzle_agent_message(&self) -> PuzzleAgentMessageTableHandle<'_>; -} - -impl PuzzleAgentMessageTableAccess for super::RemoteTables { - fn puzzle_agent_message(&self) -> PuzzleAgentMessageTableHandle<'_> { - PuzzleAgentMessageTableHandle { - imp: self - .imp - .get_table::("puzzle_agent_message"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct PuzzleAgentMessageInsertCallbackId(__sdk::CallbackId); -pub struct PuzzleAgentMessageDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for PuzzleAgentMessageTableHandle<'ctx> { - type Row = PuzzleAgentMessageRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for PuzzleAgentMessageTableHandle<'ctx> { - type Row = PuzzleAgentMessageRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = PuzzleAgentMessageInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleAgentMessageInsertCallbackId { - PuzzleAgentMessageInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleAgentMessageInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = PuzzleAgentMessageDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleAgentMessageDeleteCallbackId { - PuzzleAgentMessageDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PuzzleAgentMessageDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for PuzzleAgentMessageTableHandle<'ctx> { - type InsertCallbackId = PuzzleAgentMessageInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleAgentMessageInsertCallbackId { - PuzzleAgentMessageInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleAgentMessageInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for PuzzleAgentMessageTableHandle<'ctx> { - type DeleteCallbackId = PuzzleAgentMessageDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleAgentMessageDeleteCallbackId { - PuzzleAgentMessageDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PuzzleAgentMessageDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct PuzzleAgentMessageUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for PuzzleAgentMessageTableHandle<'ctx> { - type UpdateCallbackId = PuzzleAgentMessageUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PuzzleAgentMessageUpdateCallbackId { - PuzzleAgentMessageUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PuzzleAgentMessageUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for PuzzleAgentMessageTableHandle<'ctx> { - type UpdateCallbackId = PuzzleAgentMessageUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PuzzleAgentMessageUpdateCallbackId { - PuzzleAgentMessageUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PuzzleAgentMessageUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `message_id` unique index on the table `puzzle_agent_message`, -/// which allows point queries on the field of the same name -/// via the [`PuzzleAgentMessageMessageIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.puzzle_agent_message().message_id().find(...)`. -pub struct PuzzleAgentMessageMessageIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> PuzzleAgentMessageTableHandle<'ctx> { - /// Get a handle on the `message_id` unique index on the table `puzzle_agent_message`. - pub fn message_id(&self) -> PuzzleAgentMessageMessageIdUnique<'ctx> { - PuzzleAgentMessageMessageIdUnique { - imp: self.imp.get_unique_constraint::("message_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> PuzzleAgentMessageMessageIdUnique<'ctx> { - /// Find the subscribed row whose `message_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("puzzle_agent_message"); - _table.add_unique_constraint::("message_id", |row| &row.message_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `PuzzleAgentMessageRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait puzzle_agent_messageQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `PuzzleAgentMessageRow`. - fn puzzle_agent_message(&self) -> __sdk::__query_builder::Table; -} - -impl puzzle_agent_messageQueryTableAccess for __sdk::QueryTableAccessor { - fn puzzle_agent_message(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("puzzle_agent_message") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_agent_session_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_agent_session_row_type.rs deleted file mode 100644 index e056ada1a..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_agent_session_row_type.rs +++ /dev/null @@ -1,92 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::puzzle_agent_stage_type::PuzzleAgentStage; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct PuzzleAgentSessionRow { - pub session_id: String, - pub owner_user_id: String, - pub seed_text: String, - pub current_turn: u32, - pub progress_percent: u32, - pub stage: PuzzleAgentStage, - pub anchor_pack_json: String, - pub draft_json: Option, - pub last_assistant_reply: Option, - pub published_profile_id: Option, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for PuzzleAgentSessionRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `PuzzleAgentSessionRow`. -/// -/// Provides typed access to columns for query building. -pub struct PuzzleAgentSessionRowCols { - pub session_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub seed_text: __sdk::__query_builder::Col, - pub current_turn: __sdk::__query_builder::Col, - pub progress_percent: __sdk::__query_builder::Col, - pub stage: __sdk::__query_builder::Col, - pub anchor_pack_json: __sdk::__query_builder::Col, - pub draft_json: __sdk::__query_builder::Col>, - pub last_assistant_reply: __sdk::__query_builder::Col>, - pub published_profile_id: __sdk::__query_builder::Col>, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for PuzzleAgentSessionRow { - type Cols = PuzzleAgentSessionRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - PuzzleAgentSessionRowCols { - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - seed_text: __sdk::__query_builder::Col::new(table_name, "seed_text"), - current_turn: __sdk::__query_builder::Col::new(table_name, "current_turn"), - progress_percent: __sdk::__query_builder::Col::new(table_name, "progress_percent"), - stage: __sdk::__query_builder::Col::new(table_name, "stage"), - anchor_pack_json: __sdk::__query_builder::Col::new(table_name, "anchor_pack_json"), - draft_json: __sdk::__query_builder::Col::new(table_name, "draft_json"), - last_assistant_reply: __sdk::__query_builder::Col::new( - table_name, - "last_assistant_reply", - ), - published_profile_id: __sdk::__query_builder::Col::new( - table_name, - "published_profile_id", - ), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `PuzzleAgentSessionRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct PuzzleAgentSessionRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for PuzzleAgentSessionRow { - type IxCols = PuzzleAgentSessionRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - PuzzleAgentSessionRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for PuzzleAgentSessionRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_agent_session_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_agent_session_table.rs deleted file mode 100644 index a4072181c..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_agent_session_table.rs +++ /dev/null @@ -1,231 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::puzzle_agent_session_row_type::PuzzleAgentSessionRow; -use super::puzzle_agent_stage_type::PuzzleAgentStage; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `puzzle_agent_session`. -/// -/// Obtain a handle from the [`PuzzleAgentSessionTableAccess::puzzle_agent_session`] method on [`super::RemoteTables`], -/// like `ctx.db.puzzle_agent_session()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.puzzle_agent_session().on_insert(...)`. -pub struct PuzzleAgentSessionTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `puzzle_agent_session`. -pub struct PuzzleAgentSessionTableAccessor; - -impl __sdk::TableAccessor for PuzzleAgentSessionTableAccessor { - type Row = PuzzleAgentSessionRow; - type Handle<'db> = PuzzleAgentSessionTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.puzzle_agent_session() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `puzzle_agent_session`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait PuzzleAgentSessionTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`PuzzleAgentSessionTableHandle`], which mediates access to the table `puzzle_agent_session`. - fn puzzle_agent_session(&self) -> PuzzleAgentSessionTableHandle<'_>; -} - -impl PuzzleAgentSessionTableAccess for super::RemoteTables { - fn puzzle_agent_session(&self) -> PuzzleAgentSessionTableHandle<'_> { - PuzzleAgentSessionTableHandle { - imp: self - .imp - .get_table::("puzzle_agent_session"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct PuzzleAgentSessionInsertCallbackId(__sdk::CallbackId); -pub struct PuzzleAgentSessionDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for PuzzleAgentSessionTableHandle<'ctx> { - type Row = PuzzleAgentSessionRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for PuzzleAgentSessionTableHandle<'ctx> { - type Row = PuzzleAgentSessionRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = PuzzleAgentSessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleAgentSessionInsertCallbackId { - PuzzleAgentSessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleAgentSessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = PuzzleAgentSessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleAgentSessionDeleteCallbackId { - PuzzleAgentSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PuzzleAgentSessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for PuzzleAgentSessionTableHandle<'ctx> { - type InsertCallbackId = PuzzleAgentSessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleAgentSessionInsertCallbackId { - PuzzleAgentSessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleAgentSessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for PuzzleAgentSessionTableHandle<'ctx> { - type DeleteCallbackId = PuzzleAgentSessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleAgentSessionDeleteCallbackId { - PuzzleAgentSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PuzzleAgentSessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct PuzzleAgentSessionUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for PuzzleAgentSessionTableHandle<'ctx> { - type UpdateCallbackId = PuzzleAgentSessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PuzzleAgentSessionUpdateCallbackId { - PuzzleAgentSessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PuzzleAgentSessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for PuzzleAgentSessionTableHandle<'ctx> { - type UpdateCallbackId = PuzzleAgentSessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PuzzleAgentSessionUpdateCallbackId { - PuzzleAgentSessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PuzzleAgentSessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `session_id` unique index on the table `puzzle_agent_session`, -/// which allows point queries on the field of the same name -/// via the [`PuzzleAgentSessionSessionIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.puzzle_agent_session().session_id().find(...)`. -pub struct PuzzleAgentSessionSessionIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> PuzzleAgentSessionTableHandle<'ctx> { - /// Get a handle on the `session_id` unique index on the table `puzzle_agent_session`. - pub fn session_id(&self) -> PuzzleAgentSessionSessionIdUnique<'ctx> { - PuzzleAgentSessionSessionIdUnique { - imp: self.imp.get_unique_constraint::("session_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> PuzzleAgentSessionSessionIdUnique<'ctx> { - /// Find the subscribed row whose `session_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("puzzle_agent_session"); - _table.add_unique_constraint::("session_id", |row| &row.session_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `PuzzleAgentSessionRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait puzzle_agent_sessionQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `PuzzleAgentSessionRow`. - fn puzzle_agent_session(&self) -> __sdk::__query_builder::Table; -} - -impl puzzle_agent_sessionQueryTableAccess for __sdk::QueryTableAccessor { - fn puzzle_agent_session(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("puzzle_agent_session") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_agent_stage_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_agent_stage_type.rs deleted file mode 100644 index 9d41ea54d..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_agent_stage_type.rs +++ /dev/null @@ -1,24 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum PuzzleAgentStage { - CollectingAnchors, - - DraftReady, - - ImageRefining, - - ReadyToPublish, - - Published, -} - -impl __sdk::InModule for PuzzleAgentStage { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_background_compile_task_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_background_compile_task_row_type.rs deleted file mode 100644 index 49e1bf07e..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_background_compile_task_row_type.rs +++ /dev/null @@ -1,66 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct PuzzleBackgroundCompileTaskRow { - pub task_id: String, - pub claim_id: String, - pub session_id: String, - pub owner_user_id: String, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for PuzzleBackgroundCompileTaskRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `PuzzleBackgroundCompileTaskRow`. -/// -/// Provides typed access to columns for query building. -pub struct PuzzleBackgroundCompileTaskRowCols { - pub task_id: __sdk::__query_builder::Col, - pub claim_id: __sdk::__query_builder::Col, - pub session_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for PuzzleBackgroundCompileTaskRow { - type Cols = PuzzleBackgroundCompileTaskRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - PuzzleBackgroundCompileTaskRowCols { - task_id: __sdk::__query_builder::Col::new(table_name, "task_id"), - claim_id: __sdk::__query_builder::Col::new(table_name, "claim_id"), - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `PuzzleBackgroundCompileTaskRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct PuzzleBackgroundCompileTaskRowIxCols { - pub session_id: __sdk::__query_builder::IxCol, - pub task_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for PuzzleBackgroundCompileTaskRow { - type IxCols = PuzzleBackgroundCompileTaskRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - PuzzleBackgroundCompileTaskRowIxCols { - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - task_id: __sdk::__query_builder::IxCol::new(table_name, "task_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for PuzzleBackgroundCompileTaskRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_background_compile_task_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_background_compile_task_table.rs deleted file mode 100644 index 4982944ad..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_background_compile_task_table.rs +++ /dev/null @@ -1,238 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::puzzle_background_compile_task_row_type::PuzzleBackgroundCompileTaskRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `puzzle_background_compile_task`. -/// -/// Obtain a handle from the [`PuzzleBackgroundCompileTaskTableAccess::puzzle_background_compile_task`] method on [`super::RemoteTables`], -/// like `ctx.db.puzzle_background_compile_task()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.puzzle_background_compile_task().on_insert(...)`. -pub struct PuzzleBackgroundCompileTaskTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `puzzle_background_compile_task`. -pub struct PuzzleBackgroundCompileTaskTableAccessor; - -impl __sdk::TableAccessor for PuzzleBackgroundCompileTaskTableAccessor { - type Row = PuzzleBackgroundCompileTaskRow; - type Handle<'db> = PuzzleBackgroundCompileTaskTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.puzzle_background_compile_task() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `puzzle_background_compile_task`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait PuzzleBackgroundCompileTaskTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`PuzzleBackgroundCompileTaskTableHandle`], which mediates access to the table `puzzle_background_compile_task`. - fn puzzle_background_compile_task(&self) -> PuzzleBackgroundCompileTaskTableHandle<'_>; -} - -impl PuzzleBackgroundCompileTaskTableAccess for super::RemoteTables { - fn puzzle_background_compile_task(&self) -> PuzzleBackgroundCompileTaskTableHandle<'_> { - PuzzleBackgroundCompileTaskTableHandle { - imp: self - .imp - .get_table::("puzzle_background_compile_task"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct PuzzleBackgroundCompileTaskInsertCallbackId(__sdk::CallbackId); -pub struct PuzzleBackgroundCompileTaskDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for PuzzleBackgroundCompileTaskTableHandle<'ctx> { - type Row = PuzzleBackgroundCompileTaskRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for PuzzleBackgroundCompileTaskTableHandle<'ctx> { - type Row = PuzzleBackgroundCompileTaskRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = PuzzleBackgroundCompileTaskInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleBackgroundCompileTaskInsertCallbackId { - PuzzleBackgroundCompileTaskInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleBackgroundCompileTaskInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = PuzzleBackgroundCompileTaskDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleBackgroundCompileTaskDeleteCallbackId { - PuzzleBackgroundCompileTaskDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PuzzleBackgroundCompileTaskDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for PuzzleBackgroundCompileTaskTableHandle<'ctx> { - type InsertCallbackId = PuzzleBackgroundCompileTaskInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleBackgroundCompileTaskInsertCallbackId { - PuzzleBackgroundCompileTaskInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleBackgroundCompileTaskInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for PuzzleBackgroundCompileTaskTableHandle<'ctx> { - type DeleteCallbackId = PuzzleBackgroundCompileTaskDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleBackgroundCompileTaskDeleteCallbackId { - PuzzleBackgroundCompileTaskDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PuzzleBackgroundCompileTaskDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct PuzzleBackgroundCompileTaskUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for PuzzleBackgroundCompileTaskTableHandle<'ctx> { - type UpdateCallbackId = PuzzleBackgroundCompileTaskUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PuzzleBackgroundCompileTaskUpdateCallbackId { - PuzzleBackgroundCompileTaskUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PuzzleBackgroundCompileTaskUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for PuzzleBackgroundCompileTaskTableHandle<'ctx> { - type UpdateCallbackId = PuzzleBackgroundCompileTaskUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PuzzleBackgroundCompileTaskUpdateCallbackId { - PuzzleBackgroundCompileTaskUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PuzzleBackgroundCompileTaskUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `task_id` unique index on the table `puzzle_background_compile_task`, -/// which allows point queries on the field of the same name -/// via the [`PuzzleBackgroundCompileTaskTaskIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.puzzle_background_compile_task().task_id().find(...)`. -pub struct PuzzleBackgroundCompileTaskTaskIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> PuzzleBackgroundCompileTaskTableHandle<'ctx> { - /// Get a handle on the `task_id` unique index on the table `puzzle_background_compile_task`. - pub fn task_id(&self) -> PuzzleBackgroundCompileTaskTaskIdUnique<'ctx> { - PuzzleBackgroundCompileTaskTaskIdUnique { - imp: self.imp.get_unique_constraint::("task_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> PuzzleBackgroundCompileTaskTaskIdUnique<'ctx> { - /// Find the subscribed row whose `task_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache - .get_or_make_table::("puzzle_background_compile_task"); - _table.add_unique_constraint::("task_id", |row| &row.task_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse( - "TableUpdate", - "TableUpdate", - ) - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `PuzzleBackgroundCompileTaskRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait puzzle_background_compile_taskQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `PuzzleBackgroundCompileTaskRow`. - fn puzzle_background_compile_task( - &self, - ) -> __sdk::__query_builder::Table; -} - -impl puzzle_background_compile_taskQueryTableAccess for __sdk::QueryTableAccessor { - fn puzzle_background_compile_task( - &self, - ) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("puzzle_background_compile_task") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_agent_session_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_agent_session_row_type.rs deleted file mode 100644 index 697bb9222..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_agent_session_row_type.rs +++ /dev/null @@ -1,72 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct PuzzleClearAgentSessionRow { - pub session_id: String, - pub owner_user_id: String, - pub status: String, - pub draft_json: String, - pub published_profile_id: String, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for PuzzleClearAgentSessionRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `PuzzleClearAgentSessionRow`. -/// -/// Provides typed access to columns for query building. -pub struct PuzzleClearAgentSessionRowCols { - pub session_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub status: __sdk::__query_builder::Col, - pub draft_json: __sdk::__query_builder::Col, - pub published_profile_id: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for PuzzleClearAgentSessionRow { - type Cols = PuzzleClearAgentSessionRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - PuzzleClearAgentSessionRowCols { - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - status: __sdk::__query_builder::Col::new(table_name, "status"), - draft_json: __sdk::__query_builder::Col::new(table_name, "draft_json"), - published_profile_id: __sdk::__query_builder::Col::new( - table_name, - "published_profile_id", - ), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `PuzzleClearAgentSessionRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct PuzzleClearAgentSessionRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for PuzzleClearAgentSessionRow { - type IxCols = PuzzleClearAgentSessionRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - PuzzleClearAgentSessionRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for PuzzleClearAgentSessionRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_agent_session_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_agent_session_table.rs deleted file mode 100644 index 68f508729..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_agent_session_table.rs +++ /dev/null @@ -1,235 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::puzzle_clear_agent_session_row_type::PuzzleClearAgentSessionRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `puzzle_clear_agent_session`. -/// -/// Obtain a handle from the [`PuzzleClearAgentSessionTableAccess::puzzle_clear_agent_session`] method on [`super::RemoteTables`], -/// like `ctx.db.puzzle_clear_agent_session()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.puzzle_clear_agent_session().on_insert(...)`. -pub struct PuzzleClearAgentSessionTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `puzzle_clear_agent_session`. -pub struct PuzzleClearAgentSessionTableAccessor; - -impl __sdk::TableAccessor for PuzzleClearAgentSessionTableAccessor { - type Row = PuzzleClearAgentSessionRow; - type Handle<'db> = PuzzleClearAgentSessionTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.puzzle_clear_agent_session() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `puzzle_clear_agent_session`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait PuzzleClearAgentSessionTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`PuzzleClearAgentSessionTableHandle`], which mediates access to the table `puzzle_clear_agent_session`. - fn puzzle_clear_agent_session(&self) -> PuzzleClearAgentSessionTableHandle<'_>; -} - -impl PuzzleClearAgentSessionTableAccess for super::RemoteTables { - fn puzzle_clear_agent_session(&self) -> PuzzleClearAgentSessionTableHandle<'_> { - PuzzleClearAgentSessionTableHandle { - imp: self - .imp - .get_table::("puzzle_clear_agent_session"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct PuzzleClearAgentSessionInsertCallbackId(__sdk::CallbackId); -pub struct PuzzleClearAgentSessionDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for PuzzleClearAgentSessionTableHandle<'ctx> { - type Row = PuzzleClearAgentSessionRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for PuzzleClearAgentSessionTableHandle<'ctx> { - type Row = PuzzleClearAgentSessionRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = PuzzleClearAgentSessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleClearAgentSessionInsertCallbackId { - PuzzleClearAgentSessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleClearAgentSessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = PuzzleClearAgentSessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleClearAgentSessionDeleteCallbackId { - PuzzleClearAgentSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PuzzleClearAgentSessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for PuzzleClearAgentSessionTableHandle<'ctx> { - type InsertCallbackId = PuzzleClearAgentSessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleClearAgentSessionInsertCallbackId { - PuzzleClearAgentSessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleClearAgentSessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for PuzzleClearAgentSessionTableHandle<'ctx> { - type DeleteCallbackId = PuzzleClearAgentSessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleClearAgentSessionDeleteCallbackId { - PuzzleClearAgentSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PuzzleClearAgentSessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct PuzzleClearAgentSessionUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for PuzzleClearAgentSessionTableHandle<'ctx> { - type UpdateCallbackId = PuzzleClearAgentSessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PuzzleClearAgentSessionUpdateCallbackId { - PuzzleClearAgentSessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PuzzleClearAgentSessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for PuzzleClearAgentSessionTableHandle<'ctx> { - type UpdateCallbackId = PuzzleClearAgentSessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PuzzleClearAgentSessionUpdateCallbackId { - PuzzleClearAgentSessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PuzzleClearAgentSessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `session_id` unique index on the table `puzzle_clear_agent_session`, -/// which allows point queries on the field of the same name -/// via the [`PuzzleClearAgentSessionSessionIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.puzzle_clear_agent_session().session_id().find(...)`. -pub struct PuzzleClearAgentSessionSessionIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> PuzzleClearAgentSessionTableHandle<'ctx> { - /// Get a handle on the `session_id` unique index on the table `puzzle_clear_agent_session`. - pub fn session_id(&self) -> PuzzleClearAgentSessionSessionIdUnique<'ctx> { - PuzzleClearAgentSessionSessionIdUnique { - imp: self.imp.get_unique_constraint::("session_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> PuzzleClearAgentSessionSessionIdUnique<'ctx> { - /// Find the subscribed row whose `session_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("puzzle_clear_agent_session"); - _table.add_unique_constraint::("session_id", |row| &row.session_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `PuzzleClearAgentSessionRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait puzzle_clear_agent_sessionQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `PuzzleClearAgentSessionRow`. - fn puzzle_clear_agent_session( - &self, - ) -> __sdk::__query_builder::Table; -} - -impl puzzle_clear_agent_sessionQueryTableAccess for __sdk::QueryTableAccessor { - fn puzzle_clear_agent_session( - &self, - ) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("puzzle_clear_agent_session") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_event_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_event_row_type.rs deleted file mode 100644 index 00fcb66f9..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_event_row_type.rs +++ /dev/null @@ -1,71 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct PuzzleClearEventRow { - pub event_id: String, - pub owner_user_id: String, - pub profile_id: String, - pub run_id: String, - pub event_type: String, - pub result: String, - pub occurred_at: __sdk::Timestamp, -} - -impl __sdk::InModule for PuzzleClearEventRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `PuzzleClearEventRow`. -/// -/// Provides typed access to columns for query building. -pub struct PuzzleClearEventRowCols { - pub event_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub profile_id: __sdk::__query_builder::Col, - pub run_id: __sdk::__query_builder::Col, - pub event_type: __sdk::__query_builder::Col, - pub result: __sdk::__query_builder::Col, - pub occurred_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for PuzzleClearEventRow { - type Cols = PuzzleClearEventRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - PuzzleClearEventRowCols { - event_id: __sdk::__query_builder::Col::new(table_name, "event_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - run_id: __sdk::__query_builder::Col::new(table_name, "run_id"), - event_type: __sdk::__query_builder::Col::new(table_name, "event_type"), - result: __sdk::__query_builder::Col::new(table_name, "result"), - occurred_at: __sdk::__query_builder::Col::new(table_name, "occurred_at"), - } - } -} - -/// Indexed column accessor struct for the table `PuzzleClearEventRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct PuzzleClearEventRowIxCols { - pub event_id: __sdk::__query_builder::IxCol, - pub profile_id: __sdk::__query_builder::IxCol, - pub run_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for PuzzleClearEventRow { - type IxCols = PuzzleClearEventRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - PuzzleClearEventRowIxCols { - event_id: __sdk::__query_builder::IxCol::new(table_name, "event_id"), - profile_id: __sdk::__query_builder::IxCol::new(table_name, "profile_id"), - run_id: __sdk::__query_builder::IxCol::new(table_name, "run_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for PuzzleClearEventRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_event_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_event_table.rs deleted file mode 100644 index 4f506a433..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_event_table.rs +++ /dev/null @@ -1,230 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::puzzle_clear_event_row_type::PuzzleClearEventRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `puzzle_clear_event`. -/// -/// Obtain a handle from the [`PuzzleClearEventTableAccess::puzzle_clear_event`] method on [`super::RemoteTables`], -/// like `ctx.db.puzzle_clear_event()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.puzzle_clear_event().on_insert(...)`. -pub struct PuzzleClearEventTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `puzzle_clear_event`. -pub struct PuzzleClearEventTableAccessor; - -impl __sdk::TableAccessor for PuzzleClearEventTableAccessor { - type Row = PuzzleClearEventRow; - type Handle<'db> = PuzzleClearEventTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.puzzle_clear_event() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `puzzle_clear_event`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait PuzzleClearEventTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`PuzzleClearEventTableHandle`], which mediates access to the table `puzzle_clear_event`. - fn puzzle_clear_event(&self) -> PuzzleClearEventTableHandle<'_>; -} - -impl PuzzleClearEventTableAccess for super::RemoteTables { - fn puzzle_clear_event(&self) -> PuzzleClearEventTableHandle<'_> { - PuzzleClearEventTableHandle { - imp: self - .imp - .get_table::("puzzle_clear_event"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct PuzzleClearEventInsertCallbackId(__sdk::CallbackId); -pub struct PuzzleClearEventDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for PuzzleClearEventTableHandle<'ctx> { - type Row = PuzzleClearEventRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for PuzzleClearEventTableHandle<'ctx> { - type Row = PuzzleClearEventRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = PuzzleClearEventInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleClearEventInsertCallbackId { - PuzzleClearEventInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleClearEventInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = PuzzleClearEventDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleClearEventDeleteCallbackId { - PuzzleClearEventDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PuzzleClearEventDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for PuzzleClearEventTableHandle<'ctx> { - type InsertCallbackId = PuzzleClearEventInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleClearEventInsertCallbackId { - PuzzleClearEventInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleClearEventInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for PuzzleClearEventTableHandle<'ctx> { - type DeleteCallbackId = PuzzleClearEventDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleClearEventDeleteCallbackId { - PuzzleClearEventDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PuzzleClearEventDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct PuzzleClearEventUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for PuzzleClearEventTableHandle<'ctx> { - type UpdateCallbackId = PuzzleClearEventUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PuzzleClearEventUpdateCallbackId { - PuzzleClearEventUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PuzzleClearEventUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for PuzzleClearEventTableHandle<'ctx> { - type UpdateCallbackId = PuzzleClearEventUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PuzzleClearEventUpdateCallbackId { - PuzzleClearEventUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PuzzleClearEventUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `event_id` unique index on the table `puzzle_clear_event`, -/// which allows point queries on the field of the same name -/// via the [`PuzzleClearEventEventIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.puzzle_clear_event().event_id().find(...)`. -pub struct PuzzleClearEventEventIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> PuzzleClearEventTableHandle<'ctx> { - /// Get a handle on the `event_id` unique index on the table `puzzle_clear_event`. - pub fn event_id(&self) -> PuzzleClearEventEventIdUnique<'ctx> { - PuzzleClearEventEventIdUnique { - imp: self.imp.get_unique_constraint::("event_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> PuzzleClearEventEventIdUnique<'ctx> { - /// Find the subscribed row whose `event_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("puzzle_clear_event"); - _table.add_unique_constraint::("event_id", |row| &row.event_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `PuzzleClearEventRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait puzzle_clear_eventQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `PuzzleClearEventRow`. - fn puzzle_clear_event(&self) -> __sdk::__query_builder::Table; -} - -impl puzzle_clear_eventQueryTableAccess for __sdk::QueryTableAccessor { - fn puzzle_clear_event(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("puzzle_clear_event") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_runtime_run_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_runtime_run_row_type.rs deleted file mode 100644 index fa99c892f..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_runtime_run_row_type.rs +++ /dev/null @@ -1,83 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct PuzzleClearRuntimeRunRow { - pub run_id: String, - pub owner_user_id: String, - pub profile_id: String, - pub status: String, - pub level_index: u32, - pub clears_done: u32, - pub snapshot_json: String, - pub started_at_ms: i64, - pub finished_at_ms: i64, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for PuzzleClearRuntimeRunRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `PuzzleClearRuntimeRunRow`. -/// -/// Provides typed access to columns for query building. -pub struct PuzzleClearRuntimeRunRowCols { - pub run_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub profile_id: __sdk::__query_builder::Col, - pub status: __sdk::__query_builder::Col, - pub level_index: __sdk::__query_builder::Col, - pub clears_done: __sdk::__query_builder::Col, - pub snapshot_json: __sdk::__query_builder::Col, - pub started_at_ms: __sdk::__query_builder::Col, - pub finished_at_ms: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for PuzzleClearRuntimeRunRow { - type Cols = PuzzleClearRuntimeRunRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - PuzzleClearRuntimeRunRowCols { - run_id: __sdk::__query_builder::Col::new(table_name, "run_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - status: __sdk::__query_builder::Col::new(table_name, "status"), - level_index: __sdk::__query_builder::Col::new(table_name, "level_index"), - clears_done: __sdk::__query_builder::Col::new(table_name, "clears_done"), - snapshot_json: __sdk::__query_builder::Col::new(table_name, "snapshot_json"), - started_at_ms: __sdk::__query_builder::Col::new(table_name, "started_at_ms"), - finished_at_ms: __sdk::__query_builder::Col::new(table_name, "finished_at_ms"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `PuzzleClearRuntimeRunRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct PuzzleClearRuntimeRunRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub profile_id: __sdk::__query_builder::IxCol, - pub run_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for PuzzleClearRuntimeRunRow { - type IxCols = PuzzleClearRuntimeRunRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - PuzzleClearRuntimeRunRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::IxCol::new(table_name, "profile_id"), - run_id: __sdk::__query_builder::IxCol::new(table_name, "run_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for PuzzleClearRuntimeRunRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_runtime_run_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_runtime_run_table.rs deleted file mode 100644 index dc7a1f89b..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_runtime_run_table.rs +++ /dev/null @@ -1,231 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::puzzle_clear_runtime_run_row_type::PuzzleClearRuntimeRunRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `puzzle_clear_runtime_run`. -/// -/// Obtain a handle from the [`PuzzleClearRuntimeRunTableAccess::puzzle_clear_runtime_run`] method on [`super::RemoteTables`], -/// like `ctx.db.puzzle_clear_runtime_run()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.puzzle_clear_runtime_run().on_insert(...)`. -pub struct PuzzleClearRuntimeRunTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `puzzle_clear_runtime_run`. -pub struct PuzzleClearRuntimeRunTableAccessor; - -impl __sdk::TableAccessor for PuzzleClearRuntimeRunTableAccessor { - type Row = PuzzleClearRuntimeRunRow; - type Handle<'db> = PuzzleClearRuntimeRunTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.puzzle_clear_runtime_run() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `puzzle_clear_runtime_run`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait PuzzleClearRuntimeRunTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`PuzzleClearRuntimeRunTableHandle`], which mediates access to the table `puzzle_clear_runtime_run`. - fn puzzle_clear_runtime_run(&self) -> PuzzleClearRuntimeRunTableHandle<'_>; -} - -impl PuzzleClearRuntimeRunTableAccess for super::RemoteTables { - fn puzzle_clear_runtime_run(&self) -> PuzzleClearRuntimeRunTableHandle<'_> { - PuzzleClearRuntimeRunTableHandle { - imp: self - .imp - .get_table::("puzzle_clear_runtime_run"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct PuzzleClearRuntimeRunInsertCallbackId(__sdk::CallbackId); -pub struct PuzzleClearRuntimeRunDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for PuzzleClearRuntimeRunTableHandle<'ctx> { - type Row = PuzzleClearRuntimeRunRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for PuzzleClearRuntimeRunTableHandle<'ctx> { - type Row = PuzzleClearRuntimeRunRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = PuzzleClearRuntimeRunInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleClearRuntimeRunInsertCallbackId { - PuzzleClearRuntimeRunInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleClearRuntimeRunInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = PuzzleClearRuntimeRunDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleClearRuntimeRunDeleteCallbackId { - PuzzleClearRuntimeRunDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PuzzleClearRuntimeRunDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for PuzzleClearRuntimeRunTableHandle<'ctx> { - type InsertCallbackId = PuzzleClearRuntimeRunInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleClearRuntimeRunInsertCallbackId { - PuzzleClearRuntimeRunInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleClearRuntimeRunInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for PuzzleClearRuntimeRunTableHandle<'ctx> { - type DeleteCallbackId = PuzzleClearRuntimeRunDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleClearRuntimeRunDeleteCallbackId { - PuzzleClearRuntimeRunDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PuzzleClearRuntimeRunDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct PuzzleClearRuntimeRunUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for PuzzleClearRuntimeRunTableHandle<'ctx> { - type UpdateCallbackId = PuzzleClearRuntimeRunUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PuzzleClearRuntimeRunUpdateCallbackId { - PuzzleClearRuntimeRunUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PuzzleClearRuntimeRunUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for PuzzleClearRuntimeRunTableHandle<'ctx> { - type UpdateCallbackId = PuzzleClearRuntimeRunUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PuzzleClearRuntimeRunUpdateCallbackId { - PuzzleClearRuntimeRunUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PuzzleClearRuntimeRunUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `run_id` unique index on the table `puzzle_clear_runtime_run`, -/// which allows point queries on the field of the same name -/// via the [`PuzzleClearRuntimeRunRunIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.puzzle_clear_runtime_run().run_id().find(...)`. -pub struct PuzzleClearRuntimeRunRunIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> PuzzleClearRuntimeRunTableHandle<'ctx> { - /// Get a handle on the `run_id` unique index on the table `puzzle_clear_runtime_run`. - pub fn run_id(&self) -> PuzzleClearRuntimeRunRunIdUnique<'ctx> { - PuzzleClearRuntimeRunRunIdUnique { - imp: self.imp.get_unique_constraint::("run_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> PuzzleClearRuntimeRunRunIdUnique<'ctx> { - /// Find the subscribed row whose `run_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("puzzle_clear_runtime_run"); - _table.add_unique_constraint::("run_id", |row| &row.run_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `PuzzleClearRuntimeRunRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait puzzle_clear_runtime_runQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `PuzzleClearRuntimeRunRow`. - fn puzzle_clear_runtime_run(&self) -> __sdk::__query_builder::Table; -} - -impl puzzle_clear_runtime_runQueryTableAccess for __sdk::QueryTableAccessor { - fn puzzle_clear_runtime_run(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("puzzle_clear_runtime_run") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_work_profile_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_work_profile_row_type.rs deleted file mode 100644 index 601eb56a0..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_work_profile_row_type.rs +++ /dev/null @@ -1,139 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct PuzzleClearWorkProfileRow { - pub profile_id: String, - pub work_id: String, - pub owner_user_id: String, - pub source_session_id: String, - pub author_display_name: String, - pub work_title: String, - pub work_description: String, - pub theme_prompt: String, - pub generate_board_background: bool, - pub board_background_asset_json: String, - pub board_background_prompt: Option, - pub card_back_image_src: String, - pub atlas_asset_json: String, - pub pattern_groups_json: String, - pub card_assets_json: String, - pub cover_image_src: String, - pub generation_status: String, - pub publication_status: String, - pub play_count: u32, - pub updated_at: __sdk::Timestamp, - pub published_at: Option<__sdk::Timestamp>, - pub visible: bool, -} - -impl __sdk::InModule for PuzzleClearWorkProfileRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `PuzzleClearWorkProfileRow`. -/// -/// Provides typed access to columns for query building. -pub struct PuzzleClearWorkProfileRowCols { - pub profile_id: __sdk::__query_builder::Col, - pub work_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub source_session_id: __sdk::__query_builder::Col, - pub author_display_name: __sdk::__query_builder::Col, - pub work_title: __sdk::__query_builder::Col, - pub work_description: __sdk::__query_builder::Col, - pub theme_prompt: __sdk::__query_builder::Col, - pub generate_board_background: __sdk::__query_builder::Col, - pub board_background_asset_json: __sdk::__query_builder::Col, - pub board_background_prompt: - __sdk::__query_builder::Col>, - pub card_back_image_src: __sdk::__query_builder::Col, - pub atlas_asset_json: __sdk::__query_builder::Col, - pub pattern_groups_json: __sdk::__query_builder::Col, - pub card_assets_json: __sdk::__query_builder::Col, - pub cover_image_src: __sdk::__query_builder::Col, - pub generation_status: __sdk::__query_builder::Col, - pub publication_status: __sdk::__query_builder::Col, - pub play_count: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, - pub published_at: - __sdk::__query_builder::Col>, - pub visible: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for PuzzleClearWorkProfileRow { - type Cols = PuzzleClearWorkProfileRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - PuzzleClearWorkProfileRowCols { - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - work_id: __sdk::__query_builder::Col::new(table_name, "work_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - source_session_id: __sdk::__query_builder::Col::new(table_name, "source_session_id"), - author_display_name: __sdk::__query_builder::Col::new( - table_name, - "author_display_name", - ), - work_title: __sdk::__query_builder::Col::new(table_name, "work_title"), - work_description: __sdk::__query_builder::Col::new(table_name, "work_description"), - theme_prompt: __sdk::__query_builder::Col::new(table_name, "theme_prompt"), - generate_board_background: __sdk::__query_builder::Col::new( - table_name, - "generate_board_background", - ), - board_background_asset_json: __sdk::__query_builder::Col::new( - table_name, - "board_background_asset_json", - ), - board_background_prompt: __sdk::__query_builder::Col::new( - table_name, - "board_background_prompt", - ), - card_back_image_src: __sdk::__query_builder::Col::new( - table_name, - "card_back_image_src", - ), - atlas_asset_json: __sdk::__query_builder::Col::new(table_name, "atlas_asset_json"), - pattern_groups_json: __sdk::__query_builder::Col::new( - table_name, - "pattern_groups_json", - ), - card_assets_json: __sdk::__query_builder::Col::new(table_name, "card_assets_json"), - cover_image_src: __sdk::__query_builder::Col::new(table_name, "cover_image_src"), - generation_status: __sdk::__query_builder::Col::new(table_name, "generation_status"), - publication_status: __sdk::__query_builder::Col::new(table_name, "publication_status"), - play_count: __sdk::__query_builder::Col::new(table_name, "play_count"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - published_at: __sdk::__query_builder::Col::new(table_name, "published_at"), - visible: __sdk::__query_builder::Col::new(table_name, "visible"), - } - } -} - -/// Indexed column accessor struct for the table `PuzzleClearWorkProfileRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct PuzzleClearWorkProfileRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub profile_id: __sdk::__query_builder::IxCol, - pub publication_status: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for PuzzleClearWorkProfileRow { - type IxCols = PuzzleClearWorkProfileRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - PuzzleClearWorkProfileRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::IxCol::new(table_name, "profile_id"), - publication_status: __sdk::__query_builder::IxCol::new( - table_name, - "publication_status", - ), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for PuzzleClearWorkProfileRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_work_profile_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_work_profile_table.rs deleted file mode 100644 index 71c5a5084..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_clear_work_profile_table.rs +++ /dev/null @@ -1,234 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::puzzle_clear_work_profile_row_type::PuzzleClearWorkProfileRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `puzzle_clear_work_profile`. -/// -/// Obtain a handle from the [`PuzzleClearWorkProfileTableAccess::puzzle_clear_work_profile`] method on [`super::RemoteTables`], -/// like `ctx.db.puzzle_clear_work_profile()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.puzzle_clear_work_profile().on_insert(...)`. -pub struct PuzzleClearWorkProfileTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `puzzle_clear_work_profile`. -pub struct PuzzleClearWorkProfileTableAccessor; - -impl __sdk::TableAccessor for PuzzleClearWorkProfileTableAccessor { - type Row = PuzzleClearWorkProfileRow; - type Handle<'db> = PuzzleClearWorkProfileTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.puzzle_clear_work_profile() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `puzzle_clear_work_profile`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait PuzzleClearWorkProfileTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`PuzzleClearWorkProfileTableHandle`], which mediates access to the table `puzzle_clear_work_profile`. - fn puzzle_clear_work_profile(&self) -> PuzzleClearWorkProfileTableHandle<'_>; -} - -impl PuzzleClearWorkProfileTableAccess for super::RemoteTables { - fn puzzle_clear_work_profile(&self) -> PuzzleClearWorkProfileTableHandle<'_> { - PuzzleClearWorkProfileTableHandle { - imp: self - .imp - .get_table::("puzzle_clear_work_profile"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct PuzzleClearWorkProfileInsertCallbackId(__sdk::CallbackId); -pub struct PuzzleClearWorkProfileDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for PuzzleClearWorkProfileTableHandle<'ctx> { - type Row = PuzzleClearWorkProfileRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for PuzzleClearWorkProfileTableHandle<'ctx> { - type Row = PuzzleClearWorkProfileRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = PuzzleClearWorkProfileInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleClearWorkProfileInsertCallbackId { - PuzzleClearWorkProfileInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleClearWorkProfileInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = PuzzleClearWorkProfileDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleClearWorkProfileDeleteCallbackId { - PuzzleClearWorkProfileDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PuzzleClearWorkProfileDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for PuzzleClearWorkProfileTableHandle<'ctx> { - type InsertCallbackId = PuzzleClearWorkProfileInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleClearWorkProfileInsertCallbackId { - PuzzleClearWorkProfileInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleClearWorkProfileInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for PuzzleClearWorkProfileTableHandle<'ctx> { - type DeleteCallbackId = PuzzleClearWorkProfileDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleClearWorkProfileDeleteCallbackId { - PuzzleClearWorkProfileDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PuzzleClearWorkProfileDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct PuzzleClearWorkProfileUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for PuzzleClearWorkProfileTableHandle<'ctx> { - type UpdateCallbackId = PuzzleClearWorkProfileUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PuzzleClearWorkProfileUpdateCallbackId { - PuzzleClearWorkProfileUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PuzzleClearWorkProfileUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for PuzzleClearWorkProfileTableHandle<'ctx> { - type UpdateCallbackId = PuzzleClearWorkProfileUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PuzzleClearWorkProfileUpdateCallbackId { - PuzzleClearWorkProfileUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PuzzleClearWorkProfileUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `profile_id` unique index on the table `puzzle_clear_work_profile`, -/// which allows point queries on the field of the same name -/// via the [`PuzzleClearWorkProfileProfileIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.puzzle_clear_work_profile().profile_id().find(...)`. -pub struct PuzzleClearWorkProfileProfileIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> PuzzleClearWorkProfileTableHandle<'ctx> { - /// Get a handle on the `profile_id` unique index on the table `puzzle_clear_work_profile`. - pub fn profile_id(&self) -> PuzzleClearWorkProfileProfileIdUnique<'ctx> { - PuzzleClearWorkProfileProfileIdUnique { - imp: self.imp.get_unique_constraint::("profile_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> PuzzleClearWorkProfileProfileIdUnique<'ctx> { - /// Find the subscribed row whose `profile_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("puzzle_clear_work_profile"); - _table.add_unique_constraint::("profile_id", |row| &row.profile_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `PuzzleClearWorkProfileRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait puzzle_clear_work_profileQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `PuzzleClearWorkProfileRow`. - fn puzzle_clear_work_profile(&self) - -> __sdk::__query_builder::Table; -} - -impl puzzle_clear_work_profileQueryTableAccess for __sdk::QueryTableAccessor { - fn puzzle_clear_work_profile( - &self, - ) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("puzzle_clear_work_profile") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_event_kind_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_event_kind_type.rs deleted file mode 100644 index 691ae326e..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_event_kind_type.rs +++ /dev/null @@ -1,16 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum PuzzleEventKind { - WorkPublished, -} - -impl __sdk::InModule for PuzzleEventKind { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_event_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_event_table.rs deleted file mode 100644 index 3610bb362..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_event_table.rs +++ /dev/null @@ -1,138 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::puzzle_event_kind_type::PuzzleEventKind; -use super::puzzle_event_type::PuzzleEvent; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `puzzle_event`. -/// -/// Obtain a handle from the [`PuzzleEventTableAccess::puzzle_event`] method on [`super::RemoteTables`], -/// like `ctx.db.puzzle_event()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.puzzle_event().on_insert(...)`. -pub struct PuzzleEventTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `puzzle_event`. -pub struct PuzzleEventTableAccessor; - -impl __sdk::TableAccessor for PuzzleEventTableAccessor { - type Row = PuzzleEvent; - type Handle<'db> = PuzzleEventTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.puzzle_event() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `puzzle_event`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait PuzzleEventTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`PuzzleEventTableHandle`], which mediates access to the table `puzzle_event`. - fn puzzle_event(&self) -> PuzzleEventTableHandle<'_>; -} - -impl PuzzleEventTableAccess for super::RemoteTables { - fn puzzle_event(&self) -> PuzzleEventTableHandle<'_> { - PuzzleEventTableHandle { - imp: self.imp.get_table::("puzzle_event"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct PuzzleEventInsertCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for PuzzleEventTableHandle<'ctx> { - type Row = PuzzleEvent; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::EventTable for PuzzleEventTableHandle<'ctx> { - type Row = PuzzleEvent; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = PuzzleEventInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleEventInsertCallbackId { - PuzzleEventInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleEventInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for PuzzleEventTableHandle<'ctx> { - type InsertCallbackId = PuzzleEventInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleEventInsertCallbackId { - PuzzleEventInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleEventInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("puzzle_event"); - _table.add_unique_constraint::("event_id", |row| &row.event_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `PuzzleEvent`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait puzzle_eventQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `PuzzleEvent`. - fn puzzle_event(&self) -> __sdk::__query_builder::Table; -} - -impl puzzle_eventQueryTableAccess for __sdk::QueryTableAccessor { - fn puzzle_event(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("puzzle_event") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_event_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_event_type.rs deleted file mode 100644 index d4d14856a..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_event_type.rs +++ /dev/null @@ -1,71 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::puzzle_event_kind_type::PuzzleEventKind; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct PuzzleEvent { - pub event_id: String, - pub profile_id: String, - pub work_id: String, - pub session_id: Option, - pub owner_user_id: String, - pub event_kind: PuzzleEventKind, - pub occurred_at: __sdk::Timestamp, -} - -impl __sdk::InModule for PuzzleEvent { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `PuzzleEvent`. -/// -/// Provides typed access to columns for query building. -pub struct PuzzleEventCols { - pub event_id: __sdk::__query_builder::Col, - pub profile_id: __sdk::__query_builder::Col, - pub work_id: __sdk::__query_builder::Col, - pub session_id: __sdk::__query_builder::Col>, - pub owner_user_id: __sdk::__query_builder::Col, - pub event_kind: __sdk::__query_builder::Col, - pub occurred_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for PuzzleEvent { - type Cols = PuzzleEventCols; - fn cols(table_name: &'static str) -> Self::Cols { - PuzzleEventCols { - event_id: __sdk::__query_builder::Col::new(table_name, "event_id"), - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - work_id: __sdk::__query_builder::Col::new(table_name, "work_id"), - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - event_kind: __sdk::__query_builder::Col::new(table_name, "event_kind"), - occurred_at: __sdk::__query_builder::Col::new(table_name, "occurred_at"), - } - } -} - -/// Indexed column accessor struct for the table `PuzzleEvent`. -/// -/// Provides typed access to indexed columns for query building. -pub struct PuzzleEventIxCols { - pub event_id: __sdk::__query_builder::IxCol, - pub owner_user_id: __sdk::__query_builder::IxCol, - pub profile_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for PuzzleEvent { - type IxCols = PuzzleEventIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - PuzzleEventIxCols { - event_id: __sdk::__query_builder::IxCol::new(table_name, "event_id"), - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::IxCol::new(table_name, "profile_id"), - } - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_leaderboard_entry_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_leaderboard_entry_row_type.rs deleted file mode 100644 index a9b1a782c..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_leaderboard_entry_row_type.rs +++ /dev/null @@ -1,70 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct PuzzleLeaderboardEntryRow { - pub entry_id: String, - pub profile_id: String, - pub grid_size: u32, - pub user_id: String, - pub nickname: String, - pub best_elapsed_ms: u64, - pub last_run_id: String, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for PuzzleLeaderboardEntryRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `PuzzleLeaderboardEntryRow`. -/// -/// Provides typed access to columns for query building. -pub struct PuzzleLeaderboardEntryRowCols { - pub entry_id: __sdk::__query_builder::Col, - pub profile_id: __sdk::__query_builder::Col, - pub grid_size: __sdk::__query_builder::Col, - pub user_id: __sdk::__query_builder::Col, - pub nickname: __sdk::__query_builder::Col, - pub best_elapsed_ms: __sdk::__query_builder::Col, - pub last_run_id: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for PuzzleLeaderboardEntryRow { - type Cols = PuzzleLeaderboardEntryRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - PuzzleLeaderboardEntryRowCols { - entry_id: __sdk::__query_builder::Col::new(table_name, "entry_id"), - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - grid_size: __sdk::__query_builder::Col::new(table_name, "grid_size"), - user_id: __sdk::__query_builder::Col::new(table_name, "user_id"), - nickname: __sdk::__query_builder::Col::new(table_name, "nickname"), - best_elapsed_ms: __sdk::__query_builder::Col::new(table_name, "best_elapsed_ms"), - last_run_id: __sdk::__query_builder::Col::new(table_name, "last_run_id"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `PuzzleLeaderboardEntryRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct PuzzleLeaderboardEntryRowIxCols { - pub entry_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for PuzzleLeaderboardEntryRow { - type IxCols = PuzzleLeaderboardEntryRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - PuzzleLeaderboardEntryRowIxCols { - entry_id: __sdk::__query_builder::IxCol::new(table_name, "entry_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for PuzzleLeaderboardEntryRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_leaderboard_entry_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_leaderboard_entry_table.rs deleted file mode 100644 index 45bb2eb2a..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_leaderboard_entry_table.rs +++ /dev/null @@ -1,231 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::puzzle_leaderboard_entry_row_type::PuzzleLeaderboardEntryRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `puzzle_leaderboard_entry`. -/// -/// Obtain a handle from the [`PuzzleLeaderboardEntryTableAccess::puzzle_leaderboard_entry`] method on [`super::RemoteTables`], -/// like `ctx.db.puzzle_leaderboard_entry()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.puzzle_leaderboard_entry().on_insert(...)`. -pub struct PuzzleLeaderboardEntryTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `puzzle_leaderboard_entry`. -pub struct PuzzleLeaderboardEntryTableAccessor; - -impl __sdk::TableAccessor for PuzzleLeaderboardEntryTableAccessor { - type Row = PuzzleLeaderboardEntryRow; - type Handle<'db> = PuzzleLeaderboardEntryTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.puzzle_leaderboard_entry() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `puzzle_leaderboard_entry`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait PuzzleLeaderboardEntryTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`PuzzleLeaderboardEntryTableHandle`], which mediates access to the table `puzzle_leaderboard_entry`. - fn puzzle_leaderboard_entry(&self) -> PuzzleLeaderboardEntryTableHandle<'_>; -} - -impl PuzzleLeaderboardEntryTableAccess for super::RemoteTables { - fn puzzle_leaderboard_entry(&self) -> PuzzleLeaderboardEntryTableHandle<'_> { - PuzzleLeaderboardEntryTableHandle { - imp: self - .imp - .get_table::("puzzle_leaderboard_entry"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct PuzzleLeaderboardEntryInsertCallbackId(__sdk::CallbackId); -pub struct PuzzleLeaderboardEntryDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for PuzzleLeaderboardEntryTableHandle<'ctx> { - type Row = PuzzleLeaderboardEntryRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for PuzzleLeaderboardEntryTableHandle<'ctx> { - type Row = PuzzleLeaderboardEntryRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = PuzzleLeaderboardEntryInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleLeaderboardEntryInsertCallbackId { - PuzzleLeaderboardEntryInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleLeaderboardEntryInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = PuzzleLeaderboardEntryDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleLeaderboardEntryDeleteCallbackId { - PuzzleLeaderboardEntryDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PuzzleLeaderboardEntryDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for PuzzleLeaderboardEntryTableHandle<'ctx> { - type InsertCallbackId = PuzzleLeaderboardEntryInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleLeaderboardEntryInsertCallbackId { - PuzzleLeaderboardEntryInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleLeaderboardEntryInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for PuzzleLeaderboardEntryTableHandle<'ctx> { - type DeleteCallbackId = PuzzleLeaderboardEntryDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleLeaderboardEntryDeleteCallbackId { - PuzzleLeaderboardEntryDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PuzzleLeaderboardEntryDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct PuzzleLeaderboardEntryUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for PuzzleLeaderboardEntryTableHandle<'ctx> { - type UpdateCallbackId = PuzzleLeaderboardEntryUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PuzzleLeaderboardEntryUpdateCallbackId { - PuzzleLeaderboardEntryUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PuzzleLeaderboardEntryUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for PuzzleLeaderboardEntryTableHandle<'ctx> { - type UpdateCallbackId = PuzzleLeaderboardEntryUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PuzzleLeaderboardEntryUpdateCallbackId { - PuzzleLeaderboardEntryUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PuzzleLeaderboardEntryUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `entry_id` unique index on the table `puzzle_leaderboard_entry`, -/// which allows point queries on the field of the same name -/// via the [`PuzzleLeaderboardEntryEntryIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.puzzle_leaderboard_entry().entry_id().find(...)`. -pub struct PuzzleLeaderboardEntryEntryIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> PuzzleLeaderboardEntryTableHandle<'ctx> { - /// Get a handle on the `entry_id` unique index on the table `puzzle_leaderboard_entry`. - pub fn entry_id(&self) -> PuzzleLeaderboardEntryEntryIdUnique<'ctx> { - PuzzleLeaderboardEntryEntryIdUnique { - imp: self.imp.get_unique_constraint::("entry_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> PuzzleLeaderboardEntryEntryIdUnique<'ctx> { - /// Find the subscribed row whose `entry_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("puzzle_leaderboard_entry"); - _table.add_unique_constraint::("entry_id", |row| &row.entry_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `PuzzleLeaderboardEntryRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait puzzle_leaderboard_entryQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `PuzzleLeaderboardEntryRow`. - fn puzzle_leaderboard_entry(&self) -> __sdk::__query_builder::Table; -} - -impl puzzle_leaderboard_entryQueryTableAccess for __sdk::QueryTableAccessor { - fn puzzle_leaderboard_entry(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("puzzle_leaderboard_entry") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_publication_status_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_publication_status_type.rs deleted file mode 100644 index 38ece3cf5..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_publication_status_type.rs +++ /dev/null @@ -1,18 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum PuzzlePublicationStatus { - Draft, - - Published, -} - -impl __sdk::InModule for PuzzlePublicationStatus { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_runtime_run_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_runtime_run_row_type.rs deleted file mode 100644 index e610dfbf4..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_runtime_run_row_type.rs +++ /dev/null @@ -1,96 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct PuzzleRuntimeRunRow { - pub run_id: String, - pub owner_user_id: String, - pub entry_profile_id: String, - pub current_profile_id: String, - pub cleared_level_count: u32, - pub current_level_index: u32, - pub current_grid_size: u32, - pub played_profile_ids_json: String, - pub previous_level_tags_json: String, - pub snapshot_json: String, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for PuzzleRuntimeRunRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `PuzzleRuntimeRunRow`. -/// -/// Provides typed access to columns for query building. -pub struct PuzzleRuntimeRunRowCols { - pub run_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub entry_profile_id: __sdk::__query_builder::Col, - pub current_profile_id: __sdk::__query_builder::Col, - pub cleared_level_count: __sdk::__query_builder::Col, - pub current_level_index: __sdk::__query_builder::Col, - pub current_grid_size: __sdk::__query_builder::Col, - pub played_profile_ids_json: __sdk::__query_builder::Col, - pub previous_level_tags_json: __sdk::__query_builder::Col, - pub snapshot_json: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for PuzzleRuntimeRunRow { - type Cols = PuzzleRuntimeRunRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - PuzzleRuntimeRunRowCols { - run_id: __sdk::__query_builder::Col::new(table_name, "run_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - entry_profile_id: __sdk::__query_builder::Col::new(table_name, "entry_profile_id"), - current_profile_id: __sdk::__query_builder::Col::new(table_name, "current_profile_id"), - cleared_level_count: __sdk::__query_builder::Col::new( - table_name, - "cleared_level_count", - ), - current_level_index: __sdk::__query_builder::Col::new( - table_name, - "current_level_index", - ), - current_grid_size: __sdk::__query_builder::Col::new(table_name, "current_grid_size"), - played_profile_ids_json: __sdk::__query_builder::Col::new( - table_name, - "played_profile_ids_json", - ), - previous_level_tags_json: __sdk::__query_builder::Col::new( - table_name, - "previous_level_tags_json", - ), - snapshot_json: __sdk::__query_builder::Col::new(table_name, "snapshot_json"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `PuzzleRuntimeRunRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct PuzzleRuntimeRunRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub run_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for PuzzleRuntimeRunRow { - type IxCols = PuzzleRuntimeRunRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - PuzzleRuntimeRunRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - run_id: __sdk::__query_builder::IxCol::new(table_name, "run_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for PuzzleRuntimeRunRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_runtime_run_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_runtime_run_table.rs deleted file mode 100644 index d8772725a..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_runtime_run_table.rs +++ /dev/null @@ -1,230 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::puzzle_runtime_run_row_type::PuzzleRuntimeRunRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `puzzle_runtime_run`. -/// -/// Obtain a handle from the [`PuzzleRuntimeRunTableAccess::puzzle_runtime_run`] method on [`super::RemoteTables`], -/// like `ctx.db.puzzle_runtime_run()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.puzzle_runtime_run().on_insert(...)`. -pub struct PuzzleRuntimeRunTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `puzzle_runtime_run`. -pub struct PuzzleRuntimeRunTableAccessor; - -impl __sdk::TableAccessor for PuzzleRuntimeRunTableAccessor { - type Row = PuzzleRuntimeRunRow; - type Handle<'db> = PuzzleRuntimeRunTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.puzzle_runtime_run() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `puzzle_runtime_run`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait PuzzleRuntimeRunTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`PuzzleRuntimeRunTableHandle`], which mediates access to the table `puzzle_runtime_run`. - fn puzzle_runtime_run(&self) -> PuzzleRuntimeRunTableHandle<'_>; -} - -impl PuzzleRuntimeRunTableAccess for super::RemoteTables { - fn puzzle_runtime_run(&self) -> PuzzleRuntimeRunTableHandle<'_> { - PuzzleRuntimeRunTableHandle { - imp: self - .imp - .get_table::("puzzle_runtime_run"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct PuzzleRuntimeRunInsertCallbackId(__sdk::CallbackId); -pub struct PuzzleRuntimeRunDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for PuzzleRuntimeRunTableHandle<'ctx> { - type Row = PuzzleRuntimeRunRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for PuzzleRuntimeRunTableHandle<'ctx> { - type Row = PuzzleRuntimeRunRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = PuzzleRuntimeRunInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleRuntimeRunInsertCallbackId { - PuzzleRuntimeRunInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleRuntimeRunInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = PuzzleRuntimeRunDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleRuntimeRunDeleteCallbackId { - PuzzleRuntimeRunDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PuzzleRuntimeRunDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for PuzzleRuntimeRunTableHandle<'ctx> { - type InsertCallbackId = PuzzleRuntimeRunInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleRuntimeRunInsertCallbackId { - PuzzleRuntimeRunInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleRuntimeRunInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for PuzzleRuntimeRunTableHandle<'ctx> { - type DeleteCallbackId = PuzzleRuntimeRunDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleRuntimeRunDeleteCallbackId { - PuzzleRuntimeRunDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PuzzleRuntimeRunDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct PuzzleRuntimeRunUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for PuzzleRuntimeRunTableHandle<'ctx> { - type UpdateCallbackId = PuzzleRuntimeRunUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PuzzleRuntimeRunUpdateCallbackId { - PuzzleRuntimeRunUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PuzzleRuntimeRunUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for PuzzleRuntimeRunTableHandle<'ctx> { - type UpdateCallbackId = PuzzleRuntimeRunUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PuzzleRuntimeRunUpdateCallbackId { - PuzzleRuntimeRunUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PuzzleRuntimeRunUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `run_id` unique index on the table `puzzle_runtime_run`, -/// which allows point queries on the field of the same name -/// via the [`PuzzleRuntimeRunRunIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.puzzle_runtime_run().run_id().find(...)`. -pub struct PuzzleRuntimeRunRunIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> PuzzleRuntimeRunTableHandle<'ctx> { - /// Get a handle on the `run_id` unique index on the table `puzzle_runtime_run`. - pub fn run_id(&self) -> PuzzleRuntimeRunRunIdUnique<'ctx> { - PuzzleRuntimeRunRunIdUnique { - imp: self.imp.get_unique_constraint::("run_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> PuzzleRuntimeRunRunIdUnique<'ctx> { - /// Find the subscribed row whose `run_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("puzzle_runtime_run"); - _table.add_unique_constraint::("run_id", |row| &row.run_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `PuzzleRuntimeRunRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait puzzle_runtime_runQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `PuzzleRuntimeRunRow`. - fn puzzle_runtime_run(&self) -> __sdk::__query_builder::Table; -} - -impl puzzle_runtime_runQueryTableAccess for __sdk::QueryTableAccessor { - fn puzzle_runtime_run(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("puzzle_runtime_run") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_work_profile_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_work_profile_row_type.rs deleted file mode 100644 index db43f53a6..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_work_profile_row_type.rs +++ /dev/null @@ -1,141 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::puzzle_publication_status_type::PuzzlePublicationStatus; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct PuzzleWorkProfileRow { - pub profile_id: String, - pub work_id: String, - pub owner_user_id: String, - pub source_session_id: Option, - pub author_display_name: String, - pub work_title: String, - pub work_description: String, - pub level_name: String, - pub summary: String, - pub theme_tags_json: String, - pub cover_image_src: Option, - pub cover_asset_id: Option, - pub levels_json: String, - pub publication_status: PuzzlePublicationStatus, - pub play_count: u32, - pub anchor_pack_json: String, - pub publish_ready: bool, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, - pub published_at: Option<__sdk::Timestamp>, - pub remix_count: u32, - pub like_count: u32, - pub point_incentive_total_half_points: u64, - pub point_incentive_claimed_points: u64, - pub visible: bool, -} - -impl __sdk::InModule for PuzzleWorkProfileRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `PuzzleWorkProfileRow`. -/// -/// Provides typed access to columns for query building. -pub struct PuzzleWorkProfileRowCols { - pub profile_id: __sdk::__query_builder::Col, - pub work_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub source_session_id: __sdk::__query_builder::Col>, - pub author_display_name: __sdk::__query_builder::Col, - pub work_title: __sdk::__query_builder::Col, - pub work_description: __sdk::__query_builder::Col, - pub level_name: __sdk::__query_builder::Col, - pub summary: __sdk::__query_builder::Col, - pub theme_tags_json: __sdk::__query_builder::Col, - pub cover_image_src: __sdk::__query_builder::Col>, - pub cover_asset_id: __sdk::__query_builder::Col>, - pub levels_json: __sdk::__query_builder::Col, - pub publication_status: - __sdk::__query_builder::Col, - pub play_count: __sdk::__query_builder::Col, - pub anchor_pack_json: __sdk::__query_builder::Col, - pub publish_ready: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, - pub published_at: __sdk::__query_builder::Col>, - pub remix_count: __sdk::__query_builder::Col, - pub like_count: __sdk::__query_builder::Col, - pub point_incentive_total_half_points: __sdk::__query_builder::Col, - pub point_incentive_claimed_points: __sdk::__query_builder::Col, - pub visible: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for PuzzleWorkProfileRow { - type Cols = PuzzleWorkProfileRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - PuzzleWorkProfileRowCols { - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - work_id: __sdk::__query_builder::Col::new(table_name, "work_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - source_session_id: __sdk::__query_builder::Col::new(table_name, "source_session_id"), - author_display_name: __sdk::__query_builder::Col::new( - table_name, - "author_display_name", - ), - work_title: __sdk::__query_builder::Col::new(table_name, "work_title"), - work_description: __sdk::__query_builder::Col::new(table_name, "work_description"), - level_name: __sdk::__query_builder::Col::new(table_name, "level_name"), - summary: __sdk::__query_builder::Col::new(table_name, "summary"), - theme_tags_json: __sdk::__query_builder::Col::new(table_name, "theme_tags_json"), - cover_image_src: __sdk::__query_builder::Col::new(table_name, "cover_image_src"), - cover_asset_id: __sdk::__query_builder::Col::new(table_name, "cover_asset_id"), - levels_json: __sdk::__query_builder::Col::new(table_name, "levels_json"), - publication_status: __sdk::__query_builder::Col::new(table_name, "publication_status"), - play_count: __sdk::__query_builder::Col::new(table_name, "play_count"), - anchor_pack_json: __sdk::__query_builder::Col::new(table_name, "anchor_pack_json"), - publish_ready: __sdk::__query_builder::Col::new(table_name, "publish_ready"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - published_at: __sdk::__query_builder::Col::new(table_name, "published_at"), - remix_count: __sdk::__query_builder::Col::new(table_name, "remix_count"), - like_count: __sdk::__query_builder::Col::new(table_name, "like_count"), - point_incentive_total_half_points: __sdk::__query_builder::Col::new( - table_name, - "point_incentive_total_half_points", - ), - point_incentive_claimed_points: __sdk::__query_builder::Col::new( - table_name, - "point_incentive_claimed_points", - ), - visible: __sdk::__query_builder::Col::new(table_name, "visible"), - } - } -} - -/// Indexed column accessor struct for the table `PuzzleWorkProfileRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct PuzzleWorkProfileRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub profile_id: __sdk::__query_builder::IxCol, - pub publication_status: - __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for PuzzleWorkProfileRow { - type IxCols = PuzzleWorkProfileRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - PuzzleWorkProfileRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::IxCol::new(table_name, "profile_id"), - publication_status: __sdk::__query_builder::IxCol::new( - table_name, - "publication_status", - ), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for PuzzleWorkProfileRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_work_profile_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_work_profile_table.rs deleted file mode 100644 index d585413c0..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_work_profile_table.rs +++ /dev/null @@ -1,231 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::puzzle_publication_status_type::PuzzlePublicationStatus; -use super::puzzle_work_profile_row_type::PuzzleWorkProfileRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `puzzle_work_profile`. -/// -/// Obtain a handle from the [`PuzzleWorkProfileTableAccess::puzzle_work_profile`] method on [`super::RemoteTables`], -/// like `ctx.db.puzzle_work_profile()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.puzzle_work_profile().on_insert(...)`. -pub struct PuzzleWorkProfileTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `puzzle_work_profile`. -pub struct PuzzleWorkProfileTableAccessor; - -impl __sdk::TableAccessor for PuzzleWorkProfileTableAccessor { - type Row = PuzzleWorkProfileRow; - type Handle<'db> = PuzzleWorkProfileTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.puzzle_work_profile() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `puzzle_work_profile`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait PuzzleWorkProfileTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`PuzzleWorkProfileTableHandle`], which mediates access to the table `puzzle_work_profile`. - fn puzzle_work_profile(&self) -> PuzzleWorkProfileTableHandle<'_>; -} - -impl PuzzleWorkProfileTableAccess for super::RemoteTables { - fn puzzle_work_profile(&self) -> PuzzleWorkProfileTableHandle<'_> { - PuzzleWorkProfileTableHandle { - imp: self - .imp - .get_table::("puzzle_work_profile"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct PuzzleWorkProfileInsertCallbackId(__sdk::CallbackId); -pub struct PuzzleWorkProfileDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for PuzzleWorkProfileTableHandle<'ctx> { - type Row = PuzzleWorkProfileRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for PuzzleWorkProfileTableHandle<'ctx> { - type Row = PuzzleWorkProfileRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = PuzzleWorkProfileInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleWorkProfileInsertCallbackId { - PuzzleWorkProfileInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleWorkProfileInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = PuzzleWorkProfileDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleWorkProfileDeleteCallbackId { - PuzzleWorkProfileDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PuzzleWorkProfileDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for PuzzleWorkProfileTableHandle<'ctx> { - type InsertCallbackId = PuzzleWorkProfileInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleWorkProfileInsertCallbackId { - PuzzleWorkProfileInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PuzzleWorkProfileInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for PuzzleWorkProfileTableHandle<'ctx> { - type DeleteCallbackId = PuzzleWorkProfileDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PuzzleWorkProfileDeleteCallbackId { - PuzzleWorkProfileDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PuzzleWorkProfileDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct PuzzleWorkProfileUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for PuzzleWorkProfileTableHandle<'ctx> { - type UpdateCallbackId = PuzzleWorkProfileUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PuzzleWorkProfileUpdateCallbackId { - PuzzleWorkProfileUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PuzzleWorkProfileUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for PuzzleWorkProfileTableHandle<'ctx> { - type UpdateCallbackId = PuzzleWorkProfileUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PuzzleWorkProfileUpdateCallbackId { - PuzzleWorkProfileUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PuzzleWorkProfileUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `profile_id` unique index on the table `puzzle_work_profile`, -/// which allows point queries on the field of the same name -/// via the [`PuzzleWorkProfileProfileIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.puzzle_work_profile().profile_id().find(...)`. -pub struct PuzzleWorkProfileProfileIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> PuzzleWorkProfileTableHandle<'ctx> { - /// Get a handle on the `profile_id` unique index on the table `puzzle_work_profile`. - pub fn profile_id(&self) -> PuzzleWorkProfileProfileIdUnique<'ctx> { - PuzzleWorkProfileProfileIdUnique { - imp: self.imp.get_unique_constraint::("profile_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> PuzzleWorkProfileProfileIdUnique<'ctx> { - /// Find the subscribed row whose `profile_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("puzzle_work_profile"); - _table.add_unique_constraint::("profile_id", |row| &row.profile_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `PuzzleWorkProfileRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait puzzle_work_profileQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `PuzzleWorkProfileRow`. - fn puzzle_work_profile(&self) -> __sdk::__query_builder::Table; -} - -impl puzzle_work_profileQueryTableAccess for __sdk::QueryTableAccessor { - fn puzzle_work_profile(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("puzzle_work_profile") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/query_analytics_metric_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/query_analytics_metric_procedure.rs index 7973f5469..adc25bfaf 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/query_analytics_metric_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/query_analytics_metric_procedure.rs @@ -31,10 +31,10 @@ pub trait query_analytics_metric { input: AnalyticsMetricQueryInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl query_analytics_metric for super::RemoteProcedures { input: AnalyticsMetricQueryInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AnalyticsMetricQueryProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_hostile_npc_defeated_signal_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_hostile_npc_defeated_signal_type.rs deleted file mode 100644 index d12363ff4..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_hostile_npc_defeated_signal_type.rs +++ /dev/null @@ -1,16 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct QuestHostileNpcDefeatedSignal { - pub scene_id: Option, - pub hostile_npc_id: String, -} - -impl __sdk::InModule for QuestHostileNpcDefeatedSignal { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_item_delivered_signal_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_item_delivered_signal_type.rs deleted file mode 100644 index 4e1d0a5d3..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_item_delivered_signal_type.rs +++ /dev/null @@ -1,17 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct QuestItemDeliveredSignal { - pub npc_id: String, - pub item_id: String, - pub quantity: u32, -} - -impl __sdk::InModule for QuestItemDeliveredSignal { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_log_event_kind_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_log_event_kind_type.rs deleted file mode 100644 index c3176590d..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_log_event_kind_type.rs +++ /dev/null @@ -1,24 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum QuestLogEventKind { - Accepted, - - Progressed, - - Completed, - - CompletionAcknowledged, - - TurnedIn, -} - -impl __sdk::InModule for QuestLogEventKind { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_log_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_log_table.rs deleted file mode 100644 index 4f297bbf9..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_log_table.rs +++ /dev/null @@ -1,232 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::quest_log_event_kind_type::QuestLogEventKind; -use super::quest_log_type::QuestLog; -use super::quest_progress_signal_type::QuestProgressSignal; -use super::quest_signal_kind_type::QuestSignalKind; -use super::quest_status_type::QuestStatus; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `quest_log`. -/// -/// Obtain a handle from the [`QuestLogTableAccess::quest_log`] method on [`super::RemoteTables`], -/// like `ctx.db.quest_log()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.quest_log().on_insert(...)`. -pub struct QuestLogTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `quest_log`. -pub struct QuestLogTableAccessor; - -impl __sdk::TableAccessor for QuestLogTableAccessor { - type Row = QuestLog; - type Handle<'db> = QuestLogTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.quest_log() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `quest_log`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait QuestLogTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`QuestLogTableHandle`], which mediates access to the table `quest_log`. - fn quest_log(&self) -> QuestLogTableHandle<'_>; -} - -impl QuestLogTableAccess for super::RemoteTables { - fn quest_log(&self) -> QuestLogTableHandle<'_> { - QuestLogTableHandle { - imp: self.imp.get_table::("quest_log"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct QuestLogInsertCallbackId(__sdk::CallbackId); -pub struct QuestLogDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for QuestLogTableHandle<'ctx> { - type Row = QuestLog; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for QuestLogTableHandle<'ctx> { - type Row = QuestLog; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = QuestLogInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> QuestLogInsertCallbackId { - QuestLogInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: QuestLogInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = QuestLogDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> QuestLogDeleteCallbackId { - QuestLogDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: QuestLogDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for QuestLogTableHandle<'ctx> { - type InsertCallbackId = QuestLogInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> QuestLogInsertCallbackId { - QuestLogInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: QuestLogInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for QuestLogTableHandle<'ctx> { - type DeleteCallbackId = QuestLogDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> QuestLogDeleteCallbackId { - QuestLogDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: QuestLogDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct QuestLogUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for QuestLogTableHandle<'ctx> { - type UpdateCallbackId = QuestLogUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> QuestLogUpdateCallbackId { - QuestLogUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: QuestLogUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for QuestLogTableHandle<'ctx> { - type UpdateCallbackId = QuestLogUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> QuestLogUpdateCallbackId { - QuestLogUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: QuestLogUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `log_id` unique index on the table `quest_log`, -/// which allows point queries on the field of the same name -/// via the [`QuestLogLogIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.quest_log().log_id().find(...)`. -pub struct QuestLogLogIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> QuestLogTableHandle<'ctx> { - /// Get a handle on the `log_id` unique index on the table `quest_log`. - pub fn log_id(&self) -> QuestLogLogIdUnique<'ctx> { - QuestLogLogIdUnique { - imp: self.imp.get_unique_constraint::("log_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> QuestLogLogIdUnique<'ctx> { - /// Find the subscribed row whose `log_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("quest_log"); - _table.add_unique_constraint::("log_id", |row| &row.log_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `QuestLog`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait quest_logQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `QuestLog`. - fn quest_log(&self) -> __sdk::__query_builder::Table; -} - -impl quest_logQueryTableAccess for __sdk::QueryTableAccessor { - fn quest_log(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("quest_log") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_log_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_log_type.rs deleted file mode 100644 index d893857a9..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_log_type.rs +++ /dev/null @@ -1,93 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::quest_log_event_kind_type::QuestLogEventKind; -use super::quest_progress_signal_type::QuestProgressSignal; -use super::quest_signal_kind_type::QuestSignalKind; -use super::quest_status_type::QuestStatus; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct QuestLog { - pub log_id: String, - pub quest_id: String, - pub runtime_session_id: String, - pub actor_user_id: String, - pub event_kind: QuestLogEventKind, - pub status_after: QuestStatus, - pub signal_kind: Option, - pub signal: Option, - pub step_id: Option, - pub step_progress: Option, - pub created_at: __sdk::Timestamp, -} - -impl __sdk::InModule for QuestLog { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `QuestLog`. -/// -/// Provides typed access to columns for query building. -pub struct QuestLogCols { - pub log_id: __sdk::__query_builder::Col, - pub quest_id: __sdk::__query_builder::Col, - pub runtime_session_id: __sdk::__query_builder::Col, - pub actor_user_id: __sdk::__query_builder::Col, - pub event_kind: __sdk::__query_builder::Col, - pub status_after: __sdk::__query_builder::Col, - pub signal_kind: __sdk::__query_builder::Col>, - pub signal: __sdk::__query_builder::Col>, - pub step_id: __sdk::__query_builder::Col>, - pub step_progress: __sdk::__query_builder::Col>, - pub created_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for QuestLog { - type Cols = QuestLogCols; - fn cols(table_name: &'static str) -> Self::Cols { - QuestLogCols { - log_id: __sdk::__query_builder::Col::new(table_name, "log_id"), - quest_id: __sdk::__query_builder::Col::new(table_name, "quest_id"), - runtime_session_id: __sdk::__query_builder::Col::new(table_name, "runtime_session_id"), - actor_user_id: __sdk::__query_builder::Col::new(table_name, "actor_user_id"), - event_kind: __sdk::__query_builder::Col::new(table_name, "event_kind"), - status_after: __sdk::__query_builder::Col::new(table_name, "status_after"), - signal_kind: __sdk::__query_builder::Col::new(table_name, "signal_kind"), - signal: __sdk::__query_builder::Col::new(table_name, "signal"), - step_id: __sdk::__query_builder::Col::new(table_name, "step_id"), - step_progress: __sdk::__query_builder::Col::new(table_name, "step_progress"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - } - } -} - -/// Indexed column accessor struct for the table `QuestLog`. -/// -/// Provides typed access to indexed columns for query building. -pub struct QuestLogIxCols { - pub actor_user_id: __sdk::__query_builder::IxCol, - pub log_id: __sdk::__query_builder::IxCol, - pub quest_id: __sdk::__query_builder::IxCol, - pub runtime_session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for QuestLog { - type IxCols = QuestLogIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - QuestLogIxCols { - actor_user_id: __sdk::__query_builder::IxCol::new(table_name, "actor_user_id"), - log_id: __sdk::__query_builder::IxCol::new(table_name, "log_id"), - quest_id: __sdk::__query_builder::IxCol::new(table_name, "quest_id"), - runtime_session_id: __sdk::__query_builder::IxCol::new( - table_name, - "runtime_session_id", - ), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for QuestLog {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_narrative_binding_snapshot_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_narrative_binding_snapshot_type.rs deleted file mode 100644 index 730e7565e..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_narrative_binding_snapshot_type.rs +++ /dev/null @@ -1,24 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::quest_narrative_origin_type::QuestNarrativeOrigin; -use super::quest_narrative_type_type::QuestNarrativeType; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct QuestNarrativeBindingSnapshot { - pub origin: QuestNarrativeOrigin, - pub narrative_type: QuestNarrativeType, - pub dramatic_need: String, - pub issuer_goal: String, - pub player_hook: String, - pub world_reason: String, - pub followup_hooks: Vec, -} - -impl __sdk::InModule for QuestNarrativeBindingSnapshot { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_narrative_origin_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_narrative_origin_type.rs deleted file mode 100644 index 34ce63f34..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_narrative_origin_type.rs +++ /dev/null @@ -1,18 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum QuestNarrativeOrigin { - AiCompiled, - - FallbackBuilder, -} - -impl __sdk::InModule for QuestNarrativeOrigin { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_narrative_type_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_narrative_type_type.rs deleted file mode 100644 index ac5319cda..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_narrative_type_type.rs +++ /dev/null @@ -1,26 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum QuestNarrativeType { - Bounty, - - Escort, - - Investigation, - - Retrieval, - - Relationship, - - Trial, -} - -impl __sdk::InModule for QuestNarrativeType { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_npc_spar_completed_signal_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_npc_spar_completed_signal_type.rs deleted file mode 100644 index a0f1f8bbf..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_npc_spar_completed_signal_type.rs +++ /dev/null @@ -1,15 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct QuestNpcSparCompletedSignal { - pub npc_id: String, -} - -impl __sdk::InModule for QuestNpcSparCompletedSignal { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_npc_talk_completed_signal_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_npc_talk_completed_signal_type.rs deleted file mode 100644 index 39042f374..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_npc_talk_completed_signal_type.rs +++ /dev/null @@ -1,15 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct QuestNpcTalkCompletedSignal { - pub npc_id: String, -} - -impl __sdk::InModule for QuestNpcTalkCompletedSignal { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_objective_kind_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_objective_kind_type.rs deleted file mode 100644 index 665faa305..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_objective_kind_type.rs +++ /dev/null @@ -1,26 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum QuestObjectiveKind { - DefeatHostileNpc, - - InspectTreasure, - - SparWithNpc, - - TalkToNpc, - - ReachScene, - - DeliverItem, -} - -impl __sdk::InModule for QuestObjectiveKind { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_objective_snapshot_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_objective_snapshot_type.rs deleted file mode 100644 index 38682e687..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_objective_snapshot_type.rs +++ /dev/null @@ -1,22 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::quest_objective_kind_type::QuestObjectiveKind; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct QuestObjectiveSnapshot { - pub kind: QuestObjectiveKind, - pub target_hostile_npc_id: Option, - pub target_npc_id: Option, - pub target_scene_id: Option, - pub target_item_id: Option, - pub required_count: u32, -} - -impl __sdk::InModule for QuestObjectiveSnapshot { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_progress_signal_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_progress_signal_type.rs deleted file mode 100644 index 5764d2733..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_progress_signal_type.rs +++ /dev/null @@ -1,32 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::quest_hostile_npc_defeated_signal_type::QuestHostileNpcDefeatedSignal; -use super::quest_item_delivered_signal_type::QuestItemDeliveredSignal; -use super::quest_npc_spar_completed_signal_type::QuestNpcSparCompletedSignal; -use super::quest_npc_talk_completed_signal_type::QuestNpcTalkCompletedSignal; -use super::quest_scene_reached_signal_type::QuestSceneReachedSignal; -use super::quest_treasure_inspected_signal_type::QuestTreasureInspectedSignal; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub enum QuestProgressSignal { - HostileNpcDefeated(QuestHostileNpcDefeatedSignal), - - TreasureInspected(QuestTreasureInspectedSignal), - - NpcSparCompleted(QuestNpcSparCompletedSignal), - - NpcTalkCompleted(QuestNpcTalkCompletedSignal), - - SceneReached(QuestSceneReachedSignal), - - ItemDelivered(QuestItemDeliveredSignal), -} - -impl __sdk::InModule for QuestProgressSignal { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_record_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_record_table.rs deleted file mode 100644 index c7ba519e2..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_record_table.rs +++ /dev/null @@ -1,233 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::quest_narrative_binding_snapshot_type::QuestNarrativeBindingSnapshot; -use super::quest_objective_snapshot_type::QuestObjectiveSnapshot; -use super::quest_record_type::QuestRecord; -use super::quest_reward_snapshot_type::QuestRewardSnapshot; -use super::quest_status_type::QuestStatus; -use super::quest_step_snapshot_type::QuestStepSnapshot; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `quest_record`. -/// -/// Obtain a handle from the [`QuestRecordTableAccess::quest_record`] method on [`super::RemoteTables`], -/// like `ctx.db.quest_record()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.quest_record().on_insert(...)`. -pub struct QuestRecordTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `quest_record`. -pub struct QuestRecordTableAccessor; - -impl __sdk::TableAccessor for QuestRecordTableAccessor { - type Row = QuestRecord; - type Handle<'db> = QuestRecordTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.quest_record() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `quest_record`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait QuestRecordTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`QuestRecordTableHandle`], which mediates access to the table `quest_record`. - fn quest_record(&self) -> QuestRecordTableHandle<'_>; -} - -impl QuestRecordTableAccess for super::RemoteTables { - fn quest_record(&self) -> QuestRecordTableHandle<'_> { - QuestRecordTableHandle { - imp: self.imp.get_table::("quest_record"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct QuestRecordInsertCallbackId(__sdk::CallbackId); -pub struct QuestRecordDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for QuestRecordTableHandle<'ctx> { - type Row = QuestRecord; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for QuestRecordTableHandle<'ctx> { - type Row = QuestRecord; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = QuestRecordInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> QuestRecordInsertCallbackId { - QuestRecordInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: QuestRecordInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = QuestRecordDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> QuestRecordDeleteCallbackId { - QuestRecordDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: QuestRecordDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for QuestRecordTableHandle<'ctx> { - type InsertCallbackId = QuestRecordInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> QuestRecordInsertCallbackId { - QuestRecordInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: QuestRecordInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for QuestRecordTableHandle<'ctx> { - type DeleteCallbackId = QuestRecordDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> QuestRecordDeleteCallbackId { - QuestRecordDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: QuestRecordDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct QuestRecordUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for QuestRecordTableHandle<'ctx> { - type UpdateCallbackId = QuestRecordUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> QuestRecordUpdateCallbackId { - QuestRecordUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: QuestRecordUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for QuestRecordTableHandle<'ctx> { - type UpdateCallbackId = QuestRecordUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> QuestRecordUpdateCallbackId { - QuestRecordUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: QuestRecordUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `quest_id` unique index on the table `quest_record`, -/// which allows point queries on the field of the same name -/// via the [`QuestRecordQuestIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.quest_record().quest_id().find(...)`. -pub struct QuestRecordQuestIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> QuestRecordTableHandle<'ctx> { - /// Get a handle on the `quest_id` unique index on the table `quest_record`. - pub fn quest_id(&self) -> QuestRecordQuestIdUnique<'ctx> { - QuestRecordQuestIdUnique { - imp: self.imp.get_unique_constraint::("quest_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> QuestRecordQuestIdUnique<'ctx> { - /// Find the subscribed row whose `quest_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("quest_record"); - _table.add_unique_constraint::("quest_id", |row| &row.quest_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `QuestRecord`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait quest_recordQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `QuestRecord`. - fn quest_record(&self) -> __sdk::__query_builder::Table; -} - -impl quest_recordQueryTableAccess for __sdk::QueryTableAccessor { - fn quest_record(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("quest_record") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_record_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_record_type.rs deleted file mode 100644 index 4243e91c6..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_record_type.rs +++ /dev/null @@ -1,166 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::quest_narrative_binding_snapshot_type::QuestNarrativeBindingSnapshot; -use super::quest_objective_snapshot_type::QuestObjectiveSnapshot; -use super::quest_reward_snapshot_type::QuestRewardSnapshot; -use super::quest_status_type::QuestStatus; -use super::quest_step_snapshot_type::QuestStepSnapshot; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct QuestRecord { - pub quest_id: String, - pub runtime_session_id: String, - pub story_session_id: Option, - pub actor_user_id: String, - pub issuer_npc_id: String, - pub issuer_npc_name: String, - pub scene_id: Option, - pub chapter_id: Option, - pub act_id: Option, - pub thread_id: Option, - pub contract_id: Option, - pub title: String, - pub description: String, - pub summary: String, - pub objective: QuestObjectiveSnapshot, - pub progress: u32, - pub status: QuestStatus, - pub completion_notified: bool, - pub reward: QuestRewardSnapshot, - pub reward_text: String, - pub narrative_binding: QuestNarrativeBindingSnapshot, - pub steps: Vec, - pub active_step_id: Option, - pub visible_stage: u32, - pub hidden_flags: Vec, - pub discovered_fact_ids: Vec, - pub related_carrier_ids: Vec, - pub consequence_ids: Vec, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, - pub completed_at: Option<__sdk::Timestamp>, - pub turned_in_at: Option<__sdk::Timestamp>, -} - -impl __sdk::InModule for QuestRecord { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `QuestRecord`. -/// -/// Provides typed access to columns for query building. -pub struct QuestRecordCols { - pub quest_id: __sdk::__query_builder::Col, - pub runtime_session_id: __sdk::__query_builder::Col, - pub story_session_id: __sdk::__query_builder::Col>, - pub actor_user_id: __sdk::__query_builder::Col, - pub issuer_npc_id: __sdk::__query_builder::Col, - pub issuer_npc_name: __sdk::__query_builder::Col, - pub scene_id: __sdk::__query_builder::Col>, - pub chapter_id: __sdk::__query_builder::Col>, - pub act_id: __sdk::__query_builder::Col>, - pub thread_id: __sdk::__query_builder::Col>, - pub contract_id: __sdk::__query_builder::Col>, - pub title: __sdk::__query_builder::Col, - pub description: __sdk::__query_builder::Col, - pub summary: __sdk::__query_builder::Col, - pub objective: __sdk::__query_builder::Col, - pub progress: __sdk::__query_builder::Col, - pub status: __sdk::__query_builder::Col, - pub completion_notified: __sdk::__query_builder::Col, - pub reward: __sdk::__query_builder::Col, - pub reward_text: __sdk::__query_builder::Col, - pub narrative_binding: __sdk::__query_builder::Col, - pub steps: __sdk::__query_builder::Col>, - pub active_step_id: __sdk::__query_builder::Col>, - pub visible_stage: __sdk::__query_builder::Col, - pub hidden_flags: __sdk::__query_builder::Col>, - pub discovered_fact_ids: __sdk::__query_builder::Col>, - pub related_carrier_ids: __sdk::__query_builder::Col>, - pub consequence_ids: __sdk::__query_builder::Col>, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, - pub completed_at: __sdk::__query_builder::Col>, - pub turned_in_at: __sdk::__query_builder::Col>, -} - -impl __sdk::__query_builder::HasCols for QuestRecord { - type Cols = QuestRecordCols; - fn cols(table_name: &'static str) -> Self::Cols { - QuestRecordCols { - quest_id: __sdk::__query_builder::Col::new(table_name, "quest_id"), - runtime_session_id: __sdk::__query_builder::Col::new(table_name, "runtime_session_id"), - story_session_id: __sdk::__query_builder::Col::new(table_name, "story_session_id"), - actor_user_id: __sdk::__query_builder::Col::new(table_name, "actor_user_id"), - issuer_npc_id: __sdk::__query_builder::Col::new(table_name, "issuer_npc_id"), - issuer_npc_name: __sdk::__query_builder::Col::new(table_name, "issuer_npc_name"), - scene_id: __sdk::__query_builder::Col::new(table_name, "scene_id"), - chapter_id: __sdk::__query_builder::Col::new(table_name, "chapter_id"), - act_id: __sdk::__query_builder::Col::new(table_name, "act_id"), - thread_id: __sdk::__query_builder::Col::new(table_name, "thread_id"), - contract_id: __sdk::__query_builder::Col::new(table_name, "contract_id"), - title: __sdk::__query_builder::Col::new(table_name, "title"), - description: __sdk::__query_builder::Col::new(table_name, "description"), - summary: __sdk::__query_builder::Col::new(table_name, "summary"), - objective: __sdk::__query_builder::Col::new(table_name, "objective"), - progress: __sdk::__query_builder::Col::new(table_name, "progress"), - status: __sdk::__query_builder::Col::new(table_name, "status"), - completion_notified: __sdk::__query_builder::Col::new( - table_name, - "completion_notified", - ), - reward: __sdk::__query_builder::Col::new(table_name, "reward"), - reward_text: __sdk::__query_builder::Col::new(table_name, "reward_text"), - narrative_binding: __sdk::__query_builder::Col::new(table_name, "narrative_binding"), - steps: __sdk::__query_builder::Col::new(table_name, "steps"), - active_step_id: __sdk::__query_builder::Col::new(table_name, "active_step_id"), - visible_stage: __sdk::__query_builder::Col::new(table_name, "visible_stage"), - hidden_flags: __sdk::__query_builder::Col::new(table_name, "hidden_flags"), - discovered_fact_ids: __sdk::__query_builder::Col::new( - table_name, - "discovered_fact_ids", - ), - related_carrier_ids: __sdk::__query_builder::Col::new( - table_name, - "related_carrier_ids", - ), - consequence_ids: __sdk::__query_builder::Col::new(table_name, "consequence_ids"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - completed_at: __sdk::__query_builder::Col::new(table_name, "completed_at"), - turned_in_at: __sdk::__query_builder::Col::new(table_name, "turned_in_at"), - } - } -} - -/// Indexed column accessor struct for the table `QuestRecord`. -/// -/// Provides typed access to indexed columns for query building. -pub struct QuestRecordIxCols { - pub actor_user_id: __sdk::__query_builder::IxCol, - pub issuer_npc_id: __sdk::__query_builder::IxCol, - pub quest_id: __sdk::__query_builder::IxCol, - pub runtime_session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for QuestRecord { - type IxCols = QuestRecordIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - QuestRecordIxCols { - actor_user_id: __sdk::__query_builder::IxCol::new(table_name, "actor_user_id"), - issuer_npc_id: __sdk::__query_builder::IxCol::new(table_name, "issuer_npc_id"), - quest_id: __sdk::__query_builder::IxCol::new(table_name, "quest_id"), - runtime_session_id: __sdk::__query_builder::IxCol::new( - table_name, - "runtime_session_id", - ), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for QuestRecord {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_reward_equipment_slot_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_reward_equipment_slot_type.rs deleted file mode 100644 index 43a942c4e..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_reward_equipment_slot_type.rs +++ /dev/null @@ -1,20 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum QuestRewardEquipmentSlot { - Weapon, - - Armor, - - Relic, -} - -impl __sdk::InModule for QuestRewardEquipmentSlot { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_reward_intel_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_reward_intel_type.rs deleted file mode 100644 index 9938686aa..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_reward_intel_type.rs +++ /dev/null @@ -1,16 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct QuestRewardIntel { - pub rumor_text: String, - pub unlocked_scene_id: Option, -} - -impl __sdk::InModule for QuestRewardIntel { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_reward_item_rarity_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_reward_item_rarity_type.rs deleted file mode 100644 index 7fc4f7ec0..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_reward_item_rarity_type.rs +++ /dev/null @@ -1,24 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum QuestRewardItemRarity { - Common, - - Uncommon, - - Rare, - - Epic, - - Legendary, -} - -impl __sdk::InModule for QuestRewardItemRarity { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_reward_item_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_reward_item_type.rs deleted file mode 100644 index a62f9d933..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_reward_item_type.rs +++ /dev/null @@ -1,27 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::quest_reward_equipment_slot_type::QuestRewardEquipmentSlot; -use super::quest_reward_item_rarity_type::QuestRewardItemRarity; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct QuestRewardItem { - pub item_id: String, - pub category: String, - pub name: String, - pub description: Option, - pub quantity: u32, - pub rarity: QuestRewardItemRarity, - pub tags: Vec, - pub stackable: bool, - pub stack_key: String, - pub equipment_slot_id: Option, -} - -impl __sdk::InModule for QuestRewardItem { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_reward_snapshot_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_reward_snapshot_type.rs deleted file mode 100644 index 995e84ad8..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_reward_snapshot_type.rs +++ /dev/null @@ -1,23 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::quest_reward_intel_type::QuestRewardIntel; -use super::quest_reward_item_type::QuestRewardItem; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct QuestRewardSnapshot { - pub affinity_bonus: i32, - pub currency: i64, - pub experience: Option, - pub items: Vec, - pub intel: Option, - pub story_hint: Option, -} - -impl __sdk::InModule for QuestRewardSnapshot { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_scene_reached_signal_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_scene_reached_signal_type.rs deleted file mode 100644 index 723d9325b..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_scene_reached_signal_type.rs +++ /dev/null @@ -1,15 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct QuestSceneReachedSignal { - pub scene_id: String, -} - -impl __sdk::InModule for QuestSceneReachedSignal { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_signal_kind_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_signal_kind_type.rs deleted file mode 100644 index 04ea66614..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_signal_kind_type.rs +++ /dev/null @@ -1,26 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum QuestSignalKind { - HostileNpcDefeated, - - TreasureInspected, - - NpcSparCompleted, - - NpcTalkCompleted, - - SceneReached, - - ItemDelivered, -} - -impl __sdk::InModule for QuestSignalKind { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_status_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_status_type.rs deleted file mode 100644 index f5defbb7a..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_status_type.rs +++ /dev/null @@ -1,26 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum QuestStatus { - Active, - - ReadyToTurnIn, - - Completed, - - TurnedIn, - - Failed, - - Expired, -} - -impl __sdk::InModule for QuestStatus { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_step_snapshot_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_step_snapshot_type.rs deleted file mode 100644 index 0f27cb9ed..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_step_snapshot_type.rs +++ /dev/null @@ -1,27 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::quest_objective_kind_type::QuestObjectiveKind; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct QuestStepSnapshot { - pub step_id: String, - pub kind: QuestObjectiveKind, - pub target_hostile_npc_id: Option, - pub target_npc_id: Option, - pub target_scene_id: Option, - pub target_item_id: Option, - pub required_count: u32, - pub progress: u32, - pub title: String, - pub reveal_text: String, - pub complete_text: String, -} - -impl __sdk::InModule for QuestStepSnapshot { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/quest_treasure_inspected_signal_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/quest_treasure_inspected_signal_type.rs deleted file mode 100644 index 51caed77c..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/quest_treasure_inspected_signal_type.rs +++ /dev/null @@ -1,15 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct QuestTreasureInspectedSignal { - pub scene_id: Option, -} - -impl __sdk::InModule for QuestTreasureInspectedSignal { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/record_daily_login_tracking_event_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/record_daily_login_tracking_event_and_return_procedure.rs index c131f3bab..9365d3359 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/record_daily_login_tracking_event_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/record_daily_login_tracking_event_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait record_daily_login_tracking_event_and_return { input: RuntimeProfileTaskCenterGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl record_daily_login_tracking_event_and_return for super::RemoteProcedures { input: RuntimeProfileTaskCenterGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeTrackingEventProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/record_profile_recharge_refund_observation_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/record_profile_recharge_refund_observation_and_return_procedure.rs index 5c450a579..2ee1c67a6 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/record_profile_recharge_refund_observation_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/record_profile_recharge_refund_observation_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait record_profile_recharge_refund_observation_and_return { input: RuntimeProfileRechargeRefundObservationInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl record_profile_recharge_refund_observation_and_return for super::RemoteProc input: RuntimeProfileRechargeRefundObservationInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRechargeRefundProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/record_tracking_event_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/record_tracking_event_and_return_procedure.rs index c09132c01..01361ec79 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/record_tracking_event_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/record_tracking_event_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait record_tracking_event_and_return { input: RuntimeTrackingEventInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl record_tracking_event_and_return for super::RemoteProcedures { input: RuntimeTrackingEventInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeTrackingEventProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/record_tracking_events_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/record_tracking_events_and_return_procedure.rs index 428e378f6..ba28d1a80 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/record_tracking_events_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/record_tracking_events_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait record_tracking_events_and_return { inputs: Vec, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl record_tracking_events_and_return for super::RemoteProcedures { inputs: Vec, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeTrackingEventBatchProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/redeem_profile_referral_invite_code_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/redeem_profile_referral_invite_code_procedure.rs index efebd26a0..44354acdf 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/redeem_profile_referral_invite_code_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/redeem_profile_referral_invite_code_procedure.rs @@ -31,10 +31,10 @@ pub trait redeem_profile_referral_invite_code { input: RuntimeReferralRedeemInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl redeem_profile_referral_invite_code for super::RemoteProcedures { input: RuntimeReferralRedeemInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeReferralRedeemProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/redeem_profile_reward_code_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/redeem_profile_reward_code_procedure.rs index 38fc64f51..4d048a49b 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/redeem_profile_reward_code_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/redeem_profile_reward_code_procedure.rs @@ -31,10 +31,10 @@ pub trait redeem_profile_reward_code { input: RuntimeProfileRewardCodeRedeemInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl redeem_profile_reward_code for super::RemoteProcedures { input: RuntimeProfileRewardCodeRedeemInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRewardCodeRedeemProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/refund_profile_wallet_points_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/refund_profile_wallet_points_and_return_procedure.rs index a4bbd3787..fb86172c0 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/refund_profile_wallet_points_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/refund_profile_wallet_points_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait refund_profile_wallet_points_and_return { input: RuntimeProfileWalletAdjustmentInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl refund_profile_wallet_points_and_return for super::RemoteProcedures { input: RuntimeProfileWalletAdjustmentInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileWalletAdjustmentProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/release_profile_recharge_refund_hold_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/release_profile_recharge_refund_hold_and_return_procedure.rs index 74e5ecadb..8697385ea 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/release_profile_recharge_refund_hold_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/release_profile_recharge_refund_hold_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait release_profile_recharge_refund_hold_and_return { input: RuntimeProfileRechargeRefundHoldReleaseInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl release_profile_recharge_refund_hold_and_return for super::RemoteProcedures input: RuntimeProfileRechargeRefundHoldReleaseInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRechargeRefundHoldProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/rename_editor_project_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/rename_editor_project_and_return_procedure.rs index 923337242..408122981 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/rename_editor_project_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/rename_editor_project_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait rename_editor_project_and_return { input: EditorProjectRenameInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl rename_editor_project_and_return for super::RemoteProcedures { input: EditorProjectRenameInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorProjectProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/renew_external_generation_job_lease_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/renew_external_generation_job_lease_and_return_procedure.rs index 0b31241b0..4cbd45fc1 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/renew_external_generation_job_lease_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/renew_external_generation_job_lease_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait renew_external_generation_job_lease_and_return { input: ExternalGenerationJobRenewLeaseInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl renew_external_generation_job_lease_and_return for super::RemoteProcedures input: ExternalGenerationJobRenewLeaseInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ExternalGenerationJobProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/repair_editor_asset_media_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/repair_editor_asset_media_and_return_procedure.rs index 63499dde6..1b035028b 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/repair_editor_asset_media_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/repair_editor_asset_media_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait repair_editor_asset_media_and_return { input: EditorAssetMediaRepairInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl repair_editor_asset_media_and_return for super::RemoteProcedures { input: EditorAssetMediaRepairInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorAssetProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/repair_editor_canvas_resources_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/repair_editor_canvas_resources_and_return_procedure.rs index 1960b07fe..a45b084b1 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/repair_editor_canvas_resources_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/repair_editor_canvas_resources_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait repair_editor_canvas_resources_and_return { input: EditorCanvasResourceRepairInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl repair_editor_canvas_resources_and_return for super::RemoteProcedures { input: EditorCanvasResourceRepairInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorCanvasResourceRepairProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/repair_editor_project_resource_media_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/repair_editor_project_resource_media_and_return_procedure.rs index 47b5c9178..7e521cd37 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/repair_editor_project_resource_media_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/repair_editor_project_resource_media_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait repair_editor_project_resource_media_and_return { input: EditorProjectResourceMediaRepairInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl repair_editor_project_resource_media_and_return for super::RemoteProcedures input: EditorProjectResourceMediaRepairInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorProjectResourceProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/resolve_editor_reference_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/resolve_editor_reference_and_return_procedure.rs index f25481dbf..e57f5cfb9 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/resolve_editor_reference_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/resolve_editor_reference_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait resolve_editor_reference_and_return { input: EditorReferenceResolveInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl resolve_editor_reference_and_return for super::RemoteProcedures { input: EditorReferenceResolveInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorReferenceProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/resolve_profile_recharge_refund_manual_review_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/resolve_profile_recharge_refund_manual_review_and_return_procedure.rs index ceb9383a9..96f8eb1fe 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/resolve_profile_recharge_refund_manual_review_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/resolve_profile_recharge_refund_manual_review_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait resolve_profile_recharge_refund_manual_review_and_return { input: RuntimeProfileRechargeRefundManualReviewResolveInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl resolve_profile_recharge_refund_manual_review_and_return for super::RemoteP input: RuntimeProfileRechargeRefundManualReviewResolveInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRechargeRefundProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/revoke_database_migration_operator_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/revoke_database_migration_operator_procedure.rs index fe0329266..feb5086ed 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/revoke_database_migration_operator_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/revoke_database_migration_operator_procedure.rs @@ -31,10 +31,10 @@ pub trait revoke_database_migration_operator { input: DatabaseMigrationRevokeOperatorInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl revoke_database_migration_operator for super::RemoteProcedures { input: DatabaseMigrationRevokeOperatorInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, DatabaseMigrationOperatorProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/revoke_external_api_key_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/revoke_external_api_key_and_return_procedure.rs index 9faef438c..d893b2180 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/revoke_external_api_key_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/revoke_external_api_key_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait revoke_external_api_key_and_return { input: ExternalApiKeyRevokeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl revoke_external_api_key_and_return for super::RemoteProcedures { input: ExternalApiKeyRevokeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ExternalApiKeyProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/rollback_editor_canvas_layout_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/rollback_editor_canvas_layout_and_return_procedure.rs index 0c43310f5..ef6918cf8 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/rollback_editor_canvas_layout_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/rollback_editor_canvas_layout_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait rollback_editor_canvas_layout_and_return { input: EditorCanvasLayoutMigrationInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl rollback_editor_canvas_layout_and_return for super::RemoteProcedures { input: EditorCanvasLayoutMigrationInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorCanvasLayoutMigrationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/rotate_editor_generation_runtime_service_identity_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/rotate_editor_generation_runtime_service_identity_and_return_procedure.rs index 25abb2448..5c4593116 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/rotate_editor_generation_runtime_service_identity_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/rotate_editor_generation_runtime_service_identity_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait rotate_editor_generation_runtime_service_identity_and_return { input: EditorGenerationRuntimeIdentityRotateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl rotate_editor_generation_runtime_service_identity_and_return for super::Rem input: EditorGenerationRuntimeIdentityRotateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorGenerationPricingConfigProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_draft_card_kind_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_draft_card_kind_type.rs deleted file mode 100644 index e082dc367..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_draft_card_kind_type.rs +++ /dev/null @@ -1,34 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum RpgAgentDraftCardKind { - World, - - Camp, - - Faction, - - Character, - - Landmark, - - Thread, - - Chapter, - - SceneChapter, - - Carrier, - - SidequestSeed, -} - -impl __sdk::InModule for RpgAgentDraftCardKind { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_draft_card_status_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_draft_card_status_type.rs deleted file mode 100644 index 391625f52..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_draft_card_status_type.rs +++ /dev/null @@ -1,22 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum RpgAgentDraftCardStatus { - Suggested, - - Confirmed, - - Locked, - - Warning, -} - -impl __sdk::InModule for RpgAgentDraftCardStatus { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_message_kind_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_message_kind_type.rs deleted file mode 100644 index fc54a7b19..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_message_kind_type.rs +++ /dev/null @@ -1,26 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum RpgAgentMessageKind { - Chat, - - Clarification, - - Summary, - - Checkpoint, - - Warning, - - ActionResult, -} - -impl __sdk::InModule for RpgAgentMessageKind { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_message_role_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_message_role_type.rs deleted file mode 100644 index 67e383f20..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_message_role_type.rs +++ /dev/null @@ -1,20 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum RpgAgentMessageRole { - User, - - Assistant, - - System, -} - -impl __sdk::InModule for RpgAgentMessageRole { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_operation_status_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_operation_status_type.rs deleted file mode 100644 index 555c04391..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_operation_status_type.rs +++ /dev/null @@ -1,22 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum RpgAgentOperationStatus { - Queued, - - Running, - - Completed, - - Failed, -} - -impl __sdk::InModule for RpgAgentOperationStatus { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_operation_type_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_operation_type_type.rs deleted file mode 100644 index 8ae1d00e3..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_operation_type_type.rs +++ /dev/null @@ -1,44 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum RpgAgentOperationType { - ProcessMessage, - - DraftFoundation, - - UpdateDraftCard, - - SyncResultProfile, - - GenerateCharacters, - - GenerateLandmarks, - - DeleteCharacters, - - DeleteLandmarks, - - GenerateRoleAssets, - - SyncRoleAssets, - - GenerateSceneAssets, - - SyncSceneAssets, - - ExpandLongTail, - - PublishWorld, - - RevertCheckpoint, -} - -impl __sdk::InModule for RpgAgentOperationType { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_stage_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_stage_type.rs deleted file mode 100644 index 1a94e20f0..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_stage_type.rs +++ /dev/null @@ -1,32 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum RpgAgentStage { - CollectingIntent, - - Clarifying, - - FoundationReview, - - ObjectRefining, - - VisualRefining, - - LongTailReview, - - ReadyToPublish, - - Published, - - Error, -} - -impl __sdk::InModule for RpgAgentStage { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/runtime_item_equipment_slot_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/runtime_item_equipment_slot_type.rs deleted file mode 100644 index b539d4f3f..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/runtime_item_equipment_slot_type.rs +++ /dev/null @@ -1,20 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum RuntimeItemEquipmentSlot { - Weapon, - - Armor, - - Relic, -} - -impl __sdk::InModule for RuntimeItemEquipmentSlot { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/runtime_item_reward_item_rarity_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/runtime_item_reward_item_rarity_type.rs deleted file mode 100644 index dc4250abc..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/runtime_item_reward_item_rarity_type.rs +++ /dev/null @@ -1,24 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum RuntimeItemRewardItemRarity { - Common, - - Uncommon, - - Rare, - - Epic, - - Legendary, -} - -impl __sdk::InModule for RuntimeItemRewardItemRarity { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/runtime_item_reward_item_snapshot_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/runtime_item_reward_item_snapshot_type.rs deleted file mode 100644 index 4df1f2488..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/runtime_item_reward_item_snapshot_type.rs +++ /dev/null @@ -1,27 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::runtime_item_equipment_slot_type::RuntimeItemEquipmentSlot; -use super::runtime_item_reward_item_rarity_type::RuntimeItemRewardItemRarity; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct RuntimeItemRewardItemSnapshot { - pub item_id: String, - pub category: String, - pub item_name: String, - pub description: Option, - pub quantity: u32, - pub rarity: RuntimeItemRewardItemRarity, - pub tags: Vec, - pub stackable: bool, - pub stack_key: String, - pub equipment_slot_id: Option, -} - -impl __sdk::InModule for RuntimeItemRewardItemSnapshot { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/save_editor_project_layout_ack_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/save_editor_project_layout_ack_procedure.rs index d2e864785..a564b72be 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/save_editor_project_layout_ack_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/save_editor_project_layout_ack_procedure.rs @@ -31,10 +31,10 @@ pub trait save_editor_project_layout_ack { input: EditorProjectLayoutSaveInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl save_editor_project_layout_ack for super::RemoteProcedures { input: EditorProjectLayoutSaveInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorProjectLayoutSaveProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/save_editor_project_layout_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/save_editor_project_layout_and_return_procedure.rs index e4eb529dc..17585bdf2 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/save_editor_project_layout_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/save_editor_project_layout_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait save_editor_project_layout_and_return { input: EditorProjectLayoutSaveInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl save_editor_project_layout_and_return for super::RemoteProcedures { input: EditorProjectLayoutSaveInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorProjectProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/save_editor_project_layout_v_2_ack_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/save_editor_project_layout_v_2_ack_procedure.rs index 144a5fc12..457b4a069 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/save_editor_project_layout_v_2_ack_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/save_editor_project_layout_v_2_ack_procedure.rs @@ -31,10 +31,10 @@ pub trait save_editor_project_layout_v_2_ack { input: EditorProjectLayoutSaveV2Input, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl save_editor_project_layout_v_2_ack for super::RemoteProcedures { input: EditorProjectLayoutSaveV2Input, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorProjectLayoutSaveV2ProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/save_editor_project_layout_v_2_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/save_editor_project_layout_v_2_and_return_procedure.rs index f53a28da4..4d5eabf86 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/save_editor_project_layout_v_2_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/save_editor_project_layout_v_2_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait save_editor_project_layout_v_2_and_return { input: EditorProjectLayoutSaveV2Input, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl save_editor_project_layout_v_2_and_return for super::RemoteProcedures { input: EditorProjectLayoutSaveV2Input, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorProjectProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/seed_analytics_date_dimensions_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/seed_analytics_date_dimensions_reducer.rs index 29d3b91d9..6e2ac3ad9 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/seed_analytics_date_dimensions_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/seed_analytics_date_dimensions_reducer.rs @@ -50,11 +50,9 @@ pub trait seed_analytics_date_dimensions { &self, input: AnalyticsDateDimensionSeedInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -63,11 +61,9 @@ impl seed_analytics_date_dimensions for super::RemoteReducers { &self, input: AnalyticsDateDimensionSeedInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(SeedAnalyticsDateDimensionsArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/set_editor_showcase_asset_like_for_viewer_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/set_editor_showcase_asset_like_for_viewer_and_return_procedure.rs index cca99f26e..ffe419e01 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/set_editor_showcase_asset_like_for_viewer_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/set_editor_showcase_asset_like_for_viewer_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait set_editor_showcase_asset_like_for_viewer_and_return { input: EditorShowcaseAssetLikeToggleInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl set_editor_showcase_asset_like_for_viewer_and_return for super::RemoteProce input: EditorShowcaseAssetLikeToggleInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorShowcaseAssetViewerProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_agent_message_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/square_hole_agent_message_row_type.rs deleted file mode 100644 index 5455e365f..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_agent_message_row_type.rs +++ /dev/null @@ -1,66 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct SquareHoleAgentMessageRow { - pub message_id: String, - pub session_id: String, - pub role: String, - pub kind: String, - pub text: String, - pub created_at: __sdk::Timestamp, -} - -impl __sdk::InModule for SquareHoleAgentMessageRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `SquareHoleAgentMessageRow`. -/// -/// Provides typed access to columns for query building. -pub struct SquareHoleAgentMessageRowCols { - pub message_id: __sdk::__query_builder::Col, - pub session_id: __sdk::__query_builder::Col, - pub role: __sdk::__query_builder::Col, - pub kind: __sdk::__query_builder::Col, - pub text: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for SquareHoleAgentMessageRow { - type Cols = SquareHoleAgentMessageRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - SquareHoleAgentMessageRowCols { - message_id: __sdk::__query_builder::Col::new(table_name, "message_id"), - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - role: __sdk::__query_builder::Col::new(table_name, "role"), - kind: __sdk::__query_builder::Col::new(table_name, "kind"), - text: __sdk::__query_builder::Col::new(table_name, "text"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - } - } -} - -/// Indexed column accessor struct for the table `SquareHoleAgentMessageRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct SquareHoleAgentMessageRowIxCols { - pub message_id: __sdk::__query_builder::IxCol, - pub session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for SquareHoleAgentMessageRow { - type IxCols = SquareHoleAgentMessageRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - SquareHoleAgentMessageRowIxCols { - message_id: __sdk::__query_builder::IxCol::new(table_name, "message_id"), - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for SquareHoleAgentMessageRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_agent_message_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/square_hole_agent_message_table.rs deleted file mode 100644 index 41991f0c1..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_agent_message_table.rs +++ /dev/null @@ -1,234 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::square_hole_agent_message_row_type::SquareHoleAgentMessageRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `square_hole_agent_message`. -/// -/// Obtain a handle from the [`SquareHoleAgentMessageTableAccess::square_hole_agent_message`] method on [`super::RemoteTables`], -/// like `ctx.db.square_hole_agent_message()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.square_hole_agent_message().on_insert(...)`. -pub struct SquareHoleAgentMessageTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `square_hole_agent_message`. -pub struct SquareHoleAgentMessageTableAccessor; - -impl __sdk::TableAccessor for SquareHoleAgentMessageTableAccessor { - type Row = SquareHoleAgentMessageRow; - type Handle<'db> = SquareHoleAgentMessageTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.square_hole_agent_message() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `square_hole_agent_message`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait SquareHoleAgentMessageTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`SquareHoleAgentMessageTableHandle`], which mediates access to the table `square_hole_agent_message`. - fn square_hole_agent_message(&self) -> SquareHoleAgentMessageTableHandle<'_>; -} - -impl SquareHoleAgentMessageTableAccess for super::RemoteTables { - fn square_hole_agent_message(&self) -> SquareHoleAgentMessageTableHandle<'_> { - SquareHoleAgentMessageTableHandle { - imp: self - .imp - .get_table::("square_hole_agent_message"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct SquareHoleAgentMessageInsertCallbackId(__sdk::CallbackId); -pub struct SquareHoleAgentMessageDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for SquareHoleAgentMessageTableHandle<'ctx> { - type Row = SquareHoleAgentMessageRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for SquareHoleAgentMessageTableHandle<'ctx> { - type Row = SquareHoleAgentMessageRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = SquareHoleAgentMessageInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> SquareHoleAgentMessageInsertCallbackId { - SquareHoleAgentMessageInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: SquareHoleAgentMessageInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = SquareHoleAgentMessageDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> SquareHoleAgentMessageDeleteCallbackId { - SquareHoleAgentMessageDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: SquareHoleAgentMessageDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for SquareHoleAgentMessageTableHandle<'ctx> { - type InsertCallbackId = SquareHoleAgentMessageInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> SquareHoleAgentMessageInsertCallbackId { - SquareHoleAgentMessageInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: SquareHoleAgentMessageInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for SquareHoleAgentMessageTableHandle<'ctx> { - type DeleteCallbackId = SquareHoleAgentMessageDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> SquareHoleAgentMessageDeleteCallbackId { - SquareHoleAgentMessageDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: SquareHoleAgentMessageDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct SquareHoleAgentMessageUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for SquareHoleAgentMessageTableHandle<'ctx> { - type UpdateCallbackId = SquareHoleAgentMessageUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> SquareHoleAgentMessageUpdateCallbackId { - SquareHoleAgentMessageUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: SquareHoleAgentMessageUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for SquareHoleAgentMessageTableHandle<'ctx> { - type UpdateCallbackId = SquareHoleAgentMessageUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> SquareHoleAgentMessageUpdateCallbackId { - SquareHoleAgentMessageUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: SquareHoleAgentMessageUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `message_id` unique index on the table `square_hole_agent_message`, -/// which allows point queries on the field of the same name -/// via the [`SquareHoleAgentMessageMessageIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.square_hole_agent_message().message_id().find(...)`. -pub struct SquareHoleAgentMessageMessageIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> SquareHoleAgentMessageTableHandle<'ctx> { - /// Get a handle on the `message_id` unique index on the table `square_hole_agent_message`. - pub fn message_id(&self) -> SquareHoleAgentMessageMessageIdUnique<'ctx> { - SquareHoleAgentMessageMessageIdUnique { - imp: self.imp.get_unique_constraint::("message_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> SquareHoleAgentMessageMessageIdUnique<'ctx> { - /// Find the subscribed row whose `message_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("square_hole_agent_message"); - _table.add_unique_constraint::("message_id", |row| &row.message_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `SquareHoleAgentMessageRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait square_hole_agent_messageQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `SquareHoleAgentMessageRow`. - fn square_hole_agent_message(&self) - -> __sdk::__query_builder::Table; -} - -impl square_hole_agent_messageQueryTableAccess for __sdk::QueryTableAccessor { - fn square_hole_agent_message( - &self, - ) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("square_hole_agent_message") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_agent_session_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/square_hole_agent_session_row_type.rs deleted file mode 100644 index 3f30cd52f..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_agent_session_row_type.rs +++ /dev/null @@ -1,90 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct SquareHoleAgentSessionRow { - pub session_id: String, - pub owner_user_id: String, - pub seed_text: String, - pub current_turn: u32, - pub progress_percent: u32, - pub stage: String, - pub config_json: String, - pub draft_json: String, - pub last_assistant_reply: String, - pub published_profile_id: String, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for SquareHoleAgentSessionRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `SquareHoleAgentSessionRow`. -/// -/// Provides typed access to columns for query building. -pub struct SquareHoleAgentSessionRowCols { - pub session_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub seed_text: __sdk::__query_builder::Col, - pub current_turn: __sdk::__query_builder::Col, - pub progress_percent: __sdk::__query_builder::Col, - pub stage: __sdk::__query_builder::Col, - pub config_json: __sdk::__query_builder::Col, - pub draft_json: __sdk::__query_builder::Col, - pub last_assistant_reply: __sdk::__query_builder::Col, - pub published_profile_id: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for SquareHoleAgentSessionRow { - type Cols = SquareHoleAgentSessionRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - SquareHoleAgentSessionRowCols { - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - seed_text: __sdk::__query_builder::Col::new(table_name, "seed_text"), - current_turn: __sdk::__query_builder::Col::new(table_name, "current_turn"), - progress_percent: __sdk::__query_builder::Col::new(table_name, "progress_percent"), - stage: __sdk::__query_builder::Col::new(table_name, "stage"), - config_json: __sdk::__query_builder::Col::new(table_name, "config_json"), - draft_json: __sdk::__query_builder::Col::new(table_name, "draft_json"), - last_assistant_reply: __sdk::__query_builder::Col::new( - table_name, - "last_assistant_reply", - ), - published_profile_id: __sdk::__query_builder::Col::new( - table_name, - "published_profile_id", - ), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `SquareHoleAgentSessionRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct SquareHoleAgentSessionRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for SquareHoleAgentSessionRow { - type IxCols = SquareHoleAgentSessionRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - SquareHoleAgentSessionRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for SquareHoleAgentSessionRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_agent_session_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/square_hole_agent_session_table.rs deleted file mode 100644 index ca8b8737f..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_agent_session_table.rs +++ /dev/null @@ -1,234 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::square_hole_agent_session_row_type::SquareHoleAgentSessionRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `square_hole_agent_session`. -/// -/// Obtain a handle from the [`SquareHoleAgentSessionTableAccess::square_hole_agent_session`] method on [`super::RemoteTables`], -/// like `ctx.db.square_hole_agent_session()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.square_hole_agent_session().on_insert(...)`. -pub struct SquareHoleAgentSessionTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `square_hole_agent_session`. -pub struct SquareHoleAgentSessionTableAccessor; - -impl __sdk::TableAccessor for SquareHoleAgentSessionTableAccessor { - type Row = SquareHoleAgentSessionRow; - type Handle<'db> = SquareHoleAgentSessionTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.square_hole_agent_session() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `square_hole_agent_session`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait SquareHoleAgentSessionTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`SquareHoleAgentSessionTableHandle`], which mediates access to the table `square_hole_agent_session`. - fn square_hole_agent_session(&self) -> SquareHoleAgentSessionTableHandle<'_>; -} - -impl SquareHoleAgentSessionTableAccess for super::RemoteTables { - fn square_hole_agent_session(&self) -> SquareHoleAgentSessionTableHandle<'_> { - SquareHoleAgentSessionTableHandle { - imp: self - .imp - .get_table::("square_hole_agent_session"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct SquareHoleAgentSessionInsertCallbackId(__sdk::CallbackId); -pub struct SquareHoleAgentSessionDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for SquareHoleAgentSessionTableHandle<'ctx> { - type Row = SquareHoleAgentSessionRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for SquareHoleAgentSessionTableHandle<'ctx> { - type Row = SquareHoleAgentSessionRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = SquareHoleAgentSessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> SquareHoleAgentSessionInsertCallbackId { - SquareHoleAgentSessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: SquareHoleAgentSessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = SquareHoleAgentSessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> SquareHoleAgentSessionDeleteCallbackId { - SquareHoleAgentSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: SquareHoleAgentSessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for SquareHoleAgentSessionTableHandle<'ctx> { - type InsertCallbackId = SquareHoleAgentSessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> SquareHoleAgentSessionInsertCallbackId { - SquareHoleAgentSessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: SquareHoleAgentSessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for SquareHoleAgentSessionTableHandle<'ctx> { - type DeleteCallbackId = SquareHoleAgentSessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> SquareHoleAgentSessionDeleteCallbackId { - SquareHoleAgentSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: SquareHoleAgentSessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct SquareHoleAgentSessionUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for SquareHoleAgentSessionTableHandle<'ctx> { - type UpdateCallbackId = SquareHoleAgentSessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> SquareHoleAgentSessionUpdateCallbackId { - SquareHoleAgentSessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: SquareHoleAgentSessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for SquareHoleAgentSessionTableHandle<'ctx> { - type UpdateCallbackId = SquareHoleAgentSessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> SquareHoleAgentSessionUpdateCallbackId { - SquareHoleAgentSessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: SquareHoleAgentSessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `session_id` unique index on the table `square_hole_agent_session`, -/// which allows point queries on the field of the same name -/// via the [`SquareHoleAgentSessionSessionIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.square_hole_agent_session().session_id().find(...)`. -pub struct SquareHoleAgentSessionSessionIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> SquareHoleAgentSessionTableHandle<'ctx> { - /// Get a handle on the `session_id` unique index on the table `square_hole_agent_session`. - pub fn session_id(&self) -> SquareHoleAgentSessionSessionIdUnique<'ctx> { - SquareHoleAgentSessionSessionIdUnique { - imp: self.imp.get_unique_constraint::("session_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> SquareHoleAgentSessionSessionIdUnique<'ctx> { - /// Find the subscribed row whose `session_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("square_hole_agent_session"); - _table.add_unique_constraint::("session_id", |row| &row.session_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `SquareHoleAgentSessionRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait square_hole_agent_sessionQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `SquareHoleAgentSessionRow`. - fn square_hole_agent_session(&self) - -> __sdk::__query_builder::Table; -} - -impl square_hole_agent_sessionQueryTableAccess for __sdk::QueryTableAccessor { - fn square_hole_agent_session( - &self, - ) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("square_hole_agent_session") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_runtime_run_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/square_hole_runtime_run_row_type.rs deleted file mode 100644 index 3acc901f9..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_runtime_run_row_type.rs +++ /dev/null @@ -1,98 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct SquareHoleRuntimeRunRow { - pub run_id: String, - pub owner_user_id: String, - pub profile_id: String, - pub status: String, - pub snapshot_version: u64, - pub started_at_ms: i64, - pub duration_limit_ms: i64, - pub finished_at_ms: i64, - pub elapsed_ms: i64, - pub total_shape_count: u32, - pub completed_shape_count: u32, - pub score: u32, - pub snapshot_json: String, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for SquareHoleRuntimeRunRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `SquareHoleRuntimeRunRow`. -/// -/// Provides typed access to columns for query building. -pub struct SquareHoleRuntimeRunRowCols { - pub run_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub profile_id: __sdk::__query_builder::Col, - pub status: __sdk::__query_builder::Col, - pub snapshot_version: __sdk::__query_builder::Col, - pub started_at_ms: __sdk::__query_builder::Col, - pub duration_limit_ms: __sdk::__query_builder::Col, - pub finished_at_ms: __sdk::__query_builder::Col, - pub elapsed_ms: __sdk::__query_builder::Col, - pub total_shape_count: __sdk::__query_builder::Col, - pub completed_shape_count: __sdk::__query_builder::Col, - pub score: __sdk::__query_builder::Col, - pub snapshot_json: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for SquareHoleRuntimeRunRow { - type Cols = SquareHoleRuntimeRunRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - SquareHoleRuntimeRunRowCols { - run_id: __sdk::__query_builder::Col::new(table_name, "run_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - status: __sdk::__query_builder::Col::new(table_name, "status"), - snapshot_version: __sdk::__query_builder::Col::new(table_name, "snapshot_version"), - started_at_ms: __sdk::__query_builder::Col::new(table_name, "started_at_ms"), - duration_limit_ms: __sdk::__query_builder::Col::new(table_name, "duration_limit_ms"), - finished_at_ms: __sdk::__query_builder::Col::new(table_name, "finished_at_ms"), - elapsed_ms: __sdk::__query_builder::Col::new(table_name, "elapsed_ms"), - total_shape_count: __sdk::__query_builder::Col::new(table_name, "total_shape_count"), - completed_shape_count: __sdk::__query_builder::Col::new( - table_name, - "completed_shape_count", - ), - score: __sdk::__query_builder::Col::new(table_name, "score"), - snapshot_json: __sdk::__query_builder::Col::new(table_name, "snapshot_json"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `SquareHoleRuntimeRunRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct SquareHoleRuntimeRunRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub profile_id: __sdk::__query_builder::IxCol, - pub run_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for SquareHoleRuntimeRunRow { - type IxCols = SquareHoleRuntimeRunRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - SquareHoleRuntimeRunRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::IxCol::new(table_name, "profile_id"), - run_id: __sdk::__query_builder::IxCol::new(table_name, "run_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for SquareHoleRuntimeRunRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_runtime_run_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/square_hole_runtime_run_table.rs deleted file mode 100644 index 01cc05452..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_runtime_run_table.rs +++ /dev/null @@ -1,231 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::square_hole_runtime_run_row_type::SquareHoleRuntimeRunRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `square_hole_runtime_run`. -/// -/// Obtain a handle from the [`SquareHoleRuntimeRunTableAccess::square_hole_runtime_run`] method on [`super::RemoteTables`], -/// like `ctx.db.square_hole_runtime_run()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.square_hole_runtime_run().on_insert(...)`. -pub struct SquareHoleRuntimeRunTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `square_hole_runtime_run`. -pub struct SquareHoleRuntimeRunTableAccessor; - -impl __sdk::TableAccessor for SquareHoleRuntimeRunTableAccessor { - type Row = SquareHoleRuntimeRunRow; - type Handle<'db> = SquareHoleRuntimeRunTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.square_hole_runtime_run() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `square_hole_runtime_run`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait SquareHoleRuntimeRunTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`SquareHoleRuntimeRunTableHandle`], which mediates access to the table `square_hole_runtime_run`. - fn square_hole_runtime_run(&self) -> SquareHoleRuntimeRunTableHandle<'_>; -} - -impl SquareHoleRuntimeRunTableAccess for super::RemoteTables { - fn square_hole_runtime_run(&self) -> SquareHoleRuntimeRunTableHandle<'_> { - SquareHoleRuntimeRunTableHandle { - imp: self - .imp - .get_table::("square_hole_runtime_run"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct SquareHoleRuntimeRunInsertCallbackId(__sdk::CallbackId); -pub struct SquareHoleRuntimeRunDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for SquareHoleRuntimeRunTableHandle<'ctx> { - type Row = SquareHoleRuntimeRunRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for SquareHoleRuntimeRunTableHandle<'ctx> { - type Row = SquareHoleRuntimeRunRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = SquareHoleRuntimeRunInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> SquareHoleRuntimeRunInsertCallbackId { - SquareHoleRuntimeRunInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: SquareHoleRuntimeRunInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = SquareHoleRuntimeRunDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> SquareHoleRuntimeRunDeleteCallbackId { - SquareHoleRuntimeRunDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: SquareHoleRuntimeRunDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for SquareHoleRuntimeRunTableHandle<'ctx> { - type InsertCallbackId = SquareHoleRuntimeRunInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> SquareHoleRuntimeRunInsertCallbackId { - SquareHoleRuntimeRunInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: SquareHoleRuntimeRunInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for SquareHoleRuntimeRunTableHandle<'ctx> { - type DeleteCallbackId = SquareHoleRuntimeRunDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> SquareHoleRuntimeRunDeleteCallbackId { - SquareHoleRuntimeRunDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: SquareHoleRuntimeRunDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct SquareHoleRuntimeRunUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for SquareHoleRuntimeRunTableHandle<'ctx> { - type UpdateCallbackId = SquareHoleRuntimeRunUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> SquareHoleRuntimeRunUpdateCallbackId { - SquareHoleRuntimeRunUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: SquareHoleRuntimeRunUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for SquareHoleRuntimeRunTableHandle<'ctx> { - type UpdateCallbackId = SquareHoleRuntimeRunUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> SquareHoleRuntimeRunUpdateCallbackId { - SquareHoleRuntimeRunUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: SquareHoleRuntimeRunUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `run_id` unique index on the table `square_hole_runtime_run`, -/// which allows point queries on the field of the same name -/// via the [`SquareHoleRuntimeRunRunIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.square_hole_runtime_run().run_id().find(...)`. -pub struct SquareHoleRuntimeRunRunIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> SquareHoleRuntimeRunTableHandle<'ctx> { - /// Get a handle on the `run_id` unique index on the table `square_hole_runtime_run`. - pub fn run_id(&self) -> SquareHoleRuntimeRunRunIdUnique<'ctx> { - SquareHoleRuntimeRunRunIdUnique { - imp: self.imp.get_unique_constraint::("run_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> SquareHoleRuntimeRunRunIdUnique<'ctx> { - /// Find the subscribed row whose `run_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("square_hole_runtime_run"); - _table.add_unique_constraint::("run_id", |row| &row.run_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `SquareHoleRuntimeRunRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait square_hole_runtime_runQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `SquareHoleRuntimeRunRow`. - fn square_hole_runtime_run(&self) -> __sdk::__query_builder::Table; -} - -impl square_hole_runtime_runQueryTableAccess for __sdk::QueryTableAccessor { - fn square_hole_runtime_run(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("square_hole_runtime_run") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_work_profile_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/square_hole_work_profile_row_type.rs deleted file mode 100644 index 9798d7da1..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_work_profile_row_type.rs +++ /dev/null @@ -1,114 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct SquareHoleWorkProfileRow { - pub profile_id: String, - pub work_id: String, - pub owner_user_id: String, - pub source_session_id: String, - pub author_display_name: String, - pub game_name: String, - pub theme_text: String, - pub twist_rule: String, - pub summary_text: String, - pub tags_json: String, - pub cover_image_src: String, - pub shape_count: u32, - pub difficulty: u32, - pub config_json: String, - pub publication_status: String, - pub play_count: u32, - pub updated_at: __sdk::Timestamp, - pub published_at: Option<__sdk::Timestamp>, - pub visible: bool, -} - -impl __sdk::InModule for SquareHoleWorkProfileRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `SquareHoleWorkProfileRow`. -/// -/// Provides typed access to columns for query building. -pub struct SquareHoleWorkProfileRowCols { - pub profile_id: __sdk::__query_builder::Col, - pub work_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub source_session_id: __sdk::__query_builder::Col, - pub author_display_name: __sdk::__query_builder::Col, - pub game_name: __sdk::__query_builder::Col, - pub theme_text: __sdk::__query_builder::Col, - pub twist_rule: __sdk::__query_builder::Col, - pub summary_text: __sdk::__query_builder::Col, - pub tags_json: __sdk::__query_builder::Col, - pub cover_image_src: __sdk::__query_builder::Col, - pub shape_count: __sdk::__query_builder::Col, - pub difficulty: __sdk::__query_builder::Col, - pub config_json: __sdk::__query_builder::Col, - pub publication_status: __sdk::__query_builder::Col, - pub play_count: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, - pub published_at: - __sdk::__query_builder::Col>, - pub visible: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for SquareHoleWorkProfileRow { - type Cols = SquareHoleWorkProfileRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - SquareHoleWorkProfileRowCols { - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - work_id: __sdk::__query_builder::Col::new(table_name, "work_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - source_session_id: __sdk::__query_builder::Col::new(table_name, "source_session_id"), - author_display_name: __sdk::__query_builder::Col::new( - table_name, - "author_display_name", - ), - game_name: __sdk::__query_builder::Col::new(table_name, "game_name"), - theme_text: __sdk::__query_builder::Col::new(table_name, "theme_text"), - twist_rule: __sdk::__query_builder::Col::new(table_name, "twist_rule"), - summary_text: __sdk::__query_builder::Col::new(table_name, "summary_text"), - tags_json: __sdk::__query_builder::Col::new(table_name, "tags_json"), - cover_image_src: __sdk::__query_builder::Col::new(table_name, "cover_image_src"), - shape_count: __sdk::__query_builder::Col::new(table_name, "shape_count"), - difficulty: __sdk::__query_builder::Col::new(table_name, "difficulty"), - config_json: __sdk::__query_builder::Col::new(table_name, "config_json"), - publication_status: __sdk::__query_builder::Col::new(table_name, "publication_status"), - play_count: __sdk::__query_builder::Col::new(table_name, "play_count"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - published_at: __sdk::__query_builder::Col::new(table_name, "published_at"), - visible: __sdk::__query_builder::Col::new(table_name, "visible"), - } - } -} - -/// Indexed column accessor struct for the table `SquareHoleWorkProfileRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct SquareHoleWorkProfileRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub profile_id: __sdk::__query_builder::IxCol, - pub publication_status: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for SquareHoleWorkProfileRow { - type IxCols = SquareHoleWorkProfileRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - SquareHoleWorkProfileRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::IxCol::new(table_name, "profile_id"), - publication_status: __sdk::__query_builder::IxCol::new( - table_name, - "publication_status", - ), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for SquareHoleWorkProfileRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_work_profile_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/square_hole_work_profile_table.rs deleted file mode 100644 index 923fe6c92..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_work_profile_table.rs +++ /dev/null @@ -1,231 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::square_hole_work_profile_row_type::SquareHoleWorkProfileRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `square_hole_work_profile`. -/// -/// Obtain a handle from the [`SquareHoleWorkProfileTableAccess::square_hole_work_profile`] method on [`super::RemoteTables`], -/// like `ctx.db.square_hole_work_profile()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.square_hole_work_profile().on_insert(...)`. -pub struct SquareHoleWorkProfileTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `square_hole_work_profile`. -pub struct SquareHoleWorkProfileTableAccessor; - -impl __sdk::TableAccessor for SquareHoleWorkProfileTableAccessor { - type Row = SquareHoleWorkProfileRow; - type Handle<'db> = SquareHoleWorkProfileTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.square_hole_work_profile() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `square_hole_work_profile`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait SquareHoleWorkProfileTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`SquareHoleWorkProfileTableHandle`], which mediates access to the table `square_hole_work_profile`. - fn square_hole_work_profile(&self) -> SquareHoleWorkProfileTableHandle<'_>; -} - -impl SquareHoleWorkProfileTableAccess for super::RemoteTables { - fn square_hole_work_profile(&self) -> SquareHoleWorkProfileTableHandle<'_> { - SquareHoleWorkProfileTableHandle { - imp: self - .imp - .get_table::("square_hole_work_profile"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct SquareHoleWorkProfileInsertCallbackId(__sdk::CallbackId); -pub struct SquareHoleWorkProfileDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for SquareHoleWorkProfileTableHandle<'ctx> { - type Row = SquareHoleWorkProfileRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for SquareHoleWorkProfileTableHandle<'ctx> { - type Row = SquareHoleWorkProfileRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = SquareHoleWorkProfileInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> SquareHoleWorkProfileInsertCallbackId { - SquareHoleWorkProfileInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: SquareHoleWorkProfileInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = SquareHoleWorkProfileDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> SquareHoleWorkProfileDeleteCallbackId { - SquareHoleWorkProfileDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: SquareHoleWorkProfileDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for SquareHoleWorkProfileTableHandle<'ctx> { - type InsertCallbackId = SquareHoleWorkProfileInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> SquareHoleWorkProfileInsertCallbackId { - SquareHoleWorkProfileInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: SquareHoleWorkProfileInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for SquareHoleWorkProfileTableHandle<'ctx> { - type DeleteCallbackId = SquareHoleWorkProfileDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> SquareHoleWorkProfileDeleteCallbackId { - SquareHoleWorkProfileDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: SquareHoleWorkProfileDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct SquareHoleWorkProfileUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for SquareHoleWorkProfileTableHandle<'ctx> { - type UpdateCallbackId = SquareHoleWorkProfileUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> SquareHoleWorkProfileUpdateCallbackId { - SquareHoleWorkProfileUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: SquareHoleWorkProfileUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for SquareHoleWorkProfileTableHandle<'ctx> { - type UpdateCallbackId = SquareHoleWorkProfileUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> SquareHoleWorkProfileUpdateCallbackId { - SquareHoleWorkProfileUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: SquareHoleWorkProfileUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `profile_id` unique index on the table `square_hole_work_profile`, -/// which allows point queries on the field of the same name -/// via the [`SquareHoleWorkProfileProfileIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.square_hole_work_profile().profile_id().find(...)`. -pub struct SquareHoleWorkProfileProfileIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> SquareHoleWorkProfileTableHandle<'ctx> { - /// Get a handle on the `profile_id` unique index on the table `square_hole_work_profile`. - pub fn profile_id(&self) -> SquareHoleWorkProfileProfileIdUnique<'ctx> { - SquareHoleWorkProfileProfileIdUnique { - imp: self.imp.get_unique_constraint::("profile_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> SquareHoleWorkProfileProfileIdUnique<'ctx> { - /// Find the subscribed row whose `profile_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("square_hole_work_profile"); - _table.add_unique_constraint::("profile_id", |row| &row.profile_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `SquareHoleWorkProfileRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait square_hole_work_profileQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `SquareHoleWorkProfileRow`. - fn square_hole_work_profile(&self) -> __sdk::__query_builder::Table; -} - -impl square_hole_work_profileQueryTableAccess for __sdk::QueryTableAccessor { - fn square_hole_work_profile(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("square_hole_work_profile") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/start_ai_task_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/start_ai_task_reducer.rs index c5cc52567..5809736bd 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/start_ai_task_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/start_ai_task_reducer.rs @@ -47,11 +47,9 @@ pub trait start_ai_task { &self, input: AiTaskStartInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl start_ai_task for super::RemoteReducers { &self, input: AiTaskStartInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(StartAiTaskArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/start_ai_task_stage_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/start_ai_task_stage_reducer.rs index 24ed5b3fa..1d7b7582a 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/start_ai_task_stage_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/start_ai_task_stage_reducer.rs @@ -47,11 +47,9 @@ pub trait start_ai_task_stage { &self, input: AiTaskStageStartInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl start_ai_task_stage for super::RemoteReducers { &self, input: AiTaskStageStartInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(StartAiTaskStageArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/story_event_kind_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/story_event_kind_type.rs deleted file mode 100644 index 29836b4a7..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/story_event_kind_type.rs +++ /dev/null @@ -1,18 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum StoryEventKind { - SessionStarted, - - StoryContinued, -} - -impl __sdk::InModule for StoryEventKind { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/story_event_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/story_event_table.rs deleted file mode 100644 index a02f01b11..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/story_event_table.rs +++ /dev/null @@ -1,229 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::story_event_kind_type::StoryEventKind; -use super::story_event_type::StoryEvent; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `story_event`. -/// -/// Obtain a handle from the [`StoryEventTableAccess::story_event`] method on [`super::RemoteTables`], -/// like `ctx.db.story_event()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.story_event().on_insert(...)`. -pub struct StoryEventTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `story_event`. -pub struct StoryEventTableAccessor; - -impl __sdk::TableAccessor for StoryEventTableAccessor { - type Row = StoryEvent; - type Handle<'db> = StoryEventTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.story_event() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `story_event`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait StoryEventTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`StoryEventTableHandle`], which mediates access to the table `story_event`. - fn story_event(&self) -> StoryEventTableHandle<'_>; -} - -impl StoryEventTableAccess for super::RemoteTables { - fn story_event(&self) -> StoryEventTableHandle<'_> { - StoryEventTableHandle { - imp: self.imp.get_table::("story_event"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct StoryEventInsertCallbackId(__sdk::CallbackId); -pub struct StoryEventDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for StoryEventTableHandle<'ctx> { - type Row = StoryEvent; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for StoryEventTableHandle<'ctx> { - type Row = StoryEvent; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = StoryEventInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> StoryEventInsertCallbackId { - StoryEventInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: StoryEventInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = StoryEventDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> StoryEventDeleteCallbackId { - StoryEventDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: StoryEventDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for StoryEventTableHandle<'ctx> { - type InsertCallbackId = StoryEventInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> StoryEventInsertCallbackId { - StoryEventInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: StoryEventInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for StoryEventTableHandle<'ctx> { - type DeleteCallbackId = StoryEventDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> StoryEventDeleteCallbackId { - StoryEventDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: StoryEventDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct StoryEventUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for StoryEventTableHandle<'ctx> { - type UpdateCallbackId = StoryEventUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> StoryEventUpdateCallbackId { - StoryEventUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: StoryEventUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for StoryEventTableHandle<'ctx> { - type UpdateCallbackId = StoryEventUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> StoryEventUpdateCallbackId { - StoryEventUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: StoryEventUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `event_id` unique index on the table `story_event`, -/// which allows point queries on the field of the same name -/// via the [`StoryEventEventIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.story_event().event_id().find(...)`. -pub struct StoryEventEventIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> StoryEventTableHandle<'ctx> { - /// Get a handle on the `event_id` unique index on the table `story_event`. - pub fn event_id(&self) -> StoryEventEventIdUnique<'ctx> { - StoryEventEventIdUnique { - imp: self.imp.get_unique_constraint::("event_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> StoryEventEventIdUnique<'ctx> { - /// Find the subscribed row whose `event_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("story_event"); - _table.add_unique_constraint::("event_id", |row| &row.event_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `StoryEvent`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait story_eventQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `StoryEvent`. - fn story_event(&self) -> __sdk::__query_builder::Table; -} - -impl story_eventQueryTableAccess for __sdk::QueryTableAccessor { - fn story_event(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("story_event") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/story_event_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/story_event_type.rs deleted file mode 100644 index 4d3bdd9f2..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/story_event_type.rs +++ /dev/null @@ -1,68 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::story_event_kind_type::StoryEventKind; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct StoryEvent { - pub event_id: String, - pub story_session_id: String, - pub event_kind: StoryEventKind, - pub narrative_text: String, - pub choice_function_id: Option, - pub created_at: __sdk::Timestamp, -} - -impl __sdk::InModule for StoryEvent { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `StoryEvent`. -/// -/// Provides typed access to columns for query building. -pub struct StoryEventCols { - pub event_id: __sdk::__query_builder::Col, - pub story_session_id: __sdk::__query_builder::Col, - pub event_kind: __sdk::__query_builder::Col, - pub narrative_text: __sdk::__query_builder::Col, - pub choice_function_id: __sdk::__query_builder::Col>, - pub created_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for StoryEvent { - type Cols = StoryEventCols; - fn cols(table_name: &'static str) -> Self::Cols { - StoryEventCols { - event_id: __sdk::__query_builder::Col::new(table_name, "event_id"), - story_session_id: __sdk::__query_builder::Col::new(table_name, "story_session_id"), - event_kind: __sdk::__query_builder::Col::new(table_name, "event_kind"), - narrative_text: __sdk::__query_builder::Col::new(table_name, "narrative_text"), - choice_function_id: __sdk::__query_builder::Col::new(table_name, "choice_function_id"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - } - } -} - -/// Indexed column accessor struct for the table `StoryEvent`. -/// -/// Provides typed access to indexed columns for query building. -pub struct StoryEventIxCols { - pub event_id: __sdk::__query_builder::IxCol, - pub story_session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for StoryEvent { - type IxCols = StoryEventIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - StoryEventIxCols { - event_id: __sdk::__query_builder::IxCol::new(table_name, "event_id"), - story_session_id: __sdk::__query_builder::IxCol::new(table_name, "story_session_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for StoryEvent {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/story_session_status_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/story_session_status_type.rs deleted file mode 100644 index f04aae19a..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/story_session_status_type.rs +++ /dev/null @@ -1,20 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum StorySessionStatus { - Active, - - Completed, - - Archived, -} - -impl __sdk::InModule for StorySessionStatus { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/story_session_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/story_session_table.rs deleted file mode 100644 index c7f0b8e02..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/story_session_table.rs +++ /dev/null @@ -1,229 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::story_session_status_type::StorySessionStatus; -use super::story_session_type::StorySession; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `story_session`. -/// -/// Obtain a handle from the [`StorySessionTableAccess::story_session`] method on [`super::RemoteTables`], -/// like `ctx.db.story_session()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.story_session().on_insert(...)`. -pub struct StorySessionTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `story_session`. -pub struct StorySessionTableAccessor; - -impl __sdk::TableAccessor for StorySessionTableAccessor { - type Row = StorySession; - type Handle<'db> = StorySessionTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.story_session() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `story_session`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait StorySessionTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`StorySessionTableHandle`], which mediates access to the table `story_session`. - fn story_session(&self) -> StorySessionTableHandle<'_>; -} - -impl StorySessionTableAccess for super::RemoteTables { - fn story_session(&self) -> StorySessionTableHandle<'_> { - StorySessionTableHandle { - imp: self.imp.get_table::("story_session"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct StorySessionInsertCallbackId(__sdk::CallbackId); -pub struct StorySessionDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for StorySessionTableHandle<'ctx> { - type Row = StorySession; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for StorySessionTableHandle<'ctx> { - type Row = StorySession; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = StorySessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> StorySessionInsertCallbackId { - StorySessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: StorySessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = StorySessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> StorySessionDeleteCallbackId { - StorySessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: StorySessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for StorySessionTableHandle<'ctx> { - type InsertCallbackId = StorySessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> StorySessionInsertCallbackId { - StorySessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: StorySessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for StorySessionTableHandle<'ctx> { - type DeleteCallbackId = StorySessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> StorySessionDeleteCallbackId { - StorySessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: StorySessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct StorySessionUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for StorySessionTableHandle<'ctx> { - type UpdateCallbackId = StorySessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> StorySessionUpdateCallbackId { - StorySessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: StorySessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for StorySessionTableHandle<'ctx> { - type UpdateCallbackId = StorySessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> StorySessionUpdateCallbackId { - StorySessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: StorySessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `story_session_id` unique index on the table `story_session`, -/// which allows point queries on the field of the same name -/// via the [`StorySessionStorySessionIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.story_session().story_session_id().find(...)`. -pub struct StorySessionStorySessionIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> StorySessionTableHandle<'ctx> { - /// Get a handle on the `story_session_id` unique index on the table `story_session`. - pub fn story_session_id(&self) -> StorySessionStorySessionIdUnique<'ctx> { - StorySessionStorySessionIdUnique { - imp: self.imp.get_unique_constraint::("story_session_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> StorySessionStorySessionIdUnique<'ctx> { - /// Find the subscribed row whose `story_session_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("story_session"); - _table.add_unique_constraint::("story_session_id", |row| &row.story_session_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `StorySession`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait story_sessionQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `StorySession`. - fn story_session(&self) -> __sdk::__query_builder::Table; -} - -impl story_sessionQueryTableAccess for __sdk::QueryTableAccessor { - fn story_session(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("story_session") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/story_session_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/story_session_type.rs deleted file mode 100644 index f95341792..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/story_session_type.rs +++ /dev/null @@ -1,97 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::story_session_status_type::StorySessionStatus; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct StorySession { - pub story_session_id: String, - pub runtime_session_id: String, - pub actor_user_id: String, - pub world_profile_id: String, - pub initial_prompt: String, - pub opening_summary: Option, - pub latest_narrative_text: String, - pub latest_choice_function_id: Option, - pub status: StorySessionStatus, - pub version: u32, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for StorySession { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `StorySession`. -/// -/// Provides typed access to columns for query building. -pub struct StorySessionCols { - pub story_session_id: __sdk::__query_builder::Col, - pub runtime_session_id: __sdk::__query_builder::Col, - pub actor_user_id: __sdk::__query_builder::Col, - pub world_profile_id: __sdk::__query_builder::Col, - pub initial_prompt: __sdk::__query_builder::Col, - pub opening_summary: __sdk::__query_builder::Col>, - pub latest_narrative_text: __sdk::__query_builder::Col, - pub latest_choice_function_id: __sdk::__query_builder::Col>, - pub status: __sdk::__query_builder::Col, - pub version: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for StorySession { - type Cols = StorySessionCols; - fn cols(table_name: &'static str) -> Self::Cols { - StorySessionCols { - story_session_id: __sdk::__query_builder::Col::new(table_name, "story_session_id"), - runtime_session_id: __sdk::__query_builder::Col::new(table_name, "runtime_session_id"), - actor_user_id: __sdk::__query_builder::Col::new(table_name, "actor_user_id"), - world_profile_id: __sdk::__query_builder::Col::new(table_name, "world_profile_id"), - initial_prompt: __sdk::__query_builder::Col::new(table_name, "initial_prompt"), - opening_summary: __sdk::__query_builder::Col::new(table_name, "opening_summary"), - latest_narrative_text: __sdk::__query_builder::Col::new( - table_name, - "latest_narrative_text", - ), - latest_choice_function_id: __sdk::__query_builder::Col::new( - table_name, - "latest_choice_function_id", - ), - status: __sdk::__query_builder::Col::new(table_name, "status"), - version: __sdk::__query_builder::Col::new(table_name, "version"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `StorySession`. -/// -/// Provides typed access to indexed columns for query building. -pub struct StorySessionIxCols { - pub actor_user_id: __sdk::__query_builder::IxCol, - pub runtime_session_id: __sdk::__query_builder::IxCol, - pub story_session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for StorySession { - type IxCols = StorySessionIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - StorySessionIxCols { - actor_user_id: __sdk::__query_builder::IxCol::new(table_name, "actor_user_id"), - runtime_session_id: __sdk::__query_builder::IxCol::new( - table_name, - "runtime_session_id", - ), - story_session_id: __sdk::__query_builder::IxCol::new(table_name, "story_session_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for StorySession {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/submit_editor_showcase_asset_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/submit_editor_showcase_asset_and_return_procedure.rs index 367fd0fdb..7002e581b 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/submit_editor_showcase_asset_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/submit_editor_showcase_asset_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait submit_editor_showcase_asset_and_return { input: EditorShowcaseAssetSubmitInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl submit_editor_showcase_asset_and_return for super::RemoteProcedures { input: EditorShowcaseAssetSubmitInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorShowcaseAssetProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/submit_profile_feedback_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/submit_profile_feedback_and_return_procedure.rs index 208a35a95..3534df7d3 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/submit_profile_feedback_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/submit_profile_feedback_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait submit_profile_feedback_and_return { input: RuntimeProfileFeedbackSubmissionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl submit_profile_feedback_and_return for super::RemoteProcedures { input: RuntimeProfileFeedbackSubmissionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileFeedbackSubmissionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/sync_auth_store_projection_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/sync_auth_store_projection_procedure.rs index d9f1ca3e3..7d4803e27 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/sync_auth_store_projection_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/sync_auth_store_projection_procedure.rs @@ -31,10 +31,10 @@ pub trait sync_auth_store_projection { input: AuthStoreProjectionView, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl sync_auth_store_projection for super::RemoteProcedures { input: AuthStoreProjectionView, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AuthStoreProjectionSyncProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/touch_editor_agent_conversation_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/touch_editor_agent_conversation_and_return_procedure.rs index e331ab348..89741e92c 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/touch_editor_agent_conversation_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/touch_editor_agent_conversation_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait touch_editor_agent_conversation_and_return { input: EditorAgentConversationTouchInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl touch_editor_agent_conversation_and_return for super::RemoteProcedures { input: EditorAgentConversationTouchInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorAgentConversationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/treasure_interaction_action_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/treasure_interaction_action_type.rs deleted file mode 100644 index a9b61b0e5..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/treasure_interaction_action_type.rs +++ /dev/null @@ -1,20 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Copy, Eq, Hash)] -pub enum TreasureInteractionAction { - Inspect, - - Leave, - - Secure, -} - -impl __sdk::InModule for TreasureInteractionAction { - type Module = super::RemoteModule; -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/treasure_record_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/treasure_record_table.rs deleted file mode 100644 index 090bcae75..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/treasure_record_table.rs +++ /dev/null @@ -1,232 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::runtime_item_reward_item_snapshot_type::RuntimeItemRewardItemSnapshot; -use super::treasure_interaction_action_type::TreasureInteractionAction; -use super::treasure_record_type::TreasureRecord; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `treasure_record`. -/// -/// Obtain a handle from the [`TreasureRecordTableAccess::treasure_record`] method on [`super::RemoteTables`], -/// like `ctx.db.treasure_record()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.treasure_record().on_insert(...)`. -pub struct TreasureRecordTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `treasure_record`. -pub struct TreasureRecordTableAccessor; - -impl __sdk::TableAccessor for TreasureRecordTableAccessor { - type Row = TreasureRecord; - type Handle<'db> = TreasureRecordTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.treasure_record() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `treasure_record`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait TreasureRecordTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`TreasureRecordTableHandle`], which mediates access to the table `treasure_record`. - fn treasure_record(&self) -> TreasureRecordTableHandle<'_>; -} - -impl TreasureRecordTableAccess for super::RemoteTables { - fn treasure_record(&self) -> TreasureRecordTableHandle<'_> { - TreasureRecordTableHandle { - imp: self.imp.get_table::("treasure_record"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct TreasureRecordInsertCallbackId(__sdk::CallbackId); -pub struct TreasureRecordDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for TreasureRecordTableHandle<'ctx> { - type Row = TreasureRecord; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for TreasureRecordTableHandle<'ctx> { - type Row = TreasureRecord; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = TreasureRecordInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> TreasureRecordInsertCallbackId { - TreasureRecordInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: TreasureRecordInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = TreasureRecordDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> TreasureRecordDeleteCallbackId { - TreasureRecordDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: TreasureRecordDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for TreasureRecordTableHandle<'ctx> { - type InsertCallbackId = TreasureRecordInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> TreasureRecordInsertCallbackId { - TreasureRecordInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: TreasureRecordInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for TreasureRecordTableHandle<'ctx> { - type DeleteCallbackId = TreasureRecordDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> TreasureRecordDeleteCallbackId { - TreasureRecordDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: TreasureRecordDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct TreasureRecordUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for TreasureRecordTableHandle<'ctx> { - type UpdateCallbackId = TreasureRecordUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> TreasureRecordUpdateCallbackId { - TreasureRecordUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: TreasureRecordUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for TreasureRecordTableHandle<'ctx> { - type UpdateCallbackId = TreasureRecordUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> TreasureRecordUpdateCallbackId { - TreasureRecordUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: TreasureRecordUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `treasure_record_id` unique index on the table `treasure_record`, -/// which allows point queries on the field of the same name -/// via the [`TreasureRecordTreasureRecordIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.treasure_record().treasure_record_id().find(...)`. -pub struct TreasureRecordTreasureRecordIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> TreasureRecordTableHandle<'ctx> { - /// Get a handle on the `treasure_record_id` unique index on the table `treasure_record`. - pub fn treasure_record_id(&self) -> TreasureRecordTreasureRecordIdUnique<'ctx> { - TreasureRecordTreasureRecordIdUnique { - imp: self - .imp - .get_unique_constraint::("treasure_record_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> TreasureRecordTreasureRecordIdUnique<'ctx> { - /// Find the subscribed row whose `treasure_record_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("treasure_record"); - _table.add_unique_constraint::("treasure_record_id", |row| &row.treasure_record_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `TreasureRecord`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait treasure_recordQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `TreasureRecord`. - fn treasure_record(&self) -> __sdk::__query_builder::Table; -} - -impl treasure_recordQueryTableAccess for __sdk::QueryTableAccessor { - fn treasure_record(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("treasure_record") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/treasure_record_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/treasure_record_type.rs deleted file mode 100644 index 9bcd8f6da..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/treasure_record_type.rs +++ /dev/null @@ -1,112 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::runtime_item_reward_item_snapshot_type::RuntimeItemRewardItemSnapshot; -use super::treasure_interaction_action_type::TreasureInteractionAction; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct TreasureRecord { - pub treasure_record_id: String, - pub runtime_session_id: String, - pub story_session_id: String, - pub actor_user_id: String, - pub encounter_id: String, - pub encounter_name: String, - pub scene_id: Option, - pub scene_name: Option, - pub action: TreasureInteractionAction, - pub reward_items: Vec, - pub reward_hp: u32, - pub reward_mana: u32, - pub reward_currency: u32, - pub story_hint: Option, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for TreasureRecord { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `TreasureRecord`. -/// -/// Provides typed access to columns for query building. -pub struct TreasureRecordCols { - pub treasure_record_id: __sdk::__query_builder::Col, - pub runtime_session_id: __sdk::__query_builder::Col, - pub story_session_id: __sdk::__query_builder::Col, - pub actor_user_id: __sdk::__query_builder::Col, - pub encounter_id: __sdk::__query_builder::Col, - pub encounter_name: __sdk::__query_builder::Col, - pub scene_id: __sdk::__query_builder::Col>, - pub scene_name: __sdk::__query_builder::Col>, - pub action: __sdk::__query_builder::Col, - pub reward_items: - __sdk::__query_builder::Col>, - pub reward_hp: __sdk::__query_builder::Col, - pub reward_mana: __sdk::__query_builder::Col, - pub reward_currency: __sdk::__query_builder::Col, - pub story_hint: __sdk::__query_builder::Col>, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for TreasureRecord { - type Cols = TreasureRecordCols; - fn cols(table_name: &'static str) -> Self::Cols { - TreasureRecordCols { - treasure_record_id: __sdk::__query_builder::Col::new(table_name, "treasure_record_id"), - runtime_session_id: __sdk::__query_builder::Col::new(table_name, "runtime_session_id"), - story_session_id: __sdk::__query_builder::Col::new(table_name, "story_session_id"), - actor_user_id: __sdk::__query_builder::Col::new(table_name, "actor_user_id"), - encounter_id: __sdk::__query_builder::Col::new(table_name, "encounter_id"), - encounter_name: __sdk::__query_builder::Col::new(table_name, "encounter_name"), - scene_id: __sdk::__query_builder::Col::new(table_name, "scene_id"), - scene_name: __sdk::__query_builder::Col::new(table_name, "scene_name"), - action: __sdk::__query_builder::Col::new(table_name, "action"), - reward_items: __sdk::__query_builder::Col::new(table_name, "reward_items"), - reward_hp: __sdk::__query_builder::Col::new(table_name, "reward_hp"), - reward_mana: __sdk::__query_builder::Col::new(table_name, "reward_mana"), - reward_currency: __sdk::__query_builder::Col::new(table_name, "reward_currency"), - story_hint: __sdk::__query_builder::Col::new(table_name, "story_hint"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `TreasureRecord`. -/// -/// Provides typed access to indexed columns for query building. -pub struct TreasureRecordIxCols { - pub actor_user_id: __sdk::__query_builder::IxCol, - pub encounter_id: __sdk::__query_builder::IxCol, - pub runtime_session_id: __sdk::__query_builder::IxCol, - pub story_session_id: __sdk::__query_builder::IxCol, - pub treasure_record_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for TreasureRecord { - type IxCols = TreasureRecordIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - TreasureRecordIxCols { - actor_user_id: __sdk::__query_builder::IxCol::new(table_name, "actor_user_id"), - encounter_id: __sdk::__query_builder::IxCol::new(table_name, "encounter_id"), - runtime_session_id: __sdk::__query_builder::IxCol::new( - table_name, - "runtime_session_id", - ), - story_session_id: __sdk::__query_builder::IxCol::new(table_name, "story_session_id"), - treasure_record_id: __sdk::__query_builder::IxCol::new( - table_name, - "treasure_record_id", - ), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for TreasureRecord {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/update_admin_account_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/update_admin_account_and_return_procedure.rs index e1d2deba0..1eb839663 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/update_admin_account_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/update_admin_account_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait update_admin_account_and_return { input: AdminAccountUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl update_admin_account_and_return for super::RemoteProcedures { input: AdminAccountUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AdminAccountProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/update_editor_asset_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/update_editor_asset_and_return_procedure.rs index 4e0cfd34e..1ec662919 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/update_editor_asset_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/update_editor_asset_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait update_editor_asset_and_return { input: EditorAssetUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl update_editor_asset_and_return for super::RemoteProcedures { input: EditorAssetUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorAssetProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/update_editor_asset_folder_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/update_editor_asset_folder_and_return_procedure.rs index 91ca31fc5..a5ec71437 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/update_editor_asset_folder_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/update_editor_asset_folder_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait update_editor_asset_folder_and_return { input: EditorAssetFolderUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl update_editor_asset_folder_and_return for super::RemoteProcedures { input: EditorAssetFolderUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorAssetFolderProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/update_editor_project_resource_showcase_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/update_editor_project_resource_showcase_and_return_procedure.rs index c49ab8d9d..200432a78 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/update_editor_project_resource_showcase_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/update_editor_project_resource_showcase_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait update_editor_project_resource_showcase_and_return { input: EditorProjectResourceShowcaseUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl update_editor_project_resource_showcase_and_return for super::RemoteProcedu input: EditorProjectResourceShowcaseUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorProjectResourceProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/update_editor_showcase_asset_display_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/update_editor_showcase_asset_display_and_return_procedure.rs index 85db684da..40b912558 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/update_editor_showcase_asset_display_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/update_editor_showcase_asset_display_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait update_editor_showcase_asset_display_and_return { input: EditorShowcaseAssetDisplayUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl update_editor_showcase_asset_display_and_return for super::RemoteProcedures input: EditorShowcaseAssetDisplayUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorShowcaseAssetProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/update_external_generation_job_phase_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/update_external_generation_job_phase_and_return_procedure.rs index a6cc1b841..890d5b4d6 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/update_external_generation_job_phase_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/update_external_generation_job_phase_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait update_external_generation_job_phase_and_return { input: ExternalGenerationJobPhaseUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl update_external_generation_job_phase_and_return for super::RemoteProcedures input: ExternalGenerationJobPhaseUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ExternalGenerationJobPhaseUpdateProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/upload_agc_analytics_batch_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/upload_agc_analytics_batch_procedure.rs new file mode 100644 index 000000000..c6fb47968 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/upload_agc_analytics_batch_procedure.rs @@ -0,0 +1,56 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +struct UploadAgcAnalyticsBatchArgs { + pub payload_json: String, +} + +impl __sdk::InModule for UploadAgcAnalyticsBatchArgs { + type Module = super::RemoteModule; +} + +#[allow(non_camel_case_types)] +/// Extension trait for access to the procedure `upload_agc_analytics_batch`. +/// +/// Implemented for [`super::RemoteProcedures`]. +pub trait upload_agc_analytics_batch { + fn upload_agc_analytics_batch(&self, payload_json: String) { + self.upload_agc_analytics_batch_then(payload_json, |_, _| {}); + } + + fn upload_agc_analytics_batch_then( + &self, + payload_json: String, + + __callback: impl FnOnce( + &super::ProcedureEventContext, + Result, __sdk::InternalError>, + ) + Send + + 'static, + ); +} + +impl upload_agc_analytics_batch for super::RemoteProcedures { + fn upload_agc_analytics_batch_then( + &self, + payload_json: String, + + __callback: impl FnOnce( + &super::ProcedureEventContext, + Result, __sdk::InternalError>, + ) + Send + + 'static, + ) { + self.imp + .invoke_procedure_with_callback::<_, Result>( + "upload_agc_analytics_batch", + UploadAgcAnalyticsBatchArgs { payload_json }, + __callback, + ); + } +} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/upsert_editor_generation_pricing_config_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/upsert_editor_generation_pricing_config_and_return_procedure.rs index 9cb7c1e77..e822ed9df 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/upsert_editor_generation_pricing_config_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/upsert_editor_generation_pricing_config_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait upsert_editor_generation_pricing_config_and_return { input: EditorGenerationPricingConfigUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl upsert_editor_generation_pricing_config_and_return for super::RemoteProcedu input: EditorGenerationPricingConfigUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorGenerationPricingConfigProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/upsert_editor_showcase_campaign_config_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/upsert_editor_showcase_campaign_config_and_return_procedure.rs index ae0bb7a6c..490d65d5d 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/upsert_editor_showcase_campaign_config_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/upsert_editor_showcase_campaign_config_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait upsert_editor_showcase_campaign_config_and_return { input: EditorShowcaseCampaignConfigUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl upsert_editor_showcase_campaign_config_and_return for super::RemoteProcedur input: EditorShowcaseCampaignConfigUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, EditorShowcaseCampaignConfigProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/upsert_feature_gate_config_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/upsert_feature_gate_config_procedure.rs index ece1afe07..3e7c3cfcb 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/upsert_feature_gate_config_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/upsert_feature_gate_config_procedure.rs @@ -31,10 +31,10 @@ pub trait upsert_feature_gate_config { input: FeatureGateConfigAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl upsert_feature_gate_config for super::RemoteProcedures { input: FeatureGateConfigAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, FeatureGateConfigProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/upsert_llm_router_account_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/upsert_llm_router_account_and_return_procedure.rs index db8e81711..c1881f3ce 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/upsert_llm_router_account_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/upsert_llm_router_account_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait upsert_llm_router_account_and_return { input: LlmRouterAccountUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl upsert_llm_router_account_and_return for super::RemoteProcedures { input: LlmRouterAccountUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, LlmRouterAccountProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/upsert_runtime_setting_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/upsert_runtime_setting_and_return_procedure.rs index f8fa0351a..119eab703 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/upsert_runtime_setting_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/upsert_runtime_setting_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait upsert_runtime_setting_and_return { input: RuntimeSettingUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl upsert_runtime_setting_and_return for super::RemoteProcedures { input: RuntimeSettingUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeSettingProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/validate_auth_session_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/validate_auth_session_procedure.rs index 26af4bb8f..e96904972 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/validate_auth_session_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/validate_auth_session_procedure.rs @@ -31,10 +31,10 @@ pub trait validate_auth_session { input: AuthSessionValidationInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl validate_auth_session for super::RemoteProcedures { input: AuthSessionValidationInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AuthSessionValidationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_agent_message_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_agent_message_row_type.rs deleted file mode 100644 index 184705061..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_agent_message_row_type.rs +++ /dev/null @@ -1,66 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct VisualNovelAgentMessageRow { - pub message_id: String, - pub session_id: String, - pub role: String, - pub kind: String, - pub text: String, - pub created_at: __sdk::Timestamp, -} - -impl __sdk::InModule for VisualNovelAgentMessageRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `VisualNovelAgentMessageRow`. -/// -/// Provides typed access to columns for query building. -pub struct VisualNovelAgentMessageRowCols { - pub message_id: __sdk::__query_builder::Col, - pub session_id: __sdk::__query_builder::Col, - pub role: __sdk::__query_builder::Col, - pub kind: __sdk::__query_builder::Col, - pub text: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for VisualNovelAgentMessageRow { - type Cols = VisualNovelAgentMessageRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - VisualNovelAgentMessageRowCols { - message_id: __sdk::__query_builder::Col::new(table_name, "message_id"), - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - role: __sdk::__query_builder::Col::new(table_name, "role"), - kind: __sdk::__query_builder::Col::new(table_name, "kind"), - text: __sdk::__query_builder::Col::new(table_name, "text"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - } - } -} - -/// Indexed column accessor struct for the table `VisualNovelAgentMessageRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct VisualNovelAgentMessageRowIxCols { - pub message_id: __sdk::__query_builder::IxCol, - pub session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for VisualNovelAgentMessageRow { - type IxCols = VisualNovelAgentMessageRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - VisualNovelAgentMessageRowIxCols { - message_id: __sdk::__query_builder::IxCol::new(table_name, "message_id"), - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for VisualNovelAgentMessageRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_agent_message_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_agent_message_table.rs deleted file mode 100644 index 5de1de62d..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_agent_message_table.rs +++ /dev/null @@ -1,235 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::visual_novel_agent_message_row_type::VisualNovelAgentMessageRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `visual_novel_agent_message`. -/// -/// Obtain a handle from the [`VisualNovelAgentMessageTableAccess::visual_novel_agent_message`] method on [`super::RemoteTables`], -/// like `ctx.db.visual_novel_agent_message()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.visual_novel_agent_message().on_insert(...)`. -pub struct VisualNovelAgentMessageTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `visual_novel_agent_message`. -pub struct VisualNovelAgentMessageTableAccessor; - -impl __sdk::TableAccessor for VisualNovelAgentMessageTableAccessor { - type Row = VisualNovelAgentMessageRow; - type Handle<'db> = VisualNovelAgentMessageTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.visual_novel_agent_message() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `visual_novel_agent_message`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait VisualNovelAgentMessageTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`VisualNovelAgentMessageTableHandle`], which mediates access to the table `visual_novel_agent_message`. - fn visual_novel_agent_message(&self) -> VisualNovelAgentMessageTableHandle<'_>; -} - -impl VisualNovelAgentMessageTableAccess for super::RemoteTables { - fn visual_novel_agent_message(&self) -> VisualNovelAgentMessageTableHandle<'_> { - VisualNovelAgentMessageTableHandle { - imp: self - .imp - .get_table::("visual_novel_agent_message"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct VisualNovelAgentMessageInsertCallbackId(__sdk::CallbackId); -pub struct VisualNovelAgentMessageDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for VisualNovelAgentMessageTableHandle<'ctx> { - type Row = VisualNovelAgentMessageRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for VisualNovelAgentMessageTableHandle<'ctx> { - type Row = VisualNovelAgentMessageRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = VisualNovelAgentMessageInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelAgentMessageInsertCallbackId { - VisualNovelAgentMessageInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: VisualNovelAgentMessageInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = VisualNovelAgentMessageDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelAgentMessageDeleteCallbackId { - VisualNovelAgentMessageDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: VisualNovelAgentMessageDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for VisualNovelAgentMessageTableHandle<'ctx> { - type InsertCallbackId = VisualNovelAgentMessageInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelAgentMessageInsertCallbackId { - VisualNovelAgentMessageInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: VisualNovelAgentMessageInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for VisualNovelAgentMessageTableHandle<'ctx> { - type DeleteCallbackId = VisualNovelAgentMessageDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelAgentMessageDeleteCallbackId { - VisualNovelAgentMessageDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: VisualNovelAgentMessageDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct VisualNovelAgentMessageUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for VisualNovelAgentMessageTableHandle<'ctx> { - type UpdateCallbackId = VisualNovelAgentMessageUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> VisualNovelAgentMessageUpdateCallbackId { - VisualNovelAgentMessageUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: VisualNovelAgentMessageUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for VisualNovelAgentMessageTableHandle<'ctx> { - type UpdateCallbackId = VisualNovelAgentMessageUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> VisualNovelAgentMessageUpdateCallbackId { - VisualNovelAgentMessageUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: VisualNovelAgentMessageUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `message_id` unique index on the table `visual_novel_agent_message`, -/// which allows point queries on the field of the same name -/// via the [`VisualNovelAgentMessageMessageIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.visual_novel_agent_message().message_id().find(...)`. -pub struct VisualNovelAgentMessageMessageIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> VisualNovelAgentMessageTableHandle<'ctx> { - /// Get a handle on the `message_id` unique index on the table `visual_novel_agent_message`. - pub fn message_id(&self) -> VisualNovelAgentMessageMessageIdUnique<'ctx> { - VisualNovelAgentMessageMessageIdUnique { - imp: self.imp.get_unique_constraint::("message_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> VisualNovelAgentMessageMessageIdUnique<'ctx> { - /// Find the subscribed row whose `message_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("visual_novel_agent_message"); - _table.add_unique_constraint::("message_id", |row| &row.message_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `VisualNovelAgentMessageRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait visual_novel_agent_messageQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `VisualNovelAgentMessageRow`. - fn visual_novel_agent_message( - &self, - ) -> __sdk::__query_builder::Table; -} - -impl visual_novel_agent_messageQueryTableAccess for __sdk::QueryTableAccessor { - fn visual_novel_agent_message( - &self, - ) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("visual_novel_agent_message") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_agent_session_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_agent_session_row_type.rs deleted file mode 100644 index 6d00cc9a0..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_agent_session_row_type.rs +++ /dev/null @@ -1,102 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct VisualNovelAgentSessionRow { - pub session_id: String, - pub owner_user_id: String, - pub source_mode: String, - pub status: String, - pub seed_text: String, - pub source_asset_ids_json: String, - pub current_turn: u32, - pub progress_percent: u32, - pub draft_json: String, - pub pending_action_json: String, - pub last_assistant_reply: String, - pub published_profile_id: String, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for VisualNovelAgentSessionRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `VisualNovelAgentSessionRow`. -/// -/// Provides typed access to columns for query building. -pub struct VisualNovelAgentSessionRowCols { - pub session_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub source_mode: __sdk::__query_builder::Col, - pub status: __sdk::__query_builder::Col, - pub seed_text: __sdk::__query_builder::Col, - pub source_asset_ids_json: __sdk::__query_builder::Col, - pub current_turn: __sdk::__query_builder::Col, - pub progress_percent: __sdk::__query_builder::Col, - pub draft_json: __sdk::__query_builder::Col, - pub pending_action_json: __sdk::__query_builder::Col, - pub last_assistant_reply: __sdk::__query_builder::Col, - pub published_profile_id: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for VisualNovelAgentSessionRow { - type Cols = VisualNovelAgentSessionRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - VisualNovelAgentSessionRowCols { - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - source_mode: __sdk::__query_builder::Col::new(table_name, "source_mode"), - status: __sdk::__query_builder::Col::new(table_name, "status"), - seed_text: __sdk::__query_builder::Col::new(table_name, "seed_text"), - source_asset_ids_json: __sdk::__query_builder::Col::new( - table_name, - "source_asset_ids_json", - ), - current_turn: __sdk::__query_builder::Col::new(table_name, "current_turn"), - progress_percent: __sdk::__query_builder::Col::new(table_name, "progress_percent"), - draft_json: __sdk::__query_builder::Col::new(table_name, "draft_json"), - pending_action_json: __sdk::__query_builder::Col::new( - table_name, - "pending_action_json", - ), - last_assistant_reply: __sdk::__query_builder::Col::new( - table_name, - "last_assistant_reply", - ), - published_profile_id: __sdk::__query_builder::Col::new( - table_name, - "published_profile_id", - ), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `VisualNovelAgentSessionRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct VisualNovelAgentSessionRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for VisualNovelAgentSessionRow { - type IxCols = VisualNovelAgentSessionRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - VisualNovelAgentSessionRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for VisualNovelAgentSessionRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_agent_session_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_agent_session_table.rs deleted file mode 100644 index a2ce33cd7..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_agent_session_table.rs +++ /dev/null @@ -1,235 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::visual_novel_agent_session_row_type::VisualNovelAgentSessionRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `visual_novel_agent_session`. -/// -/// Obtain a handle from the [`VisualNovelAgentSessionTableAccess::visual_novel_agent_session`] method on [`super::RemoteTables`], -/// like `ctx.db.visual_novel_agent_session()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.visual_novel_agent_session().on_insert(...)`. -pub struct VisualNovelAgentSessionTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `visual_novel_agent_session`. -pub struct VisualNovelAgentSessionTableAccessor; - -impl __sdk::TableAccessor for VisualNovelAgentSessionTableAccessor { - type Row = VisualNovelAgentSessionRow; - type Handle<'db> = VisualNovelAgentSessionTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.visual_novel_agent_session() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `visual_novel_agent_session`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait VisualNovelAgentSessionTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`VisualNovelAgentSessionTableHandle`], which mediates access to the table `visual_novel_agent_session`. - fn visual_novel_agent_session(&self) -> VisualNovelAgentSessionTableHandle<'_>; -} - -impl VisualNovelAgentSessionTableAccess for super::RemoteTables { - fn visual_novel_agent_session(&self) -> VisualNovelAgentSessionTableHandle<'_> { - VisualNovelAgentSessionTableHandle { - imp: self - .imp - .get_table::("visual_novel_agent_session"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct VisualNovelAgentSessionInsertCallbackId(__sdk::CallbackId); -pub struct VisualNovelAgentSessionDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for VisualNovelAgentSessionTableHandle<'ctx> { - type Row = VisualNovelAgentSessionRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for VisualNovelAgentSessionTableHandle<'ctx> { - type Row = VisualNovelAgentSessionRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = VisualNovelAgentSessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelAgentSessionInsertCallbackId { - VisualNovelAgentSessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: VisualNovelAgentSessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = VisualNovelAgentSessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelAgentSessionDeleteCallbackId { - VisualNovelAgentSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: VisualNovelAgentSessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for VisualNovelAgentSessionTableHandle<'ctx> { - type InsertCallbackId = VisualNovelAgentSessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelAgentSessionInsertCallbackId { - VisualNovelAgentSessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: VisualNovelAgentSessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for VisualNovelAgentSessionTableHandle<'ctx> { - type DeleteCallbackId = VisualNovelAgentSessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelAgentSessionDeleteCallbackId { - VisualNovelAgentSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: VisualNovelAgentSessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct VisualNovelAgentSessionUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for VisualNovelAgentSessionTableHandle<'ctx> { - type UpdateCallbackId = VisualNovelAgentSessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> VisualNovelAgentSessionUpdateCallbackId { - VisualNovelAgentSessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: VisualNovelAgentSessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for VisualNovelAgentSessionTableHandle<'ctx> { - type UpdateCallbackId = VisualNovelAgentSessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> VisualNovelAgentSessionUpdateCallbackId { - VisualNovelAgentSessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: VisualNovelAgentSessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `session_id` unique index on the table `visual_novel_agent_session`, -/// which allows point queries on the field of the same name -/// via the [`VisualNovelAgentSessionSessionIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.visual_novel_agent_session().session_id().find(...)`. -pub struct VisualNovelAgentSessionSessionIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> VisualNovelAgentSessionTableHandle<'ctx> { - /// Get a handle on the `session_id` unique index on the table `visual_novel_agent_session`. - pub fn session_id(&self) -> VisualNovelAgentSessionSessionIdUnique<'ctx> { - VisualNovelAgentSessionSessionIdUnique { - imp: self.imp.get_unique_constraint::("session_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> VisualNovelAgentSessionSessionIdUnique<'ctx> { - /// Find the subscribed row whose `session_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("visual_novel_agent_session"); - _table.add_unique_constraint::("session_id", |row| &row.session_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `VisualNovelAgentSessionRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait visual_novel_agent_sessionQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `VisualNovelAgentSessionRow`. - fn visual_novel_agent_session( - &self, - ) -> __sdk::__query_builder::Table; -} - -impl visual_novel_agent_sessionQueryTableAccess for __sdk::QueryTableAccessor { - fn visual_novel_agent_session( - &self, - ) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("visual_novel_agent_session") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_runtime_event_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_runtime_event_table.rs deleted file mode 100644 index 83457c6d7..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_runtime_event_table.rs +++ /dev/null @@ -1,140 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::visual_novel_runtime_event_type::VisualNovelRuntimeEvent; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `visual_novel_runtime_event`. -/// -/// Obtain a handle from the [`VisualNovelRuntimeEventTableAccess::visual_novel_runtime_event`] method on [`super::RemoteTables`], -/// like `ctx.db.visual_novel_runtime_event()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.visual_novel_runtime_event().on_insert(...)`. -pub struct VisualNovelRuntimeEventTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `visual_novel_runtime_event`. -pub struct VisualNovelRuntimeEventTableAccessor; - -impl __sdk::TableAccessor for VisualNovelRuntimeEventTableAccessor { - type Row = VisualNovelRuntimeEvent; - type Handle<'db> = VisualNovelRuntimeEventTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.visual_novel_runtime_event() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `visual_novel_runtime_event`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait VisualNovelRuntimeEventTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`VisualNovelRuntimeEventTableHandle`], which mediates access to the table `visual_novel_runtime_event`. - fn visual_novel_runtime_event(&self) -> VisualNovelRuntimeEventTableHandle<'_>; -} - -impl VisualNovelRuntimeEventTableAccess for super::RemoteTables { - fn visual_novel_runtime_event(&self) -> VisualNovelRuntimeEventTableHandle<'_> { - VisualNovelRuntimeEventTableHandle { - imp: self - .imp - .get_table::("visual_novel_runtime_event"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct VisualNovelRuntimeEventInsertCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for VisualNovelRuntimeEventTableHandle<'ctx> { - type Row = VisualNovelRuntimeEvent; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::EventTable for VisualNovelRuntimeEventTableHandle<'ctx> { - type Row = VisualNovelRuntimeEvent; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = VisualNovelRuntimeEventInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelRuntimeEventInsertCallbackId { - VisualNovelRuntimeEventInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: VisualNovelRuntimeEventInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for VisualNovelRuntimeEventTableHandle<'ctx> { - type InsertCallbackId = VisualNovelRuntimeEventInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelRuntimeEventInsertCallbackId { - VisualNovelRuntimeEventInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: VisualNovelRuntimeEventInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("visual_novel_runtime_event"); - _table.add_unique_constraint::("event_id", |row| &row.event_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `VisualNovelRuntimeEvent`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait visual_novel_runtime_eventQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `VisualNovelRuntimeEvent`. - fn visual_novel_runtime_event(&self) -> __sdk::__query_builder::Table; -} - -impl visual_novel_runtime_eventQueryTableAccess for __sdk::QueryTableAccessor { - fn visual_novel_runtime_event(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("visual_novel_runtime_event") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_runtime_event_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_runtime_event_type.rs deleted file mode 100644 index 9bb480726..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_runtime_event_type.rs +++ /dev/null @@ -1,75 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct VisualNovelRuntimeEvent { - pub event_id: String, - pub run_id: String, - pub owner_user_id: String, - pub profile_id: String, - pub event_kind: String, - pub client_event_id: String, - pub history_entry_id: String, - pub payload_json: String, - pub occurred_at: __sdk::Timestamp, -} - -impl __sdk::InModule for VisualNovelRuntimeEvent { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `VisualNovelRuntimeEvent`. -/// -/// Provides typed access to columns for query building. -pub struct VisualNovelRuntimeEventCols { - pub event_id: __sdk::__query_builder::Col, - pub run_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub profile_id: __sdk::__query_builder::Col, - pub event_kind: __sdk::__query_builder::Col, - pub client_event_id: __sdk::__query_builder::Col, - pub history_entry_id: __sdk::__query_builder::Col, - pub payload_json: __sdk::__query_builder::Col, - pub occurred_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for VisualNovelRuntimeEvent { - type Cols = VisualNovelRuntimeEventCols; - fn cols(table_name: &'static str) -> Self::Cols { - VisualNovelRuntimeEventCols { - event_id: __sdk::__query_builder::Col::new(table_name, "event_id"), - run_id: __sdk::__query_builder::Col::new(table_name, "run_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - event_kind: __sdk::__query_builder::Col::new(table_name, "event_kind"), - client_event_id: __sdk::__query_builder::Col::new(table_name, "client_event_id"), - history_entry_id: __sdk::__query_builder::Col::new(table_name, "history_entry_id"), - payload_json: __sdk::__query_builder::Col::new(table_name, "payload_json"), - occurred_at: __sdk::__query_builder::Col::new(table_name, "occurred_at"), - } - } -} - -/// Indexed column accessor struct for the table `VisualNovelRuntimeEvent`. -/// -/// Provides typed access to indexed columns for query building. -pub struct VisualNovelRuntimeEventIxCols { - pub event_id: __sdk::__query_builder::IxCol, - pub owner_user_id: __sdk::__query_builder::IxCol, - pub run_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for VisualNovelRuntimeEvent { - type IxCols = VisualNovelRuntimeEventIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - VisualNovelRuntimeEventIxCols { - event_id: __sdk::__query_builder::IxCol::new(table_name, "event_id"), - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - run_id: __sdk::__query_builder::IxCol::new(table_name, "run_id"), - } - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_runtime_history_entry_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_runtime_history_entry_row_type.rs deleted file mode 100644 index 15eb7e2bb..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_runtime_history_entry_row_type.rs +++ /dev/null @@ -1,91 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct VisualNovelRuntimeHistoryEntryRow { - pub entry_id: String, - pub run_id: String, - pub owner_user_id: String, - pub profile_id: String, - pub turn_index: u32, - pub source: String, - pub action_text: String, - pub steps_json: String, - pub snapshot_before_hash: String, - pub snapshot_after_hash: String, - pub created_at: __sdk::Timestamp, -} - -impl __sdk::InModule for VisualNovelRuntimeHistoryEntryRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `VisualNovelRuntimeHistoryEntryRow`. -/// -/// Provides typed access to columns for query building. -pub struct VisualNovelRuntimeHistoryEntryRowCols { - pub entry_id: __sdk::__query_builder::Col, - pub run_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub profile_id: __sdk::__query_builder::Col, - pub turn_index: __sdk::__query_builder::Col, - pub source: __sdk::__query_builder::Col, - pub action_text: __sdk::__query_builder::Col, - pub steps_json: __sdk::__query_builder::Col, - pub snapshot_before_hash: - __sdk::__query_builder::Col, - pub snapshot_after_hash: __sdk::__query_builder::Col, - pub created_at: - __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for VisualNovelRuntimeHistoryEntryRow { - type Cols = VisualNovelRuntimeHistoryEntryRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - VisualNovelRuntimeHistoryEntryRowCols { - entry_id: __sdk::__query_builder::Col::new(table_name, "entry_id"), - run_id: __sdk::__query_builder::Col::new(table_name, "run_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - turn_index: __sdk::__query_builder::Col::new(table_name, "turn_index"), - source: __sdk::__query_builder::Col::new(table_name, "source"), - action_text: __sdk::__query_builder::Col::new(table_name, "action_text"), - steps_json: __sdk::__query_builder::Col::new(table_name, "steps_json"), - snapshot_before_hash: __sdk::__query_builder::Col::new( - table_name, - "snapshot_before_hash", - ), - snapshot_after_hash: __sdk::__query_builder::Col::new( - table_name, - "snapshot_after_hash", - ), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - } - } -} - -/// Indexed column accessor struct for the table `VisualNovelRuntimeHistoryEntryRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct VisualNovelRuntimeHistoryEntryRowIxCols { - pub entry_id: __sdk::__query_builder::IxCol, - pub owner_user_id: __sdk::__query_builder::IxCol, - pub run_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for VisualNovelRuntimeHistoryEntryRow { - type IxCols = VisualNovelRuntimeHistoryEntryRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - VisualNovelRuntimeHistoryEntryRowIxCols { - entry_id: __sdk::__query_builder::IxCol::new(table_name, "entry_id"), - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - run_id: __sdk::__query_builder::IxCol::new(table_name, "run_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for VisualNovelRuntimeHistoryEntryRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_runtime_history_entry_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_runtime_history_entry_table.rs deleted file mode 100644 index 7936d334d..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_runtime_history_entry_table.rs +++ /dev/null @@ -1,239 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::visual_novel_runtime_history_entry_row_type::VisualNovelRuntimeHistoryEntryRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `visual_novel_runtime_history_entry`. -/// -/// Obtain a handle from the [`VisualNovelRuntimeHistoryEntryTableAccess::visual_novel_runtime_history_entry`] method on [`super::RemoteTables`], -/// like `ctx.db.visual_novel_runtime_history_entry()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.visual_novel_runtime_history_entry().on_insert(...)`. -pub struct VisualNovelRuntimeHistoryEntryTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `visual_novel_runtime_history_entry`. -pub struct VisualNovelRuntimeHistoryEntryTableAccessor; - -impl __sdk::TableAccessor for VisualNovelRuntimeHistoryEntryTableAccessor { - type Row = VisualNovelRuntimeHistoryEntryRow; - type Handle<'db> = VisualNovelRuntimeHistoryEntryTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.visual_novel_runtime_history_entry() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `visual_novel_runtime_history_entry`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait VisualNovelRuntimeHistoryEntryTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`VisualNovelRuntimeHistoryEntryTableHandle`], which mediates access to the table `visual_novel_runtime_history_entry`. - fn visual_novel_runtime_history_entry(&self) -> VisualNovelRuntimeHistoryEntryTableHandle<'_>; -} - -impl VisualNovelRuntimeHistoryEntryTableAccess for super::RemoteTables { - fn visual_novel_runtime_history_entry(&self) -> VisualNovelRuntimeHistoryEntryTableHandle<'_> { - VisualNovelRuntimeHistoryEntryTableHandle { - imp: self.imp.get_table::( - "visual_novel_runtime_history_entry", - ), - ctx: std::marker::PhantomData, - } - } -} - -pub struct VisualNovelRuntimeHistoryEntryInsertCallbackId(__sdk::CallbackId); -pub struct VisualNovelRuntimeHistoryEntryDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for VisualNovelRuntimeHistoryEntryTableHandle<'ctx> { - type Row = VisualNovelRuntimeHistoryEntryRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for VisualNovelRuntimeHistoryEntryTableHandle<'ctx> { - type Row = VisualNovelRuntimeHistoryEntryRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = VisualNovelRuntimeHistoryEntryInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelRuntimeHistoryEntryInsertCallbackId { - VisualNovelRuntimeHistoryEntryInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: VisualNovelRuntimeHistoryEntryInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = VisualNovelRuntimeHistoryEntryDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelRuntimeHistoryEntryDeleteCallbackId { - VisualNovelRuntimeHistoryEntryDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: VisualNovelRuntimeHistoryEntryDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for VisualNovelRuntimeHistoryEntryTableHandle<'ctx> { - type InsertCallbackId = VisualNovelRuntimeHistoryEntryInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelRuntimeHistoryEntryInsertCallbackId { - VisualNovelRuntimeHistoryEntryInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: VisualNovelRuntimeHistoryEntryInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for VisualNovelRuntimeHistoryEntryTableHandle<'ctx> { - type DeleteCallbackId = VisualNovelRuntimeHistoryEntryDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelRuntimeHistoryEntryDeleteCallbackId { - VisualNovelRuntimeHistoryEntryDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: VisualNovelRuntimeHistoryEntryDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct VisualNovelRuntimeHistoryEntryUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for VisualNovelRuntimeHistoryEntryTableHandle<'ctx> { - type UpdateCallbackId = VisualNovelRuntimeHistoryEntryUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> VisualNovelRuntimeHistoryEntryUpdateCallbackId { - VisualNovelRuntimeHistoryEntryUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: VisualNovelRuntimeHistoryEntryUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for VisualNovelRuntimeHistoryEntryTableHandle<'ctx> { - type UpdateCallbackId = VisualNovelRuntimeHistoryEntryUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> VisualNovelRuntimeHistoryEntryUpdateCallbackId { - VisualNovelRuntimeHistoryEntryUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: VisualNovelRuntimeHistoryEntryUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `entry_id` unique index on the table `visual_novel_runtime_history_entry`, -/// which allows point queries on the field of the same name -/// via the [`VisualNovelRuntimeHistoryEntryEntryIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.visual_novel_runtime_history_entry().entry_id().find(...)`. -pub struct VisualNovelRuntimeHistoryEntryEntryIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> VisualNovelRuntimeHistoryEntryTableHandle<'ctx> { - /// Get a handle on the `entry_id` unique index on the table `visual_novel_runtime_history_entry`. - pub fn entry_id(&self) -> VisualNovelRuntimeHistoryEntryEntryIdUnique<'ctx> { - VisualNovelRuntimeHistoryEntryEntryIdUnique { - imp: self.imp.get_unique_constraint::("entry_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> VisualNovelRuntimeHistoryEntryEntryIdUnique<'ctx> { - /// Find the subscribed row whose `entry_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::( - "visual_novel_runtime_history_entry", - ); - _table.add_unique_constraint::("entry_id", |row| &row.entry_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse( - "TableUpdate", - "TableUpdate", - ) - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `VisualNovelRuntimeHistoryEntryRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait visual_novel_runtime_history_entryQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `VisualNovelRuntimeHistoryEntryRow`. - fn visual_novel_runtime_history_entry( - &self, - ) -> __sdk::__query_builder::Table; -} - -impl visual_novel_runtime_history_entryQueryTableAccess for __sdk::QueryTableAccessor { - fn visual_novel_runtime_history_entry( - &self, - ) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("visual_novel_runtime_history_entry") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_runtime_run_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_runtime_run_row_type.rs deleted file mode 100644 index a431fd5eb..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_runtime_run_row_type.rs +++ /dev/null @@ -1,101 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct VisualNovelRuntimeRunRow { - pub run_id: String, - pub owner_user_id: String, - pub profile_id: String, - pub mode: String, - pub status: String, - pub current_scene_id: String, - pub current_phase_id: String, - pub visible_character_ids_json: String, - pub flags_json: String, - pub metrics_json: String, - pub available_choices_json: String, - pub text_mode_enabled: bool, - pub snapshot_json: String, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for VisualNovelRuntimeRunRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `VisualNovelRuntimeRunRow`. -/// -/// Provides typed access to columns for query building. -pub struct VisualNovelRuntimeRunRowCols { - pub run_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub profile_id: __sdk::__query_builder::Col, - pub mode: __sdk::__query_builder::Col, - pub status: __sdk::__query_builder::Col, - pub current_scene_id: __sdk::__query_builder::Col, - pub current_phase_id: __sdk::__query_builder::Col, - pub visible_character_ids_json: __sdk::__query_builder::Col, - pub flags_json: __sdk::__query_builder::Col, - pub metrics_json: __sdk::__query_builder::Col, - pub available_choices_json: __sdk::__query_builder::Col, - pub text_mode_enabled: __sdk::__query_builder::Col, - pub snapshot_json: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for VisualNovelRuntimeRunRow { - type Cols = VisualNovelRuntimeRunRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - VisualNovelRuntimeRunRowCols { - run_id: __sdk::__query_builder::Col::new(table_name, "run_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - mode: __sdk::__query_builder::Col::new(table_name, "mode"), - status: __sdk::__query_builder::Col::new(table_name, "status"), - current_scene_id: __sdk::__query_builder::Col::new(table_name, "current_scene_id"), - current_phase_id: __sdk::__query_builder::Col::new(table_name, "current_phase_id"), - visible_character_ids_json: __sdk::__query_builder::Col::new( - table_name, - "visible_character_ids_json", - ), - flags_json: __sdk::__query_builder::Col::new(table_name, "flags_json"), - metrics_json: __sdk::__query_builder::Col::new(table_name, "metrics_json"), - available_choices_json: __sdk::__query_builder::Col::new( - table_name, - "available_choices_json", - ), - text_mode_enabled: __sdk::__query_builder::Col::new(table_name, "text_mode_enabled"), - snapshot_json: __sdk::__query_builder::Col::new(table_name, "snapshot_json"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `VisualNovelRuntimeRunRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct VisualNovelRuntimeRunRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub profile_id: __sdk::__query_builder::IxCol, - pub run_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for VisualNovelRuntimeRunRow { - type IxCols = VisualNovelRuntimeRunRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - VisualNovelRuntimeRunRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::IxCol::new(table_name, "profile_id"), - run_id: __sdk::__query_builder::IxCol::new(table_name, "run_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for VisualNovelRuntimeRunRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_runtime_run_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_runtime_run_table.rs deleted file mode 100644 index 2578c1e6f..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_runtime_run_table.rs +++ /dev/null @@ -1,231 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::visual_novel_runtime_run_row_type::VisualNovelRuntimeRunRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `visual_novel_runtime_run`. -/// -/// Obtain a handle from the [`VisualNovelRuntimeRunTableAccess::visual_novel_runtime_run`] method on [`super::RemoteTables`], -/// like `ctx.db.visual_novel_runtime_run()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.visual_novel_runtime_run().on_insert(...)`. -pub struct VisualNovelRuntimeRunTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `visual_novel_runtime_run`. -pub struct VisualNovelRuntimeRunTableAccessor; - -impl __sdk::TableAccessor for VisualNovelRuntimeRunTableAccessor { - type Row = VisualNovelRuntimeRunRow; - type Handle<'db> = VisualNovelRuntimeRunTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.visual_novel_runtime_run() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `visual_novel_runtime_run`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait VisualNovelRuntimeRunTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`VisualNovelRuntimeRunTableHandle`], which mediates access to the table `visual_novel_runtime_run`. - fn visual_novel_runtime_run(&self) -> VisualNovelRuntimeRunTableHandle<'_>; -} - -impl VisualNovelRuntimeRunTableAccess for super::RemoteTables { - fn visual_novel_runtime_run(&self) -> VisualNovelRuntimeRunTableHandle<'_> { - VisualNovelRuntimeRunTableHandle { - imp: self - .imp - .get_table::("visual_novel_runtime_run"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct VisualNovelRuntimeRunInsertCallbackId(__sdk::CallbackId); -pub struct VisualNovelRuntimeRunDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for VisualNovelRuntimeRunTableHandle<'ctx> { - type Row = VisualNovelRuntimeRunRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for VisualNovelRuntimeRunTableHandle<'ctx> { - type Row = VisualNovelRuntimeRunRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = VisualNovelRuntimeRunInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelRuntimeRunInsertCallbackId { - VisualNovelRuntimeRunInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: VisualNovelRuntimeRunInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = VisualNovelRuntimeRunDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelRuntimeRunDeleteCallbackId { - VisualNovelRuntimeRunDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: VisualNovelRuntimeRunDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for VisualNovelRuntimeRunTableHandle<'ctx> { - type InsertCallbackId = VisualNovelRuntimeRunInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelRuntimeRunInsertCallbackId { - VisualNovelRuntimeRunInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: VisualNovelRuntimeRunInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for VisualNovelRuntimeRunTableHandle<'ctx> { - type DeleteCallbackId = VisualNovelRuntimeRunDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelRuntimeRunDeleteCallbackId { - VisualNovelRuntimeRunDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: VisualNovelRuntimeRunDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct VisualNovelRuntimeRunUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for VisualNovelRuntimeRunTableHandle<'ctx> { - type UpdateCallbackId = VisualNovelRuntimeRunUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> VisualNovelRuntimeRunUpdateCallbackId { - VisualNovelRuntimeRunUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: VisualNovelRuntimeRunUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for VisualNovelRuntimeRunTableHandle<'ctx> { - type UpdateCallbackId = VisualNovelRuntimeRunUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> VisualNovelRuntimeRunUpdateCallbackId { - VisualNovelRuntimeRunUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: VisualNovelRuntimeRunUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `run_id` unique index on the table `visual_novel_runtime_run`, -/// which allows point queries on the field of the same name -/// via the [`VisualNovelRuntimeRunRunIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.visual_novel_runtime_run().run_id().find(...)`. -pub struct VisualNovelRuntimeRunRunIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> VisualNovelRuntimeRunTableHandle<'ctx> { - /// Get a handle on the `run_id` unique index on the table `visual_novel_runtime_run`. - pub fn run_id(&self) -> VisualNovelRuntimeRunRunIdUnique<'ctx> { - VisualNovelRuntimeRunRunIdUnique { - imp: self.imp.get_unique_constraint::("run_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> VisualNovelRuntimeRunRunIdUnique<'ctx> { - /// Find the subscribed row whose `run_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("visual_novel_runtime_run"); - _table.add_unique_constraint::("run_id", |row| &row.run_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `VisualNovelRuntimeRunRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait visual_novel_runtime_runQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `VisualNovelRuntimeRunRow`. - fn visual_novel_runtime_run(&self) -> __sdk::__query_builder::Table; -} - -impl visual_novel_runtime_runQueryTableAccess for __sdk::QueryTableAccessor { - fn visual_novel_runtime_run(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("visual_novel_runtime_run") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_work_profile_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_work_profile_row_type.rs deleted file mode 100644 index d4556acb1..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_work_profile_row_type.rs +++ /dev/null @@ -1,114 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct VisualNovelWorkProfileRow { - pub profile_id: String, - pub work_id: String, - pub owner_user_id: String, - pub source_session_id: String, - pub author_display_name: String, - pub work_title: String, - pub work_description: String, - pub tags_json: String, - pub cover_image_src: String, - pub source_asset_ids_json: String, - pub draft_json: String, - pub publication_status: String, - pub publish_ready: bool, - pub play_count: u32, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, - pub published_at: Option<__sdk::Timestamp>, - pub visible: bool, -} - -impl __sdk::InModule for VisualNovelWorkProfileRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `VisualNovelWorkProfileRow`. -/// -/// Provides typed access to columns for query building. -pub struct VisualNovelWorkProfileRowCols { - pub profile_id: __sdk::__query_builder::Col, - pub work_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub source_session_id: __sdk::__query_builder::Col, - pub author_display_name: __sdk::__query_builder::Col, - pub work_title: __sdk::__query_builder::Col, - pub work_description: __sdk::__query_builder::Col, - pub tags_json: __sdk::__query_builder::Col, - pub cover_image_src: __sdk::__query_builder::Col, - pub source_asset_ids_json: __sdk::__query_builder::Col, - pub draft_json: __sdk::__query_builder::Col, - pub publication_status: __sdk::__query_builder::Col, - pub publish_ready: __sdk::__query_builder::Col, - pub play_count: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, - pub published_at: - __sdk::__query_builder::Col>, - pub visible: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for VisualNovelWorkProfileRow { - type Cols = VisualNovelWorkProfileRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - VisualNovelWorkProfileRowCols { - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - work_id: __sdk::__query_builder::Col::new(table_name, "work_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - source_session_id: __sdk::__query_builder::Col::new(table_name, "source_session_id"), - author_display_name: __sdk::__query_builder::Col::new( - table_name, - "author_display_name", - ), - work_title: __sdk::__query_builder::Col::new(table_name, "work_title"), - work_description: __sdk::__query_builder::Col::new(table_name, "work_description"), - tags_json: __sdk::__query_builder::Col::new(table_name, "tags_json"), - cover_image_src: __sdk::__query_builder::Col::new(table_name, "cover_image_src"), - source_asset_ids_json: __sdk::__query_builder::Col::new( - table_name, - "source_asset_ids_json", - ), - draft_json: __sdk::__query_builder::Col::new(table_name, "draft_json"), - publication_status: __sdk::__query_builder::Col::new(table_name, "publication_status"), - publish_ready: __sdk::__query_builder::Col::new(table_name, "publish_ready"), - play_count: __sdk::__query_builder::Col::new(table_name, "play_count"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - published_at: __sdk::__query_builder::Col::new(table_name, "published_at"), - visible: __sdk::__query_builder::Col::new(table_name, "visible"), - } - } -} - -/// Indexed column accessor struct for the table `VisualNovelWorkProfileRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct VisualNovelWorkProfileRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub profile_id: __sdk::__query_builder::IxCol, - pub publication_status: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for VisualNovelWorkProfileRow { - type IxCols = VisualNovelWorkProfileRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - VisualNovelWorkProfileRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::IxCol::new(table_name, "profile_id"), - publication_status: __sdk::__query_builder::IxCol::new( - table_name, - "publication_status", - ), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for VisualNovelWorkProfileRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_work_profile_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_work_profile_table.rs deleted file mode 100644 index b41c7f144..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_work_profile_table.rs +++ /dev/null @@ -1,234 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::visual_novel_work_profile_row_type::VisualNovelWorkProfileRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `visual_novel_work_profile`. -/// -/// Obtain a handle from the [`VisualNovelWorkProfileTableAccess::visual_novel_work_profile`] method on [`super::RemoteTables`], -/// like `ctx.db.visual_novel_work_profile()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.visual_novel_work_profile().on_insert(...)`. -pub struct VisualNovelWorkProfileTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `visual_novel_work_profile`. -pub struct VisualNovelWorkProfileTableAccessor; - -impl __sdk::TableAccessor for VisualNovelWorkProfileTableAccessor { - type Row = VisualNovelWorkProfileRow; - type Handle<'db> = VisualNovelWorkProfileTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.visual_novel_work_profile() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `visual_novel_work_profile`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait VisualNovelWorkProfileTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`VisualNovelWorkProfileTableHandle`], which mediates access to the table `visual_novel_work_profile`. - fn visual_novel_work_profile(&self) -> VisualNovelWorkProfileTableHandle<'_>; -} - -impl VisualNovelWorkProfileTableAccess for super::RemoteTables { - fn visual_novel_work_profile(&self) -> VisualNovelWorkProfileTableHandle<'_> { - VisualNovelWorkProfileTableHandle { - imp: self - .imp - .get_table::("visual_novel_work_profile"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct VisualNovelWorkProfileInsertCallbackId(__sdk::CallbackId); -pub struct VisualNovelWorkProfileDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for VisualNovelWorkProfileTableHandle<'ctx> { - type Row = VisualNovelWorkProfileRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for VisualNovelWorkProfileTableHandle<'ctx> { - type Row = VisualNovelWorkProfileRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = VisualNovelWorkProfileInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelWorkProfileInsertCallbackId { - VisualNovelWorkProfileInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: VisualNovelWorkProfileInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = VisualNovelWorkProfileDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelWorkProfileDeleteCallbackId { - VisualNovelWorkProfileDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: VisualNovelWorkProfileDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for VisualNovelWorkProfileTableHandle<'ctx> { - type InsertCallbackId = VisualNovelWorkProfileInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelWorkProfileInsertCallbackId { - VisualNovelWorkProfileInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: VisualNovelWorkProfileInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for VisualNovelWorkProfileTableHandle<'ctx> { - type DeleteCallbackId = VisualNovelWorkProfileDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> VisualNovelWorkProfileDeleteCallbackId { - VisualNovelWorkProfileDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: VisualNovelWorkProfileDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct VisualNovelWorkProfileUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for VisualNovelWorkProfileTableHandle<'ctx> { - type UpdateCallbackId = VisualNovelWorkProfileUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> VisualNovelWorkProfileUpdateCallbackId { - VisualNovelWorkProfileUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: VisualNovelWorkProfileUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for VisualNovelWorkProfileTableHandle<'ctx> { - type UpdateCallbackId = VisualNovelWorkProfileUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> VisualNovelWorkProfileUpdateCallbackId { - VisualNovelWorkProfileUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: VisualNovelWorkProfileUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `profile_id` unique index on the table `visual_novel_work_profile`, -/// which allows point queries on the field of the same name -/// via the [`VisualNovelWorkProfileProfileIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.visual_novel_work_profile().profile_id().find(...)`. -pub struct VisualNovelWorkProfileProfileIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> VisualNovelWorkProfileTableHandle<'ctx> { - /// Get a handle on the `profile_id` unique index on the table `visual_novel_work_profile`. - pub fn profile_id(&self) -> VisualNovelWorkProfileProfileIdUnique<'ctx> { - VisualNovelWorkProfileProfileIdUnique { - imp: self.imp.get_unique_constraint::("profile_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> VisualNovelWorkProfileProfileIdUnique<'ctx> { - /// Find the subscribed row whose `profile_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("visual_novel_work_profile"); - _table.add_unique_constraint::("profile_id", |row| &row.profile_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `VisualNovelWorkProfileRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait visual_novel_work_profileQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `VisualNovelWorkProfileRow`. - fn visual_novel_work_profile(&self) - -> __sdk::__query_builder::Table; -} - -impl visual_novel_work_profileQueryTableAccess for __sdk::QueryTableAccessor { - fn visual_novel_work_profile( - &self, - ) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("visual_novel_work_profile") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_agent_session_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_agent_session_row_type.rs deleted file mode 100644 index 8f918cdf2..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_agent_session_row_type.rs +++ /dev/null @@ -1,81 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct WoodenFishAgentSessionRow { - pub session_id: String, - pub owner_user_id: String, - pub current_turn: u32, - pub progress_percent: u32, - pub stage: String, - pub config_json: String, - pub draft_json: String, - pub published_profile_id: String, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for WoodenFishAgentSessionRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `WoodenFishAgentSessionRow`. -/// -/// Provides typed access to columns for query building. -pub struct WoodenFishAgentSessionRowCols { - pub session_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub current_turn: __sdk::__query_builder::Col, - pub progress_percent: __sdk::__query_builder::Col, - pub stage: __sdk::__query_builder::Col, - pub config_json: __sdk::__query_builder::Col, - pub draft_json: __sdk::__query_builder::Col, - pub published_profile_id: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for WoodenFishAgentSessionRow { - type Cols = WoodenFishAgentSessionRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - WoodenFishAgentSessionRowCols { - session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - current_turn: __sdk::__query_builder::Col::new(table_name, "current_turn"), - progress_percent: __sdk::__query_builder::Col::new(table_name, "progress_percent"), - stage: __sdk::__query_builder::Col::new(table_name, "stage"), - config_json: __sdk::__query_builder::Col::new(table_name, "config_json"), - draft_json: __sdk::__query_builder::Col::new(table_name, "draft_json"), - published_profile_id: __sdk::__query_builder::Col::new( - table_name, - "published_profile_id", - ), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `WoodenFishAgentSessionRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct WoodenFishAgentSessionRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub session_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for WoodenFishAgentSessionRow { - type IxCols = WoodenFishAgentSessionRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - WoodenFishAgentSessionRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for WoodenFishAgentSessionRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_agent_session_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_agent_session_table.rs deleted file mode 100644 index 53b91c879..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_agent_session_table.rs +++ /dev/null @@ -1,234 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::wooden_fish_agent_session_row_type::WoodenFishAgentSessionRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `wooden_fish_agent_session`. -/// -/// Obtain a handle from the [`WoodenFishAgentSessionTableAccess::wooden_fish_agent_session`] method on [`super::RemoteTables`], -/// like `ctx.db.wooden_fish_agent_session()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.wooden_fish_agent_session().on_insert(...)`. -pub struct WoodenFishAgentSessionTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `wooden_fish_agent_session`. -pub struct WoodenFishAgentSessionTableAccessor; - -impl __sdk::TableAccessor for WoodenFishAgentSessionTableAccessor { - type Row = WoodenFishAgentSessionRow; - type Handle<'db> = WoodenFishAgentSessionTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.wooden_fish_agent_session() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `wooden_fish_agent_session`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait WoodenFishAgentSessionTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`WoodenFishAgentSessionTableHandle`], which mediates access to the table `wooden_fish_agent_session`. - fn wooden_fish_agent_session(&self) -> WoodenFishAgentSessionTableHandle<'_>; -} - -impl WoodenFishAgentSessionTableAccess for super::RemoteTables { - fn wooden_fish_agent_session(&self) -> WoodenFishAgentSessionTableHandle<'_> { - WoodenFishAgentSessionTableHandle { - imp: self - .imp - .get_table::("wooden_fish_agent_session"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct WoodenFishAgentSessionInsertCallbackId(__sdk::CallbackId); -pub struct WoodenFishAgentSessionDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for WoodenFishAgentSessionTableHandle<'ctx> { - type Row = WoodenFishAgentSessionRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for WoodenFishAgentSessionTableHandle<'ctx> { - type Row = WoodenFishAgentSessionRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = WoodenFishAgentSessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> WoodenFishAgentSessionInsertCallbackId { - WoodenFishAgentSessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: WoodenFishAgentSessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = WoodenFishAgentSessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> WoodenFishAgentSessionDeleteCallbackId { - WoodenFishAgentSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: WoodenFishAgentSessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for WoodenFishAgentSessionTableHandle<'ctx> { - type InsertCallbackId = WoodenFishAgentSessionInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> WoodenFishAgentSessionInsertCallbackId { - WoodenFishAgentSessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: WoodenFishAgentSessionInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for WoodenFishAgentSessionTableHandle<'ctx> { - type DeleteCallbackId = WoodenFishAgentSessionDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> WoodenFishAgentSessionDeleteCallbackId { - WoodenFishAgentSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: WoodenFishAgentSessionDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct WoodenFishAgentSessionUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for WoodenFishAgentSessionTableHandle<'ctx> { - type UpdateCallbackId = WoodenFishAgentSessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> WoodenFishAgentSessionUpdateCallbackId { - WoodenFishAgentSessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: WoodenFishAgentSessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for WoodenFishAgentSessionTableHandle<'ctx> { - type UpdateCallbackId = WoodenFishAgentSessionUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> WoodenFishAgentSessionUpdateCallbackId { - WoodenFishAgentSessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: WoodenFishAgentSessionUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `session_id` unique index on the table `wooden_fish_agent_session`, -/// which allows point queries on the field of the same name -/// via the [`WoodenFishAgentSessionSessionIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.wooden_fish_agent_session().session_id().find(...)`. -pub struct WoodenFishAgentSessionSessionIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> WoodenFishAgentSessionTableHandle<'ctx> { - /// Get a handle on the `session_id` unique index on the table `wooden_fish_agent_session`. - pub fn session_id(&self) -> WoodenFishAgentSessionSessionIdUnique<'ctx> { - WoodenFishAgentSessionSessionIdUnique { - imp: self.imp.get_unique_constraint::("session_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> WoodenFishAgentSessionSessionIdUnique<'ctx> { - /// Find the subscribed row whose `session_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("wooden_fish_agent_session"); - _table.add_unique_constraint::("session_id", |row| &row.session_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `WoodenFishAgentSessionRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait wooden_fish_agent_sessionQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `WoodenFishAgentSessionRow`. - fn wooden_fish_agent_session(&self) - -> __sdk::__query_builder::Table; -} - -impl wooden_fish_agent_sessionQueryTableAccess for __sdk::QueryTableAccessor { - fn wooden_fish_agent_session( - &self, - ) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("wooden_fish_agent_session") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_event_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_event_row_type.rs deleted file mode 100644 index 9b000003e..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_event_row_type.rs +++ /dev/null @@ -1,71 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct WoodenFishEventRow { - pub event_id: String, - pub owner_user_id: String, - pub profile_id: String, - pub run_id: String, - pub event_type: String, - pub result: String, - pub occurred_at: __sdk::Timestamp, -} - -impl __sdk::InModule for WoodenFishEventRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `WoodenFishEventRow`. -/// -/// Provides typed access to columns for query building. -pub struct WoodenFishEventRowCols { - pub event_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub profile_id: __sdk::__query_builder::Col, - pub run_id: __sdk::__query_builder::Col, - pub event_type: __sdk::__query_builder::Col, - pub result: __sdk::__query_builder::Col, - pub occurred_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for WoodenFishEventRow { - type Cols = WoodenFishEventRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - WoodenFishEventRowCols { - event_id: __sdk::__query_builder::Col::new(table_name, "event_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - run_id: __sdk::__query_builder::Col::new(table_name, "run_id"), - event_type: __sdk::__query_builder::Col::new(table_name, "event_type"), - result: __sdk::__query_builder::Col::new(table_name, "result"), - occurred_at: __sdk::__query_builder::Col::new(table_name, "occurred_at"), - } - } -} - -/// Indexed column accessor struct for the table `WoodenFishEventRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct WoodenFishEventRowIxCols { - pub event_id: __sdk::__query_builder::IxCol, - pub profile_id: __sdk::__query_builder::IxCol, - pub run_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for WoodenFishEventRow { - type IxCols = WoodenFishEventRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - WoodenFishEventRowIxCols { - event_id: __sdk::__query_builder::IxCol::new(table_name, "event_id"), - profile_id: __sdk::__query_builder::IxCol::new(table_name, "profile_id"), - run_id: __sdk::__query_builder::IxCol::new(table_name, "run_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for WoodenFishEventRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_event_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_event_table.rs deleted file mode 100644 index 6a1c9fc8d..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_event_table.rs +++ /dev/null @@ -1,230 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::wooden_fish_event_row_type::WoodenFishEventRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `wooden_fish_event`. -/// -/// Obtain a handle from the [`WoodenFishEventTableAccess::wooden_fish_event`] method on [`super::RemoteTables`], -/// like `ctx.db.wooden_fish_event()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.wooden_fish_event().on_insert(...)`. -pub struct WoodenFishEventTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `wooden_fish_event`. -pub struct WoodenFishEventTableAccessor; - -impl __sdk::TableAccessor for WoodenFishEventTableAccessor { - type Row = WoodenFishEventRow; - type Handle<'db> = WoodenFishEventTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.wooden_fish_event() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `wooden_fish_event`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait WoodenFishEventTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`WoodenFishEventTableHandle`], which mediates access to the table `wooden_fish_event`. - fn wooden_fish_event(&self) -> WoodenFishEventTableHandle<'_>; -} - -impl WoodenFishEventTableAccess for super::RemoteTables { - fn wooden_fish_event(&self) -> WoodenFishEventTableHandle<'_> { - WoodenFishEventTableHandle { - imp: self - .imp - .get_table::("wooden_fish_event"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct WoodenFishEventInsertCallbackId(__sdk::CallbackId); -pub struct WoodenFishEventDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for WoodenFishEventTableHandle<'ctx> { - type Row = WoodenFishEventRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for WoodenFishEventTableHandle<'ctx> { - type Row = WoodenFishEventRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = WoodenFishEventInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> WoodenFishEventInsertCallbackId { - WoodenFishEventInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: WoodenFishEventInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = WoodenFishEventDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> WoodenFishEventDeleteCallbackId { - WoodenFishEventDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: WoodenFishEventDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for WoodenFishEventTableHandle<'ctx> { - type InsertCallbackId = WoodenFishEventInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> WoodenFishEventInsertCallbackId { - WoodenFishEventInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: WoodenFishEventInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for WoodenFishEventTableHandle<'ctx> { - type DeleteCallbackId = WoodenFishEventDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> WoodenFishEventDeleteCallbackId { - WoodenFishEventDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: WoodenFishEventDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct WoodenFishEventUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for WoodenFishEventTableHandle<'ctx> { - type UpdateCallbackId = WoodenFishEventUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> WoodenFishEventUpdateCallbackId { - WoodenFishEventUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: WoodenFishEventUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for WoodenFishEventTableHandle<'ctx> { - type UpdateCallbackId = WoodenFishEventUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> WoodenFishEventUpdateCallbackId { - WoodenFishEventUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: WoodenFishEventUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `event_id` unique index on the table `wooden_fish_event`, -/// which allows point queries on the field of the same name -/// via the [`WoodenFishEventEventIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.wooden_fish_event().event_id().find(...)`. -pub struct WoodenFishEventEventIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> WoodenFishEventTableHandle<'ctx> { - /// Get a handle on the `event_id` unique index on the table `wooden_fish_event`. - pub fn event_id(&self) -> WoodenFishEventEventIdUnique<'ctx> { - WoodenFishEventEventIdUnique { - imp: self.imp.get_unique_constraint::("event_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> WoodenFishEventEventIdUnique<'ctx> { - /// Find the subscribed row whose `event_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("wooden_fish_event"); - _table.add_unique_constraint::("event_id", |row| &row.event_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `WoodenFishEventRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait wooden_fish_eventQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `WoodenFishEventRow`. - fn wooden_fish_event(&self) -> __sdk::__query_builder::Table; -} - -impl wooden_fish_eventQueryTableAccess for __sdk::QueryTableAccessor { - fn wooden_fish_event(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("wooden_fish_event") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_runtime_run_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_runtime_run_row_type.rs deleted file mode 100644 index 8c12c1e53..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_runtime_run_row_type.rs +++ /dev/null @@ -1,86 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct WoodenFishRuntimeRunRow { - pub run_id: String, - pub owner_user_id: String, - pub profile_id: String, - pub status: String, - pub total_tap_count: u32, - pub word_counters_json: String, - pub started_at_ms: i64, - pub updated_at_ms: i64, - pub finished_at_ms: i64, - pub snapshot_json: String, - pub created_at: __sdk::Timestamp, - pub updated_at: __sdk::Timestamp, -} - -impl __sdk::InModule for WoodenFishRuntimeRunRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `WoodenFishRuntimeRunRow`. -/// -/// Provides typed access to columns for query building. -pub struct WoodenFishRuntimeRunRowCols { - pub run_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub profile_id: __sdk::__query_builder::Col, - pub status: __sdk::__query_builder::Col, - pub total_tap_count: __sdk::__query_builder::Col, - pub word_counters_json: __sdk::__query_builder::Col, - pub started_at_ms: __sdk::__query_builder::Col, - pub updated_at_ms: __sdk::__query_builder::Col, - pub finished_at_ms: __sdk::__query_builder::Col, - pub snapshot_json: __sdk::__query_builder::Col, - pub created_at: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for WoodenFishRuntimeRunRow { - type Cols = WoodenFishRuntimeRunRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - WoodenFishRuntimeRunRowCols { - run_id: __sdk::__query_builder::Col::new(table_name, "run_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - status: __sdk::__query_builder::Col::new(table_name, "status"), - total_tap_count: __sdk::__query_builder::Col::new(table_name, "total_tap_count"), - word_counters_json: __sdk::__query_builder::Col::new(table_name, "word_counters_json"), - started_at_ms: __sdk::__query_builder::Col::new(table_name, "started_at_ms"), - updated_at_ms: __sdk::__query_builder::Col::new(table_name, "updated_at_ms"), - finished_at_ms: __sdk::__query_builder::Col::new(table_name, "finished_at_ms"), - snapshot_json: __sdk::__query_builder::Col::new(table_name, "snapshot_json"), - created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - } - } -} - -/// Indexed column accessor struct for the table `WoodenFishRuntimeRunRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct WoodenFishRuntimeRunRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub profile_id: __sdk::__query_builder::IxCol, - pub run_id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for WoodenFishRuntimeRunRow { - type IxCols = WoodenFishRuntimeRunRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - WoodenFishRuntimeRunRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::IxCol::new(table_name, "profile_id"), - run_id: __sdk::__query_builder::IxCol::new(table_name, "run_id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for WoodenFishRuntimeRunRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_runtime_run_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_runtime_run_table.rs deleted file mode 100644 index c762aadd3..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_runtime_run_table.rs +++ /dev/null @@ -1,231 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::wooden_fish_runtime_run_row_type::WoodenFishRuntimeRunRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `wooden_fish_runtime_run`. -/// -/// Obtain a handle from the [`WoodenFishRuntimeRunTableAccess::wooden_fish_runtime_run`] method on [`super::RemoteTables`], -/// like `ctx.db.wooden_fish_runtime_run()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.wooden_fish_runtime_run().on_insert(...)`. -pub struct WoodenFishRuntimeRunTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `wooden_fish_runtime_run`. -pub struct WoodenFishRuntimeRunTableAccessor; - -impl __sdk::TableAccessor for WoodenFishRuntimeRunTableAccessor { - type Row = WoodenFishRuntimeRunRow; - type Handle<'db> = WoodenFishRuntimeRunTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.wooden_fish_runtime_run() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `wooden_fish_runtime_run`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait WoodenFishRuntimeRunTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`WoodenFishRuntimeRunTableHandle`], which mediates access to the table `wooden_fish_runtime_run`. - fn wooden_fish_runtime_run(&self) -> WoodenFishRuntimeRunTableHandle<'_>; -} - -impl WoodenFishRuntimeRunTableAccess for super::RemoteTables { - fn wooden_fish_runtime_run(&self) -> WoodenFishRuntimeRunTableHandle<'_> { - WoodenFishRuntimeRunTableHandle { - imp: self - .imp - .get_table::("wooden_fish_runtime_run"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct WoodenFishRuntimeRunInsertCallbackId(__sdk::CallbackId); -pub struct WoodenFishRuntimeRunDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for WoodenFishRuntimeRunTableHandle<'ctx> { - type Row = WoodenFishRuntimeRunRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for WoodenFishRuntimeRunTableHandle<'ctx> { - type Row = WoodenFishRuntimeRunRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = WoodenFishRuntimeRunInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> WoodenFishRuntimeRunInsertCallbackId { - WoodenFishRuntimeRunInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: WoodenFishRuntimeRunInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = WoodenFishRuntimeRunDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> WoodenFishRuntimeRunDeleteCallbackId { - WoodenFishRuntimeRunDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: WoodenFishRuntimeRunDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for WoodenFishRuntimeRunTableHandle<'ctx> { - type InsertCallbackId = WoodenFishRuntimeRunInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> WoodenFishRuntimeRunInsertCallbackId { - WoodenFishRuntimeRunInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: WoodenFishRuntimeRunInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for WoodenFishRuntimeRunTableHandle<'ctx> { - type DeleteCallbackId = WoodenFishRuntimeRunDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> WoodenFishRuntimeRunDeleteCallbackId { - WoodenFishRuntimeRunDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: WoodenFishRuntimeRunDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct WoodenFishRuntimeRunUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for WoodenFishRuntimeRunTableHandle<'ctx> { - type UpdateCallbackId = WoodenFishRuntimeRunUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> WoodenFishRuntimeRunUpdateCallbackId { - WoodenFishRuntimeRunUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: WoodenFishRuntimeRunUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for WoodenFishRuntimeRunTableHandle<'ctx> { - type UpdateCallbackId = WoodenFishRuntimeRunUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> WoodenFishRuntimeRunUpdateCallbackId { - WoodenFishRuntimeRunUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: WoodenFishRuntimeRunUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `run_id` unique index on the table `wooden_fish_runtime_run`, -/// which allows point queries on the field of the same name -/// via the [`WoodenFishRuntimeRunRunIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.wooden_fish_runtime_run().run_id().find(...)`. -pub struct WoodenFishRuntimeRunRunIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> WoodenFishRuntimeRunTableHandle<'ctx> { - /// Get a handle on the `run_id` unique index on the table `wooden_fish_runtime_run`. - pub fn run_id(&self) -> WoodenFishRuntimeRunRunIdUnique<'ctx> { - WoodenFishRuntimeRunRunIdUnique { - imp: self.imp.get_unique_constraint::("run_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> WoodenFishRuntimeRunRunIdUnique<'ctx> { - /// Find the subscribed row whose `run_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("wooden_fish_runtime_run"); - _table.add_unique_constraint::("run_id", |row| &row.run_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `WoodenFishRuntimeRunRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait wooden_fish_runtime_runQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `WoodenFishRuntimeRunRow`. - fn wooden_fish_runtime_run(&self) -> __sdk::__query_builder::Table; -} - -impl wooden_fish_runtime_runQueryTableAccess for __sdk::QueryTableAccessor { - fn wooden_fish_runtime_run(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("wooden_fish_runtime_run") - } -} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_work_profile_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_work_profile_row_type.rs deleted file mode 100644 index 5803a5988..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_work_profile_row_type.rs +++ /dev/null @@ -1,147 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct WoodenFishWorkProfileRow { - pub profile_id: String, - pub work_id: String, - pub owner_user_id: String, - pub source_session_id: String, - pub author_display_name: String, - pub work_title: String, - pub work_description: String, - pub theme_tags_json: String, - pub hit_object_prompt: String, - pub hit_object_reference_image_src: String, - pub hit_sound_prompt: String, - pub hit_object_asset_json: String, - pub hit_sound_asset_json: String, - pub floating_words_json: String, - pub cover_image_src: String, - pub generation_status: String, - pub publication_status: String, - pub play_count: u32, - pub updated_at: __sdk::Timestamp, - pub published_at: Option<__sdk::Timestamp>, - pub background_asset_json: Option, - pub back_button_asset_json: Option, - pub visible: bool, -} - -impl __sdk::InModule for WoodenFishWorkProfileRow { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `WoodenFishWorkProfileRow`. -/// -/// Provides typed access to columns for query building. -pub struct WoodenFishWorkProfileRowCols { - pub profile_id: __sdk::__query_builder::Col, - pub work_id: __sdk::__query_builder::Col, - pub owner_user_id: __sdk::__query_builder::Col, - pub source_session_id: __sdk::__query_builder::Col, - pub author_display_name: __sdk::__query_builder::Col, - pub work_title: __sdk::__query_builder::Col, - pub work_description: __sdk::__query_builder::Col, - pub theme_tags_json: __sdk::__query_builder::Col, - pub hit_object_prompt: __sdk::__query_builder::Col, - pub hit_object_reference_image_src: - __sdk::__query_builder::Col, - pub hit_sound_prompt: __sdk::__query_builder::Col, - pub hit_object_asset_json: __sdk::__query_builder::Col, - pub hit_sound_asset_json: __sdk::__query_builder::Col, - pub floating_words_json: __sdk::__query_builder::Col, - pub cover_image_src: __sdk::__query_builder::Col, - pub generation_status: __sdk::__query_builder::Col, - pub publication_status: __sdk::__query_builder::Col, - pub play_count: __sdk::__query_builder::Col, - pub updated_at: __sdk::__query_builder::Col, - pub published_at: - __sdk::__query_builder::Col>, - pub background_asset_json: - __sdk::__query_builder::Col>, - pub back_button_asset_json: - __sdk::__query_builder::Col>, - pub visible: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for WoodenFishWorkProfileRow { - type Cols = WoodenFishWorkProfileRowCols; - fn cols(table_name: &'static str) -> Self::Cols { - WoodenFishWorkProfileRowCols { - profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), - work_id: __sdk::__query_builder::Col::new(table_name, "work_id"), - owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), - source_session_id: __sdk::__query_builder::Col::new(table_name, "source_session_id"), - author_display_name: __sdk::__query_builder::Col::new( - table_name, - "author_display_name", - ), - work_title: __sdk::__query_builder::Col::new(table_name, "work_title"), - work_description: __sdk::__query_builder::Col::new(table_name, "work_description"), - theme_tags_json: __sdk::__query_builder::Col::new(table_name, "theme_tags_json"), - hit_object_prompt: __sdk::__query_builder::Col::new(table_name, "hit_object_prompt"), - hit_object_reference_image_src: __sdk::__query_builder::Col::new( - table_name, - "hit_object_reference_image_src", - ), - hit_sound_prompt: __sdk::__query_builder::Col::new(table_name, "hit_sound_prompt"), - hit_object_asset_json: __sdk::__query_builder::Col::new( - table_name, - "hit_object_asset_json", - ), - hit_sound_asset_json: __sdk::__query_builder::Col::new( - table_name, - "hit_sound_asset_json", - ), - floating_words_json: __sdk::__query_builder::Col::new( - table_name, - "floating_words_json", - ), - cover_image_src: __sdk::__query_builder::Col::new(table_name, "cover_image_src"), - generation_status: __sdk::__query_builder::Col::new(table_name, "generation_status"), - publication_status: __sdk::__query_builder::Col::new(table_name, "publication_status"), - play_count: __sdk::__query_builder::Col::new(table_name, "play_count"), - updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), - published_at: __sdk::__query_builder::Col::new(table_name, "published_at"), - background_asset_json: __sdk::__query_builder::Col::new( - table_name, - "background_asset_json", - ), - back_button_asset_json: __sdk::__query_builder::Col::new( - table_name, - "back_button_asset_json", - ), - visible: __sdk::__query_builder::Col::new(table_name, "visible"), - } - } -} - -/// Indexed column accessor struct for the table `WoodenFishWorkProfileRow`. -/// -/// Provides typed access to indexed columns for query building. -pub struct WoodenFishWorkProfileRowIxCols { - pub owner_user_id: __sdk::__query_builder::IxCol, - pub profile_id: __sdk::__query_builder::IxCol, - pub publication_status: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for WoodenFishWorkProfileRow { - type IxCols = WoodenFishWorkProfileRowIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - WoodenFishWorkProfileRowIxCols { - owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), - profile_id: __sdk::__query_builder::IxCol::new(table_name, "profile_id"), - publication_status: __sdk::__query_builder::IxCol::new( - table_name, - "publication_status", - ), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for WoodenFishWorkProfileRow {} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_work_profile_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_work_profile_table.rs deleted file mode 100644 index aa9904114..000000000 --- a/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_work_profile_table.rs +++ /dev/null @@ -1,231 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::wooden_fish_work_profile_row_type::WoodenFishWorkProfileRow; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `wooden_fish_work_profile`. -/// -/// Obtain a handle from the [`WoodenFishWorkProfileTableAccess::wooden_fish_work_profile`] method on [`super::RemoteTables`], -/// like `ctx.db.wooden_fish_work_profile()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.wooden_fish_work_profile().on_insert(...)`. -pub struct WoodenFishWorkProfileTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -/// Lifetime-aware accessor marker for the table `wooden_fish_work_profile`. -pub struct WoodenFishWorkProfileTableAccessor; - -impl __sdk::TableAccessor for WoodenFishWorkProfileTableAccessor { - type Row = WoodenFishWorkProfileRow; - type Handle<'db> = WoodenFishWorkProfileTableHandle<'db>; - - fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> { - db.wooden_fish_work_profile() - } -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `wooden_fish_work_profile`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait WoodenFishWorkProfileTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`WoodenFishWorkProfileTableHandle`], which mediates access to the table `wooden_fish_work_profile`. - fn wooden_fish_work_profile(&self) -> WoodenFishWorkProfileTableHandle<'_>; -} - -impl WoodenFishWorkProfileTableAccess for super::RemoteTables { - fn wooden_fish_work_profile(&self) -> WoodenFishWorkProfileTableHandle<'_> { - WoodenFishWorkProfileTableHandle { - imp: self - .imp - .get_table::("wooden_fish_work_profile"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct WoodenFishWorkProfileInsertCallbackId(__sdk::CallbackId); -pub struct WoodenFishWorkProfileDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableLike for WoodenFishWorkProfileTableHandle<'ctx> { - type Row = WoodenFishWorkProfileRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } -} - -impl<'ctx> __sdk::Table for WoodenFishWorkProfileTableHandle<'ctx> { - type Row = WoodenFishWorkProfileRow; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = WoodenFishWorkProfileInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> WoodenFishWorkProfileInsertCallbackId { - WoodenFishWorkProfileInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: WoodenFishWorkProfileInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = WoodenFishWorkProfileDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> WoodenFishWorkProfileDeleteCallbackId { - WoodenFishWorkProfileDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: WoodenFishWorkProfileDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -impl<'ctx> __sdk::WithInsert for WoodenFishWorkProfileTableHandle<'ctx> { - type InsertCallbackId = WoodenFishWorkProfileInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> WoodenFishWorkProfileInsertCallbackId { - WoodenFishWorkProfileInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: WoodenFishWorkProfileInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } -} - -impl<'ctx> __sdk::WithDelete for WoodenFishWorkProfileTableHandle<'ctx> { - type DeleteCallbackId = WoodenFishWorkProfileDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> WoodenFishWorkProfileDeleteCallbackId { - WoodenFishWorkProfileDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: WoodenFishWorkProfileDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct WoodenFishWorkProfileUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for WoodenFishWorkProfileTableHandle<'ctx> { - type UpdateCallbackId = WoodenFishWorkProfileUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> WoodenFishWorkProfileUpdateCallbackId { - WoodenFishWorkProfileUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: WoodenFishWorkProfileUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -impl<'ctx> __sdk::WithUpdate for WoodenFishWorkProfileTableHandle<'ctx> { - type UpdateCallbackId = WoodenFishWorkProfileUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> WoodenFishWorkProfileUpdateCallbackId { - WoodenFishWorkProfileUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: WoodenFishWorkProfileUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `profile_id` unique index on the table `wooden_fish_work_profile`, -/// which allows point queries on the field of the same name -/// via the [`WoodenFishWorkProfileProfileIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.wooden_fish_work_profile().profile_id().find(...)`. -pub struct WoodenFishWorkProfileProfileIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> WoodenFishWorkProfileTableHandle<'ctx> { - /// Get a handle on the `profile_id` unique index on the table `wooden_fish_work_profile`. - pub fn profile_id(&self) -> WoodenFishWorkProfileProfileIdUnique<'ctx> { - WoodenFishWorkProfileProfileIdUnique { - imp: self.imp.get_unique_constraint::("profile_id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> WoodenFishWorkProfileProfileIdUnique<'ctx> { - /// Find the subscribed row whose `profile_id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = - client_cache.get_or_make_table::("wooden_fish_work_profile"); - _table.add_unique_constraint::("profile_id", |row| &row.profile_id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `WoodenFishWorkProfileRow`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait wooden_fish_work_profileQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `WoodenFishWorkProfileRow`. - fn wooden_fish_work_profile(&self) -> __sdk::__query_builder::Table; -} - -impl wooden_fish_work_profileQueryTableAccess for __sdk::QueryTableAccessor { - fn wooden_fish_work_profile(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("wooden_fish_work_profile") - } -} diff --git a/server-rs/crates/spacetime-module/README.md b/server-rs/crates/spacetime-module/README.md index 8a645a68b..0b8b9230c 100644 --- a/server-rs/crates/spacetime-module/README.md +++ b/server-rs/crates/spacetime-module/README.md @@ -1,6 +1,6 @@ # spacetime-module 主工程 crate 说明 -日期:`2026-04-21` +日期:`2026-09-22` ## 1. crate 职责 @@ -14,81 +14,42 @@ ## 2. 当前阶段说明 -当前阶段已落下第一批真实 schema 骨架,并已补齐本地 standalone 启动脚本,先把 SpacetimeDB 进程入口、M3/M4 基础表以及 `M5 custom world / agent` 首批表骨架固定下来。 +当前阶段以 `src/active.rs` 的现役聚合入口为准,已覆盖资产管理、认证、AI 任务、runtime / profile、编辑器工程与精选、外部生成、游戏分发、后台存储和数据库迁移能力。 后续与本 crate 直接相关的任务包括: 1. 继续扩充模块聚合入口 -2. 继续设计表、reducer、view 的聚合方式 +2. 保持 table / reducer / view / procedure、迁移白名单和生成 bindings 同步 3. 接入身份 claims 透传 4. 在当前 scaffold 基础上接入 publish / dev 循环 -5. 在 `M7` 收口阶段拆分过大的 `src/lib.rs`,按 `runtime`、`gameplay/*`、`custom_world`、`asset_metadata`、`ai` 等业务与 SpacetimeDB 聚合层次重组目录,避免主工程 crate 回退成单大包 +5. 新增业务域时按 `src/active.rs` 的现役声明落位,禁止恢复已退役的 gameplay / custom_world / 逐玩法目录 当前已落地: 1. `spacetime-module` 真实 `cdylib` crate scaffold -2. `asset_object` 首版表骨架 -3. `bucket + object_key` 双列对象定位索引 -4. `module-assets` 的访问策略与字段校验类型接入 -5. 面向 Axum 的 `asset_object` 确认持久化入口 -6. `asset_entity_binding` 通用绑定表 -7. 面向 Axum 的 `bind_asset_object_to_entity_and_return` 绑定 procedure -8. `runtime_setting` 表与 procedure -9. `npc_state`、`story_session`、`story_event` -10. `battle_state`、`treasure_record` -11. `quest_record`、`quest_log` -12. `M5` 首批 `custom_world_profile / session / agent / gallery` 表骨架 -13. `custom world library / publish / gallery` Stage 2 procedures -14. `published profile compile` Stage 3 procedure -15. `publish_world` Stage 4 串联 procedure -16. `ai_task / ai_task_stage / ai_text_chunk / ai_result_reference` 首版 AI 真相表 -17. AI 任务最小 procedure / reducer: +2. `asset_object`、`asset_entity_binding` 与资产绑定 procedure +3. `runtime_setting`、`runtime_snapshot`、`user_browse_history` +4. `creation_entry_config`、`creation_entry_type_config`、`feature_gate_config` +5. 账号、身份、refresh session 与认证 procedure +6. profile / 钱包 / 充值 / 任务 / 邀请码 / 兑换码 / 埋点投影 +7. `ai_task`、`ai_task_stage`、`ai_text_chunk`、`ai_result_reference` 与任务事件 +8. 编辑器工程、画布、资源、素材、精选和编辑器 Agent 会话 +9. 外部生成任务、游戏分发、LLM Router、AGC 模型、外部 API Key、后台与错误报告存储 +10. 数据库导出 / 导入 / 分片导入 / operator 授权等通用迁移 procedure -- `create_ai_task` -- `create_ai_task_and_return` -- `start_ai_task` -- `start_ai_task_stage` -- `append_ai_text_chunk_and_return` -- `complete_ai_stage_and_return` -- `attach_ai_result_reference_and_return` -- `complete_ai_task_and_return` -- `fail_ai_task_and_return` -- `cancel_ai_task_and_return` +### 2.0.1 `runtime` 域落位 -18. `turn_in_quest` 与 `resolve_combat_action(Victory)` 到 `player_progression / chapter_progression` 的最小经验联动 +`src/runtime.rs` 只承担聚合职责,现役入口如下: -### 2.0.1 `runtime` 域拆分进度 +1. 表结构壳:`src/runtime/legacy_schema/{settings,snapshots,browse_history}.rs`、`src/legacy_schema/creation_entry_config.rs` +2. 现役 procedure / helper:`src/runtime/active/{settings,profile}.rs` +3. 独立配置与投影:`src/runtime/feature_gate_config.rs`、`src/runtime/analytics_date_dimension.rs` -截至 `2026-04-23`,`runtime` 域已完成第一轮真实内容拆分,根入口不再保留该域的业务 helper 实现。 - -当前 `src/runtime/` 的实际落位如下: - -1. `src/runtime/settings.rs` - - `runtime_setting` 表 - - setting 读取 / upsert procedure 与快照 helper -2. `src/runtime/snapshots.rs` - - `runtime_snapshot` 表 - - snapshot 读取 / upsert / delete helper -3. `src/runtime/browse_history.rs` - - `user_browse_history` 表 - - 浏览历史 list / upsert / clear procedure 与行转换 helper -4. `src/runtime/profile.rs` - - `profile_dashboard_state` - - `profile_wallet_ledger` - - `profile_played_world` - - `profile_save_archive` - - profile dashboard / ledger / play stats / save archive 投影与同步 helper - -`src/runtime/mod.rs` 当前只承担聚合职责: - -1. 声明 `settings / snapshots / browse_history / profile` -2. 对外统一使用 `pub use xxx::*;` 重新导出 - -后续新增 runtime 相关 table / reducer / procedure / helper 时,必须直接落到上述二级文件,禁止回写到 `src/lib.rs`。 +后续新增 runtime 相关 table / reducer / procedure / helper 时,必须直接落到对应二级文件,禁止回写到 `src/active.rs`;不得把同名旧根文件重新加入 `runtime.rs`。 ### 2.0.2 `ai` 域拆分进度 -截至 `2026-04-23`,`ai` 域也已完成第一轮真实内容拆分,根入口不再保留 `ai_task / ai_task_stage / ai_text_chunk / ai_result_reference` 的业务实现。 +截至 `2026-04-23`,`ai` 域也已完成第一轮真实内容拆分,根入口不再保留 `ai_task / ai_task_stage / ai_text_chunk / ai_result_reference / ai_task_event` 的业务实现。 当前 `src/ai/` 的实际落位如下: @@ -104,19 +65,19 @@ 3. `src/ai/snapshots.rs` - AI 任务、阶段、chunk、reference 的 row / snapshot 转换 helper -`src/ai/mod.rs` 当前只承担聚合职责: +`src/ai.rs` 当前只承担聚合职责: -1. 声明 `tasks / stages / snapshots` +1. 声明 `tasks / stages / snapshots / events` 2. 对外统一使用 `pub use xxx::*;` 3. 对内部共享的 row / snapshot helper 使用 `pub(crate) use snapshots::*;` -后续新增 AI 相关 table / reducer / procedure / helper 时,必须直接落到上述二级文件,禁止回写到 `src/lib.rs`。 +后续新增 AI 相关 table / reducer / procedure / helper 时,必须直接落到上述二级文件,禁止回写到 `src/active.rs`。 -## 2.1 `src/lib.rs` 拆分路由规则 +## 2.1 `src/active.rs` 聚合路由规则 -从 `2026-04-23` 起,`src/lib.rs` 不再允许继续承载具体业务域的 table / reducer / procedure / tx helper。 +从 `2026-04-23` 起,`src/active.rs` 不再承载具体业务域的 table / reducer / procedure / tx helper。 -根入口后续只允许保留: +根入口只允许保留: 1. `use` 聚合 2. `mod` 声明 @@ -125,62 +86,48 @@ 根入口与子模块的导入导出规则同步冻结为: -1. `src/lib.rs` 对外统一优先使用 `pub use xxx::*;` 重新导出模块内容 +1. `src/active.rs` 对外统一优先使用 `pub use xxx::*;` 重新导出模块内容 2. 已拆业务模块内部统一优先使用 `use crate::*;` 复用主入口已聚合的类型与函数 -3. 只有当 `use crate::*;` 无法覆盖或会引入明显歧义时,才补局部显式 `use` -4. 新增业务域内容禁止为了堆 `use` 列表再回写到 `src/lib.rs` +3. 只有 `use crate::*;` 无法覆盖或会引入明显歧义时,才补局部显式 `use` +4. 新增业务域内容禁止为了堆 `use` 列表再回写到 `src/active.rs` -具体内容必须落到下面的模块: +当前业务内容按以下入口落位: -1. `src/entry.rs` - - SpacetimeDB `init` 入口 -2. `src/domain_types.rs` - - 跨域共享的 SpacetimeDB 类型 -3. `src/asset_metadata/` +1. `src/asset_metadata/` - 资产对象与资产绑定真相表 -4. `src/big_fish/` - - Big Fish 创作与运行态 -5. `src/runtime/` - - runtime setting / snapshot / browse history / profile 投影 -6. `src/gameplay/` - - `story / combat / inventory / npc / quest / runtime_item / progression` -7. `src/custom_world/` - - custom world profile / session / agent / publishing / gallery / works -8. `src/ai/` - - ai task / stage / chunk / result reference -9. `src/puzzle.rs` - - 拼图玩法当前仍为单文件域模块 +2. `src/auth/` + - 登录身份、账号、refresh session 和认证 procedure +3. `src/ai/` + - AI task / stage / chunk / result reference / event +4. `src/runtime/` + - runtime setting / snapshot / browse history / profile / 入口配置 / 功能灰度 / 日期维度 +5. `src/editor_project_storage.rs` + - 编辑器工程、画布、资源、素材、精选和生成幂等 +6. `src/editor_agent_storage.rs` + - 编辑器 Agent 会话存储 +7. 其它单一领域存储入口 + - `admin_account_storage.rs`、`admin_dashboard.rs`、`agc_models.rs`、`error_report.rs`、`external_api_key_storage.rs`、`external_generation.rs`、`game_distribution.rs`、`llm_router_account.rs`、`migration.rs` ### 已冻结的二级模块落位点 1. `src/asset_metadata/objects.rs` 2. `src/asset_metadata/bindings.rs` -3. `src/big_fish/tables.rs` -4. `src/big_fish/session.rs` -5. `src/big_fish/assets.rs` -6. `src/big_fish/runtime.rs` -7. `src/runtime/settings.rs` -8. `src/runtime/snapshots.rs` -9. `src/runtime/browse_history.rs` -10. `src/runtime/profile.rs` -11. `src/gameplay/combat.rs` -12. `src/gameplay/inventory.rs` -13. `src/gameplay/npc.rs` -14. `src/gameplay/progression.rs` -15. `src/gameplay/quest.rs` -16. `src/gameplay/runtime_item.rs` -17. `src/gameplay/story.rs` -18. `src/custom_world/profile.rs` -19. `src/custom_world/session.rs` -20. `src/custom_world/agent.rs` -21. `src/custom_world/publishing.rs` -22. `src/custom_world/gallery.rs` -23. `src/custom_world/works.rs` -24. `src/ai/tasks.rs` -25. `src/ai/stages.rs` -26. `src/ai/snapshots.rs` +3. `src/auth/tables.rs` +4. `src/auth/procedures.rs` +5. `src/ai/tasks.rs` +6. `src/ai/stages.rs` +7. `src/ai/snapshots.rs` +8. `src/ai/events.rs` +9. `src/runtime/active/settings.rs` +10. `src/runtime/active/profile.rs` +11. `src/runtime/legacy_schema/settings.rs` +12. `src/runtime/legacy_schema/snapshots.rs` +13. `src/runtime/legacy_schema/browse_history.rs` +14. `src/legacy_schema/creation_entry_config.rs` +15. `src/runtime/feature_gate_config.rs` +16. `src/runtime/analytics_date_dimension.rs` -后续如果新增 SpacetimeDB 表、reducer、procedure 或同域 helper,必须先判断属于哪个一级模块与二级落位点,再写入对应文件;禁止直接追加到 `src/lib.rs`。 +后续如果新增 SpacetimeDB 表、reducer、procedure 或同域 helper,必须先判断属于哪个一级模块与二级落位点,再写入对应文件;禁止直接追加到 `src/active.rs`,也禁止恢复已删除的旧创作模板域目录。 ## 当前文档入口 @@ -197,4 +144,4 @@ 1. `spacetime-module` 只聚合状态模型,不直接承接 HTTP、Cookie、Header、OSS、短信、微信、LLM 等外部副作用。 2. 每个业务模块优先在自己的 `crates/module-*` 中定义状态与规则,再由主工程聚合。 3. 主工程不重新吞并各模块实现细节,避免回到单大包结构。 -4. `custom_world_asset_link` 仍等待 `M6 assets / OSS` 的对象槽位规则冻结后再补,不在本轮首批表骨架内提前硬落。 +4. 新增跨域状态必须先在对应 `module-*` 定义领域规则,再由 `spacetime-module` 聚合;不得从历史源码恢复已退役模块。 diff --git a/server-rs/crates/spacetime-module/src/active.rs b/server-rs/crates/spacetime-module/src/active.rs index cde34cbe6..de0a60919 100644 --- a/server-rs/crates/spacetime-module/src/active.rs +++ b/server-rs/crates/spacetime-module/src/active.rs @@ -10,6 +10,9 @@ pub(crate) use serde_json::{Map as JsonMap, Value as JsonValue, json}; pub use spacetimedb::{ Identity, ProcedureContext, ReducerContext, ScheduleAt, SpacetimeType, Table, Timestamp, }; +#[path = "agc_analytics.rs"] +mod agc_analytics_storage; +pub use agc_analytics_storage::*; mod admin_account_storage; mod admin_dashboard; #[path = "agc_models.rs"] @@ -17,12 +20,6 @@ mod agc_models; mod ai; mod asset_metadata; mod auth; -#[path = "legacy_schema/bark_battle.rs"] -mod bark_battle; -#[path = "legacy_schema/big_fish.rs"] -mod big_fish; -#[path = "legacy_schema/custom_world.rs"] -mod custom_world; mod editor_agent_storage; mod editor_project_storage; #[path = "error_report.rs"] @@ -30,52 +27,26 @@ mod error_reports_schema; mod external_api_key_storage; mod external_generation; mod game_distribution; -#[path = "legacy_schema/gameplay.rs"] -mod gameplay; -#[path = "legacy_schema/jump_hop.rs"] -mod jump_hop; #[path = "llm_router_account.rs"] mod llm_router_account_storage; pub use agc_models::*; -#[path = "legacy_schema/match3d.rs"] -mod match3d; mod migration; -#[path = "legacy_schema/puzzle.rs"] -mod puzzle; -#[path = "legacy_schema/puzzle_clear.rs"] -mod puzzle_clear; mod runtime; -#[path = "legacy_schema/square_hole.rs"] -mod square_hole; -#[path = "legacy_schema/visual_novel.rs"] -mod visual_novel; -#[path = "legacy_schema/wooden_fish.rs"] -mod wooden_fish; pub use admin_account_storage::*; pub use admin_dashboard::*; pub use ai::*; pub use asset_metadata::*; pub use auth::*; -pub use bark_battle::*; -pub use big_fish::*; -pub use custom_world::*; pub use editor_agent_storage::*; pub use editor_project_storage::*; pub use error_reports_schema::*; pub use external_api_key_storage::*; pub use external_generation::*; pub use game_distribution::*; -pub use gameplay::*; -pub use jump_hop::*; pub use llm_router_account_storage::*; -pub use match3d::*; pub use migration::*; -pub use puzzle_clear::*; pub use runtime::*; -pub use square_hole::*; -pub use visual_novel::*; -pub use wooden_fish::*; // Host-side unit tests need to link the module crate as a normal test binary. // SpacetimeDB's raw ABI imports only exist in the WASM host, so provide diff --git a/server-rs/crates/spacetime-module/src/agc_analytics.rs b/server-rs/crates/spacetime-module/src/agc_analytics.rs new file mode 100644 index 000000000..74f78b026 --- /dev/null +++ b/server-rs/crates/spacetime-module/src/agc_analytics.rs @@ -0,0 +1,314 @@ +use crate::*; +use module_runtime::agc_analytics::{ + AgcTrackingCursor, agc_time_micros, agc_tracking_filter_key, validate_agc_analytics_batch, + validate_agc_tracking_query, +}; +use shared_contracts::admin::{ + AdminAgcTrackingEventEntry, AdminAgcTrackingEventListPayload, AdminAgcTrackingEventListQuery, +}; +use shared_contracts::agc_analytics::{AgcAnalyticsAcknowledgement, AgcAnalyticsBatch, Event}; +use std::collections::BTreeMap; + +#[spacetimedb::table( + accessor = agc_tracking_event, + index(accessor = by_agc_tracking_received, btree(columns = [received_at])), + index(accessor = by_agc_tracking_user_received, btree(columns = [user_id, received_at])), + index(accessor = by_agc_tracking_name_received, btree(columns = [event_name, received_at])) +)] +#[derive(Clone, Debug, PartialEq)] +pub struct AgcTrackingEvent { + #[primary_key] + pub event_id: String, + pub schema_version: u32, + pub event_name: String, + pub event_time: Timestamp, + pub user_id: String, + pub editor_session_id: String, + pub project_id: Option, + pub creative_task_id: Option, + pub agent_run_id: Option, + pub agent_turn_id: Option, + pub status: Option, + pub error_code: Option, + pub source: String, + pub client_version: String, + pub properties_json: String, + pub batch_id: String, + pub received_at: Timestamp, +} + +fn event_row( + event: &Event, + batch_id: &str, + received_at: Timestamp, +) -> Result { + let enum_string = |v: serde_json::Value| v.as_str().unwrap_or_default().to_owned(); + Ok(AgcTrackingEvent { + event_id: event.event_id.clone(), + schema_version: event.schema_version, + event_name: event.event_name.clone(), + event_time: Timestamp::from_micros_since_unix_epoch(agc_time_micros(&event.event_time)?), + user_id: event.user_id.clone().ok_or("invalid_batch")?, + editor_session_id: event.editor_session_id.clone(), + project_id: event.project_id.clone(), + creative_task_id: event.creative_task_id.clone(), + agent_run_id: event.agent_run_id.clone(), + agent_turn_id: event.agent_turn_id.clone(), + status: event + .status + .map(|v| enum_string(serde_json::to_value(v).unwrap())), + error_code: event + .error_code + .map(|v| enum_string(serde_json::to_value(v).unwrap())), + source: enum_string(serde_json::to_value(event.source).unwrap()), + client_version: event.client_version.clone(), + properties_json: serde_json::to_string(&event.properties) + .map_err(|_| "invalid_properties")?, + batch_id: batch_id.to_owned(), + received_at, + }) +} + +// 接收批次和时间不属于原始事件内容,重传保留首次值。 +fn same_event(existing: &AgcTrackingEvent, incoming: &AgcTrackingEvent) -> bool { + let mut incoming = incoming.clone(); + incoming.batch_id = existing.batch_id.clone(); + incoming.received_at = existing.received_at; + let same_properties = serde_json::from_str::(&existing.properties_json).ok() + == serde_json::from_str::(&incoming.properties_json).ok(); + incoming.properties_json = existing.properties_json.clone(); + same_properties && existing == &incoming +} + +#[spacetimedb::procedure] +pub fn upload_agc_analytics_batch( + ctx: &mut ProcedureContext, + payload_json: String, +) -> Result { + if payload_json.len() > 2 * 1024 * 1024 { + return Err("invalid_batch".into()); + } + let batch: AgcAnalyticsBatch = + serde_json::from_str(&payload_json).map_err(|_| "invalid_batch")?; + validate_agc_analytics_batch(&batch)?; + let caller = ctx.sender(); + ctx.try_with_tx(|tx| { + crate::editor_project_storage::require_editor_generation_runtime_service_identity( + tx, caller, + )?; + // 同一事务内任一冲突返回 Err,之前插入的行一起回滚。 + for event in &batch.events { + let incoming = event_row(event, &batch.batch_id, tx.timestamp)?; + if let Some(existing) = tx.db.agc_tracking_event().event_id().find(&event.event_id) { + if !same_event(&existing, &incoming) { + return Err("agc_event_conflict".into()); + } + } else { + tx.db.agc_tracking_event().insert(incoming); + } + } + serde_json::to_string(&AgcAnalyticsAcknowledgement { + acknowledged_batch_ids: vec![batch.batch_id.clone()], + event_count: batch.events.len() as u32, + }) + .map_err(|_| "acknowledgement_failed".into()) + }) +} + +fn matches_query( + row: &AgcTrackingEvent, + query: &AdminAgcTrackingEventListQuery, + start: Option, + end: Option, +) -> bool { + query.user_id.as_ref().is_none_or(|v| v == &row.user_id) + && query + .project_id + .as_ref() + .is_none_or(|v| Some(v) == row.project_id.as_ref()) + && query + .creative_task_id + .as_ref() + .is_none_or(|v| Some(v) == row.creative_task_id.as_ref()) + && query + .agent_run_id + .as_ref() + .is_none_or(|v| Some(v) == row.agent_run_id.as_ref()) + && query + .event_name + .as_ref() + .is_none_or(|v| v == &row.event_name) + && query + .client_version + .as_ref() + .is_none_or(|v| v == &row.client_version) + && start.is_none_or(|v| row.event_time.to_micros_since_unix_epoch() >= v) + && end.is_none_or(|v| row.event_time.to_micros_since_unix_epoch() < v) +} + +fn entry(row: AgcTrackingEvent) -> Result { + Ok(AdminAgcTrackingEventEntry { + event_id: row.event_id, + schema_version: row.schema_version, + event_name: row.event_name, + event_time: module_runtime::format_utc_micros(row.event_time.to_micros_since_unix_epoch()), + user_id: row.user_id, + editor_session_id: row.editor_session_id, + project_id: row.project_id, + creative_task_id: row.creative_task_id, + agent_run_id: row.agent_run_id, + agent_turn_id: row.agent_turn_id, + status: row.status, + error_code: row.error_code, + source: row.source, + client_version: row.client_version, + properties: serde_json::from_str(&row.properties_json) + .map_err(|_| "invalid_stored_properties")?, + batch_id: row.batch_id, + received_at: module_runtime::format_utc_micros( + row.received_at.to_micros_since_unix_epoch(), + ), + }) +} + +#[spacetimedb::procedure] +pub fn list_agc_tracking_events( + ctx: &mut ProcedureContext, + query_json: String, +) -> Result { + if query_json.len() > 16384 { + return Err("invalid_agc_query".into()); + } + let query: AdminAgcTrackingEventListQuery = + serde_json::from_str(&query_json).map_err(|_| "invalid_agc_query")?; + let cursor = validate_agc_tracking_query(&query)?; + let start = query + .start_time + .as_deref() + .map(agc_time_micros) + .transpose()?; + let end = query.end_time.as_deref().map(agc_time_micros).transpose()?; + let caller = ctx.sender(); + ctx.try_with_tx(|tx| { + crate::editor_project_storage::require_editor_generation_runtime_service_identity( + tx, caller, + )?; + let snapshot = cursor + .as_ref() + .map(|v| v.snapshot) + .unwrap_or(tx.timestamp.to_micros_since_unix_epoch()); + let limit = query.limit.unwrap_or(50).clamp(1, 200) as usize; + let upper = Timestamp::from_micros_since_unix_epoch(snapshot); + let mut selected = BTreeMap::new(); + // 在数据库事务中扫描完整索引候选,再保留最大的 limit+1 个键。 + // 不依赖 SDK 迭代器顺序,不将任意 LIMIT 截断误作最新一页,内存只保留一页。 + let mut consider = |row: AgcTrackingEvent| { + let key = ( + row.event_time.to_micros_since_unix_epoch(), + row.event_id.clone(), + ); + if row.received_at.to_micros_since_unix_epoch() > snapshot + || cursor + .as_ref() + .is_some_and(|v| key >= (v.event_time, v.event_id.clone())) + || !matches_query(&row, &query, start, end) + { + return; + } + selected.insert(key, row); + if selected.len() > limit + 1 { + selected.pop_first(); + } + }; + if let Some(user_id) = &query.user_id { + for row in tx + .db + .agc_tracking_event() + .by_agc_tracking_user_received() + .filter((user_id.as_str(), ..=upper)) + { + consider(row); + } + } else if let Some(event_name) = &query.event_name { + for row in tx + .db + .agc_tracking_event() + .by_agc_tracking_name_received() + .filter((event_name.as_str(), ..=upper)) + { + consider(row); + } + } else { + for row in tx + .db + .agc_tracking_event() + .by_agc_tracking_received() + .filter(..=upper) + { + consider(row); + } + } + let has_more = selected.len() > limit; + let mut rows: Vec<_> = selected.into_iter().rev().take(limit).collect(); + let next_cursor = if has_more { + let ((event_time, event_id), _) = rows.last().expect("nonempty page"); + Some( + serde_json::to_string(&AgcTrackingCursor { + snapshot, + event_time: *event_time, + event_id: event_id.clone(), + filter_key: agc_tracking_filter_key(&query), + }) + .map_err(|_| "cursor_failed")?, + ) + } else { + None + }; + let entries = rows + .drain(..) + .map(|(_, row)| entry(row)) + .collect::, _>>()?; + serde_json::to_string(&AdminAgcTrackingEventListPayload { + entries, + next_cursor, + }) + .map_err(|_| "query_failed".into()) + }) +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn agc_replay_compares_business_fields_but_preserves_first_receipt() { + let event: Event = serde_json::from_value(serde_json::json!({ + "schema_version":1,"event_id":"790a1275-a0a0-405c-8bfd-287201bef10a", + "event_name":"editor_session_start","event_time":"2026-09-21T12:00:00.000Z", + "user_id":"a","editor_session_id":"790a1275-a0a0-405c-8bfd-287201bef10a", + "project_id":null,"creative_task_id":null,"agent_run_id":null,"agent_turn_id":null, + "status":"success","error_code":null,"source":"editor","client_version":"1", + "properties":{"entry_source":"direct_launch","first_project_id":null} + })) + .unwrap(); + let first = event_row( + &event, + "batch-1", + Timestamp::from_micros_since_unix_epoch(10), + ) + .unwrap(); + let mut replay = event_row( + &event, + "batch-2", + Timestamp::from_micros_since_unix_epoch(20), + ) + .unwrap(); + replay.properties_json = + r#"{"first_project_id":null,"entry_source":"direct_launch"}"#.into(); + assert!(same_event(&first, &replay)); + replay.user_id = "b".into(); + assert!(!same_event(&first, &replay)); + replay.user_id = "a".into(); + replay.client_version = "2".into(); + assert!(!same_event(&first, &replay)); + } +} diff --git a/server-rs/crates/spacetime-module/src/bark_battle/tables.rs b/server-rs/crates/spacetime-module/src/bark_battle/tables.rs deleted file mode 100644 index bb9398eb5..000000000 --- a/server-rs/crates/spacetime-module/src/bark_battle/tables.rs +++ /dev/null @@ -1,177 +0,0 @@ -use crate::*; - -pub(super) const WORK_VISIBLE_DEFAULT: bool = false; - -#[spacetimedb::table( - accessor = bark_battle_draft_config, - index(accessor = by_bark_battle_draft_owner_user_id, btree(columns = [owner_user_id])), - index(accessor = by_bark_battle_draft_work_id, btree(columns = [work_id])) -)] -#[derive(Clone)] -pub struct BarkBattleDraftConfigRow { - #[primary_key] - pub(crate) draft_id: String, - pub(crate) owner_user_id: String, - pub(crate) work_id: String, - pub(crate) config_version: u64, - pub(crate) ruleset_version: String, - pub(crate) difficulty_preset: String, - pub(crate) leaderboard_enabled: bool, - pub(crate) config_json: String, - pub(crate) editor_state_json: String, - pub(crate) created_at: Timestamp, - pub(crate) updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = bark_battle_published_config, - index(accessor = by_bark_battle_published_owner_user_id, btree(columns = [owner_user_id])) -)] -#[derive(Clone)] -pub struct BarkBattlePublishedConfigRow { - #[primary_key] - pub(crate) work_id: String, - pub(crate) owner_user_id: String, - pub(crate) source_draft_id: Option, - pub(crate) config_version: u64, - pub(crate) ruleset_version: String, - pub(crate) difficulty_preset: String, - pub(crate) leaderboard_enabled: bool, - pub(crate) config_json: String, - pub(crate) published_snapshot_json: String, - pub(crate) created_at: Timestamp, - pub(crate) updated_at: Timestamp, - pub(crate) published_at: Timestamp, - // 后台可见性开关;新作品默认不公开,开启后才进入公开列表。 - #[default(WORK_VISIBLE_DEFAULT)] - pub(crate) visible: bool, -} - -#[spacetimedb::table( - accessor = bark_battle_runtime_run, - index(accessor = by_bark_battle_run_owner_user_id, btree(columns = [owner_user_id])), - index(accessor = by_bark_battle_run_work_id, btree(columns = [work_id])) -)] -#[derive(Clone)] -pub struct BarkBattleRuntimeRunRow { - #[primary_key] - pub(crate) run_id: String, - pub(crate) run_token_hash: String, - pub(crate) owner_user_id: String, - pub(crate) work_id: String, - pub(crate) config_version: u64, - pub(crate) ruleset_version: String, - pub(crate) difficulty_preset: String, - pub(crate) leaderboard_enabled: bool, - pub(crate) status: String, - pub(crate) client_started_at_micros: i64, - pub(crate) server_started_at: Timestamp, - pub(crate) client_finished_at_micros: Option, - pub(crate) server_finished_at: Option, - pub(crate) metrics_json: String, - pub(crate) server_result: Option, - pub(crate) validation_status: String, - pub(crate) anti_cheat_flags_json: String, - pub(crate) leaderboard_score: Option, - pub(crate) score_id: Option, - pub(crate) created_at: Timestamp, - pub(crate) updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = bark_battle_score_record, - index(accessor = by_bark_battle_score_owner_user_id, btree(columns = [owner_user_id])), - index(accessor = by_bark_battle_score_work_id, btree(columns = [work_id])), - index(accessor = by_bark_battle_score_run_id, btree(columns = [run_id])) -)] -#[derive(Clone)] -pub struct BarkBattleScoreRecordRow { - #[primary_key] - pub(crate) score_id: String, - pub(crate) owner_user_id: String, - pub(crate) work_id: String, - pub(crate) run_id: String, - pub(crate) config_version: u64, - pub(crate) ruleset_version: String, - pub(crate) difficulty_preset: String, - pub(crate) leaderboard_enabled: bool, - pub(crate) metrics_json: String, - pub(crate) derived_metrics_json: String, - pub(crate) server_result: String, - pub(crate) validation_status: String, - pub(crate) anti_cheat_flags_json: String, - pub(crate) leaderboard_score: Option, - pub(crate) recorded_at: Timestamp, -} - -#[spacetimedb::table( - accessor = bark_battle_leaderboard_entry, - index(accessor = by_bark_battle_leaderboard_work_score, btree(columns = [work_id, leaderboard_score])), - index(accessor = by_bark_battle_leaderboard_owner_work, btree(columns = [owner_user_id, work_id])) -)] -#[derive(Clone)] -pub struct BarkBattleLeaderboardEntryRow { - #[primary_key] - pub(crate) leaderboard_entry_id: String, - pub(crate) work_id: String, - pub(crate) owner_user_id: String, - pub(crate) run_id: String, - pub(crate) score_id: String, - pub(crate) leaderboard_score: u64, - pub(crate) final_energy: f32, - pub(crate) trigger_count: u64, - pub(crate) max_volume: f32, - pub(crate) duration_closeness_ms: u64, - pub(crate) finished_at_micros: i64, - pub(crate) created_at: Timestamp, - pub(crate) updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = bark_battle_work_stats_projection, - index(accessor = by_bark_battle_work_stats_owner_user_id, btree(columns = [owner_user_id])) -)] -#[derive(Clone)] -pub struct BarkBattleWorkStatsProjectionRow { - #[primary_key] - pub(crate) work_id: String, - pub(crate) owner_user_id: String, - pub(crate) play_count: u64, - pub(crate) finished_count: u64, - pub(crate) accepted_score_count: u64, - pub(crate) leaderboard_entry_count: u64, - pub(crate) best_leaderboard_score: Option, - pub(crate) best_score_id: Option, - pub(crate) best_run_id: Option, - pub(crate) average_final_energy: f32, - pub(crate) average_trigger_count: f32, - pub(crate) last_finished_at_micros: Option, - pub(crate) stats_json: String, - pub(crate) updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = bark_battle_personal_best_projection, - index(accessor = by_bark_battle_personal_best_work_id, btree(columns = [work_id])), - index(accessor = by_bark_battle_personal_best_owner_work, btree(columns = [owner_user_id, work_id])) -)] -#[derive(Clone)] -pub struct BarkBattlePersonalBestProjectionRow { - #[primary_key] - pub(crate) personal_best_id: String, - pub(crate) owner_user_id: String, - pub(crate) work_id: String, - pub(crate) run_id: String, - pub(crate) score_id: String, - pub(crate) leaderboard_entry_id: Option, - pub(crate) leaderboard_score: Option, - pub(crate) final_energy: f32, - pub(crate) trigger_count: u64, - pub(crate) max_volume: f32, - pub(crate) duration_closeness_ms: u64, - pub(crate) server_result: String, - pub(crate) validation_status: String, - pub(crate) finished_at_micros: i64, - pub(crate) summary_json: String, - pub(crate) updated_at: Timestamp, -} diff --git a/server-rs/crates/spacetime-module/src/big_fish/events.rs b/server-rs/crates/spacetime-module/src/big_fish/events.rs deleted file mode 100644 index cd2745e13..000000000 --- a/server-rs/crates/spacetime-module/src/big_fish/events.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::*; - -/// Big Fish 创作事件类型。 -/// -/// 事件表只承接跨层订阅和审计所需的轻量事实,正式作品状态仍以 -/// `big_fish_creation_session` 和 `big_fish_asset_slot` 为准。 -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum BigFishEventKind { - PublishReadinessEvaluated, -} - -#[spacetimedb::table( - accessor = big_fish_event, - public, - event, - index(accessor = by_big_fish_event_session_id, btree(columns = [session_id])), - index(accessor = by_big_fish_event_owner_user_id, btree(columns = [owner_user_id])) -)] -pub struct BigFishEvent { - #[primary_key] - pub(crate) event_id: String, - pub(crate) session_id: String, - pub(crate) owner_user_id: String, - pub(crate) event_kind: BigFishEventKind, - pub(crate) publish_ready: bool, - pub(crate) blockers_json: String, - pub(crate) occurred_at: Timestamp, -} - -pub(crate) fn emit_big_fish_publish_readiness_event( - ctx: &ReducerContext, - event: BigFishDomainEvent, -) -> Result<(), String> { - let BigFishDomainEvent::PublishReadinessEvaluated { - session_id, - owner_user_id, - publish_ready, - blockers, - occurred_at_micros, - } = event - else { - return Ok(()); - }; - - let blockers_json = serde_json::to_string(&blockers) - .map_err(|error| format!("big_fish.publish_readiness.blockers 序列化失败: {error}"))?; - let state_slug = if publish_ready { "ready" } else { "blocked" }; - ctx.db.big_fish_event().insert(BigFishEvent { - event_id: format!("bfevt_{session_id}_{occurred_at_micros}_{state_slug}"), - session_id, - owner_user_id, - event_kind: BigFishEventKind::PublishReadinessEvaluated, - publish_ready, - blockers_json, - occurred_at: Timestamp::from_micros_since_unix_epoch(occurred_at_micros), - }); - - Ok(()) -} diff --git a/server-rs/crates/spacetime-module/src/big_fish/tables.rs b/server-rs/crates/spacetime-module/src/big_fish/tables.rs deleted file mode 100644 index fe0acb0ca..000000000 --- a/server-rs/crates/spacetime-module/src/big_fish/tables.rs +++ /dev/null @@ -1,86 +0,0 @@ -use crate::*; - -pub(super) const WORK_VISIBLE_DEFAULT: bool = false; - -#[spacetimedb::table( - accessor = big_fish_creation_session, - index(accessor = by_big_fish_session_owner_user_id, btree(columns = [owner_user_id])), - index(accessor = by_big_fish_session_stage, btree(columns = [stage])) -)] -pub struct BigFishCreationSession { - #[primary_key] - pub(crate) session_id: String, - pub(crate) owner_user_id: String, - pub(crate) seed_text: String, - pub(crate) current_turn: u32, - pub(crate) progress_percent: u32, - pub(crate) stage: BigFishCreationStage, - pub(crate) anchor_pack_json: String, - pub(crate) draft_json: Option, - pub(crate) asset_coverage_json: String, - pub(crate) last_assistant_reply: Option, - pub(crate) publish_ready: bool, - pub(crate) created_at: Timestamp, - pub(crate) updated_at: Timestamp, - #[default(0)] - pub(crate) play_count: u32, - #[default(0)] - pub(crate) remix_count: u32, - #[default(0)] - pub(crate) like_count: u32, - #[default(None::)] - pub(crate) published_at: Option, - // 后台可见性开关;新作品默认不公开,开启后才进入公开列表。 - #[default(WORK_VISIBLE_DEFAULT)] - pub(crate) visible: bool, -} - -#[spacetimedb::table( - accessor = big_fish_agent_message, - index(accessor = by_big_fish_message_session_id, btree(columns = [session_id])) -)] -pub struct BigFishAgentMessage { - #[primary_key] - pub(crate) message_id: String, - pub(crate) session_id: String, - pub(crate) role: BigFishAgentMessageRole, - pub(crate) kind: BigFishAgentMessageKind, - pub(crate) text: String, - pub(crate) created_at: Timestamp, -} - -#[spacetimedb::table( - accessor = big_fish_asset_slot, - index(accessor = by_big_fish_asset_session_id, btree(columns = [session_id])) -)] -pub struct BigFishAssetSlot { - #[primary_key] - pub(crate) slot_id: String, - pub(crate) session_id: String, - pub(crate) asset_kind: BigFishAssetKind, - pub(crate) level: Option, - pub(crate) motion_key: Option, - pub(crate) status: BigFishAssetStatus, - pub(crate) asset_url: Option, - pub(crate) prompt_snapshot: String, - pub(crate) updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = big_fish_runtime_run, - index(accessor = by_big_fish_run_owner_user_id, btree(columns = [owner_user_id])), - index(accessor = by_big_fish_run_session_id, btree(columns = [session_id])) -)] -pub struct BigFishRuntimeRun { - #[primary_key] - pub(crate) run_id: String, - pub(crate) session_id: String, - pub(crate) owner_user_id: String, - pub(crate) status: BigFishRunStatus, - pub(crate) snapshot_json: String, - pub(crate) last_input_x: f32, - pub(crate) last_input_y: f32, - pub(crate) tick: u64, - pub(crate) created_at: Timestamp, - pub(crate) updated_at: Timestamp, -} diff --git a/server-rs/crates/spacetime-module/src/jump_hop/tables.rs b/server-rs/crates/spacetime-module/src/jump_hop/tables.rs deleted file mode 100644 index 38611c169..000000000 --- a/server-rs/crates/spacetime-module/src/jump_hop/tables.rs +++ /dev/null @@ -1,121 +0,0 @@ -use crate::*; - -pub(super) const WORK_VISIBLE_DEFAULT: bool = false; - -#[spacetimedb::table( - accessor = jump_hop_agent_session, - index(accessor = by_jump_hop_agent_session_owner_user_id, btree(columns = [owner_user_id])) -)] -pub struct JumpHopAgentSessionRow { - #[primary_key] - pub(crate) session_id: String, - pub(crate) owner_user_id: String, - pub(crate) seed_text: String, - pub(crate) current_turn: u32, - pub(crate) progress_percent: u32, - pub(crate) stage: String, - pub(crate) config_json: String, - pub(crate) draft_json: String, - pub(crate) last_assistant_reply: String, - pub(crate) published_profile_id: String, - pub(crate) created_at: Timestamp, - pub(crate) updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = jump_hop_work_profile, - index(accessor = by_jump_hop_work_owner_user_id, btree(columns = [owner_user_id])), - index(accessor = by_jump_hop_work_publication_status, btree(columns = [publication_status])) -)] -pub struct JumpHopWorkProfileRow { - #[primary_key] - pub(crate) profile_id: String, - pub(crate) work_id: String, - pub(crate) owner_user_id: String, - pub(crate) source_session_id: String, - pub(crate) author_display_name: String, - pub(crate) work_title: String, - pub(crate) work_description: String, - pub(crate) theme_tags_json: String, - pub(crate) difficulty: String, - pub(crate) style_preset: String, - pub(crate) character_prompt: String, - pub(crate) tile_prompt: String, - pub(crate) end_mood_prompt: String, - pub(crate) character_asset_json: String, - pub(crate) tile_atlas_asset_json: String, - pub(crate) tile_assets_json: String, - pub(crate) path_json: String, - pub(crate) cover_image_src: String, - pub(crate) cover_composite: String, - pub(crate) generation_status: String, - pub(crate) publication_status: String, - pub(crate) play_count: u32, - pub(crate) updated_at: Timestamp, - pub(crate) published_at: Option, - // 后台可见性开关;新作品默认不公开,开启后才进入公开列表。 - #[default(WORK_VISIBLE_DEFAULT)] - pub(crate) visible: bool, - // 跳一跳生成主题独立于作品标题;旧行按 work_title 兜底。 - #[default(None::)] - pub(crate) theme_text: Option, - // 跳一跳左上角真实可点击返回按钮的独立透明资产快照;旧行为空时运行态使用样式兜底。 - #[default(None::)] - pub(crate) back_button_asset_json: Option, -} - -#[spacetimedb::table( - accessor = jump_hop_runtime_run, - index(accessor = by_jump_hop_run_owner_user_id, btree(columns = [owner_user_id])), - index(accessor = by_jump_hop_run_profile_id, btree(columns = [profile_id])) -)] -pub struct JumpHopRuntimeRunRow { - #[primary_key] - pub(crate) run_id: String, - pub(crate) owner_user_id: String, - pub(crate) profile_id: String, - pub(crate) status: String, - pub(crate) started_at_ms: i64, - pub(crate) finished_at_ms: i64, - pub(crate) current_platform_index: u32, - pub(crate) score: u32, - pub(crate) combo: u32, - pub(crate) snapshot_json: String, - pub(crate) created_at: Timestamp, - pub(crate) updated_at: Timestamp, - // draft / published,用于隔离试玩统计和公开排行榜;旧行按 published 兜底。 - #[default(None::)] - pub(crate) runtime_mode: Option, -} - -#[spacetimedb::table( - accessor = jump_hop_event, - index(accessor = by_jump_hop_event_profile_id, btree(columns = [profile_id])), - index(accessor = by_jump_hop_event_run_id, btree(columns = [run_id])) -)] -pub struct JumpHopEventRow { - #[primary_key] - pub(crate) event_id: String, - pub(crate) owner_user_id: String, - pub(crate) profile_id: String, - pub(crate) run_id: String, - pub(crate) event_type: String, - pub(crate) result: String, - pub(crate) occurred_at: Timestamp, -} - -#[spacetimedb::table( - accessor = jump_hop_leaderboard_entry, - index(accessor = by_jump_hop_leaderboard_profile_id, btree(columns = [profile_id])), - index(accessor = by_jump_hop_leaderboard_player_profile, btree(columns = [player_id, profile_id])) -)] -pub struct JumpHopLeaderboardEntryRow { - #[primary_key] - pub(crate) entry_id: String, - pub(crate) profile_id: String, - pub(crate) player_id: String, - pub(crate) successful_jump_count: u32, - pub(crate) duration_ms: u64, - pub(crate) run_id: String, - pub(crate) updated_at: Timestamp, -} diff --git a/server-rs/crates/spacetime-module/src/legacy_schema/bark_battle.rs b/server-rs/crates/spacetime-module/src/legacy_schema/bark_battle.rs deleted file mode 100644 index a52234292..000000000 --- a/server-rs/crates/spacetime-module/src/legacy_schema/bark_battle.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[path = "../bark_battle/tables.rs"] -pub(crate) mod tables; - -pub use tables::*; diff --git a/server-rs/crates/spacetime-module/src/legacy_schema/big_fish.rs b/server-rs/crates/spacetime-module/src/legacy_schema/big_fish.rs deleted file mode 100644 index 2b2ead424..000000000 --- a/server-rs/crates/spacetime-module/src/legacy_schema/big_fish.rs +++ /dev/null @@ -1,53 +0,0 @@ -#[path = "big_fish/events.rs"] -mod events; -#[path = "../big_fish/tables.rs"] -mod tables; - -pub(crate) use events::*; -pub use tables::*; - -use crate::SpacetimeType; - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum BigFishCreationStage { - CollectingAnchors, - DraftReady, - AssetRefining, - ReadyToPublish, - Published, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum BigFishAgentMessageRole { - User, - Assistant, - System, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum BigFishAgentMessageKind { - Chat, - Summary, - ActionResult, - Warning, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum BigFishAssetKind { - LevelMainImage, - LevelMotion, - StageBackground, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum BigFishAssetStatus { - Missing, - Ready, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum BigFishRunStatus { - Running, - Won, - Failed, -} diff --git a/server-rs/crates/spacetime-module/src/legacy_schema/big_fish/events.rs b/server-rs/crates/spacetime-module/src/legacy_schema/big_fish/events.rs deleted file mode 100644 index 93042bdd4..000000000 --- a/server-rs/crates/spacetime-module/src/legacy_schema/big_fish/events.rs +++ /dev/null @@ -1,24 +0,0 @@ -use crate::*; - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum BigFishEventKind { - PublishReadinessEvaluated, -} - -#[spacetimedb::table( - accessor = big_fish_event, - public, - event, - index(accessor = by_big_fish_event_session_id, btree(columns = [session_id])), - index(accessor = by_big_fish_event_owner_user_id, btree(columns = [owner_user_id])) -)] -pub struct BigFishEvent { - #[primary_key] - pub(crate) event_id: String, - pub(crate) session_id: String, - pub(crate) owner_user_id: String, - pub(crate) event_kind: BigFishEventKind, - pub(crate) publish_ready: bool, - pub(crate) blockers_json: String, - pub(crate) occurred_at: Timestamp, -} diff --git a/server-rs/crates/spacetime-module/src/legacy_schema/custom_world.rs b/server-rs/crates/spacetime-module/src/legacy_schema/custom_world.rs deleted file mode 100644 index e200feec6..000000000 --- a/server-rs/crates/spacetime-module/src/legacy_schema/custom_world.rs +++ /dev/null @@ -1,305 +0,0 @@ -use crate::*; - -const WORK_VISIBLE_DEFAULT: bool = false; - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum CustomWorldPublicationStatus { - Draft, - Published, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum CustomWorldThemeMode { - Martial, - Arcane, - Machina, - Tide, - Rift, - Mythic, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum CustomWorldGenerationMode { - Fast, - Full, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum CustomWorldSessionStatus { - Clarifying, - ReadyToGenerate, - Generating, - Completed, - GenerationError, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum RpgAgentStage { - CollectingIntent, - Clarifying, - FoundationReview, - ObjectRefining, - VisualRefining, - LongTailReview, - ReadyToPublish, - Published, - Error, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum RpgAgentMessageRole { - User, - Assistant, - System, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum RpgAgentMessageKind { - Chat, - Clarification, - Summary, - Checkpoint, - Warning, - ActionResult, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum RpgAgentOperationType { - ProcessMessage, - DraftFoundation, - UpdateDraftCard, - SyncResultProfile, - GenerateCharacters, - GenerateLandmarks, - DeleteCharacters, - DeleteLandmarks, - GenerateRoleAssets, - SyncRoleAssets, - GenerateSceneAssets, - SyncSceneAssets, - ExpandLongTail, - PublishWorld, - RevertCheckpoint, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum RpgAgentOperationStatus { - Queued, - Running, - Completed, - Failed, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum RpgAgentDraftCardKind { - World, - Camp, - Faction, - Character, - Landmark, - Thread, - Chapter, - SceneChapter, - Carrier, - SidequestSeed, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum RpgAgentDraftCardStatus { - Suggested, - Confirmed, - Locked, - Warning, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum CustomWorldRoleAssetStatus { - Missing, - VisualReady, - AnimationsReady, - Complete, -} - -#[spacetimedb::table( - accessor = custom_world_profile, - index(accessor = by_custom_world_profile_owner_user_id, btree(columns = [owner_user_id])), - index( - accessor = by_custom_world_profile_publication_status, - btree(columns = [publication_status]) - ) -)] -pub struct CustomWorldProfile { - #[primary_key] - pub(crate) profile_id: String, - pub(crate) owner_user_id: String, - pub(crate) public_work_code: Option, - pub(crate) author_public_user_code: Option, - pub(crate) source_agent_session_id: Option, - pub(crate) publication_status: CustomWorldPublicationStatus, - pub(crate) world_name: String, - pub(crate) subtitle: String, - pub(crate) summary_text: String, - pub(crate) theme_mode: CustomWorldThemeMode, - pub(crate) cover_image_src: Option, - pub(crate) profile_payload_json: String, - pub(crate) playable_npc_count: u32, - pub(crate) landmark_count: u32, - #[default(0)] - pub(crate) play_count: u32, - #[default(0)] - pub(crate) remix_count: u32, - #[default(0)] - pub(crate) like_count: u32, - pub(crate) author_display_name: String, - pub(crate) published_at: Option, - pub(crate) deleted_at: Option, - pub(crate) created_at: Timestamp, - pub(crate) updated_at: Timestamp, - #[default(WORK_VISIBLE_DEFAULT)] - pub(crate) visible: bool, -} - -#[spacetimedb::table( - accessor = custom_world_session, - index(accessor = by_custom_world_session_owner_user_id, btree(columns = [owner_user_id])) -)] -pub struct CustomWorldSession { - #[primary_key] - session_id: String, - owner_user_id: String, - generation_mode: CustomWorldGenerationMode, - status: CustomWorldSessionStatus, - setting_text: String, - creator_intent_json: Option, - question_snapshot_json: String, - result_payload_json: Option, - last_error_message: Option, - created_at: Timestamp, - updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = custom_world_agent_session, - index( - accessor = by_custom_world_agent_session_owner_user_id, - btree(columns = [owner_user_id]) - ), - index(accessor = by_custom_world_agent_session_stage, btree(columns = [stage])) -)] -pub struct CustomWorldAgentSession { - #[primary_key] - session_id: String, - owner_user_id: String, - seed_text: String, - current_turn: u32, - progress_percent: u32, - stage: RpgAgentStage, - focus_card_id: Option, - anchor_content_json: String, - creator_intent_json: Option, - creator_intent_readiness_json: String, - anchor_pack_json: Option, - lock_state_json: Option, - draft_profile_json: Option, - last_assistant_reply: Option, - publish_gate_json: Option, - result_preview_json: Option, - pending_clarifications_json: String, - quality_findings_json: String, - suggested_actions_json: String, - recommended_replies_json: String, - asset_coverage_json: String, - checkpoints_json: String, - created_at: Timestamp, - updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = custom_world_agent_message, - index(accessor = by_custom_world_agent_message_session_id, btree(columns = [session_id])) -)] -pub struct CustomWorldAgentMessage { - #[primary_key] - message_id: String, - session_id: String, - role: RpgAgentMessageRole, - kind: RpgAgentMessageKind, - text: String, - related_operation_id: Option, - created_at: Timestamp, -} - -#[derive(Clone)] -#[spacetimedb::table( - accessor = custom_world_agent_operation, - index(accessor = by_custom_world_agent_operation_session_id, btree(columns = [session_id])) -)] -pub struct CustomWorldAgentOperation { - #[primary_key] - operation_id: String, - session_id: String, - operation_type: RpgAgentOperationType, - status: RpgAgentOperationStatus, - phase_label: String, - phase_detail: String, - progress: u32, - error_message: Option, - created_at: Timestamp, - updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = custom_world_draft_card, - index(accessor = by_custom_world_draft_card_session_id, btree(columns = [session_id])), - index(accessor = by_custom_world_draft_card_kind, btree(columns = [kind])) -)] -pub struct CustomWorldDraftCard { - #[primary_key] - card_id: String, - session_id: String, - kind: RpgAgentDraftCardKind, - status: RpgAgentDraftCardStatus, - title: String, - subtitle: String, - summary: String, - linked_ids_json: String, - warning_count: u32, - asset_status: Option, - asset_status_label: Option, - detail_payload_json: Option, - created_at: Timestamp, - updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = custom_world_gallery_entry, - public, - index(accessor = by_custom_world_gallery_owner_user_id, btree(columns = [owner_user_id])), - index(accessor = by_custom_world_gallery_theme_mode, btree(columns = [theme_mode])), - index(accessor = by_custom_world_gallery_public_work_code, btree(columns = [public_work_code])) -)] -pub struct CustomWorldGalleryEntry { - #[primary_key] - pub(crate) profile_id: String, - pub(crate) owner_user_id: String, - pub(crate) public_work_code: String, - pub(crate) author_public_user_code: String, - pub(crate) author_display_name: String, - pub(crate) world_name: String, - pub(crate) subtitle: String, - pub(crate) summary_text: String, - pub(crate) cover_image_src: Option, - pub(crate) theme_mode: CustomWorldThemeMode, - pub(crate) playable_npc_count: u32, - pub(crate) landmark_count: u32, - #[default(0)] - pub(crate) play_count: u32, - #[default(0)] - pub(crate) remix_count: u32, - #[default(0)] - pub(crate) like_count: u32, - pub(crate) published_at: Timestamp, - pub(crate) updated_at: Timestamp, - #[default(WORK_VISIBLE_DEFAULT)] - pub(crate) visible: bool, -} diff --git a/server-rs/crates/spacetime-module/src/legacy_schema/gameplay.rs b/server-rs/crates/spacetime-module/src/legacy_schema/gameplay.rs deleted file mode 100644 index 06abf1d6b..000000000 --- a/server-rs/crates/spacetime-module/src/legacy_schema/gameplay.rs +++ /dev/null @@ -1,271 +0,0 @@ -#[path = "gameplay/schema_types.rs"] -mod schema_types; - -use crate::*; -pub use schema_types::*; - -#[spacetimedb::table(accessor = player_progression)] -pub struct PlayerProgression { - #[primary_key] - user_id: String, - level: u32, - current_level_xp: u32, - total_xp: u32, - xp_to_next_level: u32, - pending_level_ups: u32, - last_granted_source: Option, - created_at: Timestamp, - updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = chapter_progression, - index(accessor = by_chapter_progression_user_id, btree(columns = [user_id])), - index(accessor = by_chapter_progression_chapter_id, btree(columns = [chapter_id])), - index(accessor = by_chapter_progression_user_chapter, btree(columns = [user_id, chapter_id])) -)] -pub struct ChapterProgression { - #[primary_key] - chapter_progression_id: String, - user_id: String, - chapter_id: String, - chapter_index: u32, - total_chapters: u32, - entry_pseudo_level_millis: u32, - exit_pseudo_level_millis: u32, - entry_level: u32, - exit_level: u32, - planned_total_xp: u32, - planned_quest_xp: u32, - planned_hostile_xp: u32, - actual_quest_xp: u32, - actual_hostile_xp: u32, - expected_hostile_defeat_count: u32, - actual_hostile_defeat_count: u32, - level_at_entry: u32, - level_at_exit: Option, - pace_band: ChapterPaceBand, - created_at: Timestamp, - updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = npc_state, - index(accessor = by_runtime_session_id, btree(columns = [runtime_session_id])), - index(accessor = by_npc_id, btree(columns = [npc_id])), - index(accessor = by_runtime_session_npc, btree(columns = [runtime_session_id, npc_id])) -)] -pub struct NpcState { - #[primary_key] - npc_state_id: String, - runtime_session_id: String, - npc_id: String, - npc_name: String, - affinity: i32, - relation_state: NpcRelationState, - help_used: bool, - chatted_count: u32, - gifts_given: u32, - recruited: bool, - trade_stock_signature: Option, - revealed_facts: Vec, - known_attribute_rumors: Vec, - first_meaningful_contact_resolved: bool, - seen_backstory_chapter_ids: Vec, - stance_profile: NpcStanceProfile, - created_at: Timestamp, - updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = story_session, - index(accessor = by_runtime_session_id, btree(columns = [runtime_session_id])), - index(accessor = by_actor_user_id, btree(columns = [actor_user_id])) -)] -pub struct StorySession { - #[primary_key] - story_session_id: String, - runtime_session_id: String, - actor_user_id: String, - world_profile_id: String, - initial_prompt: String, - opening_summary: Option, - latest_narrative_text: String, - latest_choice_function_id: Option, - status: StorySessionStatus, - version: u32, - created_at: Timestamp, - updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = story_event, - index(accessor = by_story_session_id, btree(columns = [story_session_id])) -)] -pub struct StoryEvent { - #[primary_key] - event_id: String, - story_session_id: String, - event_kind: StoryEventKind, - narrative_text: String, - choice_function_id: Option, - created_at: Timestamp, -} - -#[spacetimedb::table( - accessor = inventory_slot, - index(accessor = by_inventory_runtime_session_id, btree(columns = [runtime_session_id])), - index(accessor = by_inventory_actor_user_id, btree(columns = [actor_user_id])), - index(accessor = by_inventory_container_slot, btree(columns = [container_kind, slot_key])), - index(accessor = by_inventory_item_id, btree(columns = [item_id])) -)] -pub struct InventorySlot { - #[primary_key] - slot_id: String, - runtime_session_id: String, - story_session_id: Option, - actor_user_id: String, - container_kind: InventoryContainerKind, - slot_key: String, - item_id: String, - category: String, - name: String, - description: Option, - quantity: u32, - rarity: InventoryItemRarity, - tags: Vec, - stackable: bool, - stack_key: String, - equipment_slot_id: Option, - source_kind: InventoryItemSourceKind, - source_reference_id: Option, - created_at: Timestamp, - updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = battle_state, - index(accessor = by_battle_story_session_id, btree(columns = [story_session_id])), - index(accessor = by_battle_runtime_session_id, btree(columns = [runtime_session_id])), - index(accessor = by_battle_actor_user_id, btree(columns = [actor_user_id])) -)] -pub struct BattleState { - #[primary_key] - battle_state_id: String, - story_session_id: String, - runtime_session_id: String, - actor_user_id: String, - chapter_id: Option, - target_npc_id: String, - target_name: String, - battle_mode: BattleMode, - status: BattleStatus, - player_hp: i32, - player_max_hp: i32, - player_mana: i32, - player_max_mana: i32, - target_hp: i32, - target_max_hp: i32, - experience_reward: u32, - reward_items: Vec, - turn_index: u32, - last_action_function_id: Option, - last_action_text: Option, - last_result_text: Option, - last_damage_dealt: i32, - last_damage_taken: i32, - last_outcome: CombatOutcome, - version: u32, - created_at: Timestamp, - updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = treasure_record, - index(accessor = by_treasure_story_session_id, btree(columns = [story_session_id])), - index(accessor = by_treasure_runtime_session_id, btree(columns = [runtime_session_id])), - index(accessor = by_treasure_actor_user_id, btree(columns = [actor_user_id])), - index(accessor = by_treasure_encounter_id, btree(columns = [encounter_id])) -)] -pub struct TreasureRecord { - #[primary_key] - treasure_record_id: String, - runtime_session_id: String, - story_session_id: String, - actor_user_id: String, - encounter_id: String, - encounter_name: String, - scene_id: Option, - scene_name: Option, - action: TreasureInteractionAction, - reward_items: Vec, - reward_hp: u32, - reward_mana: u32, - reward_currency: u32, - story_hint: Option, - created_at: Timestamp, - updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = quest_record, - index(accessor = by_runtime_session_id, btree(columns = [runtime_session_id])), - index(accessor = by_actor_user_id, btree(columns = [actor_user_id])), - index(accessor = by_issuer_npc_id, btree(columns = [issuer_npc_id])) -)] -pub struct QuestRecord { - #[primary_key] - quest_id: String, - runtime_session_id: String, - story_session_id: Option, - actor_user_id: String, - issuer_npc_id: String, - issuer_npc_name: String, - scene_id: Option, - chapter_id: Option, - act_id: Option, - thread_id: Option, - contract_id: Option, - title: String, - description: String, - summary: String, - objective: QuestObjectiveSnapshot, - progress: u32, - status: QuestStatus, - completion_notified: bool, - reward: QuestRewardSnapshot, - reward_text: String, - narrative_binding: QuestNarrativeBindingSnapshot, - steps: Vec, - active_step_id: Option, - visible_stage: u32, - hidden_flags: Vec, - discovered_fact_ids: Vec, - related_carrier_ids: Vec, - consequence_ids: Vec, - created_at: Timestamp, - updated_at: Timestamp, - completed_at: Option, - turned_in_at: Option, -} - -#[spacetimedb::table( - accessor = quest_log, - index(accessor = by_quest_id, btree(columns = [quest_id])), - index(accessor = by_runtime_session_id, btree(columns = [runtime_session_id])), - index(accessor = by_actor_user_id, btree(columns = [actor_user_id])) -)] -pub struct QuestLog { - #[primary_key] - log_id: String, - quest_id: String, - runtime_session_id: String, - actor_user_id: String, - event_kind: QuestLogEventKind, - status_after: QuestStatus, - signal_kind: Option, - signal: Option, - step_id: Option, - step_progress: Option, - created_at: Timestamp, -} diff --git a/server-rs/crates/spacetime-module/src/legacy_schema/gameplay/schema_types.rs b/server-rs/crates/spacetime-module/src/legacy_schema/gameplay/schema_types.rs deleted file mode 100644 index 37e35fd27..000000000 --- a/server-rs/crates/spacetime-module/src/legacy_schema/gameplay/schema_types.rs +++ /dev/null @@ -1,328 +0,0 @@ -use crate::SpacetimeType; - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum PlayerProgressionGrantSource { - Quest, - HostileNpc, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum ChapterPaceBand { - OpeningFast, - Steady, - Pressure, - FinaleDense, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum NpcRelationStance { - Hostile, - Guarded, - Neutral, - Cooperative, - Bonded, -} - -#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] -pub struct NpcRelationState { - pub affinity: i32, - pub stance: NpcRelationStance, -} - -#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] -pub struct NpcStanceProfile { - pub trust: u8, - pub warmth: u8, - pub ideological_fit: u8, - pub fear_or_guard: u8, - pub loyalty: u8, - pub current_conflict_tag: Option, - pub recent_approvals: Vec, - pub recent_disapprovals: Vec, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum StorySessionStatus { - Active, - Completed, - Archived, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum StoryEventKind { - SessionStarted, - StoryContinued, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum InventoryContainerKind { - Backpack, - Equipment, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum InventoryItemRarity { - Common, - Uncommon, - Rare, - Epic, - Legendary, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum InventoryEquipmentSlot { - Weapon, - Armor, - Relic, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum InventoryItemSourceKind { - StoryReward, - QuestReward, - TreasureReward, - NpcGift, - NpcTrade, - CombatDrop, - ForgeCraft, - ForgeReforge, - ManualPatch, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum BattleMode { - Fight, - Spar, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum BattleStatus { - Ongoing, - Resolved, - Aborted, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum CombatOutcome { - Ongoing, - Victory, - SparComplete, - Escaped, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum RuntimeItemRewardItemRarity { - Common, - Uncommon, - Rare, - Epic, - Legendary, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum RuntimeItemEquipmentSlot { - Weapon, - Armor, - Relic, -} - -#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] -pub struct RuntimeItemRewardItemSnapshot { - pub item_id: String, - pub category: String, - pub item_name: String, - pub description: Option, - pub quantity: u32, - pub rarity: RuntimeItemRewardItemRarity, - pub tags: Vec, - pub stackable: bool, - pub stack_key: String, - pub equipment_slot_id: Option, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum TreasureInteractionAction { - Inspect, - Leave, - Secure, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum QuestStatus { - Active, - ReadyToTurnIn, - Completed, - TurnedIn, - Failed, - Expired, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum QuestNarrativeType { - Bounty, - Escort, - Investigation, - Retrieval, - Relationship, - Trial, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum QuestObjectiveKind { - DefeatHostileNpc, - InspectTreasure, - SparWithNpc, - TalkToNpc, - ReachScene, - DeliverItem, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum QuestRewardItemRarity { - Common, - Uncommon, - Rare, - Epic, - Legendary, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum QuestRewardEquipmentSlot { - Weapon, - Armor, - Relic, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum QuestNarrativeOrigin { - AiCompiled, - FallbackBuilder, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum QuestLogEventKind { - Accepted, - Progressed, - Completed, - CompletionAcknowledged, - TurnedIn, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum QuestSignalKind { - HostileNpcDefeated, - TreasureInspected, - NpcSparCompleted, - NpcTalkCompleted, - SceneReached, - ItemDelivered, -} - -#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] -pub struct QuestRewardItem { - pub item_id: String, - pub category: String, - pub name: String, - pub description: Option, - pub quantity: u32, - pub rarity: QuestRewardItemRarity, - pub tags: Vec, - pub stackable: bool, - pub stack_key: String, - pub equipment_slot_id: Option, -} - -#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] -pub struct QuestRewardIntel { - pub rumor_text: String, - pub unlocked_scene_id: Option, -} - -#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] -pub struct QuestRewardSnapshot { - pub affinity_bonus: i32, - pub currency: i64, - pub experience: Option, - pub items: Vec, - pub intel: Option, - pub story_hint: Option, -} - -#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] -pub struct QuestNarrativeBindingSnapshot { - pub origin: QuestNarrativeOrigin, - pub narrative_type: QuestNarrativeType, - pub dramatic_need: String, - pub issuer_goal: String, - pub player_hook: String, - pub world_reason: String, - pub followup_hooks: Vec, -} - -#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] -pub struct QuestObjectiveSnapshot { - pub kind: QuestObjectiveKind, - pub target_hostile_npc_id: Option, - pub target_npc_id: Option, - pub target_scene_id: Option, - pub target_item_id: Option, - pub required_count: u32, -} - -#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] -pub struct QuestStepSnapshot { - pub step_id: String, - pub kind: QuestObjectiveKind, - pub target_hostile_npc_id: Option, - pub target_npc_id: Option, - pub target_scene_id: Option, - pub target_item_id: Option, - pub required_count: u32, - pub progress: u32, - pub title: String, - pub reveal_text: String, - pub complete_text: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] -pub struct QuestHostileNpcDefeatedSignal { - pub scene_id: Option, - pub hostile_npc_id: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] -pub struct QuestTreasureInspectedSignal { - pub scene_id: Option, -} - -#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] -pub struct QuestNpcSparCompletedSignal { - pub npc_id: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] -pub struct QuestNpcTalkCompletedSignal { - pub npc_id: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] -pub struct QuestSceneReachedSignal { - pub scene_id: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] -pub struct QuestItemDeliveredSignal { - pub npc_id: String, - pub item_id: String, - pub quantity: u32, -} - -#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] -pub enum QuestProgressSignal { - HostileNpcDefeated(QuestHostileNpcDefeatedSignal), - TreasureInspected(QuestTreasureInspectedSignal), - NpcSparCompleted(QuestNpcSparCompletedSignal), - NpcTalkCompleted(QuestNpcTalkCompletedSignal), - SceneReached(QuestSceneReachedSignal), - ItemDelivered(QuestItemDeliveredSignal), -} diff --git a/server-rs/crates/spacetime-module/src/legacy_schema/jump_hop.rs b/server-rs/crates/spacetime-module/src/legacy_schema/jump_hop.rs deleted file mode 100644 index 4c0c9d82f..000000000 --- a/server-rs/crates/spacetime-module/src/legacy_schema/jump_hop.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[path = "../jump_hop/tables.rs"] -pub(crate) mod tables; - -pub use tables::*; diff --git a/server-rs/crates/spacetime-module/src/legacy_schema/match3d.rs b/server-rs/crates/spacetime-module/src/legacy_schema/match3d.rs deleted file mode 100644 index cf9b65ad1..000000000 --- a/server-rs/crates/spacetime-module/src/legacy_schema/match3d.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[path = "../match3d/tables.rs"] -pub(crate) mod tables; - -pub use tables::*; diff --git a/server-rs/crates/spacetime-module/src/legacy_schema/puzzle.rs b/server-rs/crates/spacetime-module/src/legacy_schema/puzzle.rs deleted file mode 100644 index de1a22217..000000000 --- a/server-rs/crates/spacetime-module/src/legacy_schema/puzzle.rs +++ /dev/null @@ -1,181 +0,0 @@ -use crate::*; - -const PUZZLE_POINT_INCENTIVE_DEFAULT_U64: u64 = 0; -const WORK_VISIBLE_DEFAULT: bool = false; - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum PuzzleAgentStage { - CollectingAnchors, - DraftReady, - ImageRefining, - ReadyToPublish, - Published, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum PuzzleAgentMessageRole { - User, - Assistant, - System, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum PuzzleAgentMessageKind { - Chat, - Summary, - ActionResult, - Warning, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum PuzzlePublicationStatus { - Draft, - Published, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)] -pub enum PuzzleEventKind { - WorkPublished, -} - -#[spacetimedb::table( - accessor = puzzle_agent_session, - index(accessor = by_puzzle_agent_session_owner_user_id, btree(columns = [owner_user_id])) -)] -pub struct PuzzleAgentSessionRow { - #[primary_key] - session_id: String, - owner_user_id: String, - seed_text: String, - current_turn: u32, - progress_percent: u32, - stage: PuzzleAgentStage, - anchor_pack_json: String, - draft_json: Option, - last_assistant_reply: Option, - published_profile_id: Option, - created_at: Timestamp, - updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = puzzle_background_compile_task, - index(accessor = by_puzzle_background_compile_task_session_id, btree(columns = [session_id])) -)] -pub struct PuzzleBackgroundCompileTaskRow { - #[primary_key] - task_id: String, - claim_id: String, - session_id: String, - owner_user_id: String, - created_at: Timestamp, - updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = puzzle_agent_message, - index(accessor = by_puzzle_agent_message_session_id, btree(columns = [session_id])) -)] -pub struct PuzzleAgentMessageRow { - #[primary_key] - message_id: String, - session_id: String, - role: PuzzleAgentMessageRole, - kind: PuzzleAgentMessageKind, - text: String, - created_at: Timestamp, -} - -#[spacetimedb::table( - accessor = puzzle_work_profile, - index(accessor = by_puzzle_work_owner_user_id, btree(columns = [owner_user_id])), - index(accessor = by_puzzle_work_publication_status, btree(columns = [publication_status])) -)] -pub struct PuzzleWorkProfileRow { - #[primary_key] - pub(crate) profile_id: String, - pub(crate) work_id: String, - pub(crate) owner_user_id: String, - pub(crate) source_session_id: Option, - pub(crate) author_display_name: String, - pub(crate) work_title: String, - pub(crate) work_description: String, - pub(crate) level_name: String, - pub(crate) summary: String, - pub(crate) theme_tags_json: String, - pub(crate) cover_image_src: Option, - pub(crate) cover_asset_id: Option, - pub(crate) levels_json: String, - pub(crate) publication_status: PuzzlePublicationStatus, - pub(crate) play_count: u32, - pub(crate) anchor_pack_json: String, - pub(crate) publish_ready: bool, - pub(crate) created_at: Timestamp, - pub(crate) updated_at: Timestamp, - pub(crate) published_at: Option, - #[default(0)] - pub(crate) remix_count: u32, - #[default(0)] - pub(crate) like_count: u32, - #[default(PUZZLE_POINT_INCENTIVE_DEFAULT_U64)] - pub(crate) point_incentive_total_half_points: u64, - #[default(PUZZLE_POINT_INCENTIVE_DEFAULT_U64)] - pub(crate) point_incentive_claimed_points: u64, - #[default(WORK_VISIBLE_DEFAULT)] - pub(crate) visible: bool, -} - -#[spacetimedb::table( - accessor = puzzle_event, - public, - event, - index(accessor = by_puzzle_event_profile_id, btree(columns = [profile_id])), - index(accessor = by_puzzle_event_owner_user_id, btree(columns = [owner_user_id])) -)] -pub struct PuzzleEvent { - #[primary_key] - event_id: String, - profile_id: String, - work_id: String, - session_id: Option, - owner_user_id: String, - event_kind: PuzzleEventKind, - occurred_at: Timestamp, -} - -#[spacetimedb::table( - accessor = puzzle_runtime_run, - index(accessor = by_puzzle_runtime_run_owner_user_id, btree(columns = [owner_user_id])) -)] -pub struct PuzzleRuntimeRunRow { - #[primary_key] - run_id: String, - owner_user_id: String, - entry_profile_id: String, - current_profile_id: String, - cleared_level_count: u32, - current_level_index: u32, - current_grid_size: u32, - played_profile_ids_json: String, - previous_level_tags_json: String, - snapshot_json: String, - created_at: Timestamp, - updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = puzzle_leaderboard_entry, - index(accessor = by_puzzle_leaderboard_profile_grid, btree(columns = [profile_id, grid_size])), - index(accessor = by_puzzle_leaderboard_user_profile_grid, btree(columns = [user_id, profile_id, grid_size])) -)] -pub struct PuzzleLeaderboardEntryRow { - #[primary_key] - entry_id: String, - profile_id: String, - grid_size: u32, - user_id: String, - nickname: String, - best_elapsed_ms: u64, - last_run_id: String, - updated_at: Timestamp, -} diff --git a/server-rs/crates/spacetime-module/src/legacy_schema/puzzle_clear.rs b/server-rs/crates/spacetime-module/src/legacy_schema/puzzle_clear.rs deleted file mode 100644 index ea0da1995..000000000 --- a/server-rs/crates/spacetime-module/src/legacy_schema/puzzle_clear.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[path = "../puzzle_clear/tables.rs"] -pub(crate) mod tables; - -pub use tables::*; diff --git a/server-rs/crates/spacetime-module/src/legacy_schema/square_hole.rs b/server-rs/crates/spacetime-module/src/legacy_schema/square_hole.rs deleted file mode 100644 index afc8c131b..000000000 --- a/server-rs/crates/spacetime-module/src/legacy_schema/square_hole.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[path = "../square_hole/tables.rs"] -pub(crate) mod tables; - -pub use tables::*; diff --git a/server-rs/crates/spacetime-module/src/legacy_schema/visual_novel.rs b/server-rs/crates/spacetime-module/src/legacy_schema/visual_novel.rs deleted file mode 100644 index 9f4faa0f4..000000000 --- a/server-rs/crates/spacetime-module/src/legacy_schema/visual_novel.rs +++ /dev/null @@ -1,132 +0,0 @@ -use crate::*; - -const WORK_VISIBLE_DEFAULT: bool = false; -pub const VISUAL_NOVEL_PUBLICATION_PUBLISHED: &str = "published"; - -#[spacetimedb::table( - accessor = visual_novel_agent_session, - index(accessor = by_visual_novel_agent_session_owner_user_id, btree(columns = [owner_user_id])) -)] -pub struct VisualNovelAgentSessionRow { - #[primary_key] - pub(crate) session_id: String, - pub(crate) owner_user_id: String, - pub(crate) source_mode: String, - pub(crate) status: String, - pub(crate) seed_text: String, - pub(crate) source_asset_ids_json: String, - pub(crate) current_turn: u32, - pub(crate) progress_percent: u32, - pub(crate) draft_json: String, - pub(crate) pending_action_json: String, - pub(crate) last_assistant_reply: String, - pub(crate) published_profile_id: String, - pub(crate) created_at: Timestamp, - pub(crate) updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = visual_novel_agent_message, - index(accessor = by_visual_novel_agent_message_session_id, btree(columns = [session_id])) -)] -pub struct VisualNovelAgentMessageRow { - #[primary_key] - pub(crate) message_id: String, - pub(crate) session_id: String, - pub(crate) role: String, - pub(crate) kind: String, - pub(crate) text: String, - pub(crate) created_at: Timestamp, -} - -#[spacetimedb::table( - accessor = visual_novel_work_profile, - index(accessor = by_visual_novel_work_owner_user_id, btree(columns = [owner_user_id])), - index(accessor = by_visual_novel_work_publication_status, btree(columns = [publication_status])) -)] -pub struct VisualNovelWorkProfileRow { - #[primary_key] - pub(crate) profile_id: String, - pub(crate) work_id: String, - pub(crate) owner_user_id: String, - pub(crate) source_session_id: String, - pub(crate) author_display_name: String, - pub(crate) work_title: String, - pub(crate) work_description: String, - pub(crate) tags_json: String, - pub(crate) cover_image_src: String, - pub(crate) source_asset_ids_json: String, - pub(crate) draft_json: String, - pub(crate) publication_status: String, - pub(crate) publish_ready: bool, - pub(crate) play_count: u32, - pub(crate) created_at: Timestamp, - pub(crate) updated_at: Timestamp, - pub(crate) published_at: Option, - #[default(WORK_VISIBLE_DEFAULT)] - pub(crate) visible: bool, -} - -#[spacetimedb::table( - accessor = visual_novel_runtime_run, - index(accessor = by_visual_novel_run_owner_user_id, btree(columns = [owner_user_id])), - index(accessor = by_visual_novel_run_profile_id, btree(columns = [profile_id])) -)] -pub struct VisualNovelRuntimeRunRow { - #[primary_key] - pub(crate) run_id: String, - pub(crate) owner_user_id: String, - pub(crate) profile_id: String, - pub(crate) mode: String, - pub(crate) status: String, - pub(crate) current_scene_id: String, - pub(crate) current_phase_id: String, - pub(crate) visible_character_ids_json: String, - pub(crate) flags_json: String, - pub(crate) metrics_json: String, - pub(crate) available_choices_json: String, - pub(crate) text_mode_enabled: bool, - pub(crate) snapshot_json: String, - pub(crate) created_at: Timestamp, - pub(crate) updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = visual_novel_runtime_history_entry, - index(accessor = by_visual_novel_history_run_id, btree(columns = [run_id])), - index(accessor = by_visual_novel_history_owner_user_id, btree(columns = [owner_user_id])) -)] -pub struct VisualNovelRuntimeHistoryEntryRow { - #[primary_key] - pub(crate) entry_id: String, - pub(crate) run_id: String, - pub(crate) owner_user_id: String, - pub(crate) profile_id: String, - pub(crate) turn_index: u32, - pub(crate) source: String, - pub(crate) action_text: String, - pub(crate) steps_json: String, - pub(crate) snapshot_before_hash: String, - pub(crate) snapshot_after_hash: String, - pub(crate) created_at: Timestamp, -} - -#[spacetimedb::table( - accessor = visual_novel_runtime_event, - public, - event, - index(accessor = by_visual_novel_runtime_event_run_id, btree(columns = [run_id])), - index(accessor = by_visual_novel_runtime_event_owner_user_id, btree(columns = [owner_user_id])) -)] -pub struct VisualNovelRuntimeEvent { - #[primary_key] - pub(crate) event_id: String, - pub(crate) run_id: String, - pub(crate) owner_user_id: String, - pub(crate) profile_id: String, - pub(crate) event_kind: String, - pub(crate) client_event_id: String, - pub(crate) history_entry_id: String, - pub(crate) payload_json: String, - pub(crate) occurred_at: Timestamp, -} diff --git a/server-rs/crates/spacetime-module/src/legacy_schema/wooden_fish.rs b/server-rs/crates/spacetime-module/src/legacy_schema/wooden_fish.rs deleted file mode 100644 index 94746e1b9..000000000 --- a/server-rs/crates/spacetime-module/src/legacy_schema/wooden_fish.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[path = "../wooden_fish/tables.rs"] -pub(crate) mod tables; - -pub use tables::*; diff --git a/server-rs/crates/spacetime-module/src/match3d/tables.rs b/server-rs/crates/spacetime-module/src/match3d/tables.rs deleted file mode 100644 index 00f89afe3..000000000 --- a/server-rs/crates/spacetime-module/src/match3d/tables.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::*; - -pub(super) const WORK_VISIBLE_DEFAULT: bool = false; - -#[spacetimedb::table( - accessor = match3d_agent_session, - index(accessor = by_match3d_agent_session_owner_user_id, btree(columns = [owner_user_id])) -)] -pub struct Match3DAgentSessionRow { - #[primary_key] - pub(crate) session_id: String, - pub(crate) owner_user_id: String, - pub(crate) seed_text: String, - pub(crate) current_turn: u32, - pub(crate) progress_percent: u32, - pub(crate) stage: String, - pub(crate) config_json: String, - pub(crate) draft_json: String, - pub(crate) last_assistant_reply: String, - pub(crate) published_profile_id: String, - pub(crate) created_at: Timestamp, - pub(crate) updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = match3d_agent_message, - index(accessor = by_match3d_agent_message_session_id, btree(columns = [session_id])) -)] -pub struct Match3DAgentMessageRow { - #[primary_key] - pub(crate) message_id: String, - pub(crate) session_id: String, - pub(crate) role: String, - pub(crate) kind: String, - pub(crate) text: String, - pub(crate) created_at: Timestamp, -} - -#[spacetimedb::table( - accessor = match_3_d_work_profile, - index(accessor = by_match3d_work_owner_user_id, btree(columns = [owner_user_id])), - index(accessor = by_match3d_work_publication_status, btree(columns = [publication_status])) -)] -pub struct Match3DWorkProfileRow { - #[primary_key] - pub(crate) profile_id: String, - pub(crate) owner_user_id: String, - pub(crate) source_session_id: String, - pub(crate) author_display_name: String, - pub(crate) game_name: String, - pub(crate) theme_text: String, - pub(crate) summary_text: String, - pub(crate) tags_json: String, - pub(crate) cover_image_src: String, - pub(crate) cover_asset_id: String, - pub(crate) clear_count: u32, - pub(crate) difficulty: u32, - pub(crate) config_json: String, - pub(crate) publication_status: String, - pub(crate) play_count: u32, - pub(crate) updated_at: Timestamp, - pub(crate) published_at: Option, - #[default(None::)] - pub(crate) generated_item_assets_json: Option, - // 后台可见性开关;新作品默认不公开,开启后才进入公开列表。 - #[default(WORK_VISIBLE_DEFAULT)] - pub(crate) visible: bool, -} - -#[spacetimedb::table( - accessor = match3d_runtime_run, - index(accessor = by_match3d_run_owner_user_id, btree(columns = [owner_user_id])), - index(accessor = by_match3d_run_profile_id, btree(columns = [profile_id])) -)] -pub struct Match3DRuntimeRunRow { - #[primary_key] - pub(crate) run_id: String, - pub(crate) owner_user_id: String, - pub(crate) profile_id: String, - pub(crate) status: String, - pub(crate) snapshot_version: u32, - pub(crate) started_at_ms: i64, - pub(crate) duration_limit_ms: i64, - pub(crate) finished_at_ms: i64, - pub(crate) elapsed_ms: i64, - pub(crate) clear_count: u32, - pub(crate) total_item_count: u32, - pub(crate) cleared_item_count: u32, - pub(crate) failure_reason: String, - pub(crate) snapshot_json: String, - pub(crate) created_at: Timestamp, - pub(crate) updated_at: Timestamp, -} diff --git a/server-rs/crates/spacetime-module/src/migration.rs b/server-rs/crates/spacetime-module/src/migration.rs index f45c5776d..b674363ad 100644 --- a/server-rs/crates/spacetime-module/src/migration.rs +++ b/server-rs/crates/spacetime-module/src/migration.rs @@ -9,39 +9,7 @@ use spacetimedb::sats::ser::serde::SerializeWrapper; use std::collections::HashSet; use crate::agc_models::agc_model_catalog; -use crate::bark_battle::tables::{ - bark_battle_draft_config, bark_battle_leaderboard_entry, bark_battle_personal_best_projection, - bark_battle_published_config, bark_battle_runtime_run, bark_battle_score_record, - bark_battle_work_stats_projection, -}; -use crate::big_fish::big_fish_runtime_run; -use crate::jump_hop::tables::{ - jump_hop_agent_session, jump_hop_event, jump_hop_leaderboard_entry, jump_hop_runtime_run, - jump_hop_work_profile, -}; use crate::llm_router_account_storage::llm_router_account; -use crate::match3d::tables::{ - match_3_d_work_profile, match3d_agent_message, match3d_agent_session, match3d_runtime_run, -}; -use crate::puzzle::{ - puzzle_agent_message, puzzle_agent_session, puzzle_background_compile_task, puzzle_event, - puzzle_leaderboard_entry, puzzle_runtime_run, puzzle_work_profile, -}; -use crate::puzzle_clear::tables::{ - puzzle_clear_agent_session, puzzle_clear_event, puzzle_clear_runtime_run, - puzzle_clear_work_profile, -}; -use crate::square_hole::tables::{ - square_hole_agent_message, square_hole_agent_session, square_hole_runtime_run, - square_hole_work_profile, -}; -use crate::wooden_fish::tables::{ - wooden_fish_agent_session, wooden_fish_event, wooden_fish_runtime_run, wooden_fish_work_profile, -}; -use crate::{ - visual_novel_agent_message, visual_novel_agent_session, visual_novel_runtime_event, - visual_novel_runtime_history_entry, visual_novel_runtime_run, visual_novel_work_profile, -}; const MIGRATION_SCHEMA_VERSION: u32 = 1; const MIGRATION_MAX_TABLE_NAME_LEN: usize = 96; @@ -205,6 +173,7 @@ macro_rules! migration_tables { profile_wallet_config, analytics_date_dimension, tracking_event, + agc_tracking_event, tracking_daily_stat, profile_task_config, profile_task_progress, @@ -231,23 +200,6 @@ macro_rules! migration_tables { profile_recharge_order_expiration_timer, profile_feedback_submission, profile_save_archive, - player_progression, - chapter_progression, - npc_state, - story_session, - story_event, - inventory_slot, - battle_state, - treasure_record, - quest_record, - quest_log, - custom_world_profile, - custom_world_session, - custom_world_agent_session, - custom_world_agent_message, - custom_world_agent_operation, - custom_world_draft_card, - custom_world_gallery_entry, asset_object, asset_entity_binding, asset_event, @@ -281,52 +233,7 @@ macro_rules! migration_tables { editor_generation_runtime_identity_rotation, editor_generation_operation, editor_idempotent_create_receipt, - puzzle_agent_session, - puzzle_background_compile_task, - puzzle_agent_message, - puzzle_work_profile, - puzzle_event, - puzzle_runtime_run, - puzzle_leaderboard_entry, - puzzle_clear_agent_session, - puzzle_clear_work_profile, - puzzle_clear_runtime_run, - puzzle_clear_event, - bark_battle_draft_config, - bark_battle_published_config, - bark_battle_runtime_run, - bark_battle_score_record, - bark_battle_leaderboard_entry, - bark_battle_work_stats_projection, - bark_battle_personal_best_projection, - match3d_agent_session, - match3d_agent_message, - match_3_d_work_profile, - match3d_runtime_run, - jump_hop_agent_session, - jump_hop_work_profile, - jump_hop_runtime_run, - jump_hop_event, - jump_hop_leaderboard_entry, - wooden_fish_agent_session, - wooden_fish_work_profile, - wooden_fish_runtime_run, - wooden_fish_event, - square_hole_agent_session, - square_hole_agent_message, - square_hole_work_profile, - square_hole_runtime_run, - visual_novel_agent_session, - visual_novel_agent_message, - visual_novel_work_profile, - visual_novel_runtime_run, - visual_novel_runtime_history_entry, - visual_novel_runtime_event, - big_fish_creation_session, - big_fish_agent_message, - big_fish_asset_slot, - big_fish_runtime_run, - big_fish_event + // 旧创作模板历史表已从 schema 与迁移白名单中删除;新增可迁移表必须在此显式登记。 } }; } @@ -374,163 +281,6 @@ macro_rules! clear_migration_table { }; } -// 阶段一固定清空清单:只覆盖已经退役的玩法表,不接受调用方动态指定表名。 -// TODO(phase 2): 完成数据备份、客户端兼容性和运行态确认后,再从 active.rs、legacy_schema、 -// migration 白名单和生成绑定中移除这些表定义;本阶段只清空行,不改变 schema。 -macro_rules! retired_migration_tables { - ($macro_name:ident $(, $arg:expr)*) => { - $macro_name! { - $($arg,)* - player_progression, - chapter_progression, - npc_state, - story_session, - story_event, - inventory_slot, - battle_state, - treasure_record, - quest_record, - quest_log, - custom_world_profile, - custom_world_session, - custom_world_agent_session, - custom_world_agent_message, - custom_world_agent_operation, - custom_world_draft_card, - custom_world_gallery_entry, - puzzle_agent_session, - puzzle_background_compile_task, - puzzle_agent_message, - puzzle_work_profile, - puzzle_event, - puzzle_runtime_run, - puzzle_leaderboard_entry, - puzzle_clear_agent_session, - puzzle_clear_work_profile, - puzzle_clear_runtime_run, - puzzle_clear_event, - bark_battle_draft_config, - bark_battle_published_config, - bark_battle_runtime_run, - bark_battle_score_record, - bark_battle_leaderboard_entry, - bark_battle_work_stats_projection, - bark_battle_personal_best_projection, - match3d_agent_session, - match3d_agent_message, - match_3_d_work_profile, - match3d_runtime_run, - jump_hop_agent_session, - jump_hop_work_profile, - jump_hop_runtime_run, - jump_hop_event, - jump_hop_leaderboard_entry, - wooden_fish_agent_session, - wooden_fish_work_profile, - wooden_fish_runtime_run, - wooden_fish_event, - square_hole_agent_session, - square_hole_agent_message, - square_hole_work_profile, - square_hole_runtime_run, - visual_novel_agent_session, - visual_novel_agent_message, - visual_novel_work_profile, - visual_novel_runtime_run, - visual_novel_runtime_history_entry, - visual_novel_runtime_event, - big_fish_creation_session, - big_fish_agent_message, - big_fish_asset_slot, - big_fish_runtime_run, - big_fish_event, - } - }; -} - -macro_rules! retired_migration_table_name_list { - ($($table:ident),+ $(,)?) => { - &[$(stringify!($table)),+] - }; -} - -const RETIRED_MIGRATION_TABLE_NAMES: &[&str] = - retired_migration_tables!(retired_migration_table_name_list); - -macro_rules! clear_retired_migration_table { - ($ctx:expr, $dry_run:expr, $stats:expr, $($table:ident),+ $(,)?) => { - $( - let rows = $ctx.db.$table().iter().collect::>(); - let row_count_before = rows.len() as u64; - if !$dry_run { - for row in rows { - $ctx.db.$table().delete(row); - } - } - $stats.push(DatabaseMigrationClearTableStat { - table_name: stringify!($table).to_string(), - row_count_before, - cleared_row_count: if $dry_run { 0 } else { row_count_before }, - }); - )+ - }; -} - -fn clear_retired_database_tables_tx( - ctx: &ReducerContext, - dry_run: bool, -) -> Vec { - let mut stats = Vec::with_capacity(RETIRED_MIGRATION_TABLE_NAMES.len()); - retired_migration_tables!(clear_retired_migration_table, ctx, dry_run, stats); - stats -} - -#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] -pub struct DatabaseMigrationClearRetiredTablesInput { - pub dry_run: bool, -} - -#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] -pub struct DatabaseMigrationClearTableStat { - pub table_name: String, - pub row_count_before: u64, - pub cleared_row_count: u64, -} - -#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] -pub struct DatabaseMigrationClearRetiredTablesResult { - pub ok: bool, - pub dry_run: bool, - pub table_stats: Vec, - pub error_message: Option, -} - -#[spacetimedb::procedure] -pub fn clear_retired_database_tables( - ctx: &mut ProcedureContext, - input: DatabaseMigrationClearRetiredTablesInput, -) -> DatabaseMigrationClearRetiredTablesResult { - let dry_run = input.dry_run; - let caller = ctx.sender(); - match ctx.try_with_tx(|tx| { - require_migration_operator(tx, caller)?; - Ok::<_, String>(clear_retired_database_tables_tx(tx, dry_run)) - }) { - Ok(table_stats) => DatabaseMigrationClearRetiredTablesResult { - ok: true, - dry_run, - table_stats, - error_message: None, - }, - Err(error) => DatabaseMigrationClearRetiredTablesResult { - ok: false, - dry_run, - table_stats: Vec::new(), - error_message: Some(error), - }, - } -} - // 迁移权限独立存表,避免把 private 表导出能力开放给任意登录身份。 #[spacetimedb::procedure] pub fn authorize_database_migration_operator( @@ -1600,147 +1350,6 @@ fn normalize_migration_row(table_name: &str, value: &serde_json::Value) -> serde .or_insert(serde_json::Value::Null); } } - if table_name == "big_fish_creation_session" { - if let Some(object) = next_value.as_object_mut() { - // 中文注释:旧迁移包没有公开游玩次数字段,导入时按新建作品默认 0 兼容。 - object - .entry("play_count".to_string()) - .or_insert_with(|| serde_json::Value::from(0)); - object - .entry("remix_count".to_string()) - .or_insert_with(|| serde_json::Value::from(0)); - object - .entry("like_count".to_string()) - .or_insert_with(|| serde_json::Value::from(0)); - object - .entry("published_at".to_string()) - .or_insert(serde_json::Value::Null); - } - } - if table_name == "custom_world_profile" || table_name == "custom_world_gallery_entry" { - if let Some(object) = next_value.as_object_mut() { - // 中文注释:作品可见性字段晚于首版作品表加入,旧迁移包保留历史公开默认。 - object - .entry("visible".to_string()) - .or_insert_with(|| serde_json::Value::Bool(true)); - // 中文注释:自定义世界公开互动计数字段晚于基础作品表加入,旧迁移包按 0 兼容。 - object - .entry("play_count".to_string()) - .or_insert_with(|| serde_json::Value::from(0)); - object - .entry("remix_count".to_string()) - .or_insert_with(|| serde_json::Value::from(0)); - object - .entry("like_count".to_string()) - .or_insert_with(|| serde_json::Value::from(0)); - } - } - if table_name == "puzzle_work_profile" { - if let Some(object) = next_value.as_object_mut() { - // 中文注释:作品可见性字段晚于首版作品表加入,旧迁移包保留历史公开默认。 - object - .entry("visible".to_string()) - .or_insert_with(|| serde_json::Value::Bool(true)); - // 中文注释:拼图公开互动计数晚于基础作品表加入,旧迁移包按 0 兼容。 - object - .entry("play_count".to_string()) - .or_insert_with(|| serde_json::Value::from(0)); - object - .entry("remix_count".to_string()) - .or_insert_with(|| serde_json::Value::from(0)); - object - .entry("like_count".to_string()) - .or_insert_with(|| serde_json::Value::from(0)); - object - .entry("point_incentive_total_half_points".to_string()) - .or_insert_with(|| serde_json::Value::from(0)); - object - .entry("point_incentive_claimed_points".to_string()) - .or_insert_with(|| serde_json::Value::from(0)); - // 中文注释:拼图多关卡字段晚于旧作品表加入,旧迁移包留空并由读取层补出首关。 - object - .entry("levels_json".to_string()) - .or_insert_with(|| serde_json::Value::from("")); - // 中文注释:作品名称/描述从旧关卡名/画面摘要拆出,旧行保留旧值做兼容回填。 - let fallback_title = object - .get("level_name") - .cloned() - .unwrap_or_else(|| serde_json::Value::from("")); - object - .entry("work_title".to_string()) - .or_insert(fallback_title); - let fallback_description = object - .get("summary") - .cloned() - .unwrap_or_else(|| serde_json::Value::from("")); - object - .entry("work_description".to_string()) - .or_insert(fallback_description); - } - } - if table_name == "big_fish_creation_session" { - if let Some(object) = next_value.as_object_mut() { - // 中文注释:作品可见性字段晚于大鱼吃小鱼创作会话表加入,旧迁移包保留历史公开默认。 - object - .entry("visible".to_string()) - .or_insert_with(|| serde_json::Value::Bool(true)); - } - } - if matches!( - table_name, - "jump_hop_work_profile" - | "puzzle_clear_work_profile" - | "square_hole_work_profile" - | "visual_novel_work_profile" - | "bark_battle_published_config" - ) { - if let Some(object) = next_value.as_object_mut() { - // 中文注释:作品可见性字段晚于首版作品表加入,旧迁移包保留历史公开默认。 - object - .entry("visible".to_string()) - .or_insert_with(|| serde_json::Value::Bool(true)); - if table_name == "puzzle_clear_work_profile" { - // 中文注释:拼消消底图提示词字段晚于作品表加入,旧迁移包按空提示词兼容。 - object - .entry("board_background_prompt".to_string()) - .or_insert(serde_json::Value::Null); - } - if table_name == "jump_hop_work_profile" { - // 中文注释:跳一跳主题返回按钮资产晚于首版作品表加入,旧迁移包按未生成按钮兼容。 - object - .entry("back_button_asset_json".to_string()) - .or_insert(serde_json::Value::Null); - } - } - } - if table_name == "match_3_d_work_profile" || table_name == "match3d_work_profile" { - if let Some(object) = next_value.as_object_mut() { - // 中文注释:作品可见性字段晚于首版作品表加入,旧迁移包保留历史公开默认。 - object - .entry("visible".to_string()) - .or_insert_with(|| serde_json::Value::Bool(true)); - // 中文注释:抓大鹅生成素材字段晚于基础作品表加入,旧迁移包按未生成素材兼容。 - object - .entry("generated_item_assets_json".to_string()) - .or_insert(serde_json::Value::Null); - } - } - if table_name == "wooden_fish_work_profile" { - if let Some(object) = next_value.as_object_mut() { - // 中文注释:作品可见性字段晚于首版作品表加入,旧迁移包保留历史公开默认。 - object - .entry("visible".to_string()) - .or_insert_with(|| serde_json::Value::Bool(true)); - // 中文注释:敲木鱼背景环境图晚于首版作品表加入,旧迁移包按未生成背景兼容。 - object - .entry("background_asset_json".to_string()) - .or_insert(serde_json::Value::Null); - // 中文注释:敲木鱼返回按钮图晚于首版作品表加入,旧迁移包按未生成返回按钮兼容。 - object - .entry("back_button_asset_json".to_string()) - .or_insert(serde_json::Value::Null); - } - } if table_name == "editor_project_resource" { if let Some(object) = next_value.as_object_mut() { // 中文注释:精选公开开关晚于画布资源表加入,旧生成资源按默认公开兼容。 @@ -1883,23 +1492,6 @@ fn is_supported_migration_table(table_name: &str) -> bool { mod migration_bootstrap_secret_tests { use super::*; - #[test] - fn retired_migration_table_list_is_fixed_and_excludes_active_tables() { - assert_eq!(RETIRED_MIGRATION_TABLE_NAMES.len(), 63); - let mut unique_names = RETIRED_MIGRATION_TABLE_NAMES.to_vec(); - unique_names.sort_unstable(); - unique_names.dedup(); - assert_eq!(unique_names.len(), RETIRED_MIGRATION_TABLE_NAMES.len()); - for active_table in [ - "runtime_setting", - "runtime_snapshot", - "user_browse_history", - "creation_entry_config", - ] { - assert!(!RETIRED_MIGRATION_TABLE_NAMES.contains(&active_table)); - } - } - #[test] fn old_profile_redeem_code_rows_default_to_open_validity_window() { let normalized = normalize_migration_row( diff --git a/server-rs/crates/spacetime-module/src/puzzle_clear/tables.rs b/server-rs/crates/spacetime-module/src/puzzle_clear/tables.rs deleted file mode 100644 index 391ac787e..000000000 --- a/server-rs/crates/spacetime-module/src/puzzle_clear/tables.rs +++ /dev/null @@ -1,88 +0,0 @@ -use crate::*; - -pub(super) const WORK_VISIBLE_DEFAULT: bool = false; - -#[spacetimedb::table( - accessor = puzzle_clear_agent_session, - index(accessor = by_puzzle_clear_agent_session_owner_user_id, btree(columns = [owner_user_id])) -)] -pub struct PuzzleClearAgentSessionRow { - #[primary_key] - pub(crate) session_id: String, - pub(crate) owner_user_id: String, - pub(crate) status: String, - pub(crate) draft_json: String, - pub(crate) published_profile_id: String, - pub(crate) created_at: Timestamp, - pub(crate) updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = puzzle_clear_work_profile, - index(accessor = by_puzzle_clear_work_owner_user_id, btree(columns = [owner_user_id])), - index(accessor = by_puzzle_clear_work_publication_status, btree(columns = [publication_status])) -)] -pub struct PuzzleClearWorkProfileRow { - #[primary_key] - pub(crate) profile_id: String, - pub(crate) work_id: String, - pub(crate) owner_user_id: String, - pub(crate) source_session_id: String, - pub(crate) author_display_name: String, - pub(crate) work_title: String, - pub(crate) work_description: String, - pub(crate) theme_prompt: String, - pub(crate) generate_board_background: bool, - pub(crate) board_background_asset_json: String, - #[default(None::)] - pub(crate) board_background_prompt: Option, - pub(crate) card_back_image_src: String, - pub(crate) atlas_asset_json: String, - pub(crate) pattern_groups_json: String, - pub(crate) card_assets_json: String, - pub(crate) cover_image_src: String, - pub(crate) generation_status: String, - pub(crate) publication_status: String, - pub(crate) play_count: u32, - pub(crate) updated_at: Timestamp, - pub(crate) published_at: Option, - // 中文注释:后台可见性开关,新作品默认不公开,开启后才进入公开列表。 - #[default(WORK_VISIBLE_DEFAULT)] - pub(crate) visible: bool, -} - -#[spacetimedb::table( - accessor = puzzle_clear_runtime_run, - index(accessor = by_puzzle_clear_run_owner_user_id, btree(columns = [owner_user_id])), - index(accessor = by_puzzle_clear_run_profile_id, btree(columns = [profile_id])) -)] -pub struct PuzzleClearRuntimeRunRow { - #[primary_key] - pub(crate) run_id: String, - pub(crate) owner_user_id: String, - pub(crate) profile_id: String, - pub(crate) status: String, - pub(crate) level_index: u32, - pub(crate) clears_done: u32, - pub(crate) snapshot_json: String, - pub(crate) started_at_ms: i64, - pub(crate) finished_at_ms: i64, - pub(crate) created_at: Timestamp, - pub(crate) updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = puzzle_clear_event, - index(accessor = by_puzzle_clear_event_profile_id, btree(columns = [profile_id])), - index(accessor = by_puzzle_clear_event_run_id, btree(columns = [run_id])) -)] -pub struct PuzzleClearEventRow { - #[primary_key] - pub(crate) event_id: String, - pub(crate) owner_user_id: String, - pub(crate) profile_id: String, - pub(crate) run_id: String, - pub(crate) event_type: String, - pub(crate) result: String, - pub(crate) occurred_at: Timestamp, -} diff --git a/server-rs/crates/spacetime-module/src/square_hole/tables.rs b/server-rs/crates/spacetime-module/src/square_hole/tables.rs deleted file mode 100644 index f86e870b9..000000000 --- a/server-rs/crates/spacetime-module/src/square_hole/tables.rs +++ /dev/null @@ -1,91 +0,0 @@ -use crate::*; - -pub(super) const WORK_VISIBLE_DEFAULT: bool = false; - -#[spacetimedb::table( - accessor = square_hole_agent_session, - index(accessor = by_square_hole_agent_session_owner_user_id, btree(columns = [owner_user_id])) -)] -pub struct SquareHoleAgentSessionRow { - #[primary_key] - pub(crate) session_id: String, - pub(crate) owner_user_id: String, - pub(crate) seed_text: String, - pub(crate) current_turn: u32, - pub(crate) progress_percent: u32, - pub(crate) stage: String, - pub(crate) config_json: String, - pub(crate) draft_json: String, - pub(crate) last_assistant_reply: String, - pub(crate) published_profile_id: String, - pub(crate) created_at: Timestamp, - pub(crate) updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = square_hole_agent_message, - index(accessor = by_square_hole_agent_message_session_id, btree(columns = [session_id])) -)] -pub struct SquareHoleAgentMessageRow { - #[primary_key] - pub(crate) message_id: String, - pub(crate) session_id: String, - pub(crate) role: String, - pub(crate) kind: String, - pub(crate) text: String, - pub(crate) created_at: Timestamp, -} - -#[spacetimedb::table( - accessor = square_hole_work_profile, - index(accessor = by_square_hole_work_owner_user_id, btree(columns = [owner_user_id])), - index(accessor = by_square_hole_work_publication_status, btree(columns = [publication_status])) -)] -pub struct SquareHoleWorkProfileRow { - #[primary_key] - pub(crate) profile_id: String, - pub(crate) work_id: String, - pub(crate) owner_user_id: String, - pub(crate) source_session_id: String, - pub(crate) author_display_name: String, - pub(crate) game_name: String, - pub(crate) theme_text: String, - pub(crate) twist_rule: String, - pub(crate) summary_text: String, - pub(crate) tags_json: String, - pub(crate) cover_image_src: String, - pub(crate) shape_count: u32, - pub(crate) difficulty: u32, - pub(crate) config_json: String, - pub(crate) publication_status: String, - pub(crate) play_count: u32, - pub(crate) updated_at: Timestamp, - pub(crate) published_at: Option, - // 后台可见性开关;新作品默认不公开,开启后才进入公开列表。 - #[default(WORK_VISIBLE_DEFAULT)] - pub(crate) visible: bool, -} - -#[spacetimedb::table( - accessor = square_hole_runtime_run, - index(accessor = by_square_hole_run_owner_user_id, btree(columns = [owner_user_id])), - index(accessor = by_square_hole_run_profile_id, btree(columns = [profile_id])) -)] -pub struct SquareHoleRuntimeRunRow { - #[primary_key] - pub(crate) run_id: String, - pub(crate) owner_user_id: String, - pub(crate) profile_id: String, - pub(crate) status: String, - pub(crate) snapshot_version: u64, - pub(crate) started_at_ms: i64, - pub(crate) duration_limit_ms: i64, - pub(crate) finished_at_ms: i64, - pub(crate) elapsed_ms: i64, - pub(crate) total_shape_count: u32, - pub(crate) completed_shape_count: u32, - pub(crate) score: u32, - pub(crate) snapshot_json: String, - pub(crate) created_at: Timestamp, - pub(crate) updated_at: Timestamp, -} diff --git a/server-rs/crates/spacetime-module/src/wooden_fish/tables.rs b/server-rs/crates/spacetime-module/src/wooden_fish/tables.rs deleted file mode 100644 index bb911b4ce..000000000 --- a/server-rs/crates/spacetime-module/src/wooden_fish/tables.rs +++ /dev/null @@ -1,94 +0,0 @@ -use crate::*; - -pub(super) const WORK_VISIBLE_DEFAULT: bool = false; - -#[spacetimedb::table( - accessor = wooden_fish_agent_session, - index(accessor = by_wooden_fish_agent_session_owner_user_id, btree(columns = [owner_user_id])) -)] -pub struct WoodenFishAgentSessionRow { - #[primary_key] - pub(crate) session_id: String, - pub(crate) owner_user_id: String, - pub(crate) current_turn: u32, - pub(crate) progress_percent: u32, - pub(crate) stage: String, - pub(crate) config_json: String, - pub(crate) draft_json: String, - pub(crate) published_profile_id: String, - pub(crate) created_at: Timestamp, - pub(crate) updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = wooden_fish_work_profile, - index(accessor = by_wooden_fish_work_owner_user_id, btree(columns = [owner_user_id])), - index(accessor = by_wooden_fish_work_publication_status, btree(columns = [publication_status])) -)] -pub struct WoodenFishWorkProfileRow { - #[primary_key] - pub(crate) profile_id: String, - pub(crate) work_id: String, - pub(crate) owner_user_id: String, - pub(crate) source_session_id: String, - pub(crate) author_display_name: String, - pub(crate) work_title: String, - pub(crate) work_description: String, - pub(crate) theme_tags_json: String, - pub(crate) hit_object_prompt: String, - pub(crate) hit_object_reference_image_src: String, - pub(crate) hit_sound_prompt: String, - pub(crate) hit_object_asset_json: String, - pub(crate) hit_sound_asset_json: String, - pub(crate) floating_words_json: String, - pub(crate) cover_image_src: String, - pub(crate) generation_status: String, - pub(crate) publication_status: String, - pub(crate) play_count: u32, - pub(crate) updated_at: Timestamp, - pub(crate) published_at: Option, - #[default(None::)] - pub(crate) background_asset_json: Option, - #[default(None::)] - pub(crate) back_button_asset_json: Option, - // 后台可见性开关;新作品默认不公开,开启后才进入公开列表。 - #[default(WORK_VISIBLE_DEFAULT)] - pub(crate) visible: bool, -} - -#[spacetimedb::table( - accessor = wooden_fish_runtime_run, - index(accessor = by_wooden_fish_run_owner_user_id, btree(columns = [owner_user_id])), - index(accessor = by_wooden_fish_run_profile_id, btree(columns = [profile_id])) -)] -pub struct WoodenFishRuntimeRunRow { - #[primary_key] - pub(crate) run_id: String, - pub(crate) owner_user_id: String, - pub(crate) profile_id: String, - pub(crate) status: String, - pub(crate) total_tap_count: u32, - pub(crate) word_counters_json: String, - pub(crate) started_at_ms: i64, - pub(crate) updated_at_ms: i64, - pub(crate) finished_at_ms: i64, - pub(crate) snapshot_json: String, - pub(crate) created_at: Timestamp, - pub(crate) updated_at: Timestamp, -} - -#[spacetimedb::table( - accessor = wooden_fish_event, - index(accessor = by_wooden_fish_event_profile_id, btree(columns = [profile_id])), - index(accessor = by_wooden_fish_event_run_id, btree(columns = [run_id])) -)] -pub struct WoodenFishEventRow { - #[primary_key] - pub(crate) event_id: String, - pub(crate) owner_user_id: String, - pub(crate) profile_id: String, - pub(crate) run_id: String, - pub(crate) event_type: String, - pub(crate) result: String, - pub(crate) occurred_at: Timestamp, -}