@beignet/next 0.0.33 → 0.0.35

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/src/index.ts CHANGED
@@ -9,13 +9,13 @@ import type { PaymentsPort, PaymentWebhookEvent } from "@beignet/core/payments";
9
9
  import type { AnyPorts, StorageObject, StoragePort } from "@beignet/core/ports";
10
10
  import type {
11
11
  InferProviderPorts,
12
+ ProviderInstrumentationPort,
12
13
  ServiceProvider,
13
14
  } from "@beignet/core/providers";
14
15
  import { resolveProviderInstrumentationPort } from "@beignet/core/providers";
15
16
  import {
16
17
  createInlineScheduleRunner,
17
18
  type ScheduleDef,
18
- type ScheduleInstrumentation,
19
19
  type StandardSchema,
20
20
  } from "@beignet/core/schedules";
21
21
  import type {
@@ -44,37 +44,6 @@ import {
44
44
  } from "@beignet/core/webhooks";
45
45
  import { createFetchHandler, toRequestLike, toWebResponse } from "@beignet/web";
46
46
 
47
- /**
48
- * Server types re-exported for Next.js apps.
49
- */
50
- export type {
51
- AnyUseCaseLike,
52
- CreateServerOptions,
53
- HandlerRouteDef,
54
- RawRouteInit,
55
- RouteDef,
56
- RouteGroup,
57
- RouteHook,
58
- ServerInstance,
59
- UseCaseRouteDef,
60
- } from "@beignet/core/server";
61
- /**
62
- * Server helpers re-exported for Next.js apps.
63
- */
64
- export {
65
- contractsFromRoutes,
66
- createServer,
67
- defaultBinderInput,
68
- defineRoute,
69
- defineRouteGroup,
70
- defineRoutes,
71
- } from "@beignet/core/server";
72
-
73
- /**
74
- * Web Fetch adapter helpers re-exported for Next.js route helpers.
75
- */
76
- export { createFetchHandler, toRequestLike, toWebResponse } from "@beignet/web";
77
-
78
47
  type AnyProvider = ServiceProvider<
79
48
  unknown,
80
49
  // biome-ignore lint/suspicious/noExplicitAny: provider config types are erased at this level
@@ -437,8 +406,8 @@ type ScheduleRouteLogger = {
437
406
 
438
407
  type ScheduleRoutePorts = {
439
408
  logger?: ScheduleRouteLogger;
440
- devtools?: ScheduleInstrumentation;
441
- instrumentation?: ScheduleInstrumentation;
409
+ devtools?: ProviderInstrumentationPort;
410
+ instrumentation?: ProviderInstrumentationPort;
442
411
  };
443
412
 
444
413
  type ScheduleRouteContext = {
@@ -874,13 +843,6 @@ export function createHealthRoute<Ports extends AnyPorts>(
874
843
  };
875
844
  }
876
845
 
877
- /**
878
- * Convert a Beignet response into a native `Response`.
879
- *
880
- * This is the Next-named alias for `toWebResponse(...)` from `@beignet/web`.
881
- */
882
- export const toNextResponse = toWebResponse;
883
-
884
846
  function resolveConfigValue(
885
847
  value: string | (() => string | undefined) | undefined,
886
848
  ): string | undefined {
@@ -1288,10 +1250,8 @@ export function createUploadRoute(
1288
1250
  if (!uploadName) {
1289
1251
  return Response.json(
1290
1252
  {
1291
- error: {
1292
- code: "UPLOAD_NOT_FOUND",
1293
- message: "Upload route is missing an upload name.",
1294
- },
1253
+ code: "UPLOAD_NOT_FOUND",
1254
+ message: "Upload route is missing an upload name.",
1295
1255
  },
1296
1256
  { status: 404 },
1297
1257
  );
@@ -1304,11 +1264,9 @@ export function createUploadRoute(
1304
1264
  ) {
1305
1265
  return Response.json(
1306
1266
  {
1307
- error: {
1308
- code: "INVALID_UPLOAD_ACTION",
1309
- message:
1310
- 'Upload route action must be "prepare", "complete", or "upload".',
1311
- },
1267
+ code: "INVALID_UPLOAD_ACTION",
1268
+ message:
1269
+ 'Upload route action must be "prepare", "complete", or "upload".',
1312
1270
  },
1313
1271
  { status: 400 },
1314
1272
  );
@@ -1324,7 +1282,7 @@ export function createUploadRoute(
1324
1282
  };
1325
1283
  }
1326
1284
 
1327
- function cronRouteJson(
1285
+ function routeJson(
1328
1286
  body: unknown,
1329
1287
  status: number,
1330
1288
  headers: HeadersInit | undefined,
@@ -1335,26 +1293,37 @@ function cronRouteJson(
1335
1293
  });
1336
1294
  }
1337
1295
 
1338
- function paymentWebhookJson(
1339
- body: unknown,
1340
- status: number,
1341
- headers: HeadersInit | undefined,
1342
- ): Response {
1343
- return Response.json(body, {
1344
- status,
1345
- headers,
1346
- });
1347
- }
1348
-
1349
- function webhookRouteJson(
1350
- body: unknown,
1296
+ type OperationalErrorCode =
1297
+ | "CRON_SECRET_NOT_CONFIGURED"
1298
+ | "OUTBOX_DRAIN_FAILED"
1299
+ | "PAYMENT_WEBHOOK_BODY_READ_FAILED"
1300
+ | "PAYMENT_WEBHOOK_CONTEXT_FAILED"
1301
+ | "PAYMENT_WEBHOOK_HANDLER_FAILED"
1302
+ | "PAYMENT_WEBHOOK_SIGNATURE_MISSING"
1303
+ | "PAYMENT_WEBHOOK_VERIFICATION_FAILED"
1304
+ | "SCHEDULE_FAILED"
1305
+ | "UNAUTHORIZED"
1306
+ | "WEBHOOK_BODY_READ_FAILED"
1307
+ | "WEBHOOK_CONTEXT_FAILED"
1308
+ | "WEBHOOK_HANDLER_FAILED"
1309
+ | "WEBHOOK_VERIFICATION_FAILED";
1310
+
1311
+ function operationalErrorJson(
1312
+ code: OperationalErrorCode,
1313
+ message: string,
1351
1314
  status: number,
1352
1315
  headers: HeadersInit | undefined,
1316
+ details?: unknown,
1353
1317
  ): Response {
1354
- return Response.json(body, {
1318
+ return routeJson(
1319
+ {
1320
+ code,
1321
+ message,
1322
+ ...(details !== undefined ? { details } : {}),
1323
+ },
1355
1324
  status,
1356
1325
  headers,
1357
- });
1326
+ );
1358
1327
  }
1359
1328
 
1360
1329
  function toHttpResponseHeaders(
@@ -1450,22 +1419,6 @@ export function createOutboxDrainRoute<Ctx extends OutboxDrainContext>(
1450
1419
  }): Promise<Response> => {
1451
1420
  const nativeReq = nativeRequestOf(req);
1452
1421
  const headers = resolveHeaders(options.headers, nativeReq);
1453
- const secret = options.secret;
1454
-
1455
- if (!secret) {
1456
- return cronRouteJson(
1457
- {
1458
- ok: false,
1459
- error: "CRON_SECRET is not configured.",
1460
- },
1461
- 500,
1462
- headers,
1463
- );
1464
- }
1465
-
1466
- if (!(await isAuthorizedCronRequest(nativeReq, secret))) {
1467
- return cronRouteJson({ ok: false, error: "Unauthorized" }, 401, headers);
1468
- }
1469
1422
 
1470
1423
  try {
1471
1424
  const drainCtx = ctx;
@@ -1513,7 +1466,7 @@ export function createOutboxDrainRoute<Ctx extends OutboxDrainContext>(
1513
1466
  );
1514
1467
  }
1515
1468
 
1516
- return cronRouteJson(
1469
+ return routeJson(
1517
1470
  {
1518
1471
  ok: true,
1519
1472
  result,
@@ -1524,11 +1477,9 @@ export function createOutboxDrainRoute<Ctx extends OutboxDrainContext>(
1524
1477
  } catch (error) {
1525
1478
  ctx.ports.logger?.error("Outbox drain failed", { error });
1526
1479
 
1527
- return cronRouteJson(
1528
- {
1529
- ok: false,
1530
- error: "Outbox drain failed.",
1531
- },
1480
+ return operationalErrorJson(
1481
+ "OUTBOX_DRAIN_FAILED",
1482
+ "Outbox drain failed.",
1532
1483
  500,
1533
1484
  headers,
1534
1485
  );
@@ -1552,44 +1503,37 @@ export function createOutboxDrainRoute<Ctx extends OutboxDrainContext>(
1552
1503
  };
1553
1504
 
1554
1505
  const drainPendingOutbox = async (req: Request): Promise<Response> => {
1555
- const server = await resolveServerSource(options.server);
1556
-
1557
- const runner =
1558
- pipelineRunners[req.method.toUpperCase() === "GET" ? "GET" : "POST"];
1559
- const pipelined = runner(server);
1560
- if (pipelined) return pipelined(req);
1561
-
1562
- // Minimal servers without rawRoute(...) — usually test fakes — keep the
1563
- // original flow: authorize before touching context, then drain inline.
1564
1506
  const headers = resolveHeaders(options.headers, req);
1565
1507
  const secret = options.secret;
1566
1508
 
1567
1509
  if (!secret) {
1568
- return cronRouteJson(
1569
- {
1570
- ok: false,
1571
- error: "CRON_SECRET is not configured.",
1572
- },
1510
+ return operationalErrorJson(
1511
+ "CRON_SECRET_NOT_CONFIGURED",
1512
+ "CRON_SECRET is not configured.",
1573
1513
  500,
1574
1514
  headers,
1575
1515
  );
1576
1516
  }
1577
1517
 
1578
1518
  if (!(await isAuthorizedCronRequest(req, secret))) {
1579
- return cronRouteJson({ ok: false, error: "Unauthorized" }, 401, headers);
1519
+ return operationalErrorJson("UNAUTHORIZED", "Unauthorized", 401, headers);
1580
1520
  }
1581
1521
 
1522
+ const server = await resolveServerSource(options.server);
1523
+ const runner =
1524
+ pipelineRunners[req.method.toUpperCase() === "GET" ? "GET" : "POST"];
1525
+ const pipelined = runner(server);
1526
+ if (pipelined) return pipelined(req);
1527
+
1582
1528
  let ctx: Ctx;
1583
1529
  try {
1584
1530
  ctx = await server.createRequestContext(toRequestLike(req));
1585
1531
  } catch (error) {
1586
1532
  console.error("Outbox drain context failed", { error });
1587
1533
 
1588
- return cronRouteJson(
1589
- {
1590
- ok: false,
1591
- error: "Outbox drain failed.",
1592
- },
1534
+ return operationalErrorJson(
1535
+ "OUTBOX_DRAIN_FAILED",
1536
+ "Outbox drain failed.",
1593
1537
  500,
1594
1538
  headers,
1595
1539
  );
@@ -1638,11 +1582,9 @@ export function createWebhookRoute<
1638
1582
  try {
1639
1583
  rawBody = await req.text();
1640
1584
  } catch {
1641
- return webhookRouteJson(
1642
- {
1643
- ok: false,
1644
- error: "Webhook body read failed.",
1645
- },
1585
+ return operationalErrorJson(
1586
+ "WEBHOOK_BODY_READ_FAILED",
1587
+ "Webhook body read failed.",
1646
1588
  400,
1647
1589
  headers,
1648
1590
  );
@@ -1688,11 +1630,9 @@ export function createWebhookRoute<
1688
1630
  traceId: ctx.traceId,
1689
1631
  });
1690
1632
 
1691
- return webhookRouteJson(
1692
- {
1693
- ok: false,
1694
- error: "Webhook verification failed.",
1695
- },
1633
+ return operationalErrorJson(
1634
+ "WEBHOOK_VERIFICATION_FAILED",
1635
+ "Webhook verification failed.",
1696
1636
  400,
1697
1637
  headers,
1698
1638
  );
@@ -1737,11 +1677,9 @@ export function createWebhookRoute<
1737
1677
  eventType: event.type,
1738
1678
  });
1739
1679
 
1740
- return webhookRouteJson(
1741
- {
1742
- ok: false,
1743
- error: "Webhook handler failed.",
1744
- },
1680
+ return operationalErrorJson(
1681
+ "WEBHOOK_HANDLER_FAILED",
1682
+ "Webhook handler failed.",
1745
1683
  500,
1746
1684
  headers,
1747
1685
  );
@@ -1773,11 +1711,9 @@ export function createWebhookRoute<
1773
1711
  try {
1774
1712
  rawBody = await req.text();
1775
1713
  } catch {
1776
- return webhookRouteJson(
1777
- {
1778
- ok: false,
1779
- error: "Webhook body read failed.",
1780
- },
1714
+ return operationalErrorJson(
1715
+ "WEBHOOK_BODY_READ_FAILED",
1716
+ "Webhook body read failed.",
1781
1717
  400,
1782
1718
  headers,
1783
1719
  );
@@ -1789,11 +1725,9 @@ export function createWebhookRoute<
1789
1725
  try {
1790
1726
  ctx = await server.createRequestContext(contextRequest);
1791
1727
  } catch {
1792
- return webhookRouteJson(
1793
- {
1794
- ok: false,
1795
- error: "Webhook context failed.",
1796
- },
1728
+ return operationalErrorJson(
1729
+ "WEBHOOK_CONTEXT_FAILED",
1730
+ "Webhook context failed.",
1797
1731
  500,
1798
1732
  headers,
1799
1733
  );
@@ -1835,11 +1769,9 @@ export function createPaymentWebhookRoute<
1835
1769
  const signature = new Headers(req.headers).get(signatureHeader);
1836
1770
 
1837
1771
  if (!signature) {
1838
- return paymentWebhookJson(
1839
- {
1840
- ok: false,
1841
- error: `Missing ${signatureHeader} header.`,
1842
- },
1772
+ return operationalErrorJson(
1773
+ "PAYMENT_WEBHOOK_SIGNATURE_MISSING",
1774
+ `Missing ${signatureHeader} header.`,
1843
1775
  400,
1844
1776
  headers,
1845
1777
  );
@@ -1850,11 +1782,9 @@ export function createPaymentWebhookRoute<
1850
1782
  try {
1851
1783
  rawBody = await req.text();
1852
1784
  } catch {
1853
- return paymentWebhookJson(
1854
- {
1855
- ok: false,
1856
- error: "Payment webhook body read failed.",
1857
- },
1785
+ return operationalErrorJson(
1786
+ "PAYMENT_WEBHOOK_BODY_READ_FAILED",
1787
+ "Payment webhook body read failed.",
1858
1788
  400,
1859
1789
  headers,
1860
1790
  );
@@ -1874,11 +1804,9 @@ export function createPaymentWebhookRoute<
1874
1804
  traceId: ctx.traceId,
1875
1805
  });
1876
1806
 
1877
- return paymentWebhookJson(
1878
- {
1879
- ok: false,
1880
- error: "Payment webhook verification failed.",
1881
- },
1807
+ return operationalErrorJson(
1808
+ "PAYMENT_WEBHOOK_VERIFICATION_FAILED",
1809
+ "Payment webhook verification failed.",
1882
1810
  400,
1883
1811
  headers,
1884
1812
  );
@@ -1921,11 +1849,9 @@ export function createPaymentWebhookRoute<
1921
1849
  eventType: event.type,
1922
1850
  });
1923
1851
 
1924
- return paymentWebhookJson(
1925
- {
1926
- ok: false,
1927
- error: "Payment webhook handler failed.",
1928
- },
1852
+ return operationalErrorJson(
1853
+ "PAYMENT_WEBHOOK_HANDLER_FAILED",
1854
+ "Payment webhook handler failed.",
1929
1855
  500,
1930
1856
  headers,
1931
1857
  );
@@ -1955,11 +1881,9 @@ export function createPaymentWebhookRoute<
1955
1881
  const headers = resolveHeaders(options.headers, req);
1956
1882
 
1957
1883
  if (!req.headers.get(signatureHeader)) {
1958
- return paymentWebhookJson(
1959
- {
1960
- ok: false,
1961
- error: `Missing ${signatureHeader} header.`,
1962
- },
1884
+ return operationalErrorJson(
1885
+ "PAYMENT_WEBHOOK_SIGNATURE_MISSING",
1886
+ `Missing ${signatureHeader} header.`,
1963
1887
  400,
1964
1888
  headers,
1965
1889
  );
@@ -1969,11 +1893,9 @@ export function createPaymentWebhookRoute<
1969
1893
  try {
1970
1894
  rawBody = await req.text();
1971
1895
  } catch {
1972
- return paymentWebhookJson(
1973
- {
1974
- ok: false,
1975
- error: "Payment webhook body read failed.",
1976
- },
1896
+ return operationalErrorJson(
1897
+ "PAYMENT_WEBHOOK_BODY_READ_FAILED",
1898
+ "Payment webhook body read failed.",
1977
1899
  400,
1978
1900
  headers,
1979
1901
  );
@@ -1983,11 +1905,9 @@ export function createPaymentWebhookRoute<
1983
1905
  try {
1984
1906
  ctx = await server.createRequestContext(toContextRequest(req, rawBody));
1985
1907
  } catch {
1986
- return paymentWebhookJson(
1987
- {
1988
- ok: false,
1989
- error: "Payment webhook context failed.",
1990
- },
1908
+ return operationalErrorJson(
1909
+ "PAYMENT_WEBHOOK_CONTEXT_FAILED",
1910
+ "Payment webhook context failed.",
1991
1911
  500,
1992
1912
  headers,
1993
1913
  );
@@ -2039,28 +1959,11 @@ export function createScheduleRoute<Ctx extends ScheduleRouteContext>(
2039
1959
  }): Promise<Response> => {
2040
1960
  const nativeReq = nativeRequestOf(req);
2041
1961
  const headers = resolveHeaders(options.headers, nativeReq);
2042
- const secret = options.secret;
2043
-
2044
- if (!secret) {
2045
- return cronRouteJson(
2046
- {
2047
- ok: false,
2048
- error: "CRON_SECRET is not configured.",
2049
- scheduleName: schedule.name,
2050
- },
2051
- 500,
2052
- headers,
2053
- );
2054
- }
2055
-
2056
- if (!(await isAuthorizedCronRequest(nativeReq, secret))) {
2057
- return cronRouteJson({ ok: false, error: "Unauthorized" }, 401, headers);
2058
- }
2059
1962
 
2060
1963
  try {
2061
1964
  const runner = createInlineScheduleRunner<Ctx>({
2062
1965
  ctx,
2063
- instrumentation: resolveProviderInstrumentationPort(ctx.ports),
1966
+ instrumentation: ctx.ports,
2064
1967
  instrumentationContext: {
2065
1968
  requestId: ctx.requestId,
2066
1969
  traceId: ctx.traceId,
@@ -2077,7 +1980,7 @@ export function createScheduleRoute<Ctx extends ScheduleRouteContext>(
2077
1980
  source: options.source ?? "next-cron-route",
2078
1981
  });
2079
1982
 
2080
- return cronRouteJson(
1983
+ return routeJson(
2081
1984
  {
2082
1985
  ok: true,
2083
1986
  scheduleName: schedule.name,
@@ -2086,14 +1989,12 @@ export function createScheduleRoute<Ctx extends ScheduleRouteContext>(
2086
1989
  headers,
2087
1990
  );
2088
1991
  } catch {
2089
- return cronRouteJson(
2090
- {
2091
- ok: false,
2092
- error: "Schedule failed.",
2093
- scheduleName: schedule.name,
2094
- },
1992
+ return operationalErrorJson(
1993
+ "SCHEDULE_FAILED",
1994
+ "Schedule failed.",
2095
1995
  500,
2096
1996
  headers,
1997
+ { scheduleName: schedule.name },
2097
1998
  );
2098
1999
  }
2099
2000
  };
@@ -2115,46 +2016,39 @@ export function createScheduleRoute<Ctx extends ScheduleRouteContext>(
2115
2016
  };
2116
2017
 
2117
2018
  const runScheduleFromRequest = async (req: Request): Promise<Response> => {
2118
- const server = await resolveServerSource(options.server);
2119
-
2120
- const runner =
2121
- pipelineRunners[req.method.toUpperCase() === "GET" ? "GET" : "POST"];
2122
- const pipelined = runner(server);
2123
- if (pipelined) return pipelined(req);
2124
-
2125
- // Minimal servers without rawRoute(...) — usually test fakes — keep the
2126
- // original flow: authorize before touching context, then run inline.
2127
2019
  const headers = resolveHeaders(options.headers, req);
2128
2020
  const secret = options.secret;
2129
2021
 
2130
2022
  if (!secret) {
2131
- return cronRouteJson(
2132
- {
2133
- ok: false,
2134
- error: "CRON_SECRET is not configured.",
2135
- scheduleName: schedule.name,
2136
- },
2023
+ return operationalErrorJson(
2024
+ "CRON_SECRET_NOT_CONFIGURED",
2025
+ "CRON_SECRET is not configured.",
2137
2026
  500,
2138
2027
  headers,
2028
+ { scheduleName: schedule.name },
2139
2029
  );
2140
2030
  }
2141
2031
 
2142
2032
  if (!(await isAuthorizedCronRequest(req, secret))) {
2143
- return cronRouteJson({ ok: false, error: "Unauthorized" }, 401, headers);
2033
+ return operationalErrorJson("UNAUTHORIZED", "Unauthorized", 401, headers);
2144
2034
  }
2145
2035
 
2036
+ const server = await resolveServerSource(options.server);
2037
+ const runner =
2038
+ pipelineRunners[req.method.toUpperCase() === "GET" ? "GET" : "POST"];
2039
+ const pipelined = runner(server);
2040
+ if (pipelined) return pipelined(req);
2041
+
2146
2042
  let ctx: Ctx;
2147
2043
  try {
2148
2044
  ctx = await server.createRequestContext(toRequestLike(req));
2149
2045
  } catch {
2150
- return cronRouteJson(
2151
- {
2152
- ok: false,
2153
- error: "Schedule failed.",
2154
- scheduleName: schedule.name,
2155
- },
2046
+ return operationalErrorJson(
2047
+ "SCHEDULE_FAILED",
2048
+ "Schedule failed.",
2156
2049
  500,
2157
2050
  headers,
2051
+ { scheduleName: schedule.name },
2158
2052
  );
2159
2053
  }
2160
2054