chore: rename project from glossa to lila

- Update all package names from @glossa/* to @lila/*
- Update all imports, container names, volume names
- Update documentation references
- Recreate database with new credentials
This commit is contained in:
lila 2026-04-13 10:00:52 +02:00
parent 1699f78f0b
commit 3f7bc4111e
37 changed files with 116 additions and 182 deletions

View file

@ -1 +1 @@
# glossa
# lila

View file

@ -1,5 +1,5 @@
{
"name": "@glossa/api",
"name": "@lila/api",
"version": "1.0.0",
"private": true,
"type": "module",
@ -10,8 +10,8 @@
"test": "vitest"
},
"dependencies": {
"@glossa/db": "workspace:*",
"@glossa/shared": "workspace:*",
"@lila/db": "workspace:*",
"@lila/shared": "workspace:*",
"better-auth": "^1.6.2",
"cors": "^2.8.6",
"express": "^5.2.1"

View file

@ -1,12 +1,9 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import request from "supertest";
vi.mock("@glossa/db", () => ({
getGameTerms: vi.fn(),
getDistractors: vi.fn(),
}));
vi.mock("@lila/db", () => ({ getGameTerms: vi.fn(), getDistractors: vi.fn() }));
import { getGameTerms, getDistractors } from "@glossa/db";
import { getGameTerms, getDistractors } from "@lila/db";
import { createApp } from "../app.js";
const app = createApp();

View file

@ -1,5 +1,5 @@
import type { Request, Response, NextFunction } from "express";
import { GameRequestSchema, AnswerSubmissionSchema } from "@glossa/shared";
import { GameRequestSchema, AnswerSubmissionSchema } from "@lila/shared";
import { createGameSession, evaluateAnswer } from "../services/gameService.js";
import { ValidationError } from "../errors/AppError.js";

View file

@ -1,7 +1,7 @@
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "@glossa/db";
import * as schema from "@glossa/db/schema";
import { db } from "@lila/db";
import * as schema from "@lila/db/schema";
export const auth = betterAuth({
database: drizzleAdapter(db, { provider: "pg", schema }),

View file

@ -1,12 +1,9 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import type { GameRequest, AnswerSubmission } from "@glossa/shared";
import type { GameRequest, AnswerSubmission } from "@lila/shared";
vi.mock("@glossa/db", () => ({
getGameTerms: vi.fn(),
getDistractors: vi.fn(),
}));
vi.mock("@lila/db", () => ({ getGameTerms: vi.fn(), getDistractors: vi.fn() }));
import { getGameTerms, getDistractors } from "@glossa/db";
import { getGameTerms, getDistractors } from "@lila/db";
import { createGameSession, evaluateAnswer } from "./gameService.js";
const mockGetGameTerms = vi.mocked(getGameTerms);

View file

@ -1,5 +1,5 @@
import { randomUUID } from "crypto";
import { getGameTerms, getDistractors } from "@glossa/db";
import { getGameTerms, getDistractors } from "@lila/db";
import type {
GameRequest,
GameSession,
@ -7,7 +7,7 @@ import type {
AnswerOption,
AnswerSubmission,
AnswerResult,
} from "@glossa/shared";
} from "@lila/shared";
import { InMemoryGameSessionStore } from "../gameSessionStore/index.js";
import { NotFoundError } from "../errors/AppError.js";

View file

@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>glossa</title>
<title>lila</title>
<!--TODO: add favicon-->
<link rel="icon" href="data:," />
</head>

View file

@ -1,5 +1,5 @@
{
"name": "@glossa/web",
"name": "@lila/web",
"private": true,
"version": "0.0.0",
"type": "module",
@ -9,7 +9,7 @@
"preview": "vite preview"
},
"dependencies": {
"@glossa/shared": "workspace:*",
"@lila/shared": "workspace:*",
"@tailwindcss/vite": "^4.2.2",
"@tanstack/react-router": "^1.168.1",
"@tanstack/react-router-devtools": "^1.166.10",

View file

@ -4,8 +4,8 @@ import {
SUPPORTED_POS,
DIFFICULTY_LEVELS,
GAME_ROUNDS,
} from "@glossa/shared";
import type { GameRequest } from "@glossa/shared";
} from "@lila/shared";
import type { GameRequest } from "@lila/shared";
const LABELS: Record<string, string> = {
en: "English",
@ -92,7 +92,7 @@ export const GameSetup = ({ onStart }: GameSetupProps) => {
return (
<div className="flex flex-col items-center gap-6 w-full max-w-md mx-auto">
<div className="bg-white rounded-3xl shadow-lg p-8 w-full text-center">
<h1 className="text-3xl font-bold text-purple-900 mb-1">Glossa</h1>
<h1 className="text-3xl font-bold text-purple-900 mb-1">lila</h1>
<p className="text-sm text-gray-400">Set up your quiz</p>
</div>

View file

@ -1,5 +1,5 @@
import { useState } from "react";
import type { GameQuestion, AnswerResult } from "@glossa/shared";
import type { GameQuestion, AnswerResult } from "@lila/shared";
import { OptionButton } from "./OptionButton";
type QuestionCardProps = {

View file

@ -1,4 +1,4 @@
import type { AnswerResult } from "@glossa/shared";
import type { AnswerResult } from "@lila/shared";
type ScoreScreenProps = { results: AnswerResult[]; onPlayAgain: () => void };

View file

@ -14,7 +14,7 @@ const LoginPage = () => {
return (
<div className="flex flex-col items-center justify-center gap-4 p-8">
<h1 className="text-2xl font-bold">Sign in to Glossa</h1>
<h1 className="text-2xl font-bold">sign in to lila</h1>
<button
className="w-64 rounded bg-gray-800 px-4 py-2 text-white hover:bg-gray-700"
onClick={() =>

View file

@ -1,6 +1,6 @@
import { createFileRoute, redirect } from "@tanstack/react-router";
import { useState, useCallback } from "react";
import type { GameSession, GameRequest, AnswerResult } from "@glossa/shared";
import type { GameSession, GameRequest, AnswerResult } from "@lila/shared";
import { QuestionCard } from "../components/game/QuestionCard";
import { ScoreScreen } from "../components/game/ScoreScreen";
import { GameSetup } from "../components/game/GameSetup";

View file

@ -12,7 +12,7 @@
"noEmit": true,
"target": "ES2023",
"types": ["vite/client", "vitest/globals"],
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo"
},
"include": ["src", "vitest.config.ts"],
"include": ["src", "vitest.config.ts"]
}

View file

@ -1,6 +1,6 @@
services:
database:
container_name: glossa-database
container_name: lila-database
image: postgres:18.3-alpine3.23
env_file:
- .env
@ -9,7 +9,7 @@ services:
ports:
- "5432:5432"
volumes:
- glossa-db:/var/lib/postgresql/data
- lila-db:/var/lib/postgresql/data
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
@ -18,7 +18,7 @@ services:
retries: 5
valkey:
container_name: glossa-valkey
container_name: lila-valkey
image: valkey/valkey:9.1-alpine3.23
ports:
- "6379:6379"
@ -30,7 +30,7 @@ services:
retries: 5
api:
container_name: glossa-api
container_name: lila-api
build:
context: .
dockerfile: ./apps/api/Dockerfile
@ -57,7 +57,7 @@ services:
condition: service_healthy
web:
container_name: glossa-web
container_name: lila-web
build:
context: .
dockerfile: ./apps/web/Dockerfile
@ -75,4 +75,4 @@ services:
condition: service_healthy
volumes:
glossa-db:
lila-db:

View file

@ -140,7 +140,7 @@ Returns all validation failures at once, not just the first. Output is verbose (
### Mocked DB for unit tests (not test database)
Unit tests mock `@glossa/db` via `vi.mock` — the real database is never touched. Tests run in milliseconds with no infrastructure dependency. Integration tests with a real test DB are deferred post-MVP.
Unit tests mock `@lila/db` via `vi.mock` — the real database is never touched. Tests run in milliseconds with no infrastructure dependency. Integration tests with a real test DB are deferred post-MVP.
### Co-located test files
@ -322,7 +322,7 @@ The `exports` field must be an object, not an array:
## Known Issues / Dev Notes
### glossa-web has no healthcheck
### lila-web has no healthcheck
Vite's dev server has no built-in health endpoint. `depends_on` uses API healthcheck as proxy. For production (Nginx), add a health endpoint or TCP port check.

View file

@ -19,8 +19,8 @@ Progress: resolved 577, reused 0, downloaded 0, added 0, done
WARN Issues with peer dependencies found
.
└─┬ eslint-plugin-react-hooks 7.0.1
└── ✕ unmet peer eslint@"^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0": found 10.0.3
. | +3 +
└── ✕ unmet peer eslint@"^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0": found 10.0.3
. | +3 +
Done in 5.6s using pnpm v10.33.0
### env managing
@ -43,7 +43,7 @@ app publication/verification:
Branding and Data Access (Scope) Verification
In addition to brand verification, your app may also need to be verified to use certain scopes. You can view and track this on the Verification Center page:
In addition to brand verification, your app may also need to be verified to use certain scopes. You can view and track this on the Verification Center page:
Branding status: This tracks the verification of your app's public-facing brand (name, logo, etc.).
Data access status: This tracks the verification of the specific data (scopes) your app is requesting to access.
@ -51,9 +51,9 @@ In addition to brand verification, your app may also need to be verified to use
Note: You must have a published branding status before you can request verification for data access (scopes).
Manage App Audience Configuration
Publishing Status
Manage your app publishing status in the Audience page of the Google Auth Platform.
Manage your app publishing status in the Audience page of the Google Auth Platform.
User Type
Manage your app audience in the Audience page of the Google Auth Platform.
Manage your app audience in the Audience page of the Google Auth Platform.
[link](https://support.google.com/cloud/answer/15549049?visit_id=01775982668127-2568683599515917262&rd=1#publishing-status&zippy=%2Cpublishing-status%2Cuser-type)

View file

@ -1,4 +1,4 @@
# Glossa — Roadmap
# lila — Roadmap
Each phase produces a working increment. Nothing is built speculatively.
@ -28,6 +28,7 @@ Each phase produces a working increment. Nothing is built speculatively.
**Done when:** API returns quiz sessions with distractors, error handling and tests in place.
### Data pipeline
- [x] Run `extract-en-it-nouns.py` locally → generates JSON
- [x] Write Drizzle schema: `terms`, `translations`, `term_glosses`, `decks`, `deck_terms`
- [x] Write and run migration (includes CHECK constraints)
@ -37,11 +38,13 @@ Each phase produces a working increment. Nothing is built speculatively.
- [x] Expand data pipeline — import all OMW languages and POS
### Schemas
- [x] Define `GameRequestSchema` in `packages/shared`
- [x] Define `AnswerOption`, `GameQuestion`, `GameSession`, `AnswerSubmission`, `AnswerResult` schemas
- [x] Derived types exported from constants (`SupportedLanguageCode`, `SupportedPos`, `DifficultyLevel`)
### Model layer
- [x] `getGameTerms()` with POS / language / difficulty / limit filters
- [x] Double join on `translations` (source + target language)
- [x] Gloss left join
@ -49,21 +52,25 @@ Each phase produces a working increment. Nothing is built speculatively.
- [x] Models correctly placed in `packages/db`
### Service layer
- [x] `createGameSession()` — fetches terms, fetches distractors, shuffles options, stores session
- [x] `evaluateAnswer()` — looks up session, compares submitted optionId to stored correct answer
- [x] `GameSessionStore` interface + `InMemoryGameSessionStore` (swappable to Valkey)
### API endpoints
- [x] `POST /api/v1/game/start` — route, controller, service
- [x] `POST /api/v1/game/answer` — route, controller, service
- [x] End-to-end pipeline verified with test script
### Error handling
- [x] Typed error classes: `AppError`, `ValidationError` (400), `NotFoundError` (404)
- [x] Central error middleware in `app.ts`
- [x] Controllers cleaned up: validate → call service → `next(error)` on failure
### Tests
- [x] Unit tests for `createGameSession` (question shape, options, distractors, gloss)
- [x] Unit tests for `evaluateAnswer` (correct, incorrect, missing session, missing question)
- [x] Integration tests for both endpoints via supertest (200, 400, 404)

View file

@ -1,4 +1,4 @@
# Glossa — Project Specification
# lila — Project Specification
> **This document is the single source of truth for the project.**
> It is written to be handed to any LLM as context. It contains the project vision, the current MVP scope, the tech stack, the architecture, and the roadmap.
@ -51,7 +51,7 @@ This is the full vision. The MVP deliberately ignores most of it.
| Feature | Why cut |
| ------------------------------- | -------------------------------------- |
| Authentication (Better Auth) | No user accounts needed for a demo |
| Authentication (Better Auth) | No user accounts needed for a demo |
| Multiplayer (WebSockets, rooms) | Core quiz works without it |
| Valkey / Redis cache | Only needed for multiplayer room state |
| Deployment to Hetzner | Ship to people locally first |
@ -259,8 +259,8 @@ After completing a task: share the code, ask what to refactor and why. The LLM s
## 11. Post-MVP Ladder
| Phase | What it adds |
| ----------------- | -------------------------------------------------------------- |
| Auth | Auth | Better Auth (Google + GitHub), embedded in Express API, user rows in DB |
| ----------------- | -------------------------------------------------------------- | ----------------------------------------------------------------------- |
| Auth | Auth | Better Auth (Google + GitHub), embedded in Express API, user rows in DB |
| User Stats | Games played, score history, profile page |
| Multiplayer Lobby | Room creation, join by code, WebSocket connection |
| Multiplayer Game | Simultaneous answers, server timer, live scores, winner screen |

View file

@ -1,11 +1,11 @@
{
"name": "glossa",
"name": "lila",
"version": "1.0.0",
"description": "a vocabulary trainer",
"private": true,
"scripts": {
"build": "pnpm --filter @glossa/shared build && pnpm --filter @glossa/db build && pnpm --filter @glossa/api build",
"dev": "concurrently --names \"api,web\" -c \"magenta.bold,green.bold\" \"pnpm --filter @glossa/api dev\" \"pnpm --filter @glossa/web dev\"",
"build": "pnpm --filter @lila/shared build && pnpm --filter @lila/db build && pnpm --filter @lila/api build",
"dev": "concurrently --names \"api,web\" -c \"magenta.bold,green.bold\" \"pnpm --filter @lila/api dev\" \"pnpm --filter @lila/web dev\"",
"test": "vitest",
"test:run": "vitest run",
"lint": "eslint .",

View file

@ -110,12 +110,8 @@
"name": "account_user_id_user_id_fk",
"tableFrom": "account",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@ -149,12 +145,8 @@
"name": "deck_terms_deck_id_decks_id_fk",
"tableFrom": "deck_terms",
"tableTo": "decks",
"columnsFrom": [
"deck_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["deck_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@ -162,12 +154,8 @@
"name": "deck_terms_term_id_terms_id_fk",
"tableFrom": "deck_terms",
"tableTo": "terms",
"columnsFrom": [
"term_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["term_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@ -175,10 +163,7 @@
"compositePrimaryKeys": {
"deck_terms_deck_id_term_id_pk": {
"name": "deck_terms_deck_id_term_id_pk",
"columns": [
"deck_id",
"term_id"
]
"columns": ["deck_id", "term_id"]
}
},
"uniqueConstraints": {},
@ -265,10 +250,7 @@
"unique_deck_name": {
"name": "unique_deck_name",
"nullsNotDistinct": false,
"columns": [
"name",
"source_language"
]
"columns": ["name", "source_language"]
}
},
"policies": {},
@ -368,12 +350,8 @@
"name": "session_user_id_user_id_fk",
"tableFrom": "session",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@ -383,9 +361,7 @@
"session_token_unique": {
"name": "session_token_unique",
"nullsNotDistinct": false,
"columns": [
"token"
]
"columns": ["token"]
}
},
"policies": {},
@ -435,12 +411,8 @@
"name": "term_glosses_term_id_terms_id_fk",
"tableFrom": "term_glosses",
"tableTo": "terms",
"columnsFrom": [
"term_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["term_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@ -450,10 +422,7 @@
"unique_term_gloss": {
"name": "unique_term_gloss",
"nullsNotDistinct": false,
"columns": [
"term_id",
"language_code"
]
"columns": ["term_id", "language_code"]
}
},
"policies": {},
@ -488,12 +457,8 @@
"name": "term_topics_term_id_terms_id_fk",
"tableFrom": "term_topics",
"tableTo": "terms",
"columnsFrom": [
"term_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["term_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@ -501,12 +466,8 @@
"name": "term_topics_topic_id_topics_id_fk",
"tableFrom": "term_topics",
"tableTo": "topics",
"columnsFrom": [
"topic_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["topic_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@ -514,10 +475,7 @@
"compositePrimaryKeys": {
"term_topics_term_id_topic_id_pk": {
"name": "term_topics_term_id_topic_id_pk",
"columns": [
"term_id",
"topic_id"
]
"columns": ["term_id", "topic_id"]
}
},
"uniqueConstraints": {},
@ -591,10 +549,7 @@
"unique_source_id": {
"name": "unique_source_id",
"nullsNotDistinct": false,
"columns": [
"source",
"source_id"
]
"columns": ["source", "source_id"]
}
},
"policies": {},
@ -650,9 +605,7 @@
"topics_slug_unique": {
"name": "topics_slug_unique",
"nullsNotDistinct": false,
"columns": [
"slug"
]
"columns": ["slug"]
}
},
"policies": {},
@ -748,12 +701,8 @@
"name": "translations_term_id_terms_id_fk",
"tableFrom": "translations",
"tableTo": "terms",
"columnsFrom": [
"term_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["term_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@ -763,11 +712,7 @@
"unique_translations": {
"name": "unique_translations",
"nullsNotDistinct": false,
"columns": [
"term_id",
"language_code",
"text"
]
"columns": ["term_id", "language_code", "text"]
}
},
"policies": {},
@ -844,9 +789,7 @@
"user_email_unique": {
"name": "user_email_unique",
"nullsNotDistinct": false,
"columns": [
"email"
]
"columns": ["email"]
}
},
"policies": {},
@ -903,23 +846,17 @@
"users_openauth_sub_unique": {
"name": "users_openauth_sub_unique",
"nullsNotDistinct": false,
"columns": [
"openauth_sub"
]
"columns": ["openauth_sub"]
},
"users_email_unique": {
"name": "users_email_unique",
"nullsNotDistinct": false,
"columns": [
"email"
]
"columns": ["email"]
},
"users_display_name_unique": {
"name": "users_display_name_unique",
"nullsNotDistinct": false,
"columns": [
"display_name"
]
"columns": ["display_name"]
}
},
"policies": {},
@ -1000,9 +937,5 @@
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}
"_meta": { "columns": {}, "schemas": {}, "tables": {} }
}

View file

@ -38,4 +38,4 @@
"breakpoints": true
}
]
}
}

View file

@ -1,5 +1,5 @@
{
"name": "@glossa/db",
"name": "@lila/db",
"version": "1.0.0",
"private": true,
"type": "module",
@ -11,7 +11,7 @@
"db:build-deck": "npx tsx src/generating-deck.ts"
},
"dependencies": {
"@glossa/shared": "workspace:*",
"@lila/shared": "workspace:*",
"dotenv": "^17.3.1",
"drizzle-orm": "^0.45.1",
"pg": "^8.20.0",

View file

@ -21,9 +21,9 @@ import {
SUPPORTED_POS,
CEFR_LEVELS,
DIFFICULTY_LEVELS,
} from "@glossa/shared";
import { db } from "@glossa/db";
import { terms, translations } from "@glossa/db/schema";
} from "@lila/shared";
import { db } from "@lila/db";
import { terms, translations } from "@lila/db/schema";
type POS = (typeof SUPPORTED_POS)[number];
type LanguageCode = (typeof SUPPORTED_LANGUAGE_CODES)[number];
@ -165,7 +165,7 @@ async function checkCoverage(language: LanguageCode): Promise<void> {
const main = async () => {
console.log("##########################################");
console.log("Glossa — CEFR Coverage Check");
console.log("lila — CEFR Coverage Check");
console.log("##########################################");
for (const language of SUPPORTED_LANGUAGE_CODES) {

View file

@ -19,7 +19,7 @@ import {
CEFR_LEVELS,
SUPPORTED_DECK_TYPES,
DIFFICULTY_LEVELS,
} from "@glossa/shared";
} from "@lila/shared";
export const terms = pgTable(
"terms",

View file

@ -1,6 +1,6 @@
import fs from "node:fs/promises";
import { db } from "@glossa/db";
import { translations, terms, decks, deck_terms } from "@glossa/db/schema";
import { db } from "@lila/db";
import { translations, terms, decks, deck_terms } from "@lila/db/schema";
import { inArray, and, eq, ne, countDistinct } from "drizzle-orm";
type DbOrTx = Parameters<Parameters<typeof db.transaction>[0]>[0];

View file

@ -1,13 +1,13 @@
import { db } from "@glossa/db";
import { db } from "@lila/db";
import { eq, and, isNotNull, sql, ne } from "drizzle-orm";
import { terms, translations, term_glosses } from "@glossa/db/schema";
import { terms, translations, term_glosses } from "@lila/db/schema";
import { alias } from "drizzle-orm/pg-core";
import type {
SupportedLanguageCode,
SupportedPos,
DifficultyLevel,
} from "@glossa/shared";
} from "@lila/shared";
export type TranslationPairRow = {
termId: string;

View file

@ -6,9 +6,9 @@ import {
SUPPORTED_POS,
CEFR_LEVELS,
DIFFICULTY_LEVELS,
} from "@glossa/shared";
import { db } from "@glossa/db";
import { translations, terms } from "@glossa/db/schema";
} from "@lila/shared";
import { db } from "@lila/db";
import { translations, terms } from "@lila/db/schema";
type POS = (typeof SUPPORTED_POS)[number];
type LanguageCode = (typeof SUPPORTED_LANGUAGE_CODES)[number];
@ -130,7 +130,7 @@ async function enrichLanguage(language: LanguageCode): Promise<void> {
const main = async () => {
console.log("##########################################");
console.log("Glossa — CEFR Enrichment");
console.log("lila — CEFR Enrichment");
console.log("##########################################\n");
for (const lang of SUPPORTED_LANGUAGE_CODES) {

View file

@ -1,9 +1,9 @@
import fs from "node:fs/promises";
import { and, count, eq, inArray } from "drizzle-orm";
import { SUPPORTED_LANGUAGE_CODES, SUPPORTED_POS } from "@glossa/shared";
import { db } from "@glossa/db";
import { terms, translations, term_glosses } from "@glossa/db/schema";
import { SUPPORTED_LANGUAGE_CODES, SUPPORTED_POS } from "@lila/shared";
import { db } from "@lila/db";
import { terms, translations, term_glosses } from "@lila/db/schema";
type POS = (typeof SUPPORTED_POS)[number];
type LanguageCode = (typeof SUPPORTED_LANGUAGE_CODES)[number];
@ -129,7 +129,7 @@ async function processBatch(batch: SynsetRecord[]): Promise<void> {
const main = async () => {
console.log("\n##########################################");
console.log("Glossa — OMW seed");
console.log("lila — OMW seed");
console.log("##########################################\n");
// One file per POS — names are derived from SUPPORTED_POS so adding a new

View file

@ -1,5 +1,5 @@
{
"name": "@glossa/shared",
"name": "@lila/shared",
"version": "1.0.0",
"private": true,
"type": "module",

8
pnpm-lock.yaml generated
View file

@ -47,10 +47,10 @@ importers:
apps/api:
dependencies:
'@glossa/db':
'@lila/db':
specifier: workspace:*
version: link:../../packages/db
'@glossa/shared':
'@lila/shared':
specifier: workspace:*
version: link:../../packages/shared
better-auth:
@ -81,7 +81,7 @@ importers:
apps/web:
dependencies:
'@glossa/shared':
'@lila/shared':
specifier: workspace:*
version: link:../../packages/shared
'@tailwindcss/vite':
@ -130,7 +130,7 @@ importers:
packages/db:
dependencies:
'@glossa/shared':
'@lila/shared':
specifier: workspace:*
version: link:../shared
dotenv:

View file

@ -4,7 +4,7 @@ This directory contains the source data files and extraction/merge pipeline for
## Overview
The pipeline transforms raw vocabulary data from multiple sources into a standardized format, resolves conflicts between sources, and produces an authoritative CEFR dataset per language. This dataset is then used by the Glossa database package to update translation records.
The pipeline transforms raw vocabulary data from multiple sources into a standardized format, resolves conflicts between sources, and produces an authoritative CEFR dataset per language. This dataset is then used by the lila database package to update translation records.
## Supported Languages
@ -195,7 +195,7 @@ To add a new source:
## Constants and Constraints
The pipeline respects these constraints from the Glossa shared constants:
The pipeline respects these constraints from the lila shared constants:
- **Supported languages:** en, it
- **Supported parts of speech:** noun, verb

View file

@ -18,7 +18,7 @@ import csv
import json
from pathlib import Path
# Constants matching @glossa/shared
# Constants matching @lila/shared
SUPPORTED_POS = ["noun", "verb"]
CEFR_LEVELS = ["A1", "A2", "B1", "B2", "C1", "C2"]

View file

@ -10,7 +10,7 @@ from pathlib import Path
import xlrd
# Constants matching @glossa/shared
# Constants matching @lila/shared
SUPPORTED_POS = ["noun", "verb"]
CEFR_LEVELS = ["A1", "A2", "B1", "B2", "C1", "C2"]

View file

@ -15,7 +15,7 @@ import csv
import json
from pathlib import Path
# Constants matching @glossa/shared
# Constants matching @lila/shared
SUPPORTED_POS = ["noun", "verb"]
CEFR_LEVELS = ["A1", "A2", "B1", "B2", "C1", "C2"]

View file

@ -17,7 +17,7 @@ Output format (normalized):
import json
from pathlib import Path
# Constants matching @glossa/shared
# Constants matching @lila/shared
SUPPORTED_POS = ["noun", "verb"]
CEFR_LEVELS = ["A1", "A2", "B1", "B2", "C1", "C2"]