Оновлення
Інструкції з міграції між версіями Hopak.js.
Кожен minor-реліз @hopak/core вносить контрольовані зміни у публічний API. Ця сторінка збирає кроки міграції — найновіше зверху. Оберіть розділ, що відповідає Вашій поточній версії.
Якщо Ви починаєте з нуля, пропустіть цю сторінку та йдіть до Швидкий старт.
0.4.x до 0.5
@hopak/core@0.5.0 переглядає ескейп-шляхи на інтерфейсі Database. .model() лишається 90% типізованим шляхом; два інші слоти стали гострішими:
db.sql— новий. Tagged-template SQL для тих ~5% запитів, що не вкладаються у.model(): window-функції, рекурсивні CTE, vendor-specific JSON / FTS,EXPLAIN ANALYZE. Інтерполяції параметризуються, тожsql`SELECT * FROM post WHERE id = ${id}`безпечний — SQL injection через${...}тут принципово неможлива. Типізоване повернення:db.sql<Post>`...`даєPromise<readonly Post[]>.db.builder()— перейменовано зdb.raw(). Те саме повернення (Drizzle-клієнт діалекту), зрозуміліша назва. Для <1%, де треба композиція query-білдера за межами.sql.db.execute(sql, params?)— позначено як@deprecated. Працює у 0.5.x; буде прибрано в 0.6.0. Новий код пишеdb.sql.
Ієрархія ескейпу стала пласкою:
model() ← 90% запитів
↓
db.sql`...` ← raw SQL з типами (≈5% escape)
↓
db.builder() ← Drizzle query builder (<1% escape)
Кроки переходу
-
Перейменуйте
db.raw()→db.builder(). Те саме повернення, без змін поведінки. Пошук+заміна безпечна.// було const drizzle = db.raw() as BunSQLiteDatabase; // стало const drizzle = db.builder() as BunSQLiteDatabase; -
Для нового коду надавайте перевагу
db.sqlзамістьdb.execute(...). Forwarder лишається, тож наявні виклики компілюються без змін, але нова робота іде на tagged template.// було await db.execute('UPDATE post SET published = ? WHERE id = ?', [true, id]); // стало await db.sql`UPDATE post SET published = ${true} WHERE id = ${id}`; // для читання (нова можливість) const rows = await db.sql<{ day: string; n: number }>` SELECT DATE(created_at) AS day, COUNT(*) AS n FROM post WHERE published = true GROUP BY day ORDER BY day DESC `; -
У файлах міграцій —
ctx.sql.hopak migrate newтепер генерує скелет уже зctx.sql. Існуючі міграції наctx.execute(...)виконуються незмінно — переписувати їх до 0.6.0 не потрібно.// нові згенеровані міграції export async function up(ctx: MigrationContext): Promise<void> { await ctx.sql`ALTER TABLE post ADD COLUMN views INTEGER NOT NULL DEFAULT 0`; }
Що змінилося під капотом
db.raw() завжди повертав Drizzle-клієнт діалекту, типізований як unknown. Викликач робив cast у { all?, execute? } і розгалужувався по діалектах, щоб прочитати один SELECT — так робив і власний tracker.ts фреймворку для читання _hopak_migrations. Новий db.sql — driver-native: чистий tag-to-SQL компілятор перетворює ${value}-інтерполяції на placeholder’и потрібного діалекту (? або $N), далі statement іде прямо у bun:sqlite.prepare().all(), postgres.js sql.unsafe() або mysql2.pool.execute() — Drizzle на read-шляху немає взагалі. Усередині транзакції Postgres і MySQL ще йдуть через Drizzle tx handle (native-конекшн звідти не дістати), але форма стабільна у межах мажору Drizzle і покрита тестами.
Перейменування raw → builder — косметичне, але уточнює намір: .builder() повертає білдер, а не «щось для сирого SQL». Примітив для raw SQL тепер — .sql.
0.3.x до 0.4
@hopak/core@0.4.0 міняє runtime валідації з Zod на Valibot — бандл ~10× менший, парсинг ~2–3× швидший, той самий API validate() / buildModelSchema(). Код, що користується лише model-driven валідацією Hopak, продовжує працювати без змін. Breaking — лише для проєктів, які імпортували Zod безпосередньо у файлах маршрутів.
Що саме змінюється
-
@hopak/coreбільше не залежить відzod. Якщо Ваш код проєкту імпортувавzodтранзитивно через@hopak/core, додайте його до Вашого власногоpackage.json. -
Типи
RouteSchemas.body | query | paramsтепер є схемами Valibot (v.GenericSchema), а неz.ZodType. Файли маршрутів, які передавали схеми Zod напряму, потрібно перевести на Valibot:// before import { z } from 'zod'; export const post: RouteHandler = { body: z.object({ title: z.string().min(3) }), handler: async (ctx) => { /* ... */ }, }; // after import * as v from 'valibot'; export const post: RouteHandler = { body: v.object({ title: v.pipe(v.string(), v.minLength(3)) }), handler: async (ctx) => { /* ... */ }, }; -
Повідомлення про помилки від валідаторів використовують стандартні повідомлення Valibot. Якщо Ваші тести звіряються з точним текстом повідомлень, перезняте snapshot-и.
-
Експорт типу
ZodFieldSchemaперейменовано наFieldSchema.
Як перейти
bun add valibot у Вашому проєкті, перепишіть усі написані вручну схеми у файлах маршрутів на примітиви v.*. Схеми моделей, побудовані через buildModelSchema(model), змін не потребують.
Що змінилося під капотом
Valibot — це tree-shakeable валідатор з pipe-композицією; кожне правило — окрема функція, яку Ви комбінуєте через v.pipe. Саме тому бандл стискається: якщо Ви використовуєте лише v.string, то лише це й потрапляє в бандл. Форма API відрізняється від Zod (z.string().min(3) → v.pipe(v.string(), v.minLength(3))), але семантика збігається. Дивіться Валідація та Помилки для актуальної форми помилок.
0.2.x до 0.3
@hopak/core@0.3.0 додає міграції. hopak sync досі працює для greenfield-проєктів, але його роль зміщується — тепер це шлях dev-бутстрапу, а не еволюції схеми. Це non-breaking, якщо Ви не впроваджуєте міграції; щойно Ви їх увімкнете, починають діяти правила нижче.
Що змінюється, якщо Ви на 0.2.x
hopak syncтепер відмовляється виконуватись (exit1), щойно вapp/migrations/з’являються будь-які.tsфайли. Повідомлення вказує Вам наhopak migrate up. Якщо Ви не додаєте міграцій,syncповодиться точно так само, як і раніше.- Виклик
db.sync()на стартіhopak devпропускається, коли вapp/migrations/є файли. З міграціями рантайм ніколи не змінює схему самостійно — Ви контролюєте кожну зміну. hopak syncтепер виводить попередження про дрейф, коли модель оголошує колонки, яких немає в активній БД. Це інформаційне повідомлення; воно вказує наhopak migrate init, щоб почати відстеження..index()на полі тепер дійсно створюєCREATE INDEX IF NOT EXISTSпід час sync. У 0.2.x це мовчки ігнорувалося — якщо Ви додавали.index()з розрахунком на індекс, перезапустітьhopak sync, щоб його підхопити. (Якщо індекс уже існує з іншої причини, це no-op.)- Новий публічний API:
ctx.db.execute(sql, params?)для сирого SQL — переважно для файлів міграцій, але доступний усюди.
Як впровадити міграції у наявному 0.2.x-проєкті
hopak migrate init # captures the current model state
hopak migrate up # writes _hopak_migrations; no schema change
Далі кожна зміна моделі починається з hopak migrate new <name>.
Нічого не зламається, якщо Ви поки не хочете міграцій. Продовжуйте користуватись hopak sync, доки еволюція схеми (додавання колонки до наявної таблиці) не змусить перейти. Повний огляд див. у розділі Міграції.
Що змінилося під капотом
До 0.3 стан схеми обчислювався на старті: моделі були джерелом істини, а db.sync() підганяв базу під них. Це чудово працює перший тиждень і починає боліти на другому — немає історії і немає способу відкотити перейменування колонки. 0.3 вводить явний журнал (_hopak_migrations) плюс up/down функції для кожної міграції. Sync залишається господарем моменту «від нуля до одиниці»; міграції володіють кожним кроком після цього.
0.1.x до 0.2
@hopak/core@0.2.0 — це breaking-реліз. Жодна декларація більше не матеріалізується під час виконання — CRUD-ендпоінти та dev-сертифікати тепер скафолдить CLI, а рантайм просто виконує те, що лежить у Ваших файлах.
Кроки міграції
- Оновіть CLI:
bun add -g @hopak/cli@latest. - Оновіть фреймворк у Вашому проєкті:
bun add @hopak/core@latest @hopak/testing@latest. - Для кожної моделі з
{ crud: true }один раз виконайте:
Ця команда створюєhopak generate crud <model-name>app/routes/api/<plural>.tsтаapp/routes/api/<plural>/[id].tsз тими самими шістьма дієсловами, які раніше впроваджував рантайм. Приберіть{ crud: true }з файлу моделі (тепер це лише type error, на поведінку воно не впливає):// before export default model('post', { ... }, { crud: true }); // after export default model('post', { ... }); - Якщо у Вас було
server.https.enabled: true, один раз виконайтеhopak generate cert. Запуск більше не викликає openssl за Вашою спиною — якщо файлів сертифіката немає,hopak devодразу завершиться з помилкою та вказівкою на цю команду. - Якщо Ви використовували
createTestServer({ withCrud: true })з@hopak/testing, перейдіть на під’єднання маршрутів через нові хелпериcrud.*(або передавайтеrootDir, щоб тестувати проєкт наскрізно). Дивіться README пакета@hopak/testing.
Також видалено
Ці опції існували в типі, але ні до чого не були під’єднані — видалення суто механічне:
ModelOptions.ownerModelOptions.publicReadModelOptions.authModelOptions.softDelete
Більше нічого в публічному API не змінилося — моделі, зв’язки, ергономіка запитів, валідація, серіалізація, помилки, конфігурація HTTPS / CORS, hopak use, hopak sync, hopak check поводяться точно так само, як і раніше.
Що змінилося під капотом
У 0.2.0 CRUD перейшов з runtime-фічі на скафолдинг. Замість того щоб фреймворк синтезував обробники маршрутів з опцій моделі на старті, CLI пише реальні .ts файли, які Ви можете читати, редагувати та розширювати. Те саме стосується dev-сертифікатів HTTPS: явні файли на диску, жодних неявних викликів openssl. Рантайм стає меншим; те, що Ви бачите у Вашому дереві файлів, — це те, що й виконується.