@kya-os/checkpoint-nextjs 1.0.0

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.
Files changed (122) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/EDGE_RUNTIME_WASM_SETUP.md +348 -0
  3. package/README.md +414 -0
  4. package/bin/setup-edge-wasm.js +497 -0
  5. package/dist/.tsbuildinfo +1 -0
  6. package/dist/adapt.d.mts +39 -0
  7. package/dist/adapt.d.ts +39 -0
  8. package/dist/adapt.js +58 -0
  9. package/dist/adapt.js.map +1 -0
  10. package/dist/adapt.mjs +56 -0
  11. package/dist/adapt.mjs.map +1 -0
  12. package/dist/api-client.d.mts +204 -0
  13. package/dist/api-client.d.ts +204 -0
  14. package/dist/api-client.js +206 -0
  15. package/dist/api-client.js.map +1 -0
  16. package/dist/api-client.mjs +199 -0
  17. package/dist/api-client.mjs.map +1 -0
  18. package/dist/api-middleware.d.mts +156 -0
  19. package/dist/api-middleware.d.ts +156 -0
  20. package/dist/api-middleware.js +510 -0
  21. package/dist/api-middleware.js.map +1 -0
  22. package/dist/api-middleware.mjs +505 -0
  23. package/dist/api-middleware.mjs.map +1 -0
  24. package/dist/create-middleware.d.mts +17 -0
  25. package/dist/create-middleware.d.ts +17 -0
  26. package/dist/create-middleware.js +38 -0
  27. package/dist/create-middleware.js.map +1 -0
  28. package/dist/create-middleware.mjs +35 -0
  29. package/dist/create-middleware.mjs.map +1 -0
  30. package/dist/edge/index.d.mts +110 -0
  31. package/dist/edge/index.d.ts +110 -0
  32. package/dist/edge/index.js +277 -0
  33. package/dist/edge/index.js.map +1 -0
  34. package/dist/edge/index.mjs +275 -0
  35. package/dist/edge/index.mjs.map +1 -0
  36. package/dist/edge-runtime-loader.d.mts +50 -0
  37. package/dist/edge-runtime-loader.d.ts +50 -0
  38. package/dist/edge-runtime-loader.js +204 -0
  39. package/dist/edge-runtime-loader.js.map +1 -0
  40. package/dist/edge-runtime-loader.mjs +201 -0
  41. package/dist/edge-runtime-loader.mjs.map +1 -0
  42. package/dist/edge-wasm-middleware.d.mts +68 -0
  43. package/dist/edge-wasm-middleware.d.ts +68 -0
  44. package/dist/edge-wasm-middleware.js +318 -0
  45. package/dist/edge-wasm-middleware.js.map +1 -0
  46. package/dist/edge-wasm-middleware.mjs +315 -0
  47. package/dist/edge-wasm-middleware.mjs.map +1 -0
  48. package/dist/index.d.mts +25 -0
  49. package/dist/index.d.ts +25 -0
  50. package/dist/index.js +1019 -0
  51. package/dist/index.js.map +1 -0
  52. package/dist/index.mjs +979 -0
  53. package/dist/index.mjs.map +1 -0
  54. package/dist/middleware-edge.d.mts +46 -0
  55. package/dist/middleware-edge.d.ts +46 -0
  56. package/dist/middleware-edge.js +134 -0
  57. package/dist/middleware-edge.js.map +1 -0
  58. package/dist/middleware-edge.mjs +129 -0
  59. package/dist/middleware-edge.mjs.map +1 -0
  60. package/dist/middleware-node.d.mts +89 -0
  61. package/dist/middleware-node.d.ts +89 -0
  62. package/dist/middleware-node.js +127 -0
  63. package/dist/middleware-node.js.map +1 -0
  64. package/dist/middleware-node.mjs +124 -0
  65. package/dist/middleware-node.mjs.map +1 -0
  66. package/dist/middleware.d.mts +36 -0
  67. package/dist/middleware.d.ts +36 -0
  68. package/dist/middleware.js +15 -0
  69. package/dist/middleware.js.map +1 -0
  70. package/dist/middleware.mjs +12 -0
  71. package/dist/middleware.mjs.map +1 -0
  72. package/dist/nodejs-wasm-loader.d.mts +25 -0
  73. package/dist/nodejs-wasm-loader.d.ts +25 -0
  74. package/dist/nodejs-wasm-loader.js +95 -0
  75. package/dist/nodejs-wasm-loader.js.map +1 -0
  76. package/dist/nodejs-wasm-loader.mjs +85 -0
  77. package/dist/nodejs-wasm-loader.mjs.map +1 -0
  78. package/dist/policy.d.mts +162 -0
  79. package/dist/policy.d.ts +162 -0
  80. package/dist/policy.js +189 -0
  81. package/dist/policy.js.map +1 -0
  82. package/dist/policy.mjs +165 -0
  83. package/dist/policy.mjs.map +1 -0
  84. package/dist/session-tracker.d.mts +55 -0
  85. package/dist/session-tracker.d.ts +55 -0
  86. package/dist/session-tracker.js +170 -0
  87. package/dist/session-tracker.js.map +1 -0
  88. package/dist/session-tracker.mjs +167 -0
  89. package/dist/session-tracker.mjs.map +1 -0
  90. package/dist/signature-verifier.d.mts +33 -0
  91. package/dist/signature-verifier.d.ts +33 -0
  92. package/dist/signature-verifier.js +386 -0
  93. package/dist/signature-verifier.js.map +1 -0
  94. package/dist/signature-verifier.mjs +362 -0
  95. package/dist/signature-verifier.mjs.map +1 -0
  96. package/dist/translate.d.mts +33 -0
  97. package/dist/translate.d.ts +33 -0
  98. package/dist/translate.js +38 -0
  99. package/dist/translate.js.map +1 -0
  100. package/dist/translate.mjs +36 -0
  101. package/dist/translate.mjs.map +1 -0
  102. package/dist/types-C-xCUNTr.d.mts +105 -0
  103. package/dist/types-C-xCUNTr.d.ts +105 -0
  104. package/dist/wasm-middleware.d.mts +63 -0
  105. package/dist/wasm-middleware.d.ts +63 -0
  106. package/dist/wasm-middleware.js +98 -0
  107. package/dist/wasm-middleware.js.map +1 -0
  108. package/dist/wasm-middleware.mjs +95 -0
  109. package/dist/wasm-middleware.mjs.map +1 -0
  110. package/dist/wasm-setup.d.mts +46 -0
  111. package/dist/wasm-setup.d.ts +46 -0
  112. package/dist/wasm-setup.js +176 -0
  113. package/dist/wasm-setup.js.map +1 -0
  114. package/dist/wasm-setup.mjs +167 -0
  115. package/dist/wasm-setup.mjs.map +1 -0
  116. package/package.json +156 -0
  117. package/templates/middleware-wasm-100.ts +153 -0
  118. package/wasm/agentshield_wasm.d.ts +479 -0
  119. package/wasm/agentshield_wasm.js +1536 -0
  120. package/wasm/agentshield_wasm_bg.wasm +0 -0
  121. package/wasm/package.json +30 -0
  122. package/wasm.d.ts +21 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapt.ts"],"names":["acceptsHtml","encodeVerdictCookie","classifyResponseShape","NextResponse","BLOCKED_PATH","VERDICT_COOKIE_NAME"],"mappings":";;;;;;AA4CO,SAAS,mBAAA,CAAoB,UAA4B,GAAA,EAAgC;AAC9F,EAAA,MAAM,iBAAA,GAAoBA,4BAAA,CAAY,GAAA,CAAI,OAAO,CAAA;AACjD,EAAA,MAAM,aAAA,GAAgBC,qCAAoB,QAAQ,CAAA;AAClD,EAAA,MAAM,KAAA,GAAQC,sCAAA,CAAsB,QAAA,EAAU,iBAAiB,CAAA;AAE/D,EAAA,QAAQ,KAAA;AAAO,IACb,KAAK,cAAA,EAAgB;AAEnB,MAAA,MAAM,GAAA,GAAMC,oBAAa,IAAA,EAAK;AAC9B,MAAA,YAAA,CAAa,GAAA,EAAK,SAAS,OAAO,CAAA;AAClC,MAAA,gBAAA,CAAiB,KAAK,aAAa,CAAA;AACnC,MAAA,OAAO,GAAA;AAAA,IACT;AAAA,IAEA,KAAK,UAAA,EAAY;AAEf,MAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,QAAA,CAAS,QAAQ,QAAS,CAAA;AACjD,MAAA,MAAM,GAAA,GAAMA,mBAAA,CAAa,QAAA,CAAS,MAAM,CAAA;AACxC,MAAA,YAAA,CAAa,GAAA,EAAK,SAAS,OAAO,CAAA;AAClC,MAAA,gBAAA,CAAiB,KAAK,aAAa,CAAA;AACnC,MAAA,OAAO,GAAA;AAAA,IACT;AAAA,IAEA,KAAK,YAAA,EAAc;AAIjB,MAAA,MAAM,UAAA,GAAa,IAAI,GAAA,CAAIC,6BAAA,EAAc,IAAI,GAAG,CAAA;AAChD,MAAA,MAAM,MAAMD,mBAAA,CAAa,OAAA,CAAQ,YAAY,EAAE,MAAA,EAAQ,KAAK,CAAA;AAC5D,MAAA,YAAA,CAAa,GAAA,EAAK,SAAS,OAAO,CAAA;AAClC,MAAA,gBAAA,CAAiB,KAAK,aAAa,CAAA;AACnC,MAAA,OAAO,GAAA;AAAA,IACT;AAAA,IAEA,KAAK,YAAA,EAAc;AAKjB,MAAA,MAAM,IAAA,GAAO,QAAA,CAAS,IAAA,IAAQ,EAAC;AAC/B,MAAA,MAAM,GAAA,GAAMA,oBAAa,IAAA,CAAK,IAAA,EAAM,EAAE,MAAA,EAAQ,QAAA,CAAS,QAAkB,CAAA;AACzE,MAAA,YAAA,CAAa,GAAA,EAAK,SAAS,OAAO,CAAA;AAClC,MAAA,gBAAA,CAAiB,KAAK,aAAa,CAAA;AACnC,MAAA,OAAO,GAAA;AAAA,IACT;AAAA;AAEJ;AAUA,SAAS,gBAAA,CAAiB,KAAmB,KAAA,EAAqB;AAKhE,EAAA,GAAA,CAAI,QAAQ,GAAA,CAAI;AAAA,IACd,IAAA,EAAME,oCAAA;AAAA,IACN,KAAA;AAAA,IACA,IAAA,EAAM,GAAA;AAAA,IACN,QAAA,EAAU,KAAA;AAAA,IACV,QAAA,EAAU;AAAA,GACX,CAAA;AACH;AAEA,SAAS,YAAA,CAAa,KAAmB,OAAA,EAAuC;AAI9E,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAA,EAAG;AAClD,IAAA,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,GAAA,EAAK,KAAK,CAAA;AAAA,EAC5B;AACF","file":"adapt.js","sourcesContent":["/**\n * D.3 — `RenderedResponse` → `NextResponse` adapter.\n *\n * The host wrapper's *only* job on the outbound path: take the\n * transport-agnostic `RenderedResponse` Phase C's\n * `renderDecisionAsResponse` produces and translate it to a\n * `NextResponse`. Zero verdict decisions, zero engine I/O.\n *\n * Shared between the Node-runtime and Edge-runtime entries. The\n * branching here is identical in both — Next.js `NextResponse` has the\n * same API surface across runtimes; only the underlying response\n * primitive differs (Node http.ServerResponse vs Edge `Response`).\n *\n * Architectural pins per architect § 4.3 / § 4.4:\n *\n * 1. **Verdict-cookie format is contract.** Sites-1's Sonner toast\n * depends on `__checkpoint_verdict=%7B%22verdict%22%3A%22<v>%22...\n * %7D` (single URL-encoded JSON). Byte-format pinned by adapt.test.\n *\n * 2. **HTML-accepting clients → `/blocked` rewrite at status 200**\n * (so the page renders with the verdict cookie set; Sonner picks\n * up the cookie and shows the toast). Non-HTML clients → JSON 4xx.\n *\n * 3. **`X-Checkpoint-Engine` carries `result.engineInfo.name`** —\n * `checkpoint-engine-wasm` after Phase D ships. Brian's Sites-2\n * deviation note confirmed the `X-Checkpoint-*` prefix is canon.\n */\n\nimport { type NextRequest, NextResponse } from 'next/server';\n\nimport type { RenderedResponse } from '@kya-os/checkpoint-wasm-runtime/orchestrator';\nimport {\n VERDICT_COOKIE_NAME,\n BLOCKED_PATH,\n encodeVerdictCookie,\n acceptsHtml,\n classifyResponseShape,\n} from '@kya-os/checkpoint-shared';\n\n/**\n * Convert the engine's transport-agnostic `RenderedResponse` into a\n * `NextResponse`. Sites-1's Playwright suite is the regression gate;\n * any drift here is caught downstream.\n */\nexport function adaptToNextResponse(rendered: RenderedResponse, req: NextRequest): NextResponse {\n const clientAcceptsHtml = acceptsHtml(req.headers);\n const verdictCookie = encodeVerdictCookie(rendered);\n const shape = classifyResponseShape(rendered, clientAcceptsHtml);\n\n switch (shape) {\n case 'pass-through': {\n // Permit OR Observe-mode any-verdict.\n const res = NextResponse.next();\n applyHeaders(res, rendered.headers);\n setVerdictCookie(res, verdictCookie);\n return res;\n }\n\n case 'redirect': {\n // Decision::Redirect → 302 + Location.\n const target = new URL(rendered.headers.Location!);\n const res = NextResponse.redirect(target);\n applyHeaders(res, rendered.headers);\n setVerdictCookie(res, verdictCookie);\n return res;\n }\n\n case 'html-block': {\n // Sites-1 contract: HTML clients (browsers) need a renderable page\n // to show the rejection UI. The verdict cookie carries the reason;\n // the /blocked route reads it and renders the toast.\n const blockedUrl = new URL(BLOCKED_PATH, req.url);\n const res = NextResponse.rewrite(blockedUrl, { status: 200 });\n applyHeaders(res, rendered.headers);\n setVerdictCookie(res, verdictCookie);\n return res;\n }\n\n case 'json-block': {\n // The orchestrator's RenderedResponse already supplies the correct\n // status (401/403/422/...); we just need to materialise the body.\n // application/problem+json (Instruct) uses the Content-Type from\n // rendered.headers; defaults to application/json for everything else.\n const body = rendered.body ?? {};\n const res = NextResponse.json(body, { status: rendered.status as number });\n applyHeaders(res, rendered.headers);\n setVerdictCookie(res, verdictCookie);\n return res;\n }\n }\n}\n\n// -----------------------------------------------------------------------------\n// Helpers — Next.js-specific glue. The framework-agnostic primitives\n// (encodeVerdictCookie, acceptsHtml, classifyResponseShape,\n// VERDICT_COOKIE_NAME, BLOCKED_PATH) live in `@kya-os/checkpoint-shared`\n// so checkpoint-express + future host wrappers produce byte-identical\n// cookies and route HTML/JSON branching the same way.\n// -----------------------------------------------------------------------------\n\nfunction setVerdictCookie(res: NextResponse, value: string): void {\n // Path / SameSite / HttpOnly chosen for the Sonner-bridge use case:\n // path=/ so any route can read it, SameSite=Lax so first-party\n // navigations carry it, HttpOnly=false so the client-side toast JS\n // can read it (it's verdict UX, not a session token).\n res.cookies.set({\n name: VERDICT_COOKIE_NAME,\n value,\n path: '/',\n sameSite: 'lax',\n httpOnly: false,\n });\n}\n\nfunction applyHeaders(res: NextResponse, headers: Record<string, string>): void {\n // NextResponse.next() / rewrite() / json() return responses with\n // some default headers; orchestrator headers (X-Checkpoint-*, Location)\n // override. We don't strip pre-existing headers — only set new ones.\n for (const [key, value] of Object.entries(headers)) {\n res.headers.set(key, value);\n }\n}\n"]}
package/dist/adapt.mjs ADDED
@@ -0,0 +1,56 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { acceptsHtml, encodeVerdictCookie, classifyResponseShape, BLOCKED_PATH, VERDICT_COOKIE_NAME } from '@kya-os/checkpoint-shared';
3
+
4
+ // src/adapt.ts
5
+ function adaptToNextResponse(rendered, req) {
6
+ const clientAcceptsHtml = acceptsHtml(req.headers);
7
+ const verdictCookie = encodeVerdictCookie(rendered);
8
+ const shape = classifyResponseShape(rendered, clientAcceptsHtml);
9
+ switch (shape) {
10
+ case "pass-through": {
11
+ const res = NextResponse.next();
12
+ applyHeaders(res, rendered.headers);
13
+ setVerdictCookie(res, verdictCookie);
14
+ return res;
15
+ }
16
+ case "redirect": {
17
+ const target = new URL(rendered.headers.Location);
18
+ const res = NextResponse.redirect(target);
19
+ applyHeaders(res, rendered.headers);
20
+ setVerdictCookie(res, verdictCookie);
21
+ return res;
22
+ }
23
+ case "html-block": {
24
+ const blockedUrl = new URL(BLOCKED_PATH, req.url);
25
+ const res = NextResponse.rewrite(blockedUrl, { status: 200 });
26
+ applyHeaders(res, rendered.headers);
27
+ setVerdictCookie(res, verdictCookie);
28
+ return res;
29
+ }
30
+ case "json-block": {
31
+ const body = rendered.body ?? {};
32
+ const res = NextResponse.json(body, { status: rendered.status });
33
+ applyHeaders(res, rendered.headers);
34
+ setVerdictCookie(res, verdictCookie);
35
+ return res;
36
+ }
37
+ }
38
+ }
39
+ function setVerdictCookie(res, value) {
40
+ res.cookies.set({
41
+ name: VERDICT_COOKIE_NAME,
42
+ value,
43
+ path: "/",
44
+ sameSite: "lax",
45
+ httpOnly: false
46
+ });
47
+ }
48
+ function applyHeaders(res, headers) {
49
+ for (const [key, value] of Object.entries(headers)) {
50
+ res.headers.set(key, value);
51
+ }
52
+ }
53
+
54
+ export { adaptToNextResponse };
55
+ //# sourceMappingURL=adapt.mjs.map
56
+ //# sourceMappingURL=adapt.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapt.ts"],"names":[],"mappings":";;;;AA4CO,SAAS,mBAAA,CAAoB,UAA4B,GAAA,EAAgC;AAC9F,EAAA,MAAM,iBAAA,GAAoB,WAAA,CAAY,GAAA,CAAI,OAAO,CAAA;AACjD,EAAA,MAAM,aAAA,GAAgB,oBAAoB,QAAQ,CAAA;AAClD,EAAA,MAAM,KAAA,GAAQ,qBAAA,CAAsB,QAAA,EAAU,iBAAiB,CAAA;AAE/D,EAAA,QAAQ,KAAA;AAAO,IACb,KAAK,cAAA,EAAgB;AAEnB,MAAA,MAAM,GAAA,GAAM,aAAa,IAAA,EAAK;AAC9B,MAAA,YAAA,CAAa,GAAA,EAAK,SAAS,OAAO,CAAA;AAClC,MAAA,gBAAA,CAAiB,KAAK,aAAa,CAAA;AACnC,MAAA,OAAO,GAAA;AAAA,IACT;AAAA,IAEA,KAAK,UAAA,EAAY;AAEf,MAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,QAAA,CAAS,QAAQ,QAAS,CAAA;AACjD,MAAA,MAAM,GAAA,GAAM,YAAA,CAAa,QAAA,CAAS,MAAM,CAAA;AACxC,MAAA,YAAA,CAAa,GAAA,EAAK,SAAS,OAAO,CAAA;AAClC,MAAA,gBAAA,CAAiB,KAAK,aAAa,CAAA;AACnC,MAAA,OAAO,GAAA;AAAA,IACT;AAAA,IAEA,KAAK,YAAA,EAAc;AAIjB,MAAA,MAAM,UAAA,GAAa,IAAI,GAAA,CAAI,YAAA,EAAc,IAAI,GAAG,CAAA;AAChD,MAAA,MAAM,MAAM,YAAA,CAAa,OAAA,CAAQ,YAAY,EAAE,MAAA,EAAQ,KAAK,CAAA;AAC5D,MAAA,YAAA,CAAa,GAAA,EAAK,SAAS,OAAO,CAAA;AAClC,MAAA,gBAAA,CAAiB,KAAK,aAAa,CAAA;AACnC,MAAA,OAAO,GAAA;AAAA,IACT;AAAA,IAEA,KAAK,YAAA,EAAc;AAKjB,MAAA,MAAM,IAAA,GAAO,QAAA,CAAS,IAAA,IAAQ,EAAC;AAC/B,MAAA,MAAM,GAAA,GAAM,aAAa,IAAA,CAAK,IAAA,EAAM,EAAE,MAAA,EAAQ,QAAA,CAAS,QAAkB,CAAA;AACzE,MAAA,YAAA,CAAa,GAAA,EAAK,SAAS,OAAO,CAAA;AAClC,MAAA,gBAAA,CAAiB,KAAK,aAAa,CAAA;AACnC,MAAA,OAAO,GAAA;AAAA,IACT;AAAA;AAEJ;AAUA,SAAS,gBAAA,CAAiB,KAAmB,KAAA,EAAqB;AAKhE,EAAA,GAAA,CAAI,QAAQ,GAAA,CAAI;AAAA,IACd,IAAA,EAAM,mBAAA;AAAA,IACN,KAAA;AAAA,IACA,IAAA,EAAM,GAAA;AAAA,IACN,QAAA,EAAU,KAAA;AAAA,IACV,QAAA,EAAU;AAAA,GACX,CAAA;AACH;AAEA,SAAS,YAAA,CAAa,KAAmB,OAAA,EAAuC;AAI9E,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAA,EAAG;AAClD,IAAA,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,GAAA,EAAK,KAAK,CAAA;AAAA,EAC5B;AACF","file":"adapt.mjs","sourcesContent":["/**\n * D.3 — `RenderedResponse` → `NextResponse` adapter.\n *\n * The host wrapper's *only* job on the outbound path: take the\n * transport-agnostic `RenderedResponse` Phase C's\n * `renderDecisionAsResponse` produces and translate it to a\n * `NextResponse`. Zero verdict decisions, zero engine I/O.\n *\n * Shared between the Node-runtime and Edge-runtime entries. The\n * branching here is identical in both — Next.js `NextResponse` has the\n * same API surface across runtimes; only the underlying response\n * primitive differs (Node http.ServerResponse vs Edge `Response`).\n *\n * Architectural pins per architect § 4.3 / § 4.4:\n *\n * 1. **Verdict-cookie format is contract.** Sites-1's Sonner toast\n * depends on `__checkpoint_verdict=%7B%22verdict%22%3A%22<v>%22...\n * %7D` (single URL-encoded JSON). Byte-format pinned by adapt.test.\n *\n * 2. **HTML-accepting clients → `/blocked` rewrite at status 200**\n * (so the page renders with the verdict cookie set; Sonner picks\n * up the cookie and shows the toast). Non-HTML clients → JSON 4xx.\n *\n * 3. **`X-Checkpoint-Engine` carries `result.engineInfo.name`** —\n * `checkpoint-engine-wasm` after Phase D ships. Brian's Sites-2\n * deviation note confirmed the `X-Checkpoint-*` prefix is canon.\n */\n\nimport { type NextRequest, NextResponse } from 'next/server';\n\nimport type { RenderedResponse } from '@kya-os/checkpoint-wasm-runtime/orchestrator';\nimport {\n VERDICT_COOKIE_NAME,\n BLOCKED_PATH,\n encodeVerdictCookie,\n acceptsHtml,\n classifyResponseShape,\n} from '@kya-os/checkpoint-shared';\n\n/**\n * Convert the engine's transport-agnostic `RenderedResponse` into a\n * `NextResponse`. Sites-1's Playwright suite is the regression gate;\n * any drift here is caught downstream.\n */\nexport function adaptToNextResponse(rendered: RenderedResponse, req: NextRequest): NextResponse {\n const clientAcceptsHtml = acceptsHtml(req.headers);\n const verdictCookie = encodeVerdictCookie(rendered);\n const shape = classifyResponseShape(rendered, clientAcceptsHtml);\n\n switch (shape) {\n case 'pass-through': {\n // Permit OR Observe-mode any-verdict.\n const res = NextResponse.next();\n applyHeaders(res, rendered.headers);\n setVerdictCookie(res, verdictCookie);\n return res;\n }\n\n case 'redirect': {\n // Decision::Redirect → 302 + Location.\n const target = new URL(rendered.headers.Location!);\n const res = NextResponse.redirect(target);\n applyHeaders(res, rendered.headers);\n setVerdictCookie(res, verdictCookie);\n return res;\n }\n\n case 'html-block': {\n // Sites-1 contract: HTML clients (browsers) need a renderable page\n // to show the rejection UI. The verdict cookie carries the reason;\n // the /blocked route reads it and renders the toast.\n const blockedUrl = new URL(BLOCKED_PATH, req.url);\n const res = NextResponse.rewrite(blockedUrl, { status: 200 });\n applyHeaders(res, rendered.headers);\n setVerdictCookie(res, verdictCookie);\n return res;\n }\n\n case 'json-block': {\n // The orchestrator's RenderedResponse already supplies the correct\n // status (401/403/422/...); we just need to materialise the body.\n // application/problem+json (Instruct) uses the Content-Type from\n // rendered.headers; defaults to application/json for everything else.\n const body = rendered.body ?? {};\n const res = NextResponse.json(body, { status: rendered.status as number });\n applyHeaders(res, rendered.headers);\n setVerdictCookie(res, verdictCookie);\n return res;\n }\n }\n}\n\n// -----------------------------------------------------------------------------\n// Helpers — Next.js-specific glue. The framework-agnostic primitives\n// (encodeVerdictCookie, acceptsHtml, classifyResponseShape,\n// VERDICT_COOKIE_NAME, BLOCKED_PATH) live in `@kya-os/checkpoint-shared`\n// so checkpoint-express + future host wrappers produce byte-identical\n// cookies and route HTML/JSON branching the same way.\n// -----------------------------------------------------------------------------\n\nfunction setVerdictCookie(res: NextResponse, value: string): void {\n // Path / SameSite / HttpOnly chosen for the Sonner-bridge use case:\n // path=/ so any route can read it, SameSite=Lax so first-party\n // navigations carry it, HttpOnly=false so the client-side toast JS\n // can read it (it's verdict UX, not a session token).\n res.cookies.set({\n name: VERDICT_COOKIE_NAME,\n value,\n path: '/',\n sameSite: 'lax',\n httpOnly: false,\n });\n}\n\nfunction applyHeaders(res: NextResponse, headers: Record<string, string>): void {\n // NextResponse.next() / rewrite() / json() return responses with\n // some default headers; orchestrator headers (X-Checkpoint-*, Location)\n // override. We don't strip pre-existing headers — only set new ones.\n for (const [key, value] of Object.entries(headers)) {\n res.headers.set(key, value);\n }\n}\n"]}
@@ -0,0 +1,204 @@
1
+ import { EnforcementAction } from '@kya-os/checkpoint-shared';
2
+ export { EnforcementAction } from '@kya-os/checkpoint-shared';
3
+
4
+ /**
5
+ * AgentShield API Client
6
+ *
7
+ * Lightweight client for calling the AgentShield enforce API from middleware.
8
+ * Designed for Edge Runtime compatibility (no Node.js-specific APIs).
9
+ */
10
+
11
+ /**
12
+ * API client configuration
13
+ */
14
+ interface CheckpointApiClientConfig {
15
+ /** API key for authentication */
16
+ apiKey: string;
17
+ /** API base URL (defaults to production) */
18
+ baseUrl?: string;
19
+ /**
20
+ * Use edge detection for lower latency (~30-50ms vs ~150ms) and better coverage.
21
+ * Edge detection can identify non-JS clients (curl, Python, Claude Code WebFetch)
22
+ * that the pixel cannot detect since they don't execute JavaScript.
23
+ * @default true
24
+ */
25
+ useEdge?: boolean;
26
+ /** Request timeout in milliseconds (default: 5000) */
27
+ timeout?: number;
28
+ /** Enable debug logging */
29
+ debug?: boolean;
30
+ }
31
+
32
+ /**
33
+ * Enforcement decision from the API
34
+ */
35
+ interface EnforcementDecision {
36
+ action: EnforcementAction;
37
+ reason: string;
38
+ isAgent: boolean;
39
+ confidence: number;
40
+ agentName?: string;
41
+ agentType?: string;
42
+ redirectUrl?: string;
43
+ message?: string;
44
+ metadata?: {
45
+ policyVersion?: string;
46
+ signatureVerified?: boolean;
47
+ denyListMatch?: {
48
+ clientDid?: string;
49
+ agentDid?: string;
50
+ clientName?: string;
51
+ reason?: string;
52
+ };
53
+ };
54
+ }
55
+ /**
56
+ * Detection result (optional in response)
57
+ */
58
+ interface DetectionResult {
59
+ isAgent: boolean;
60
+ confidence: number;
61
+ agentName?: string;
62
+ agentType?: string;
63
+ /** Detection class: 'human', 'ai_agent', 'bot', 'incomplete_data' */
64
+ detectionClass?: string;
65
+ verificationMethod?: string;
66
+ reasons?: string[];
67
+ /** Detection engine used: 'wasm' or 'javascript-fallback' */
68
+ detectionMethod?: string;
69
+ }
70
+ /**
71
+ * Enforce API response
72
+ */
73
+ interface EnforceResponse {
74
+ success: boolean;
75
+ data?: {
76
+ decision: EnforcementDecision;
77
+ processingTimeMs: number;
78
+ requestId: string;
79
+ detection?: DetectionResult;
80
+ };
81
+ error?: {
82
+ code: string;
83
+ message: string;
84
+ };
85
+ }
86
+ /**
87
+ * Request input for enforce API
88
+ */
89
+ interface EnforceInput {
90
+ /** HTTP headers from the incoming request */
91
+ headers?: Record<string, string>;
92
+ /** User-Agent header */
93
+ userAgent?: string;
94
+ /** Client IP address */
95
+ ipAddress?: string;
96
+ /** Request path */
97
+ path?: string;
98
+ /** Request URL */
99
+ url?: string;
100
+ /** HTTP method */
101
+ method?: string;
102
+ /** Request ID for tracing */
103
+ requestId?: string;
104
+ /** Options */
105
+ options?: {
106
+ /** Include full detection result */
107
+ includeDetectionResult?: boolean;
108
+ /** Cache TTL override */
109
+ cacheTTL?: number;
110
+ };
111
+ }
112
+ /**
113
+ * Input for logging a detection result
114
+ */
115
+ interface LogDetectionInput {
116
+ /** Detection result from Gateway */
117
+ detection: DetectionResult;
118
+ /** Request context */
119
+ context: {
120
+ userAgent?: string;
121
+ ipAddress?: string;
122
+ path?: string;
123
+ url?: string;
124
+ method?: string;
125
+ };
126
+ /** Source of the detection */
127
+ source?: 'gateway' | 'middleware';
128
+ }
129
+ /**
130
+ * AgentShield API Client
131
+ *
132
+ * @example
133
+ * ```typescript
134
+ * const client = new CheckpointApiClient({
135
+ * apiKey: process.env.CHECKPOINT_API_KEY!,
136
+ * });
137
+ *
138
+ * const result = await client.enforce({
139
+ * headers: Object.fromEntries(request.headers),
140
+ * path: request.nextUrl.pathname,
141
+ * method: request.method,
142
+ * });
143
+ *
144
+ * if (result.decision.action === 'block') {
145
+ * return new Response('Access denied', { status: 403 });
146
+ * }
147
+ * ```
148
+ */
149
+ declare class CheckpointApiClient {
150
+ private apiKey;
151
+ private baseUrl;
152
+ private useEdge;
153
+ private timeout;
154
+ private debug;
155
+ constructor(config: CheckpointApiClientConfig);
156
+ /**
157
+ * Call the enforce API to check if a request should be allowed
158
+ */
159
+ enforce(input: EnforceInput): Promise<EnforceResponse>;
160
+ /**
161
+ * Quick check - returns just the action without full response parsing
162
+ * Useful for very fast middleware that just needs allow/block
163
+ */
164
+ quickCheck(input: EnforceInput): Promise<{
165
+ action: EnforcementAction;
166
+ error?: string;
167
+ }>;
168
+ /**
169
+ * Check if this client is using edge detection (Gateway Worker)
170
+ */
171
+ isUsingEdge(): boolean;
172
+ /**
173
+ * Log a detection result to AgentShield database.
174
+ * Use after Gateway Worker detection to persist results.
175
+ * Fire-and-forget - returns immediately without waiting for DB write.
176
+ *
177
+ * @example
178
+ * ```typescript
179
+ * // After receiving Gateway response
180
+ * if (client.isUsingEdge() && response.data?.detection) {
181
+ * client.logDetection({
182
+ * detection: response.data.detection,
183
+ * context: { userAgent, ipAddress, path, url, method }
184
+ * }).catch(err => console.error('Log failed:', err));
185
+ * }
186
+ * ```
187
+ */
188
+ logDetection(input: LogDetectionInput): Promise<void>;
189
+ }
190
+ declare function getCheckpointApiClient(config?: Partial<CheckpointApiClientConfig>): CheckpointApiClient;
191
+ /**
192
+ * Reset the singleton client (useful for testing)
193
+ */
194
+ declare function resetCheckpointApiClient(): void;
195
+ /** @deprecated Renamed to {@link CheckpointApiClient}. The runtime is identical. */
196
+ declare const AgentShieldClient: typeof CheckpointApiClient;
197
+ /** @deprecated Renamed to {@link CheckpointApiClientConfig}. */
198
+ type AgentShieldClientConfig = CheckpointApiClientConfig;
199
+ /** @deprecated Renamed to {@link getCheckpointApiClient}. */
200
+ declare const getAgentShieldClient: typeof getCheckpointApiClient;
201
+ /** @deprecated Renamed to {@link resetCheckpointApiClient}. */
202
+ declare const resetAgentShieldClient: typeof resetCheckpointApiClient;
203
+
204
+ export { AgentShieldClient, type AgentShieldClientConfig, CheckpointApiClient, type CheckpointApiClientConfig, type DetectionResult, type EnforceInput, type EnforceResponse, type EnforcementDecision, type LogDetectionInput, getAgentShieldClient, getCheckpointApiClient, resetAgentShieldClient, resetCheckpointApiClient };
@@ -0,0 +1,204 @@
1
+ import { EnforcementAction } from '@kya-os/checkpoint-shared';
2
+ export { EnforcementAction } from '@kya-os/checkpoint-shared';
3
+
4
+ /**
5
+ * AgentShield API Client
6
+ *
7
+ * Lightweight client for calling the AgentShield enforce API from middleware.
8
+ * Designed for Edge Runtime compatibility (no Node.js-specific APIs).
9
+ */
10
+
11
+ /**
12
+ * API client configuration
13
+ */
14
+ interface CheckpointApiClientConfig {
15
+ /** API key for authentication */
16
+ apiKey: string;
17
+ /** API base URL (defaults to production) */
18
+ baseUrl?: string;
19
+ /**
20
+ * Use edge detection for lower latency (~30-50ms vs ~150ms) and better coverage.
21
+ * Edge detection can identify non-JS clients (curl, Python, Claude Code WebFetch)
22
+ * that the pixel cannot detect since they don't execute JavaScript.
23
+ * @default true
24
+ */
25
+ useEdge?: boolean;
26
+ /** Request timeout in milliseconds (default: 5000) */
27
+ timeout?: number;
28
+ /** Enable debug logging */
29
+ debug?: boolean;
30
+ }
31
+
32
+ /**
33
+ * Enforcement decision from the API
34
+ */
35
+ interface EnforcementDecision {
36
+ action: EnforcementAction;
37
+ reason: string;
38
+ isAgent: boolean;
39
+ confidence: number;
40
+ agentName?: string;
41
+ agentType?: string;
42
+ redirectUrl?: string;
43
+ message?: string;
44
+ metadata?: {
45
+ policyVersion?: string;
46
+ signatureVerified?: boolean;
47
+ denyListMatch?: {
48
+ clientDid?: string;
49
+ agentDid?: string;
50
+ clientName?: string;
51
+ reason?: string;
52
+ };
53
+ };
54
+ }
55
+ /**
56
+ * Detection result (optional in response)
57
+ */
58
+ interface DetectionResult {
59
+ isAgent: boolean;
60
+ confidence: number;
61
+ agentName?: string;
62
+ agentType?: string;
63
+ /** Detection class: 'human', 'ai_agent', 'bot', 'incomplete_data' */
64
+ detectionClass?: string;
65
+ verificationMethod?: string;
66
+ reasons?: string[];
67
+ /** Detection engine used: 'wasm' or 'javascript-fallback' */
68
+ detectionMethod?: string;
69
+ }
70
+ /**
71
+ * Enforce API response
72
+ */
73
+ interface EnforceResponse {
74
+ success: boolean;
75
+ data?: {
76
+ decision: EnforcementDecision;
77
+ processingTimeMs: number;
78
+ requestId: string;
79
+ detection?: DetectionResult;
80
+ };
81
+ error?: {
82
+ code: string;
83
+ message: string;
84
+ };
85
+ }
86
+ /**
87
+ * Request input for enforce API
88
+ */
89
+ interface EnforceInput {
90
+ /** HTTP headers from the incoming request */
91
+ headers?: Record<string, string>;
92
+ /** User-Agent header */
93
+ userAgent?: string;
94
+ /** Client IP address */
95
+ ipAddress?: string;
96
+ /** Request path */
97
+ path?: string;
98
+ /** Request URL */
99
+ url?: string;
100
+ /** HTTP method */
101
+ method?: string;
102
+ /** Request ID for tracing */
103
+ requestId?: string;
104
+ /** Options */
105
+ options?: {
106
+ /** Include full detection result */
107
+ includeDetectionResult?: boolean;
108
+ /** Cache TTL override */
109
+ cacheTTL?: number;
110
+ };
111
+ }
112
+ /**
113
+ * Input for logging a detection result
114
+ */
115
+ interface LogDetectionInput {
116
+ /** Detection result from Gateway */
117
+ detection: DetectionResult;
118
+ /** Request context */
119
+ context: {
120
+ userAgent?: string;
121
+ ipAddress?: string;
122
+ path?: string;
123
+ url?: string;
124
+ method?: string;
125
+ };
126
+ /** Source of the detection */
127
+ source?: 'gateway' | 'middleware';
128
+ }
129
+ /**
130
+ * AgentShield API Client
131
+ *
132
+ * @example
133
+ * ```typescript
134
+ * const client = new CheckpointApiClient({
135
+ * apiKey: process.env.CHECKPOINT_API_KEY!,
136
+ * });
137
+ *
138
+ * const result = await client.enforce({
139
+ * headers: Object.fromEntries(request.headers),
140
+ * path: request.nextUrl.pathname,
141
+ * method: request.method,
142
+ * });
143
+ *
144
+ * if (result.decision.action === 'block') {
145
+ * return new Response('Access denied', { status: 403 });
146
+ * }
147
+ * ```
148
+ */
149
+ declare class CheckpointApiClient {
150
+ private apiKey;
151
+ private baseUrl;
152
+ private useEdge;
153
+ private timeout;
154
+ private debug;
155
+ constructor(config: CheckpointApiClientConfig);
156
+ /**
157
+ * Call the enforce API to check if a request should be allowed
158
+ */
159
+ enforce(input: EnforceInput): Promise<EnforceResponse>;
160
+ /**
161
+ * Quick check - returns just the action without full response parsing
162
+ * Useful for very fast middleware that just needs allow/block
163
+ */
164
+ quickCheck(input: EnforceInput): Promise<{
165
+ action: EnforcementAction;
166
+ error?: string;
167
+ }>;
168
+ /**
169
+ * Check if this client is using edge detection (Gateway Worker)
170
+ */
171
+ isUsingEdge(): boolean;
172
+ /**
173
+ * Log a detection result to AgentShield database.
174
+ * Use after Gateway Worker detection to persist results.
175
+ * Fire-and-forget - returns immediately without waiting for DB write.
176
+ *
177
+ * @example
178
+ * ```typescript
179
+ * // After receiving Gateway response
180
+ * if (client.isUsingEdge() && response.data?.detection) {
181
+ * client.logDetection({
182
+ * detection: response.data.detection,
183
+ * context: { userAgent, ipAddress, path, url, method }
184
+ * }).catch(err => console.error('Log failed:', err));
185
+ * }
186
+ * ```
187
+ */
188
+ logDetection(input: LogDetectionInput): Promise<void>;
189
+ }
190
+ declare function getCheckpointApiClient(config?: Partial<CheckpointApiClientConfig>): CheckpointApiClient;
191
+ /**
192
+ * Reset the singleton client (useful for testing)
193
+ */
194
+ declare function resetCheckpointApiClient(): void;
195
+ /** @deprecated Renamed to {@link CheckpointApiClient}. The runtime is identical. */
196
+ declare const AgentShieldClient: typeof CheckpointApiClient;
197
+ /** @deprecated Renamed to {@link CheckpointApiClientConfig}. */
198
+ type AgentShieldClientConfig = CheckpointApiClientConfig;
199
+ /** @deprecated Renamed to {@link getCheckpointApiClient}. */
200
+ declare const getAgentShieldClient: typeof getCheckpointApiClient;
201
+ /** @deprecated Renamed to {@link resetCheckpointApiClient}. */
202
+ declare const resetAgentShieldClient: typeof resetCheckpointApiClient;
203
+
204
+ export { AgentShieldClient, type AgentShieldClientConfig, CheckpointApiClient, type CheckpointApiClientConfig, type DetectionResult, type EnforceInput, type EnforceResponse, type EnforcementDecision, type LogDetectionInput, getAgentShieldClient, getCheckpointApiClient, resetAgentShieldClient, resetCheckpointApiClient };