diff --git a/lessons/01-query-fundamentals/02-where-conditions/lesson.mdx b/lessons/01-query-fundamentals/02-where-conditions/lesson.mdx
index e712427..639a7a7 100644
--- a/lessons/01-query-fundamentals/02-where-conditions/lesson.mdx
+++ b/lessons/01-query-fundamentals/02-where-conditions/lesson.mdx
@@ -103,4 +103,4 @@ ORDER BY signed_up_at;
Mark this lesson done — we'll just confirm the sandbox is healthy.
-Up next: aggregating rows together with `GROUP BY`.
+Up next: sorting results predictably and paging through them without falling into the `OFFSET` trap.
diff --git a/lessons/01-query-fundamentals/03-sorting-and-pagination/lesson.mdx b/lessons/01-query-fundamentals/03-sorting-and-pagination/lesson.mdx
new file mode 100644
index 0000000..bc361f8
--- /dev/null
+++ b/lessons/01-query-fundamentals/03-sorting-and-pagination/lesson.mdx
@@ -0,0 +1,129 @@
+Lesson 01 introduced `ORDER BY` and `LIMIT`. This lesson goes deeper: stable sorts, dropping duplicates, and the two ways to page through a result set — including why one of them quietly breaks in production.
+
+The seed loaded an `articles` table — 30 rows, several authors, and a few intentional ties on `published_at`.
+
+## `ORDER BY`: pick a direction
+
+`ORDER BY col` sorts ascending (small to large, oldest first). Add `DESC` to flip it.
+
+
+SELECT title, views
+FROM articles
+ORDER BY views DESC
+LIMIT 5;
+
+
+The top-5 most-viewed posts. Without `LIMIT 5`, you'd get all 30, sorted.
+
+## Tie-breakers
+
+What happens when two rows have the same sort key? Postgres returns them in *some* order — but which one is implementation-defined. If the order matters, spell out a tie-breaker.
+
+
+SELECT title, author, published_at
+FROM articles
+ORDER BY published_at, id;
+
+
+`published_at` has duplicates (Ada's two articles, Grace's first two — see the seed). Adding `id` as a second sort key makes the result *deterministic*: same query, same order, every time. For pagination this isn't optional — it's a correctness requirement, as we'll see in a minute.
+
+## `NULLS FIRST` / `NULLS LAST`
+
+Postgres puts `NULL`s **last** in ascending sorts and **first** in descending sorts. Override with `NULLS FIRST` or `NULLS LAST` when you want the opposite — most often when you want "newest first, but missing dates at the bottom".
+
+
+SELECT title, published_at
+FROM articles
+ORDER BY published_at DESC NULLS LAST;
+
+
+The seed now includes a couple of `NULL` `published_at` values so you can see this directly.
+
+## `DISTINCT`: drop duplicate rows
+
+`DISTINCT` removes duplicate rows from the result. It's a post-processing step on whatever the `SELECT` list produced.
+
+
+SELECT DISTINCT author
+FROM articles
+ORDER BY author;
+
+
+Twelve articles came from a handful of repeat authors — `DISTINCT` collapses them. Note `DISTINCT` is *across all selected columns*, not just one: `SELECT DISTINCT author, published_at` would keep two rows from the same author on different days.
+
+### `DISTINCT ON (...)`: one row per group, Postgres-flavored
+
+`DISTINCT ON (col)` is a Postgres extension: "one row per distinct value of `col`, and you pick which one with `ORDER BY`". Handy for "the latest article per author":
+
+
+SELECT DISTINCT ON (author) author, title, published_at
+FROM articles
+ORDER BY author, published_at DESC;
+
+
+The first column(s) in the `ORDER BY` must match the `DISTINCT ON` list — that's the rule that lets Postgres pick "the first row per group". Inside each author, `published_at DESC` chooses the newest.
+
+## `LIMIT` and `OFFSET`: the obvious way to paginate
+
+`LIMIT N OFFSET M` says "skip M rows, then return N". The classic page-2-of-10 query:
+
+
+SELECT id, title, published_at
+FROM articles
+ORDER BY published_at DESC NULLS LAST, id DESC
+LIMIT 10 OFFSET 10;
+
+
+That's page 2 (rows 11–20). Page 3 would be `OFFSET 20`. Simple, and the right tool for small result sets.
+
+## The `OFFSET` trap
+
+`OFFSET M` makes Postgres fetch *and discard* M rows before returning anything. On page 1 that's free. On page 1000 of a million-row feed, you're scanning a million rows to throw away 999,990 of them.
+
+There's a subtler bug too: if a new row gets inserted between requesting page 1 and page 2, page 2 will repeat a row from page 1 (because everything shifted down by one). The result set isn't stable across requests.
+
+For small admin tables, `OFFSET` is fine. For user-facing feeds, infinite scroll, or anything that paginates deeply, reach for keyset pagination.
+
+## Keyset pagination: page by `WHERE`
+
+Idea: instead of "skip 10,000 rows", remember the *last row you saw* and ask for "rows after that one". With a deterministic `ORDER BY`, that's just a `WHERE` clause.
+
+Page 1:
+
+
+SELECT id, title, published_at
+FROM articles
+ORDER BY published_at DESC NULLS LAST, id DESC
+LIMIT 5;
+
+
+Note the last row's `published_at` and `id`. To get the next page, plug them into a `WHERE` filter that asks for everything strictly after that key:
+
+
+SELECT id, title, published_at
+FROM articles
+WHERE (published_at, id) < ('2024-06-24 08:30:00+00', 26)
+ORDER BY published_at DESC NULLS LAST, id DESC
+LIMIT 5;
+
+
+Two important details:
+
+1. **The tuple comparison `(a, b) < (x, y)`** does lexicographic ordering — `a < x`, OR `a = x AND b < y`. That's exactly the tie-breaker logic we wrote into `ORDER BY`. They have to match.
+2. **No `OFFSET`**. Each page is a fresh `WHERE` lookup that an index on `(published_at DESC, id DESC)` can serve in constant time, no matter how deep you go.
+
+The downside: you can't jump to "page 42" — you walk forward one page at a time. For feeds and infinite scroll that's fine; for an admin grid with a page picker, `OFFSET` is the easier fit.
+
+## What you learned
+
+- `ORDER BY` sorts; add `DESC` and `NULLS FIRST`/`LAST` as needed.
+- Always include a tie-breaker (typically the primary key) for deterministic order.
+- `DISTINCT` drops duplicate rows; `DISTINCT ON (col)` picks one row per group, chosen by `ORDER BY`.
+- `LIMIT N OFFSET M` is the obvious way to paginate — and gets slow and unstable on deep pages.
+- Keyset pagination (`WHERE (key) < (last_seen)`) pages in constant time and survives concurrent inserts.
+
+
+Mark this lesson done — we'll just confirm the sandbox is healthy.
+
+
+Up next: collapsing rows into summaries with aggregations and `GROUP BY`.
diff --git a/lessons/01-query-fundamentals/03-sorting-and-pagination/lesson.yaml b/lessons/01-query-fundamentals/03-sorting-and-pagination/lesson.yaml
new file mode 100644
index 0000000..a434773
--- /dev/null
+++ b/lessons/01-query-fundamentals/03-sorting-and-pagination/lesson.yaml
@@ -0,0 +1,19 @@
+title: Sorting and pagination
+summary: Order results predictably, drop duplicates with DISTINCT, and page through with LIMIT/OFFSET — and why keyset pagination is the better default.
+estimatedMinutes: 12
+tags:
+ - order-by
+ - distinct
+ - limit
+ - offset
+ - pagination
+authors:
+ - exekias
+seed: seed.sql
+checks:
+ - id: seed-loaded
+ type: row-count
+ description: The seeded articles table has 30 rows — click to mark this lesson done.
+ table: articles
+ expect:
+ rowCount: 30
diff --git a/lessons/01-query-fundamentals/03-sorting-and-pagination/seed.sql b/lessons/01-query-fundamentals/03-sorting-and-pagination/seed.sql
new file mode 100644
index 0000000..fc2d0e9
--- /dev/null
+++ b/lessons/01-query-fundamentals/03-sorting-and-pagination/seed.sql
@@ -0,0 +1,43 @@
+-- Seed for "03-sorting-and-pagination": a small articles feed with a few
+-- intentional ties on published_at so ORDER BY tie-breakers are visible, and
+-- some duplicate authors so DISTINCT has something to do.
+
+CREATE TABLE articles (
+ id serial PRIMARY KEY,
+ title text NOT NULL,
+ author text NOT NULL,
+ views int NOT NULL,
+ published_at timestamptz
+);
+
+INSERT INTO articles (title, author, views, published_at) VALUES
+ ('Indexing for humans', 'Ada Lovelace', 1200, '2024-01-05 09:00:00+00'),
+ ('The case for MVCC', 'Alan Turing', 890, '2024-01-05 09:00:00+00'),
+ ('Why your query is slow', 'Grace Hopper', 4300, '2024-01-12 14:00:00+00'),
+ ('EXPLAIN, explained', 'Grace Hopper', 3100, '2024-01-20 10:30:00+00'),
+ ('B-trees from first principles','Donald Knuth', 2750, '2024-01-28 08:15:00+00'),
+ ('Postgres tips, vol 1', 'Ada Lovelace', 640, '2024-02-04 16:45:00+00'),
+ ('Postgres tips, vol 2', 'Ada Lovelace', 720, '2024-02-11 16:45:00+00'),
+ ('Joins by example', 'Linus Torvalds', 1810, '2024-02-19 12:00:00+00'),
+ ('LATERAL is fine, actually', 'Barbara Liskov', 980, '2024-02-26 11:00:00+00'),
+ ('When to use JSONB', 'Guido van Rossum', 2210, '2024-03-04 09:30:00+00'),
+ ('When not to use JSONB', 'Guido van Rossum', 1560, '2024-03-11 09:30:00+00'),
+ ('Window functions in anger', 'Margaret Hamilton', 3380, '2024-03-18 13:20:00+00'),
+ ('Reading EXPLAIN ANALYZE', 'Grace Hopper', 4710, '2024-03-25 13:20:00+00'),
+ ('Vacuum and bloat', 'Dennis Ritchie', 430, '2024-04-01 07:00:00+00'),
+ ('A small note on COLLATE', 'Bjarne Stroustrup', 210, NULL),
+ ('GIN vs GiST', 'Donald Knuth', 1990, '2024-04-15 10:00:00+00'),
+ ('Trigram search basics', 'Ken Thompson', 870, '2024-04-22 10:00:00+00'),
+ ('CTEs are not optimization fences anymore','Linus Torvalds', 2540, '2024-04-29 15:15:00+00'),
+ ('Schema migrations without tears','Barbara Liskov', 3050, '2024-05-06 11:45:00+00'),
+ ('Idempotent INSERTs with ON CONFLICT','Margaret Hamilton', 2890, '2024-05-13 11:45:00+00'),
+ ('Three flavors of UUID', 'Edsger Dijkstra', 760, '2024-05-20 09:00:00+00'),
+ ('Counting is harder than it looks','Ada Lovelace', 1680, '2024-05-27 14:30:00+00'),
+ ('Pagination, the LIMIT/OFFSET trap','Grace Hopper', 5120, '2024-06-03 14:30:00+00'),
+ ('Pagination, the keyset way', 'Grace Hopper', 4870, '2024-06-10 14:30:00+00'),
+ ('Date math in Postgres', 'Guido van Rossum', 930, '2024-06-17 08:30:00+00'),
+ ('Time zones, again', 'Bjarne Stroustrup', 410, '2024-06-24 08:30:00+00'),
+ ('Generated columns: hidden gems','Dennis Ritchie', 1240, '2024-07-01 17:00:00+00'),
+ ('Foreign keys revisited', 'Ken Thompson', 1080, '2024-07-08 17:00:00+00'),
+ ('Locking, lightly', 'Edsger Dijkstra', 1340, '2024-07-15 12:30:00+00'),
+ ('How autovacuum keeps you sane','Margaret Hamilton', 980, NULL);
diff --git a/lessons/01-query-fundamentals/03-aggregations/lesson.mdx b/lessons/01-query-fundamentals/04-aggregations/lesson.mdx
similarity index 100%
rename from lessons/01-query-fundamentals/03-aggregations/lesson.mdx
rename to lessons/01-query-fundamentals/04-aggregations/lesson.mdx
diff --git a/lessons/01-query-fundamentals/03-aggregations/lesson.yaml b/lessons/01-query-fundamentals/04-aggregations/lesson.yaml
similarity index 100%
rename from lessons/01-query-fundamentals/03-aggregations/lesson.yaml
rename to lessons/01-query-fundamentals/04-aggregations/lesson.yaml
diff --git a/lessons/01-query-fundamentals/03-aggregations/seed.sql b/lessons/01-query-fundamentals/04-aggregations/seed.sql
similarity index 100%
rename from lessons/01-query-fundamentals/03-aggregations/seed.sql
rename to lessons/01-query-fundamentals/04-aggregations/seed.sql
diff --git a/package-lock.json b/package-lock.json
index e63df2a..b2d27ed 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -84,7 +84,6 @@
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
@@ -298,7 +297,6 @@
"resolved": "https://registry.npmjs.org/@better-auth/core/-/core-1.6.11.tgz",
"integrity": "sha512-LrwidLCV8azdMGjvtwp30nj9tIv1BwI3VhtC0UaGSjQkAVWw4bN42I8qwbxRziPeSQoj+zUVkOpxZzAWBDARtQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@opentelemetry/semantic-conventions": "^1.39.0",
"@standard-schema/spec": "^1.1.0",
@@ -417,7 +415,6 @@
"resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.4.0.tgz",
"integrity": "sha512-RpMtLUIQAEWMgdPLNVbIF5ON2mm+CH0U3rCdUCU1VyeAUui4m38DyK7/aXMLZov2YDjG684pS1D0MBllrmgjQA==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@noble/hashes": "^2.0.1"
}
@@ -425,8 +422,7 @@
"node_modules/@better-fetch/fetch": {
"version": "1.1.21",
"resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.1.21.tgz",
- "integrity": "sha512-/ImESw0sskqlVR94jB+5+Pxjf+xBwDZF/N5+y2/q4EqD7IARUTSpPfIo8uf39SYpCxyOCtbyYpUrZ3F/k0zT4A==",
- "peer": true
+ "integrity": "sha512-/ImESw0sskqlVR94jB+5+Pxjf+xBwDZF/N5+y2/q4EqD7IARUTSpPfIo8uf39SYpCxyOCtbyYpUrZ3F/k0zT4A=="
},
"node_modules/@drizzle-team/brocli": {
"version": "0.10.2",
@@ -487,7 +483,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -504,7 +499,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -521,7 +515,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -538,7 +531,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -555,7 +547,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -572,7 +563,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -589,7 +579,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -606,7 +595,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -623,7 +611,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -640,7 +627,6 @@
"cpu": [
"ia32"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -657,7 +643,6 @@
"cpu": [
"loong64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -674,7 +659,6 @@
"cpu": [
"mips64el"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -691,7 +675,6 @@
"cpu": [
"ppc64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -708,7 +691,6 @@
"cpu": [
"riscv64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -725,7 +707,6 @@
"cpu": [
"s390x"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -742,7 +723,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -759,7 +739,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -776,7 +755,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -793,7 +771,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -810,7 +787,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -827,7 +803,6 @@
"cpu": [
"ia32"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -844,7 +819,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -911,7 +885,6 @@
"cpu": [
"ppc64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -928,7 +901,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -945,7 +917,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -962,7 +933,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -979,7 +949,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -996,7 +965,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1013,7 +981,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1030,7 +997,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1047,7 +1013,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1064,7 +1029,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1081,7 +1045,6 @@
"cpu": [
"ia32"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1098,7 +1061,6 @@
"cpu": [
"loong64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1115,7 +1077,6 @@
"cpu": [
"mips64el"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1132,7 +1093,6 @@
"cpu": [
"ppc64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1149,7 +1109,6 @@
"cpu": [
"riscv64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1166,7 +1125,6 @@
"cpu": [
"s390x"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1183,7 +1141,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1200,7 +1157,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1217,7 +1173,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1234,7 +1189,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1251,7 +1205,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1268,7 +1221,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1285,7 +1237,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1302,7 +1253,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1319,7 +1269,6 @@
"cpu": [
"ia32"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1336,7 +1285,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2153,7 +2101,6 @@
"resolved": "https://registry.npmjs.org/@neondatabase/serverless/-/serverless-1.1.0.tgz",
"integrity": "sha512-r3ZZhRjEcfEdKIZnoB1RusNgvHuaBRqfCzV4Gi+5A9yUX0S4HTws/ASWqt13wL4y4I+0rqsWGdA2w7EQXHi3+Q==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=19.0.0"
}
@@ -2791,7 +2738,6 @@
"integrity": "sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==",
"devOptional": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@types/node": "*",
"pg-protocol": "*",
@@ -2803,7 +2749,6 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
"license": "MIT",
- "peer": true,
"dependencies": {
"csstype": "^3.2.2"
}
@@ -2879,7 +2824,6 @@
"integrity": "sha512-HPwA+hVkfcriajbNvTmZv4VRauibay+cWArYUYq7u7W7PmGShMxbPxLvrwDme55a6d5alG3nrYfhyJ/G28XlLg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.59.3",
"@typescript-eslint/types": "8.59.3",
@@ -3425,7 +3369,6 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"license": "MIT",
- "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -3852,7 +3795,6 @@
"resolved": "https://registry.npmjs.org/better-call/-/better-call-1.3.5.tgz",
"integrity": "sha512-kOFJkBP7utAQLEYrobZm3vkTH8mXq5GNgvjc5/XEST1ilVHaxXUXfeDeFlqoETMtyqS4+3/h4ONX2i++ebZrvA==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@better-auth/utils": "^0.4.0",
"@better-fetch/fetch": "^1.1.21",
@@ -3912,7 +3854,6 @@
}
],
"license": "MIT",
- "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.10.12",
"caniuse-lite": "^1.0.30001782",
@@ -4379,7 +4320,6 @@
"integrity": "sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw==",
"devOptional": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@drizzle-team/brocli": "^0.10.2",
"@esbuild-kit/esm-loader": "^2.5.5",
@@ -4395,7 +4335,6 @@
"resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.45.2.tgz",
"integrity": "sha512-kY0BSaTNYWnoDMVoyY8uxmyHjpJW1geOmBMdSSicKo9CIIWkSxMIj2rkeSR51b8KAPB7m+qysjuHme5nKP+E5Q==",
"license": "Apache-2.0",
- "peer": true,
"peerDependencies": {
"@aws-sdk/client-rds-data": ">=3",
"@cloudflare/workers-types": ">=4",
@@ -4839,7 +4778,6 @@
"integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -5025,7 +4963,6 @@
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.9",
@@ -5492,7 +5429,6 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
@@ -6452,7 +6388,6 @@
"resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz",
"integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==",
"license": "MIT",
- "peer": true,
"funding": {
"url": "https://github.com/sponsors/panva"
}
@@ -6553,7 +6488,6 @@
"resolved": "https://registry.npmjs.org/kysely/-/kysely-0.28.17.tgz",
"integrity": "sha512-nbD8lB9EB3wNdMhOCdx5Li8DxnLbvKByylRLcJ1h+4SkrowVeECAyZlyiKMThF7xFdRz0jSQ2MoJr+wXux2y0Q==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=20.0.0"
}
@@ -7789,7 +7723,6 @@
}
],
"license": "MIT",
- "peer": true,
"engines": {
"node": "^20.0.0 || >=22.0.0"
}
@@ -7822,7 +7755,6 @@
"resolved": "https://registry.npmjs.org/next/-/next-16.2.6.tgz",
"integrity": "sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@next/env": "16.2.6",
"@swc/helpers": "0.5.15",
@@ -8208,7 +8140,6 @@
"resolved": "https://registry.npmjs.org/pg/-/pg-8.20.0.tgz",
"integrity": "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==",
"license": "MIT",
- "peer": true,
"dependencies": {
"pg-connection-string": "^2.12.0",
"pg-pool": "^3.13.0",
@@ -8472,7 +8403,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
"integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -8482,7 +8412,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
"integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@@ -9336,8 +9265,7 @@
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz",
"integrity": "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/tapable": {
"version": "2.3.3",
@@ -9394,7 +9322,6 @@
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=12"
},
@@ -9507,7 +9434,6 @@
"cpu": [
"ppc64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9524,7 +9450,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9541,7 +9466,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9558,7 +9482,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9575,7 +9498,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9592,7 +9514,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9609,7 +9530,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9626,7 +9546,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9643,7 +9562,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9660,7 +9578,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9677,7 +9594,6 @@
"cpu": [
"ia32"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9694,7 +9610,6 @@
"cpu": [
"loong64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9711,7 +9626,6 @@
"cpu": [
"mips64el"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9728,7 +9642,6 @@
"cpu": [
"ppc64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9745,7 +9658,6 @@
"cpu": [
"riscv64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9762,7 +9674,6 @@
"cpu": [
"s390x"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9779,7 +9690,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9796,7 +9706,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9813,7 +9722,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9830,7 +9738,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9847,7 +9754,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9864,7 +9770,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9881,7 +9786,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9898,7 +9802,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9915,7 +9818,6 @@
"cpu": [
"ia32"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9932,7 +9834,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -10081,7 +9982,6 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
- "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -10565,7 +10465,6 @@
"resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
"integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
"license": "MIT",
- "peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}