@beignet/next 0.0.34 → 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 {
@@ -406,8 +406,8 @@ type ScheduleRouteLogger = {
406
406
 
407
407
  type ScheduleRoutePorts = {
408
408
  logger?: ScheduleRouteLogger;
409
- devtools?: ScheduleInstrumentation;
410
- instrumentation?: ScheduleInstrumentation;
409
+ devtools?: ProviderInstrumentationPort;
410
+ instrumentation?: ProviderInstrumentationPort;
411
411
  };
412
412
 
413
413
  type ScheduleRouteContext = {
@@ -1250,10 +1250,8 @@ export function createUploadRoute(
1250
1250
  if (!uploadName) {
1251
1251
  return Response.json(
1252
1252
  {
1253
- error: {
1254
- code: "UPLOAD_NOT_FOUND",
1255
- message: "Upload route is missing an upload name.",
1256
- },
1253
+ code: "UPLOAD_NOT_FOUND",
1254
+ message: "Upload route is missing an upload name.",
1257
1255
  },
1258
1256
  { status: 404 },
1259
1257
  );
@@ -1266,11 +1264,9 @@ export function createUploadRoute(
1266
1264
  ) {
1267
1265
  return Response.json(
1268
1266
  {
1269
- error: {
1270
- code: "INVALID_UPLOAD_ACTION",
1271
- message:
1272
- 'Upload route action must be "prepare", "complete", or "upload".',
1273
- },
1267
+ code: "INVALID_UPLOAD_ACTION",
1268
+ message:
1269
+ 'Upload route action must be "prepare", "complete", or "upload".',
1274
1270
  },
1275
1271
  { status: 400 },
1276
1272
  );
@@ -1286,18 +1282,7 @@ export function createUploadRoute(
1286
1282
  };
1287
1283
  }
1288
1284
 
1289
- function cronRouteJson(
1290
- body: unknown,
1291
- status: number,
1292
- headers: HeadersInit | undefined,
1293
- ): Response {
1294
- return Response.json(body, {
1295
- status,
1296
- headers,
1297
- });
1298
- }
1299
-
1300
- function paymentWebhookJson(
1285
+ function routeJson(
1301
1286
  body: unknown,
1302
1287
  status: number,
1303
1288
  headers: HeadersInit | undefined,
@@ -1308,15 +1293,37 @@ function paymentWebhookJson(
1308
1293
  });
1309
1294
  }
1310
1295
 
1311
- function webhookRouteJson(
1312
- 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,
1313
1314
  status: number,
1314
1315
  headers: HeadersInit | undefined,
1316
+ details?: unknown,
1315
1317
  ): Response {
1316
- return Response.json(body, {
1318
+ return routeJson(
1319
+ {
1320
+ code,
1321
+ message,
1322
+ ...(details !== undefined ? { details } : {}),
1323
+ },
1317
1324
  status,
1318
1325
  headers,
1319
- });
1326
+ );
1320
1327
  }
1321
1328
 
1322
1329
  function toHttpResponseHeaders(
@@ -1412,22 +1419,6 @@ export function createOutboxDrainRoute<Ctx extends OutboxDrainContext>(
1412
1419
  }): Promise<Response> => {
1413
1420
  const nativeReq = nativeRequestOf(req);
1414
1421
  const headers = resolveHeaders(options.headers, nativeReq);
1415
- const secret = options.secret;
1416
-
1417
- if (!secret) {
1418
- return cronRouteJson(
1419
- {
1420
- ok: false,
1421
- error: "CRON_SECRET is not configured.",
1422
- },
1423
- 500,
1424
- headers,
1425
- );
1426
- }
1427
-
1428
- if (!(await isAuthorizedCronRequest(nativeReq, secret))) {
1429
- return cronRouteJson({ ok: false, error: "Unauthorized" }, 401, headers);
1430
- }
1431
1422
 
1432
1423
  try {
1433
1424
  const drainCtx = ctx;
@@ -1475,7 +1466,7 @@ export function createOutboxDrainRoute<Ctx extends OutboxDrainContext>(
1475
1466
  );
1476
1467
  }
1477
1468
 
1478
- return cronRouteJson(
1469
+ return routeJson(
1479
1470
  {
1480
1471
  ok: true,
1481
1472
  result,
@@ -1486,11 +1477,9 @@ export function createOutboxDrainRoute<Ctx extends OutboxDrainContext>(
1486
1477
  } catch (error) {
1487
1478
  ctx.ports.logger?.error("Outbox drain failed", { error });
1488
1479
 
1489
- return cronRouteJson(
1490
- {
1491
- ok: false,
1492
- error: "Outbox drain failed.",
1493
- },
1480
+ return operationalErrorJson(
1481
+ "OUTBOX_DRAIN_FAILED",
1482
+ "Outbox drain failed.",
1494
1483
  500,
1495
1484
  headers,
1496
1485
  );
@@ -1514,44 +1503,37 @@ export function createOutboxDrainRoute<Ctx extends OutboxDrainContext>(
1514
1503
  };
1515
1504
 
1516
1505
  const drainPendingOutbox = async (req: Request): Promise<Response> => {
1517
- const server = await resolveServerSource(options.server);
1518
-
1519
- const runner =
1520
- pipelineRunners[req.method.toUpperCase() === "GET" ? "GET" : "POST"];
1521
- const pipelined = runner(server);
1522
- if (pipelined) return pipelined(req);
1523
-
1524
- // Minimal servers without rawRoute(...) — usually test fakes — keep the
1525
- // original flow: authorize before touching context, then drain inline.
1526
1506
  const headers = resolveHeaders(options.headers, req);
1527
1507
  const secret = options.secret;
1528
1508
 
1529
1509
  if (!secret) {
1530
- return cronRouteJson(
1531
- {
1532
- ok: false,
1533
- error: "CRON_SECRET is not configured.",
1534
- },
1510
+ return operationalErrorJson(
1511
+ "CRON_SECRET_NOT_CONFIGURED",
1512
+ "CRON_SECRET is not configured.",
1535
1513
  500,
1536
1514
  headers,
1537
1515
  );
1538
1516
  }
1539
1517
 
1540
1518
  if (!(await isAuthorizedCronRequest(req, secret))) {
1541
- return cronRouteJson({ ok: false, error: "Unauthorized" }, 401, headers);
1519
+ return operationalErrorJson("UNAUTHORIZED", "Unauthorized", 401, headers);
1542
1520
  }
1543
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
+
1544
1528
  let ctx: Ctx;
1545
1529
  try {
1546
1530
  ctx = await server.createRequestContext(toRequestLike(req));
1547
1531
  } catch (error) {
1548
1532
  console.error("Outbox drain context failed", { error });
1549
1533
 
1550
- return cronRouteJson(
1551
- {
1552
- ok: false,
1553
- error: "Outbox drain failed.",
1554
- },
1534
+ return operationalErrorJson(
1535
+ "OUTBOX_DRAIN_FAILED",
1536
+ "Outbox drain failed.",
1555
1537
  500,
1556
1538
  headers,
1557
1539
  );
@@ -1600,11 +1582,9 @@ export function createWebhookRoute<
1600
1582
  try {
1601
1583
  rawBody = await req.text();
1602
1584
  } catch {
1603
- return webhookRouteJson(
1604
- {
1605
- ok: false,
1606
- error: "Webhook body read failed.",
1607
- },
1585
+ return operationalErrorJson(
1586
+ "WEBHOOK_BODY_READ_FAILED",
1587
+ "Webhook body read failed.",
1608
1588
  400,
1609
1589
  headers,
1610
1590
  );
@@ -1650,11 +1630,9 @@ export function createWebhookRoute<
1650
1630
  traceId: ctx.traceId,
1651
1631
  });
1652
1632
 
1653
- return webhookRouteJson(
1654
- {
1655
- ok: false,
1656
- error: "Webhook verification failed.",
1657
- },
1633
+ return operationalErrorJson(
1634
+ "WEBHOOK_VERIFICATION_FAILED",
1635
+ "Webhook verification failed.",
1658
1636
  400,
1659
1637
  headers,
1660
1638
  );
@@ -1699,11 +1677,9 @@ export function createWebhookRoute<
1699
1677
  eventType: event.type,
1700
1678
  });
1701
1679
 
1702
- return webhookRouteJson(
1703
- {
1704
- ok: false,
1705
- error: "Webhook handler failed.",
1706
- },
1680
+ return operationalErrorJson(
1681
+ "WEBHOOK_HANDLER_FAILED",
1682
+ "Webhook handler failed.",
1707
1683
  500,
1708
1684
  headers,
1709
1685
  );
@@ -1735,11 +1711,9 @@ export function createWebhookRoute<
1735
1711
  try {
1736
1712
  rawBody = await req.text();
1737
1713
  } catch {
1738
- return webhookRouteJson(
1739
- {
1740
- ok: false,
1741
- error: "Webhook body read failed.",
1742
- },
1714
+ return operationalErrorJson(
1715
+ "WEBHOOK_BODY_READ_FAILED",
1716
+ "Webhook body read failed.",
1743
1717
  400,
1744
1718
  headers,
1745
1719
  );
@@ -1751,11 +1725,9 @@ export function createWebhookRoute<
1751
1725
  try {
1752
1726
  ctx = await server.createRequestContext(contextRequest);
1753
1727
  } catch {
1754
- return webhookRouteJson(
1755
- {
1756
- ok: false,
1757
- error: "Webhook context failed.",
1758
- },
1728
+ return operationalErrorJson(
1729
+ "WEBHOOK_CONTEXT_FAILED",
1730
+ "Webhook context failed.",
1759
1731
  500,
1760
1732
  headers,
1761
1733
  );
@@ -1797,11 +1769,9 @@ export function createPaymentWebhookRoute<
1797
1769
  const signature = new Headers(req.headers).get(signatureHeader);
1798
1770
 
1799
1771
  if (!signature) {
1800
- return paymentWebhookJson(
1801
- {
1802
- ok: false,
1803
- error: `Missing ${signatureHeader} header.`,
1804
- },
1772
+ return operationalErrorJson(
1773
+ "PAYMENT_WEBHOOK_SIGNATURE_MISSING",
1774
+ `Missing ${signatureHeader} header.`,
1805
1775
  400,
1806
1776
  headers,
1807
1777
  );
@@ -1812,11 +1782,9 @@ export function createPaymentWebhookRoute<
1812
1782
  try {
1813
1783
  rawBody = await req.text();
1814
1784
  } catch {
1815
- return paymentWebhookJson(
1816
- {
1817
- ok: false,
1818
- error: "Payment webhook body read failed.",
1819
- },
1785
+ return operationalErrorJson(
1786
+ "PAYMENT_WEBHOOK_BODY_READ_FAILED",
1787
+ "Payment webhook body read failed.",
1820
1788
  400,
1821
1789
  headers,
1822
1790
  );
@@ -1836,11 +1804,9 @@ export function createPaymentWebhookRoute<
1836
1804
  traceId: ctx.traceId,
1837
1805
  });
1838
1806
 
1839
- return paymentWebhookJson(
1840
- {
1841
- ok: false,
1842
- error: "Payment webhook verification failed.",
1843
- },
1807
+ return operationalErrorJson(
1808
+ "PAYMENT_WEBHOOK_VERIFICATION_FAILED",
1809
+ "Payment webhook verification failed.",
1844
1810
  400,
1845
1811
  headers,
1846
1812
  );
@@ -1883,11 +1849,9 @@ export function createPaymentWebhookRoute<
1883
1849
  eventType: event.type,
1884
1850
  });
1885
1851
 
1886
- return paymentWebhookJson(
1887
- {
1888
- ok: false,
1889
- error: "Payment webhook handler failed.",
1890
- },
1852
+ return operationalErrorJson(
1853
+ "PAYMENT_WEBHOOK_HANDLER_FAILED",
1854
+ "Payment webhook handler failed.",
1891
1855
  500,
1892
1856
  headers,
1893
1857
  );
@@ -1917,11 +1881,9 @@ export function createPaymentWebhookRoute<
1917
1881
  const headers = resolveHeaders(options.headers, req);
1918
1882
 
1919
1883
  if (!req.headers.get(signatureHeader)) {
1920
- return paymentWebhookJson(
1921
- {
1922
- ok: false,
1923
- error: `Missing ${signatureHeader} header.`,
1924
- },
1884
+ return operationalErrorJson(
1885
+ "PAYMENT_WEBHOOK_SIGNATURE_MISSING",
1886
+ `Missing ${signatureHeader} header.`,
1925
1887
  400,
1926
1888
  headers,
1927
1889
  );
@@ -1931,11 +1893,9 @@ export function createPaymentWebhookRoute<
1931
1893
  try {
1932
1894
  rawBody = await req.text();
1933
1895
  } catch {
1934
- return paymentWebhookJson(
1935
- {
1936
- ok: false,
1937
- error: "Payment webhook body read failed.",
1938
- },
1896
+ return operationalErrorJson(
1897
+ "PAYMENT_WEBHOOK_BODY_READ_FAILED",
1898
+ "Payment webhook body read failed.",
1939
1899
  400,
1940
1900
  headers,
1941
1901
  );
@@ -1945,11 +1905,9 @@ export function createPaymentWebhookRoute<
1945
1905
  try {
1946
1906
  ctx = await server.createRequestContext(toContextRequest(req, rawBody));
1947
1907
  } catch {
1948
- return paymentWebhookJson(
1949
- {
1950
- ok: false,
1951
- error: "Payment webhook context failed.",
1952
- },
1908
+ return operationalErrorJson(
1909
+ "PAYMENT_WEBHOOK_CONTEXT_FAILED",
1910
+ "Payment webhook context failed.",
1953
1911
  500,
1954
1912
  headers,
1955
1913
  );
@@ -2001,28 +1959,11 @@ export function createScheduleRoute<Ctx extends ScheduleRouteContext>(
2001
1959
  }): Promise<Response> => {
2002
1960
  const nativeReq = nativeRequestOf(req);
2003
1961
  const headers = resolveHeaders(options.headers, nativeReq);
2004
- const secret = options.secret;
2005
-
2006
- if (!secret) {
2007
- return cronRouteJson(
2008
- {
2009
- ok: false,
2010
- error: "CRON_SECRET is not configured.",
2011
- scheduleName: schedule.name,
2012
- },
2013
- 500,
2014
- headers,
2015
- );
2016
- }
2017
-
2018
- if (!(await isAuthorizedCronRequest(nativeReq, secret))) {
2019
- return cronRouteJson({ ok: false, error: "Unauthorized" }, 401, headers);
2020
- }
2021
1962
 
2022
1963
  try {
2023
1964
  const runner = createInlineScheduleRunner<Ctx>({
2024
1965
  ctx,
2025
- instrumentation: resolveProviderInstrumentationPort(ctx.ports),
1966
+ instrumentation: ctx.ports,
2026
1967
  instrumentationContext: {
2027
1968
  requestId: ctx.requestId,
2028
1969
  traceId: ctx.traceId,
@@ -2039,7 +1980,7 @@ export function createScheduleRoute<Ctx extends ScheduleRouteContext>(
2039
1980
  source: options.source ?? "next-cron-route",
2040
1981
  });
2041
1982
 
2042
- return cronRouteJson(
1983
+ return routeJson(
2043
1984
  {
2044
1985
  ok: true,
2045
1986
  scheduleName: schedule.name,
@@ -2048,14 +1989,12 @@ export function createScheduleRoute<Ctx extends ScheduleRouteContext>(
2048
1989
  headers,
2049
1990
  );
2050
1991
  } catch {
2051
- return cronRouteJson(
2052
- {
2053
- ok: false,
2054
- error: "Schedule failed.",
2055
- scheduleName: schedule.name,
2056
- },
1992
+ return operationalErrorJson(
1993
+ "SCHEDULE_FAILED",
1994
+ "Schedule failed.",
2057
1995
  500,
2058
1996
  headers,
1997
+ { scheduleName: schedule.name },
2059
1998
  );
2060
1999
  }
2061
2000
  };
@@ -2077,46 +2016,39 @@ export function createScheduleRoute<Ctx extends ScheduleRouteContext>(
2077
2016
  };
2078
2017
 
2079
2018
  const runScheduleFromRequest = async (req: Request): Promise<Response> => {
2080
- const server = await resolveServerSource(options.server);
2081
-
2082
- const runner =
2083
- pipelineRunners[req.method.toUpperCase() === "GET" ? "GET" : "POST"];
2084
- const pipelined = runner(server);
2085
- if (pipelined) return pipelined(req);
2086
-
2087
- // Minimal servers without rawRoute(...) — usually test fakes — keep the
2088
- // original flow: authorize before touching context, then run inline.
2089
2019
  const headers = resolveHeaders(options.headers, req);
2090
2020
  const secret = options.secret;
2091
2021
 
2092
2022
  if (!secret) {
2093
- return cronRouteJson(
2094
- {
2095
- ok: false,
2096
- error: "CRON_SECRET is not configured.",
2097
- scheduleName: schedule.name,
2098
- },
2023
+ return operationalErrorJson(
2024
+ "CRON_SECRET_NOT_CONFIGURED",
2025
+ "CRON_SECRET is not configured.",
2099
2026
  500,
2100
2027
  headers,
2028
+ { scheduleName: schedule.name },
2101
2029
  );
2102
2030
  }
2103
2031
 
2104
2032
  if (!(await isAuthorizedCronRequest(req, secret))) {
2105
- return cronRouteJson({ ok: false, error: "Unauthorized" }, 401, headers);
2033
+ return operationalErrorJson("UNAUTHORIZED", "Unauthorized", 401, headers);
2106
2034
  }
2107
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
+
2108
2042
  let ctx: Ctx;
2109
2043
  try {
2110
2044
  ctx = await server.createRequestContext(toRequestLike(req));
2111
2045
  } catch {
2112
- return cronRouteJson(
2113
- {
2114
- ok: false,
2115
- error: "Schedule failed.",
2116
- scheduleName: schedule.name,
2117
- },
2046
+ return operationalErrorJson(
2047
+ "SCHEDULE_FAILED",
2048
+ "Schedule failed.",
2118
2049
  500,
2119
2050
  headers,
2051
+ { scheduleName: schedule.name },
2120
2052
  );
2121
2053
  }
2122
2054