kitcn 0.32.2 → 0.33.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +109 -0
- package/dist/aggregate/index.d.ts +2 -2
- package/dist/auth/generated/index.d.ts +1 -1
- package/dist/auth/index.d.ts +16 -16
- package/dist/auth/index.js +1 -1
- package/dist/auth/nextjs/index.d.ts +2 -2
- package/dist/auth/start/server/index.d.ts +2 -2
- package/dist/{builder-Cyd5nCxZ.js → builder-DDYTlmTB.js} +12 -3
- package/dist/caller-factory-C3pcbzo0.d.ts +140 -0
- package/dist/{capabilities-BJm_VSDT.d.ts → capabilities-Bxzoofl4.d.ts} +149 -9
- package/dist/crpc/index.d.ts +3 -2
- package/dist/{generated-contract-disabled-BRm1dNQE.d.ts → generated-contract-disabled-B_EaHGCP.d.ts} +33 -33
- package/dist/{http-types-BhhPZtwa.d.ts → http-types-8FBr10yl.d.ts} +3 -79
- package/dist/{middleware-BBS7oLtT.d.ts → middleware-D2hKJuSZ.d.ts} +1 -1
- package/dist/{middleware-D61Nm-iB.js → middleware-LvZov-hA.js} +1 -1
- package/dist/orm/aggregate-index/index.d.ts +1 -1
- package/dist/orm/aggregate-index/index.js +226 -96
- package/dist/orm/index.d.ts +2 -2
- package/dist/orm/index.js +364 -108
- package/dist/orm/migrations/index.d.ts +2 -2
- package/dist/plugins/index.d.ts +1 -1
- package/dist/plugins/index.js +1 -1
- package/dist/{procedure-caller-DgMiD0-a.js → procedure-caller-DgGF_hA8.js} +1 -1
- package/dist/{procedure-name-DPYyLiVS.d.ts → procedure-name-kn-awLk1.d.ts} +12 -142
- package/dist/{query-context-D4z1CnDH.js → query-context-DQLv58LH.js} +34 -1
- package/dist/ratelimit/index.d.ts +2 -2
- package/dist/ratelimit/index.js +2 -2
- package/dist/react/index.d.ts +5 -6
- package/dist/react/index.js +24 -69
- package/dist/rsc/index.d.ts +4 -3
- package/dist/{schema-Bh7AmJwY.js → schema-BF4P0ZjS.js} +322 -1
- package/dist/server/index.d.ts +5 -4
- package/dist/server/index.js +2 -2
- package/dist/solid/index.d.ts +5 -6
- package/dist/solid/index.js +20 -66
- package/dist/transformer-BEkxlnss.d.ts +78 -0
- package/dist/{types-BXpu7xIU.d.ts → types-Cl0utsTL.d.ts} +4 -3
- package/dist/{where-clause-compiler-Dgf4lrO-.d.ts → where-clause-compiler-CoPVAVDO.d.ts} +136 -136
- package/package.json +1 -1
- package/skills/kitcn/SKILL.md +2 -1
- package/skills/kitcn/references/features/aggregates.md +13 -0
- package/skills/kitcn/references/features/auth-admin.md +1 -0
- package/skills/kitcn/references/features/orm.md +24 -4
- package/skills/kitcn/references/features/react.md +4 -5
- /package/dist/{context-utils-Cbv4r0AA.d.ts → context-utils-ax351iFc.d.ts} +0 -0
- /package/dist/{token-tlbNKQS0.d.ts → token-CZpDQUHd.d.ts} +0 -0
- /package/dist/{types-Bkeicpo6.d.ts → types-CzGsrLrY.d.ts} +0 -0
|
@@ -1313,6 +1313,327 @@ const ensureAggregateAllowedForRls = (tableConfig, rlsMode, methodName) => {
|
|
|
1313
1313
|
assertAggregateAllowedForRls(tableConfig, rlsMode, AGGREGATE_ERROR.RLS_UNSUPPORTED, methodName);
|
|
1314
1314
|
};
|
|
1315
1315
|
|
|
1316
|
+
//#endregion
|
|
1317
|
+
//#region src/orm/transaction-cache.ts
|
|
1318
|
+
/**
|
|
1319
|
+
* Per-transaction memo storage for the ORM.
|
|
1320
|
+
*
|
|
1321
|
+
* The ORM already has isolate-, execution-, statement- and row-scoped memos.
|
|
1322
|
+
* A hook needs transaction lifetime: the write barrier is built inside
|
|
1323
|
+
* `createOrmDbLifecycle`, which `createOrm` runs at module scope,
|
|
1324
|
+
* so a flag in that closure lives as long as the isolate and would leak an
|
|
1325
|
+
* answer from one transaction into the next.
|
|
1326
|
+
*
|
|
1327
|
+
* Deliberately dependency-free, for the same reason as `write-fanout`:
|
|
1328
|
+
* `aggregate-index/runtime` is contractually unreachable from `orm/index`
|
|
1329
|
+
* (`import-graph.test.ts`), so importing `lifecycle` here to read one symbol
|
|
1330
|
+
* would drag the trigger runtime into the aggregate entry's bundle.
|
|
1331
|
+
* `Symbol.for` is registry-based, so re-declaring the key resolves to the same
|
|
1332
|
+
* symbol `lifecycle` installs.
|
|
1333
|
+
*/
|
|
1334
|
+
const ORMLIFECYCLE_INNER_DB = Symbol.for("kitcn:OrmLifecycleInnerDB");
|
|
1335
|
+
const ORM_TRANSACTION_ANCHOR = Symbol.for("kitcn:OrmTransactionAnchor");
|
|
1336
|
+
/**
|
|
1337
|
+
* Pins `anchor`'s transaction onto `target`, for a db built from a writer that
|
|
1338
|
+
* cannot be resolved back to it.
|
|
1339
|
+
*
|
|
1340
|
+
* `withoutTriggers` re-roots the ORM on the raw `ctx.db`, which is the one
|
|
1341
|
+
* object in the chain that carries no inner-db symbol — so a db derived from it
|
|
1342
|
+
* would otherwise stand for a transaction of its own and miss every memo and
|
|
1343
|
+
* queued write filed under the real one.
|
|
1344
|
+
*/
|
|
1345
|
+
const markOrmTransactionAnchor = (target, db) => {
|
|
1346
|
+
const anchor = resolveOrmTransactionAnchor(db);
|
|
1347
|
+
if (!anchor || Object.hasOwn(target, ORM_TRANSACTION_ANCHOR)) return target;
|
|
1348
|
+
Object.defineProperty(target, ORM_TRANSACTION_ANCHOR, {
|
|
1349
|
+
configurable: false,
|
|
1350
|
+
enumerable: false,
|
|
1351
|
+
value: anchor,
|
|
1352
|
+
writable: false
|
|
1353
|
+
});
|
|
1354
|
+
return target;
|
|
1355
|
+
};
|
|
1356
|
+
/**
|
|
1357
|
+
* The object whose identity stands in for "this transaction".
|
|
1358
|
+
*
|
|
1359
|
+
* Convex builds `ctx.db` fresh on every UDF invocation, so it can never be
|
|
1360
|
+
* shared by two transactions. `getOrmLifecycleInnerDb` cannot be used on its
|
|
1361
|
+
* own: the lifecycle refuses to wrap readers and returns a no-op wrapper for
|
|
1362
|
+
* schemas with no triggers and no aggregate indexes, so the inner-db symbol is
|
|
1363
|
+
* absent for every query and for most mutations.
|
|
1364
|
+
*
|
|
1365
|
+
* Following the symbol to a fixed point, rather than one hop, is what makes the
|
|
1366
|
+
* answer canonical: `orm.with(hookCtx)` wraps a writer that is already a hook
|
|
1367
|
+
* wrapper, so one hop lands on the intermediate wrapper instead of the raw
|
|
1368
|
+
* writer the outer scope filed its work under. A pinned anchor wins outright,
|
|
1369
|
+
* because it is the only way a db rooted on the raw writer can name the
|
|
1370
|
+
* transaction at all.
|
|
1371
|
+
*
|
|
1372
|
+
* A nested `ctx.runMutation` shares the transaction but gets its own writer
|
|
1373
|
+
* and JS context. It cannot see caller-local memos or queued writes, nor can it
|
|
1374
|
+
* invalidate caller snapshots. Callers must flush deferred writes and expire
|
|
1375
|
+
* row snapshots before handing control to arbitrary user code.
|
|
1376
|
+
*/
|
|
1377
|
+
const resolveOrmTransactionAnchor = (db) => {
|
|
1378
|
+
if (typeof db !== "object" || db === null) return;
|
|
1379
|
+
let current = db;
|
|
1380
|
+
const seen = new Set([current]);
|
|
1381
|
+
for (;;) {
|
|
1382
|
+
const pinned = current[ORM_TRANSACTION_ANCHOR];
|
|
1383
|
+
if (typeof pinned === "object" && pinned !== null) return pinned;
|
|
1384
|
+
const inner = current[ORMLIFECYCLE_INNER_DB];
|
|
1385
|
+
if (typeof inner !== "object" || inner === null || seen.has(inner)) return current;
|
|
1386
|
+
seen.add(inner);
|
|
1387
|
+
current = inner;
|
|
1388
|
+
}
|
|
1389
|
+
};
|
|
1390
|
+
/**
|
|
1391
|
+
* One memo namespace with transaction lifetime.
|
|
1392
|
+
*
|
|
1393
|
+
* The store is a `WeakMap` keyed on the anchor rather than a slot on the db,
|
|
1394
|
+
* because `createDatabase` promises not to mutate the `ctx.db` it was handed.
|
|
1395
|
+
* Entries die with the transaction's db object.
|
|
1396
|
+
*
|
|
1397
|
+
* Callers own staleness: only memoize a fact that nothing inside the
|
|
1398
|
+
* transaction can invalidate.
|
|
1399
|
+
*/
|
|
1400
|
+
const createOrmTransactionMemo = () => {
|
|
1401
|
+
const byTransaction = /* @__PURE__ */ new WeakMap();
|
|
1402
|
+
return {
|
|
1403
|
+
get(db, key) {
|
|
1404
|
+
const anchor = resolveOrmTransactionAnchor(db);
|
|
1405
|
+
return anchor ? byTransaction.get(anchor)?.get(key) : void 0;
|
|
1406
|
+
},
|
|
1407
|
+
set(db, key, value) {
|
|
1408
|
+
const anchor = resolveOrmTransactionAnchor(db);
|
|
1409
|
+
if (!anchor) return;
|
|
1410
|
+
const existing = byTransaction.get(anchor);
|
|
1411
|
+
if (existing) {
|
|
1412
|
+
existing.set(key, value);
|
|
1413
|
+
return;
|
|
1414
|
+
}
|
|
1415
|
+
byTransaction.set(anchor, new Map([[key, value]]));
|
|
1416
|
+
}
|
|
1417
|
+
};
|
|
1418
|
+
};
|
|
1419
|
+
|
|
1420
|
+
//#endregion
|
|
1421
|
+
//#region src/orm/write-cache.ts
|
|
1422
|
+
const scopes = createOrmTransactionMemo();
|
|
1423
|
+
const activeScopes = /* @__PURE__ */ new Set();
|
|
1424
|
+
let suspended$1 = 0;
|
|
1425
|
+
/** Snapshots may survive ORM-owned work, never a return to arbitrary code. */
|
|
1426
|
+
const runInOrmWriteScope = async (db, fn) => {
|
|
1427
|
+
let scope = scopes.get(db, "write");
|
|
1428
|
+
if (!scope) {
|
|
1429
|
+
scope = {
|
|
1430
|
+
depth: 0,
|
|
1431
|
+
entries: /* @__PURE__ */ new Map()
|
|
1432
|
+
};
|
|
1433
|
+
scopes.set(db, "write", scope);
|
|
1434
|
+
}
|
|
1435
|
+
scope.entries.clear();
|
|
1436
|
+
scope.depth += 1;
|
|
1437
|
+
activeScopes.add(scope);
|
|
1438
|
+
try {
|
|
1439
|
+
return await fn();
|
|
1440
|
+
} finally {
|
|
1441
|
+
scope.entries.clear();
|
|
1442
|
+
scope.depth -= 1;
|
|
1443
|
+
if (scope.depth === 0) activeScopes.delete(scope);
|
|
1444
|
+
}
|
|
1445
|
+
};
|
|
1446
|
+
/**
|
|
1447
|
+
* User code can call a nested UDF whose isolated JS context cannot invalidate
|
|
1448
|
+
* our snapshots. Suspend every active scope, including reentrant statements,
|
|
1449
|
+
* until the callback settles; never restore pre-callback entries.
|
|
1450
|
+
*/
|
|
1451
|
+
const withoutOrmWriteCache = async (fn) => {
|
|
1452
|
+
for (const scope of activeScopes) scope.entries.clear();
|
|
1453
|
+
suspended$1 += 1;
|
|
1454
|
+
try {
|
|
1455
|
+
return await fn();
|
|
1456
|
+
} finally {
|
|
1457
|
+
suspended$1 -= 1;
|
|
1458
|
+
}
|
|
1459
|
+
};
|
|
1460
|
+
const createOrmWriteMemo = () => {
|
|
1461
|
+
const namespace = Symbol("orm-write-memo");
|
|
1462
|
+
return {
|
|
1463
|
+
get(db, key) {
|
|
1464
|
+
const scope = scopes.get(db, "write");
|
|
1465
|
+
return !suspended$1 && scope?.depth ? scope.entries.get(namespace)?.get(key) : void 0;
|
|
1466
|
+
},
|
|
1467
|
+
set(db, key, value) {
|
|
1468
|
+
const scope = scopes.get(db, "write");
|
|
1469
|
+
if (suspended$1 || !scope?.depth) return;
|
|
1470
|
+
let entries = scope.entries.get(namespace);
|
|
1471
|
+
if (!entries) {
|
|
1472
|
+
entries = /* @__PURE__ */ new Map();
|
|
1473
|
+
scope.entries.set(namespace, entries);
|
|
1474
|
+
}
|
|
1475
|
+
entries.set(key, value);
|
|
1476
|
+
}
|
|
1477
|
+
};
|
|
1478
|
+
};
|
|
1479
|
+
|
|
1480
|
+
//#endregion
|
|
1481
|
+
//#region src/orm/write-batch.ts
|
|
1482
|
+
/**
|
|
1483
|
+
* Statement-scoped deferral for the ORM write path.
|
|
1484
|
+
*
|
|
1485
|
+
* The lifecycle fires its hooks once per written document, so a subsystem that
|
|
1486
|
+
* maintains derived storage — aggregate index buckets, today — reconciles one
|
|
1487
|
+
* document at a time and rewrites the same storage document once per row. The
|
|
1488
|
+
* fold that would collapse those writes exists; what it lacks is a boundary
|
|
1489
|
+
* wide enough to fold across. A mutation statement is that boundary: one
|
|
1490
|
+
* `update()` / `delete()` / `insert()` is one unit of work whose derived writes
|
|
1491
|
+
* nobody can observe half-applied unless they read them, and a reader can be
|
|
1492
|
+
* made to drain first.
|
|
1493
|
+
*
|
|
1494
|
+
* Depends only on the anchor and row-cache lifetime, for the same reason as
|
|
1495
|
+
* `write-fanout`: the mutation builders are reachable from `orm/index`, the
|
|
1496
|
+
* aggregate runtime contractually is not (`import-graph.test.ts`), and both
|
|
1497
|
+
* ends have to name this module.
|
|
1498
|
+
*
|
|
1499
|
+
* Three invariants make it safe:
|
|
1500
|
+
*
|
|
1501
|
+
* 1. Every queued write is applied by `flushOrmWriteBatch` and nowhere else.
|
|
1502
|
+
* Deltas are commutative but the writes that apply them are absolute
|
|
1503
|
+
* read-modify-writes, so two of them interleaving is a lost update. Callers
|
|
1504
|
+
* that have no batch open still enqueue and flush immediately rather than
|
|
1505
|
+
* writing around the queue, which makes the drain the single writer and
|
|
1506
|
+
* therefore the serialization point — the role `lifecycle`'s write lock
|
|
1507
|
+
* plays for the documents it wraps.
|
|
1508
|
+
* 2. Aggregate readers and user callbacks drain first. Callback execution
|
|
1509
|
+
* suspends deferral because nested UDFs cannot access the caller's queue.
|
|
1510
|
+
* 3. A flush callback must never itself drain. It runs inside the drain, and a
|
|
1511
|
+
* drain in progress is awaited rather than skipped, so re-entering it would
|
|
1512
|
+
* deadlock instead of returning stale rows. Keep the read barrier on the
|
|
1513
|
+
* query-path entry points, which no flush callback calls.
|
|
1514
|
+
*/
|
|
1515
|
+
const batches = /* @__PURE__ */ new WeakMap();
|
|
1516
|
+
const activeBatches = /* @__PURE__ */ new Set();
|
|
1517
|
+
let suspended = 0;
|
|
1518
|
+
const getState = (db) => {
|
|
1519
|
+
const anchor = resolveOrmTransactionAnchor(db);
|
|
1520
|
+
if (!anchor) return;
|
|
1521
|
+
const existing = batches.get(anchor);
|
|
1522
|
+
if (existing) return existing;
|
|
1523
|
+
const created = {
|
|
1524
|
+
depth: 0,
|
|
1525
|
+
flushers: /* @__PURE__ */ new Set(),
|
|
1526
|
+
draining: null
|
|
1527
|
+
};
|
|
1528
|
+
batches.set(anchor, created);
|
|
1529
|
+
return created;
|
|
1530
|
+
};
|
|
1531
|
+
/**
|
|
1532
|
+
* Runs every queued flush callback until none is left.
|
|
1533
|
+
*
|
|
1534
|
+
* A callback is removed before it runs, so work enqueued while the drain is in
|
|
1535
|
+
* flight is picked up by this same loop instead of being dropped or applied
|
|
1536
|
+
* twice. `draining` is published before the first callback and cleared in the
|
|
1537
|
+
* same synchronous step as the emptiness check that ends the loop, so a
|
|
1538
|
+
* caller either sees a drain it can wait for or starts its own — never a
|
|
1539
|
+
* window where its work is queued against a drain that has already left.
|
|
1540
|
+
*/
|
|
1541
|
+
const drain = (state) => {
|
|
1542
|
+
if (state.draining) return state.draining;
|
|
1543
|
+
let settled = false;
|
|
1544
|
+
const running = (async () => {
|
|
1545
|
+
try {
|
|
1546
|
+
for (;;) {
|
|
1547
|
+
const next = state.flushers.values().next();
|
|
1548
|
+
if (next.done) return;
|
|
1549
|
+
state.flushers.delete(next.value);
|
|
1550
|
+
await next.value();
|
|
1551
|
+
}
|
|
1552
|
+
} finally {
|
|
1553
|
+
state.draining = null;
|
|
1554
|
+
settled = true;
|
|
1555
|
+
}
|
|
1556
|
+
})();
|
|
1557
|
+
if (!settled) state.draining = running;
|
|
1558
|
+
return running;
|
|
1559
|
+
};
|
|
1560
|
+
/**
|
|
1561
|
+
* Opens a write batch for the duration of `fn`.
|
|
1562
|
+
*
|
|
1563
|
+
* Nesting is reference-counted: a cascade that runs another statement inside
|
|
1564
|
+
* this one folds into the same batch rather than flushing the outer statement's
|
|
1565
|
+
* pending work early. The flush runs whether or not `fn` threw, so rows that
|
|
1566
|
+
* landed before a mid-statement throw still get their derived writes.
|
|
1567
|
+
*
|
|
1568
|
+
* When both throw, `fn`'s error wins and the flush failure rides along as its
|
|
1569
|
+
* `cause`. A plain `finally { await drain() }` would report the consequence and
|
|
1570
|
+
* swallow the reason — the statement's own failure is what a caller can act on.
|
|
1571
|
+
*/
|
|
1572
|
+
const runInOrmWriteBatch = async (db, fn) => {
|
|
1573
|
+
const state = getState(db);
|
|
1574
|
+
if (!state) return await fn();
|
|
1575
|
+
state.depth += 1;
|
|
1576
|
+
activeBatches.add(state);
|
|
1577
|
+
let failure;
|
|
1578
|
+
let result;
|
|
1579
|
+
try {
|
|
1580
|
+
result = await fn();
|
|
1581
|
+
} catch (error) {
|
|
1582
|
+
failure = { error };
|
|
1583
|
+
}
|
|
1584
|
+
state.depth -= 1;
|
|
1585
|
+
if (state.depth > 0) {
|
|
1586
|
+
if (failure) throw failure.error;
|
|
1587
|
+
return result;
|
|
1588
|
+
}
|
|
1589
|
+
try {
|
|
1590
|
+
await drain(state);
|
|
1591
|
+
} catch (flushError) {
|
|
1592
|
+
if (!failure) throw flushError;
|
|
1593
|
+
if (failure.error instanceof Error && failure.error.cause === void 0) failure.error.cause = flushError;
|
|
1594
|
+
} finally {
|
|
1595
|
+
if (state.depth === 0) activeBatches.delete(state);
|
|
1596
|
+
}
|
|
1597
|
+
if (failure) throw failure.error;
|
|
1598
|
+
return result;
|
|
1599
|
+
};
|
|
1600
|
+
/**
|
|
1601
|
+
* Queues `flush` for the next drain.
|
|
1602
|
+
*
|
|
1603
|
+
* Returns `false` only when `db` has no resolvable transaction, which is the
|
|
1604
|
+
* caller's signal that this module cannot help and the work has to be done
|
|
1605
|
+
* inline.
|
|
1606
|
+
*/
|
|
1607
|
+
const enqueueOrmWriteBatch = (db, flush) => {
|
|
1608
|
+
const state = getState(db);
|
|
1609
|
+
if (!state) return false;
|
|
1610
|
+
state.flushers.add(flush);
|
|
1611
|
+
return true;
|
|
1612
|
+
};
|
|
1613
|
+
/** True while a statement scope is holding the queue back. */
|
|
1614
|
+
const isOrmWriteBatchOpen = (db) => suspended === 0 && (getState(db)?.depth ?? 0) > 0;
|
|
1615
|
+
/** Nested UDFs cannot read or drain queues in the caller's JS context. */
|
|
1616
|
+
const runInOrmUserCallback = async (fn) => await withoutOrmWriteCache(async () => {
|
|
1617
|
+
suspended += 1;
|
|
1618
|
+
try {
|
|
1619
|
+
for (const state of activeBatches) await drain(state);
|
|
1620
|
+
return await fn();
|
|
1621
|
+
} finally {
|
|
1622
|
+
suspended -= 1;
|
|
1623
|
+
}
|
|
1624
|
+
});
|
|
1625
|
+
/**
|
|
1626
|
+
* Applies everything queued. Both the read barrier and the only writer.
|
|
1627
|
+
*
|
|
1628
|
+
* Callers must be outside any flush callback; see this module's header.
|
|
1629
|
+
*/
|
|
1630
|
+
const flushOrmWriteBatch = async (db) => {
|
|
1631
|
+
const anchor = resolveOrmTransactionAnchor(db);
|
|
1632
|
+
const state = anchor ? batches.get(anchor) : void 0;
|
|
1633
|
+
if (!state || !state.draining && state.flushers.size === 0) return;
|
|
1634
|
+
await drain(state);
|
|
1635
|
+
};
|
|
1636
|
+
|
|
1316
1637
|
//#endregion
|
|
1317
1638
|
//#region src/orm/aggregate-index/definitions.ts
|
|
1318
1639
|
const getAggregateIndexDefinitions = (tableConfig) => {
|
|
@@ -1426,4 +1747,4 @@ function aggregateExtension() {
|
|
|
1426
1747
|
}
|
|
1427
1748
|
|
|
1428
1749
|
//#endregion
|
|
1429
|
-
export {
|
|
1750
|
+
export { getOrmContext as $, canUsePrimaryIdLookupCursor as A, enforceUniqueIndexes as B, createError as C, isConvexEnforceableFilter as Ct, applyIncomingForeignKeyActionsOnDelete as D, applyDefaults as E, deserializeFilterExpression as F, evaluateFilter as G, ensureNonNullValues as H, encodeUndefinedDeep as I, getColumnName as J, extractPrimaryIdLookup as K, enforceCheckConstraints as L, collectPrimaryIdLookupRows as M, createForeignKeyProbeMemo as N, applyIncomingForeignKeyActionsOnUpdate as O, decodeUndefinedDeep as P, getMutationExecutionMode as Q, enforceForeignKeys as R, createCountError as S, convexAnd as St, ensureCountAllowedForRls as T, ensureNullableColumns as U, ensureDefaultColumns as V, evaluateCheckConstraintTriState as W, getMutationAsyncDelayMs as X, getForeignKeys as Y, getMutationCollectionLimits as Z, createOrmTransactionMemo as _, toConvexFilter as _t, AGGREGATE_STATE_TABLE as a, hydrateDateFieldsForRead as at, COUNT_ERROR as b, markLifecycleHookedTables as bt, getAggregateIndexDefinitions as c, patchReferencingRows as ct, flushOrmWriteBatch as d, selectReturningRowWithHydration as dt, getTableColumns as et, isOrmWriteBatchOpen as f, serializeFilterExpression as ft, runInOrmWriteScope as g, takeRowsWithinByteBudget as gt, createOrmWriteMemo as h, stripUnsetFields as ht, AGGREGATE_RANK_TREE_TABLE as i, hardDeleteRow as it, collectMutationRowsBounded as j, buildForeignKeyGraph as k, getRankIndexDefinitions as l, resolveOrmRuntimeDefaults as lt, runInOrmWriteBatch as m, splitReturningSelection as mt, AGGREGATE_EXTREMA_TABLE as n, getTableName as nt, aggregateExtension as o, normalizeDateFieldsForWrite as ot, runInOrmUserCallback as p, softDeleteRow as pt, getChecks as q, AGGREGATE_MEMBER_TABLE as r, getUniqueIndexes as rt, rankAggregateName as s, normalizeTemporalComparableValue as st, AGGREGATE_BUCKET_TABLE as t, getTableDeleteConfig as tt, enqueueOrmWriteBatch as u, returningSelectionReadsCreationTime as ut, markOrmTransactionAnchor as v, unsetFieldsOf as vt, ensureAggregateAllowedForRls as w, mapWithConcurrency as wt, createAggregateError as x, compileConvexFilter as xt, AGGREGATE_ERROR as y, hasLifecycleHooks as yt, enforcePolymorphicWrite as z };
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { A as
|
|
3
|
-
import { a as MergeZodObjects, c as MiddlewareMarker, d as MiddlewareProcedureType, f as MiddlewareResult, g as UnsetMarker, h as Simplify, i as IntersectIfDefined, l as MiddlewareNext, m as ResolveIfSet, n as AnyMiddlewareBuilder, o as MiddlewareBuilder, p as Overwrite, r as GetRawInputFn, s as MiddlewareFunction, t as AnyMiddleware, u as MiddlewareProcedureInfo } from "../types-
|
|
4
|
-
import {
|
|
1
|
+
import { a as CallerMeta, c as createServerCaller, i as createLazyCaller, n as createCallerFactory, o as CallerOpts, r as LazyCaller, s as ServerCaller, t as ConvexContext } from "../caller-factory-C3pcbzo0.js";
|
|
2
|
+
import { $ as createHttpProcedureBuilder, A as CRPCError, B as RuntimeEnv, C as createProcedureHandlerFactory, D as WithHttpRouter, E as typedProcedureResolver, F as getCRPCErrorFromUnknown, G as ActionProcedureBuilder, H as createApiLeaf, I as getHTTPStatusCodeFromError, J as ProcedureBuilder, K as CRPCFunctionTypeHint, L as isCRPCError, M as CRPCErrorData, N as CRPC_ERROR_CODES_BY_KEY, O as inferApiInputs, P as CRPC_ERROR_CODE_TO_HTTP, Q as HttpProcedureBuilder, R as toCRPCError, S as createProcedureCallerFactory, T as getGeneratedFunctionReference, U as createGeneratedFunctionReference, V as createEnv, W as getGeneratedValue, X as createMiddlewareFactory, Y as QueryProcedureBuilder, Z as initCRPC, _ as ProcedureSchedulableCallerFromRegistry, _t as zodOutputToConvex, a as CreateProcedureCallerFactoryOptions, at as CustomBuilder, b as createGenericCallerFactory, bt as zodToConvexFields, c as GeneratedRegistryCallerFactory, ct as ZodFromValidatorBase, d as GeneratedRegistryHandlerForContext, dt as convexToZodFields, et as extractPathParams, f as ProcedureActionCallerFromRegistry, ft as withSystemFields, g as ProcedureFromFunctionReference, gt as zid, h as ProcedureDefinition, ht as zCustomQuery, i as registerProcedureNameLookup, it as ConvexValidatorFromZodOutput, j as CRPCErrorCode, k as inferApiOutputs, l as GeneratedRegistryCallerForContext, lt as ZodValidatorFromConvex, m as ProcedureCallerFromRegistry, mt as zCustomMutation, n as ProcedureNameLookup, nt as matchPathParams, o as GeneratedProcedureRegistry, ot as ZCustomCtx, p as ProcedureCaller, pt as zCustomAction, q as MutationProcedureBuilder, r as inferProcedureNameFromCallsite, rt as ConvexValidatorFromZod, s as GeneratedProcedureRegistryEntry, st as Zid, t as ProcedureNameEntry, tt as handleHttpError, u as GeneratedRegistryHandlerFactory, ut as convexToZod, v as ProcedureScheduleCallerFromRegistry, vt as zodOutputToConvexFields, w as defineProcedure, x as createGenericHandlerFactory, y as createGeneratedRegistryRuntime, yt as zodToConvex, z as CreateEnvOptions } from "../procedure-name-kn-awLk1.js";
|
|
3
|
+
import { a as MergeZodObjects, c as MiddlewareMarker, d as MiddlewareProcedureType, f as MiddlewareResult, g as UnsetMarker, h as Simplify, i as IntersectIfDefined, l as MiddlewareNext, m as ResolveIfSet, n as AnyMiddlewareBuilder, o as MiddlewareBuilder, p as Overwrite, r as GetRawInputFn, s as MiddlewareFunction, t as AnyMiddleware, u as MiddlewareProcedureInfo } from "../types-CzGsrLrY.js";
|
|
4
|
+
import { A as HttpProcedureBuilderDef, C as extractRouteMap, D as HttpHandlerOpts, E as HttpActionHandler, M as InferHttpInput, N as ProcedureMeta, O as HttpMethod, S as createHttpRouterFactory, T as HttpActionConstructor, _ as CRPCHttpRouter, b as HttpRouterWithHono, j as HttpRouteDefinition, k as HttpProcedure, v as HttpRouterDef, w as CRPCHonoHandler, x as createHttpRouter, y as HttpRouterRecord } from "../http-types-8FBr10yl.js";
|
|
5
|
+
import { a as isMutationCtx, c as isSchedulerCtx, d as requireQueryCtx, f as requireRunMutationCtx, i as isActionCtx, l as requireActionCtx, n as RunMutationCtx, o as isQueryCtx, p as requireSchedulerCtx, r as SchedulerCtx, s as isRunMutationCtx, t as GenericCtx, u as requireMutationCtx } from "../context-utils-ax351iFc.js";
|
|
5
6
|
export { ActionProcedureBuilder, AnyMiddleware, AnyMiddlewareBuilder, CRPCError, CRPCErrorCode, CRPCErrorData, CRPCFunctionTypeHint, CRPCHonoHandler, CRPCHttpRouter, CRPC_ERROR_CODES_BY_KEY, CRPC_ERROR_CODE_TO_HTTP, CallerMeta, CallerOpts, ConvexContext, ConvexValidatorFromZod, ConvexValidatorFromZodOutput, CreateEnvOptions, CreateProcedureCallerFactoryOptions, CustomBuilder, GeneratedProcedureRegistry, GeneratedProcedureRegistryEntry, GeneratedRegistryCallerFactory, GeneratedRegistryCallerForContext, GeneratedRegistryHandlerFactory, GeneratedRegistryHandlerForContext, GenericCtx, GetRawInputFn, HttpActionConstructor, HttpActionHandler, HttpHandlerOpts, HttpMethod, HttpProcedure, HttpProcedureBuilder, HttpProcedureBuilderDef, HttpRouteDefinition, HttpRouterDef, HttpRouterRecord, HttpRouterWithHono, InferHttpInput, IntersectIfDefined, LazyCaller, MergeZodObjects, MiddlewareBuilder, MiddlewareFunction, MiddlewareMarker, MiddlewareNext, MiddlewareProcedureInfo, MiddlewareProcedureType, MiddlewareResult, MutationProcedureBuilder, Overwrite, ProcedureActionCallerFromRegistry, ProcedureBuilder, ProcedureCaller, ProcedureCallerFromRegistry, ProcedureDefinition, ProcedureFromFunctionReference, ProcedureMeta, ProcedureNameEntry, ProcedureNameLookup, ProcedureSchedulableCallerFromRegistry, ProcedureScheduleCallerFromRegistry, QueryProcedureBuilder, ResolveIfSet, RunMutationCtx, RuntimeEnv, SchedulerCtx, ServerCaller, Simplify, UnsetMarker, WithHttpRouter, ZCustomCtx, Zid, ZodFromValidatorBase, ZodValidatorFromConvex, convexToZod, convexToZodFields, createApiLeaf, createCallerFactory, createEnv, createGeneratedFunctionReference, createGeneratedRegistryRuntime, createGenericCallerFactory, createGenericHandlerFactory, createHttpProcedureBuilder, createHttpRouter, createHttpRouterFactory, createLazyCaller, createMiddlewareFactory, createProcedureCallerFactory, createProcedureHandlerFactory, createServerCaller, defineProcedure, extractPathParams, extractRouteMap, getCRPCErrorFromUnknown, getGeneratedFunctionReference, getGeneratedValue, getHTTPStatusCodeFromError, handleHttpError, inferApiInputs, inferApiOutputs, inferProcedureNameFromCallsite, initCRPC, isActionCtx, isCRPCError, isMutationCtx, isQueryCtx, isRunMutationCtx, isSchedulerCtx, matchPathParams, registerProcedureNameLookup, requireActionCtx, requireMutationCtx, requireQueryCtx, requireRunMutationCtx, requireSchedulerCtx, toCRPCError, typedProcedureResolver, withSystemFields, zCustomAction, zCustomMutation, zCustomQuery, zid, zodOutputToConvex, zodOutputToConvexFields, zodToConvex, zodToConvexFields };
|
package/dist/server/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as isMutationCtx, c as isSchedulerCtx, d as requireQueryCtx, f as requireRunMutationCtx, i as isActionCtx, l as requireActionCtx, n as createGeneratedFunctionReference, o as isQueryCtx, p as requireSchedulerCtx, r as getGeneratedValue, s as isRunMutationCtx, t as createApiLeaf, u as requireMutationCtx } from "../api-entry-Buvjl9hn.js";
|
|
2
2
|
import { n as createLazyCaller, r as createServerCaller, t as createCallerFactory } from "../caller-factory-C-N540BC.js";
|
|
3
|
-
import { A as zid, C as toCRPCError, D as zCustomAction, E as withSystemFields, M as zodOutputToConvexFields, N as zodToConvex, O as zCustomMutation, P as zodToConvexFields, S as isCRPCError, T as convexToZodFields, _ as CRPCError, a as createMiddlewareFactory, b as getCRPCErrorFromUnknown, c as registerProcedureNameLookup, d as createHttpRouterFactory, f as extractRouteMap, g as matchPathParams, h as handleHttpError, i as QueryProcedureBuilder, j as zodOutputToConvex, k as zCustomQuery, l as HttpRouterWithHono, m as extractPathParams, n as MutationProcedureBuilder, o as initCRPC, p as createHttpProcedureBuilder, r as ProcedureBuilder, s as inferProcedureNameFromCallsite, t as ActionProcedureBuilder, u as createHttpRouter, v as CRPC_ERROR_CODES_BY_KEY, w as convexToZod, x as getHTTPStatusCodeFromError, y as CRPC_ERROR_CODE_TO_HTTP } from "../builder-
|
|
4
|
-
import { a as createProcedureHandlerFactory, c as typedProcedureResolver, i as createProcedureCallerFactory, l as createEnv, n as createGenericCallerFactory, o as defineProcedure, r as createGenericHandlerFactory, s as getGeneratedFunctionReference, t as createGeneratedRegistryRuntime } from "../procedure-caller-
|
|
3
|
+
import { A as zid, C as toCRPCError, D as zCustomAction, E as withSystemFields, M as zodOutputToConvexFields, N as zodToConvex, O as zCustomMutation, P as zodToConvexFields, S as isCRPCError, T as convexToZodFields, _ as CRPCError, a as createMiddlewareFactory, b as getCRPCErrorFromUnknown, c as registerProcedureNameLookup, d as createHttpRouterFactory, f as extractRouteMap, g as matchPathParams, h as handleHttpError, i as QueryProcedureBuilder, j as zodOutputToConvex, k as zCustomQuery, l as HttpRouterWithHono, m as extractPathParams, n as MutationProcedureBuilder, o as initCRPC, p as createHttpProcedureBuilder, r as ProcedureBuilder, s as inferProcedureNameFromCallsite, t as ActionProcedureBuilder, u as createHttpRouter, v as CRPC_ERROR_CODES_BY_KEY, w as convexToZod, x as getHTTPStatusCodeFromError, y as CRPC_ERROR_CODE_TO_HTTP } from "../builder-DDYTlmTB.js";
|
|
4
|
+
import { a as createProcedureHandlerFactory, c as typedProcedureResolver, i as createProcedureCallerFactory, l as createEnv, n as createGenericCallerFactory, o as defineProcedure, r as createGenericHandlerFactory, s as getGeneratedFunctionReference, t as createGeneratedRegistryRuntime } from "../procedure-caller-DgGF_hA8.js";
|
|
5
5
|
|
|
6
6
|
export { ActionProcedureBuilder, CRPCError, CRPC_ERROR_CODES_BY_KEY, CRPC_ERROR_CODE_TO_HTTP, HttpRouterWithHono, MutationProcedureBuilder, ProcedureBuilder, QueryProcedureBuilder, convexToZod, convexToZodFields, createApiLeaf, createCallerFactory, createEnv, createGeneratedFunctionReference, createGeneratedRegistryRuntime, createGenericCallerFactory, createGenericHandlerFactory, createHttpProcedureBuilder, createHttpRouter, createHttpRouterFactory, createLazyCaller, createMiddlewareFactory, createProcedureCallerFactory, createProcedureHandlerFactory, createServerCaller, defineProcedure, extractPathParams, extractRouteMap, getCRPCErrorFromUnknown, getGeneratedFunctionReference, getGeneratedValue, getHTTPStatusCodeFromError, handleHttpError, inferProcedureNameFromCallsite, initCRPC, isActionCtx, isCRPCError, isMutationCtx, isQueryCtx, isRunMutationCtx, isSchedulerCtx, matchPathParams, registerProcedureNameLookup, requireActionCtx, requireMutationCtx, requireQueryCtx, requireRunMutationCtx, requireSchedulerCtx, toCRPCError, typedProcedureResolver, withSystemFields, zCustomAction, zCustomMutation, zCustomQuery, zid, zodOutputToConvex, zodOutputToConvexFields, zodToConvex, zodToConvexFields };
|
package/dist/solid/index.d.ts
CHANGED
|
@@ -60,8 +60,8 @@ type ConvexQueryHookOptions = {
|
|
|
60
60
|
/** Skip query silently when unauthenticated (default: false, calls onQueryUnauthorized) */skipUnauth?: boolean; /** Set to false to fetch once without subscribing (default: true) */
|
|
61
61
|
subscribe?: boolean;
|
|
62
62
|
};
|
|
63
|
-
/** Extract
|
|
64
|
-
type InfiniteQueryInput<TInput> = Omit<TInput, 'cursor' | 'limit'>;
|
|
63
|
+
/** Extract user args without hook-owned pagination transport fields */
|
|
64
|
+
type InfiniteQueryInput<TInput> = Omit<TInput, 'cursor' | 'endCursor' | 'limit'>;
|
|
65
65
|
/** Extract item type from PaginationResult<T> */
|
|
66
66
|
type ExtractPaginatedItem<TOutput> = TOutput extends {
|
|
67
67
|
page: (infer T)[];
|
|
@@ -1429,7 +1429,7 @@ declare const getConvexQueryClientSingleton: ({
|
|
|
1429
1429
|
* Pagination state persisted in queryClient.
|
|
1430
1430
|
* Enables scroll restoration when navigating back to a paginated list.
|
|
1431
1431
|
*
|
|
1432
|
-
* Uses flat { cursor, limit } structure like tRPC.
|
|
1432
|
+
* Uses flat { cursor, endCursor, limit } structure like tRPC.
|
|
1433
1433
|
*/
|
|
1434
1434
|
type PaginationState = {
|
|
1435
1435
|
id: number;
|
|
@@ -1438,13 +1438,12 @@ type PaginationState = {
|
|
|
1438
1438
|
queries: Record<number, {
|
|
1439
1439
|
/** Flat pagination args - tRPC style */args: Record<string, unknown> & {
|
|
1440
1440
|
cursor: string | null;
|
|
1441
|
+
endCursor?: string | null;
|
|
1441
1442
|
limit?: number; /** Internal pagination ID for subscription management */
|
|
1442
1443
|
__paginationId?: number;
|
|
1443
1444
|
};
|
|
1444
|
-
endCursor?: string | null;
|
|
1445
1445
|
}>;
|
|
1446
|
-
version: number;
|
|
1447
|
-
autoRecoveryAttempted?: string;
|
|
1446
|
+
version: number;
|
|
1448
1447
|
};
|
|
1449
1448
|
type PaginationStatus = 'CanLoadMore' | 'Exhausted' | 'LoadingFirstPage' | 'LoadingMore';
|
|
1450
1449
|
/** Return type for infinite query hooks */
|
package/dist/solid/index.js
CHANGED
|
@@ -2935,6 +2935,12 @@ const getConvexQueryClientSingleton = ({ authStore, convex, queryClient, symbolK
|
|
|
2935
2935
|
//#endregion
|
|
2936
2936
|
//#region src/internal/pagination.ts
|
|
2937
2937
|
const shouldSplitPaginationPage = (page, initialNumItems) => Boolean(page.splitCursor) && (page.pageStatus === "SplitRecommended" || page.pageStatus === "SplitRequired" || initialNumItems !== void 0 && page.page.length > initialNumItems * 2);
|
|
2938
|
+
const isInvalidPaginationCursor = (error) => {
|
|
2939
|
+
if (error instanceof Error && error.message.includes("InvalidCursor")) return true;
|
|
2940
|
+
if (!error || typeof error !== "object" || !("data" in error)) return false;
|
|
2941
|
+
const data = error.data;
|
|
2942
|
+
return Boolean(data && typeof data === "object" && "isConvexSystemError" in data && data.isConvexSystemError === true && "paginationError" in data && data.paginationError === "InvalidCursor");
|
|
2943
|
+
};
|
|
2938
2944
|
|
|
2939
2945
|
//#endregion
|
|
2940
2946
|
//#region src/solid/create-queries-results.ts
|
|
@@ -3020,7 +3026,7 @@ const aggregatePages = (results, hasPlaceholderData) => {
|
|
|
3020
3026
|
error,
|
|
3021
3027
|
failureReason: error,
|
|
3022
3028
|
isError: results.some((r) => r.isError),
|
|
3023
|
-
isFetchNextPageError: results.
|
|
3029
|
+
isFetchNextPageError: results.slice(1).some((result) => result.isError),
|
|
3024
3030
|
isFetching,
|
|
3025
3031
|
isLoading: status === "LoadingFirstPage",
|
|
3026
3032
|
isPlaceholderData,
|
|
@@ -3030,72 +3036,18 @@ const aggregatePages = (results, hasPlaceholderData) => {
|
|
|
3030
3036
|
status
|
|
3031
3037
|
};
|
|
3032
3038
|
};
|
|
3033
|
-
/** Build a unique key for recovery attempt detection */
|
|
3034
|
-
const buildRecoveryKey = (pageKeys, page0Cursor, page0UpdatedAt) => JSON.stringify({
|
|
3035
|
-
pageKeys,
|
|
3036
|
-
page0Cursor,
|
|
3037
|
-
page0UpdatedAt
|
|
3038
|
-
});
|
|
3039
3039
|
/**
|
|
3040
3040
|
* Hook for auto-recovering from stale cursors after WebSocket reconnection.
|
|
3041
3041
|
*
|
|
3042
3042
|
* When Convex WebSocket reconnects, page 0 (cursor: null) resubscribes and
|
|
3043
3043
|
* gets fresh data. However, pages 1+ may have stale cursors that fail.
|
|
3044
3044
|
*
|
|
3045
|
-
* This hook
|
|
3046
|
-
* enough items to cover the lost pages, preserving the user's scroll position.
|
|
3045
|
+
* This hook discards the invalid cursor chain and restarts from page one.
|
|
3047
3046
|
*/
|
|
3048
|
-
const useStaleCursorRecovery = ({
|
|
3049
|
-
createEffect(on([
|
|
3050
|
-
() => combined.isFetchNextPageError,
|
|
3051
|
-
pageResults,
|
|
3052
|
-
() => state().pageKeys,
|
|
3053
|
-
() => state().queries,
|
|
3054
|
-
() => state().autoRecoveryAttempted,
|
|
3055
|
-
argsObject
|
|
3056
|
-
], () => {
|
|
3047
|
+
const useStaleCursorRecovery = ({ combined, pageResults, resetPagination }) => {
|
|
3048
|
+
createEffect(on([() => combined.isFetchNextPageError, pageResults], () => {
|
|
3057
3049
|
if (!combined.isFetchNextPageError) return;
|
|
3058
|
-
|
|
3059
|
-
const page0Result = results[0];
|
|
3060
|
-
const page0Data = page0Result?.data;
|
|
3061
|
-
const page0UpdatedAt = page0Result?.dataUpdatedAt ?? 0;
|
|
3062
|
-
const hasPage0Data = page0Data !== void 0 && !page0Result?.isError;
|
|
3063
|
-
const hasSubsequentErrors = results.slice(1).some((q) => q?.isError && !q?.isFetching);
|
|
3064
|
-
if (!hasPage0Data || !hasSubsequentErrors || !page0Data?.continueCursor) return;
|
|
3065
|
-
const currentState = state();
|
|
3066
|
-
const recoveryKey = buildRecoveryKey(currentState.pageKeys, page0Data.continueCursor, page0UpdatedAt);
|
|
3067
|
-
if (currentState.autoRecoveryAttempted === recoveryKey) return;
|
|
3068
|
-
const erroredPageKeys = currentState.pageKeys.filter((_, i) => i > 0 && results[i]?.isError);
|
|
3069
|
-
const itemsToRecover = erroredPageKeys.reduce((sum, key) => {
|
|
3070
|
-
return sum + (currentState.queries[key]?.args?.limit ?? limit ?? 20);
|
|
3071
|
-
}, 0);
|
|
3072
|
-
console.warn("[Pagination] Auto-recovering from stale cursors", {
|
|
3073
|
-
erroredPages: erroredPageKeys.length,
|
|
3074
|
-
itemsToRecover
|
|
3075
|
-
});
|
|
3076
|
-
setState((prev) => ({
|
|
3077
|
-
...prev,
|
|
3078
|
-
id: prev.id,
|
|
3079
|
-
nextPageKey: 2,
|
|
3080
|
-
pageKeys: [prev.pageKeys[0], 1],
|
|
3081
|
-
queries: {
|
|
3082
|
-
[prev.pageKeys[0]]: prev.queries[prev.pageKeys[0]],
|
|
3083
|
-
1: { args: {
|
|
3084
|
-
...argsObject(),
|
|
3085
|
-
cursor: page0Data.continueCursor,
|
|
3086
|
-
limit: Math.min(itemsToRecover + (limit ?? 20), 500),
|
|
3087
|
-
__paginationId: prev.id
|
|
3088
|
-
} }
|
|
3089
|
-
},
|
|
3090
|
-
version: prev.version + 1,
|
|
3091
|
-
autoRecoveryAttempted: recoveryKey
|
|
3092
|
-
}));
|
|
3093
|
-
}));
|
|
3094
|
-
createEffect(on([() => combined.status, () => state().autoRecoveryAttempted], () => {
|
|
3095
|
-
if ((combined.status === "CanLoadMore" || combined.status === "Exhausted") && state().autoRecoveryAttempted) setState((prev) => ({
|
|
3096
|
-
...prev,
|
|
3097
|
-
autoRecoveryAttempted: void 0
|
|
3098
|
-
}));
|
|
3050
|
+
if (pageResults().slice(1).some((result) => result?.isError && !result.isFetching && isInvalidPaginationCursor(result.error))) resetPagination();
|
|
3099
3051
|
}));
|
|
3100
3052
|
};
|
|
3101
3053
|
/**
|
|
@@ -3232,12 +3184,9 @@ const useInfiniteQueryInternal = (query, args, options) => {
|
|
|
3232
3184
|
const [combined, setCombined] = createStore(derive());
|
|
3233
3185
|
createRenderEffect(() => setCombined(derive()));
|
|
3234
3186
|
useStaleCursorRecovery({
|
|
3235
|
-
argsObject,
|
|
3236
3187
|
combined,
|
|
3237
|
-
limit,
|
|
3238
3188
|
pageResults,
|
|
3239
|
-
setState
|
|
3240
|
-
state
|
|
3189
|
+
resetPagination: () => setState(createInitialState())
|
|
3241
3190
|
});
|
|
3242
3191
|
createEffect(on([
|
|
3243
3192
|
pageResults,
|
|
@@ -3252,15 +3201,17 @@ const useInfiniteQueryInternal = (query, args, options) => {
|
|
|
3252
3201
|
const page = pageQuery.data;
|
|
3253
3202
|
const pageKey = state().pageKeys[i];
|
|
3254
3203
|
const pageState = state().queries[pageKey];
|
|
3255
|
-
if (shouldSplitPaginationPage(page, limit) && pageState &&
|
|
3204
|
+
if (shouldSplitPaginationPage(page, limit) && pageState && pageState.args.endCursor !== page.splitCursor) {
|
|
3256
3205
|
setState((prev) => {
|
|
3257
3206
|
const currentPageState = prev.queries[pageKey];
|
|
3258
|
-
if (!currentPageState || currentPageState.endCursor) return prev;
|
|
3207
|
+
if (!currentPageState || currentPageState.args.endCursor === page.splitCursor) return prev;
|
|
3259
3208
|
const newKey = prev.nextPageKey;
|
|
3260
3209
|
const splitCursor = page.splitCursor;
|
|
3210
|
+
const endCursor = currentPageState.args.endCursor ?? page.continueCursor;
|
|
3261
3211
|
const splitPageArgs = {
|
|
3262
3212
|
...argsObject(),
|
|
3263
3213
|
cursor: splitCursor,
|
|
3214
|
+
endCursor,
|
|
3264
3215
|
limit: currentPageState.args.limit,
|
|
3265
3216
|
__paginationId: prev.id
|
|
3266
3217
|
};
|
|
@@ -3275,7 +3226,10 @@ const useInfiniteQueryInternal = (query, args, options) => {
|
|
|
3275
3226
|
...prev.queries,
|
|
3276
3227
|
[pageKey]: {
|
|
3277
3228
|
...currentPageState,
|
|
3278
|
-
|
|
3229
|
+
args: {
|
|
3230
|
+
...currentPageState.args,
|
|
3231
|
+
endCursor: splitCursor
|
|
3232
|
+
}
|
|
3279
3233
|
},
|
|
3280
3234
|
[newKey]: { args: splitPageArgs }
|
|
3281
3235
|
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
//#region src/crpc/transformer.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Generic transformer contract (mirrors tRPC shape).
|
|
4
|
+
*/
|
|
5
|
+
interface DataTransformer {
|
|
6
|
+
deserialize(object: any): any;
|
|
7
|
+
serialize(object: any): any;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Separate input/output transformers.
|
|
11
|
+
*/
|
|
12
|
+
interface CombinedDataTransformer {
|
|
13
|
+
input: DataTransformer;
|
|
14
|
+
output: DataTransformer;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Transformer config accepted by cRPC.
|
|
18
|
+
*/
|
|
19
|
+
type DataTransformerOptions = CombinedDataTransformer | DataTransformer;
|
|
20
|
+
/**
|
|
21
|
+
* Extensible tagged wire codec.
|
|
22
|
+
*/
|
|
23
|
+
interface WireCodec {
|
|
24
|
+
decode(value: unknown): unknown;
|
|
25
|
+
encode(value: unknown): unknown;
|
|
26
|
+
isType(value: unknown): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Declares that `isType` only ever claims a value where
|
|
29
|
+
* `typeof value === 'object' && value !== null` - never a primitive, a
|
|
30
|
+
* function, `null` or `undefined`.
|
|
31
|
+
*
|
|
32
|
+
* Lets `serialize` skip codec dispatch on primitives, which are the majority
|
|
33
|
+
* of visited nodes. It is opt-in because an arbitrary predicate cannot be
|
|
34
|
+
* classified by sampling values: a codec that claims, say, one specific
|
|
35
|
+
* number would be misread as object-only and silently lose its encoding.
|
|
36
|
+
* Codecs that leave it unset keep full dispatch.
|
|
37
|
+
*/
|
|
38
|
+
readonly objectsOnly?: boolean;
|
|
39
|
+
readonly tag: `$${string}`;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Date wire tag (Convex-style reserved key).
|
|
43
|
+
*/
|
|
44
|
+
declare const DATE_CODEC_TAG = "$date";
|
|
45
|
+
/**
|
|
46
|
+
* Built-in Date codec.
|
|
47
|
+
*/
|
|
48
|
+
declare const dateWireCodec: WireCodec;
|
|
49
|
+
/**
|
|
50
|
+
* Build a recursive tagged transformer from codecs.
|
|
51
|
+
*/
|
|
52
|
+
declare const createTaggedTransformer: (codecs: readonly WireCodec[]) => DataTransformer;
|
|
53
|
+
/**
|
|
54
|
+
* Default cRPC transformer (Date-enabled).
|
|
55
|
+
*/
|
|
56
|
+
declare const defaultCRPCTransformer: DataTransformer;
|
|
57
|
+
/**
|
|
58
|
+
* Normalize transformer config to split input/output shape.
|
|
59
|
+
* User transformers are additive and always composed with default Date handling.
|
|
60
|
+
*
|
|
61
|
+
* Idempotent: passing a transformer this function already resolved returns it
|
|
62
|
+
* unchanged.
|
|
63
|
+
*/
|
|
64
|
+
declare const getTransformer: (transformer?: DataTransformerOptions) => CombinedDataTransformer;
|
|
65
|
+
/**
|
|
66
|
+
* Encode request payloads (input direction).
|
|
67
|
+
*/
|
|
68
|
+
declare const encodeWire: (value: unknown, transformer?: DataTransformerOptions) => unknown;
|
|
69
|
+
/**
|
|
70
|
+
* Decode response payloads (output direction).
|
|
71
|
+
*/
|
|
72
|
+
declare const decodeWire: (value: unknown, transformer?: DataTransformerOptions) => unknown;
|
|
73
|
+
/**
|
|
74
|
+
* Exposed identity transformer for advanced composition.
|
|
75
|
+
*/
|
|
76
|
+
declare const identityTransformer: CombinedDataTransformer;
|
|
77
|
+
//#endregion
|
|
78
|
+
export { WireCodec as a, decodeWire as c, getTransformer as d, identityTransformer as f, DataTransformerOptions as i, defaultCRPCTransformer as l, DATE_CODEC_TAG as n, createTaggedTransformer as o, DataTransformer as r, dateWireCodec as s, CombinedDataTransformer as t, encodeWire as u };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as CombinedDataTransformer } from "./transformer-BEkxlnss.js";
|
|
2
|
+
import { r as HttpClientError } from "./http-types-8FBr10yl.js";
|
|
2
3
|
import { FunctionArgs, FunctionReference, FunctionReturnType } from "convex/server";
|
|
3
4
|
|
|
4
5
|
//#region src/crpc/http-client.d.ts
|
|
@@ -148,8 +149,8 @@ type PaginationOpts = {
|
|
|
148
149
|
maximumRowsRead?: number;
|
|
149
150
|
maximumBytesRead?: number;
|
|
150
151
|
};
|
|
151
|
-
/** Extract
|
|
152
|
-
type InfiniteQueryInput<TInput> = Omit<TInput, 'cursor' | 'limit'>;
|
|
152
|
+
/** Extract user args without hook-owned pagination transport fields */
|
|
153
|
+
type InfiniteQueryInput<TInput> = Omit<TInput, 'cursor' | 'endCursor' | 'limit'>;
|
|
153
154
|
/** Extract item type from PaginationResult<T> */
|
|
154
155
|
type ExtractPaginatedItem<TOutput> = TOutput extends {
|
|
155
156
|
page: (infer T)[];
|