Commit Graph
2 Commits
Author SHA1 Message Date
cec3c6aaea Refactor widget actions into the scene action pipeline (#796)
* refactor: align widget actions with scene pipeline

* feat(edit): migrate legacy teacherActions off interactive content on load

The widget-actions pipeline no longer persists a teacherActions authoring
layer; playback reads only scene.actions. Add migrateInteractiveContent to
strip the dead field from existing documents as they load through migrateScene
(wired into all store/classroom load paths). Satisfies the #794 forward-migration
acceptance item.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(generation): default widget_setState.state to {} when the LLM omits it

The removed TeacherAction->Action converter always defaulted state to {}.
Restore that guard in the structured-output parser so an action missing
state can't forward state: undefined into the widget iframe, where
SET_WIDGET_STATE handlers dereference it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(edit): also strip nested widgetConfig.teacherActions in migration

Legacy WidgetConfig variants each declared their own teacherActions, so existing
documents can carry the dead field nested inside content.widgetConfig as well as
at the top level. Extend migrateInteractiveContent to drop both, preserving all
other widgetConfig fields.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(prompts): document stable widget-action selectors for diagram/game/viz3d

The interactive-actions prompt documented stable target selectors only for
procedural-skill and simulation widgets. Add the canonical selectors the
diagram / game / visualization3d content prompts actually emit (node IDs via
revealOrder; #zoom-in-btn / #canvas-container / #speed-slider / ...; #start-btn),
plus a rule to use widget_setState or a speech-only beat instead of guessing a
target when no stable selector is known (e.g. free-form code widgets). Hardens
against widget actions silently no-oping on non-existent selectors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: 杨慎 <117187635+cosarah@users.noreply.github.com>
2026-06-28 21:13:21 +08:00
c071e02d83 feat: ACCESS_CODE site-level authentication (#407) (#411)
* feat(access-code): add status API endpoint

Returns whether ACCESS_CODE is enabled and whether the current user is
authenticated via cookie, to support the frontend access gate.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(access-code): add verify API endpoint

Creates POST /api/access-code/verify that validates ACCESS_CODE env var
and sets an HttpOnly 7-day cookie on success.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(access-code): add Next.js middleware to gate API routes

Intercepts all requests when ACCESS_CODE env var is set. API routes
return 401 without the openmaic_access cookie; page requests pass
through so the frontend can render the access-code modal.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(i18n): add accessCode translations for all 4 locales

Add accessCode top-level key to en-US, zh-CN, ja-JP, and ru-RU locale
files with title, placeholder, submit, and error strings.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs: add ACCESS_CODE documentation to .env.example

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: add AccessCodeGuard component and integrate into root layout

Wraps page children with an access-code gate that checks /api/access-code/status on mount and renders AccessCodeModal when authentication is required.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(access-code): add AccessCodeModal component

Adds the modal dialog component that prompts users for an access code,
using existing Dialog/Button/Input UI components and i18n translation keys.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(access-code): fix lint error and format files

- Fix useEffect setState pattern in access-code-guard.tsx
- Format middleware.ts and layout.tsx with Prettier

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* style(access-code): redesign modal as full-screen gate

Replace generic Radix Dialog with a custom full-screen gate:
- Mesh gradient background with noise texture
- Frosted glass card with backdrop-blur
- Staggered motion animations on mount
- Inline submit button inside input field
- Success state animation before dismissal
- Proper dark mode support

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(access-code): address code review findings

Critical:
- Middleware now validates HMAC-signed cookie tokens, not just existence
- Verify endpoint uses timingSafeEqual for constant-time comparison
- Cookie value is now `timestamp.HMAC(ACCESS_CODE, timestamp)` instead of UUID

Important:
- Middleware 401 response includes `errorCode` matching apiError shape
- Status endpoint uses apiSuccess wrapper for consistency
- Remove unused `accessCode.submit` i18n key from all 4 locales

Suggestions:
- Guard renders children during loading (overlay on top, not blocking)
- Network error defaults to enabled=true (safer than silently disabling)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(access-code): use Web Crypto API in middleware for Edge Runtime

Node.js crypto module is not available in Next.js Edge Runtime.
Replace createHmac/timingSafeEqual with crypto.subtle HMAC and
manual constant-length XOR comparison.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: 杨慎 <117187635+cosarah@users.noreply.github.com>
2026-04-12 22:14:14 +08:00