@xtandard/webhooks 0.1.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.
- package/LICENSE +21 -0
- package/README.md +315 -0
- package/bin/xtandard-webhooks.mjs +3 -0
- package/dist/basic-BIW3Rvuz.cjs +199 -0
- package/dist/basic-BIW3Rvuz.cjs.map +1 -0
- package/dist/basic-DKk0Xfuu.mjs +176 -0
- package/dist/basic-DKk0Xfuu.mjs.map +1 -0
- package/dist/chunk-D7D4PA-g.mjs +13 -0
- package/dist/cli.cjs +655 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +42 -0
- package/dist/cli.d.mts +42 -0
- package/dist/cli.mjs +653 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/contract-8h-Azxa5.d.cts +71 -0
- package/dist/contract-9XpcwcCn.mjs +22 -0
- package/dist/contract-9XpcwcCn.mjs.map +1 -0
- package/dist/contract-B2d5dNU3.cjs +33 -0
- package/dist/contract-B2d5dNU3.cjs.map +1 -0
- package/dist/contract-BEhDcd_5.mjs +28 -0
- package/dist/contract-BEhDcd_5.mjs.map +1 -0
- package/dist/contract-Bf1qguwt.cjs +57 -0
- package/dist/contract-Bf1qguwt.cjs.map +1 -0
- package/dist/contract-Bnb3fgRJ.d.cts +177 -0
- package/dist/contract-C2r2Xzwp.d.mts +46 -0
- package/dist/contract-CiPskNvS.d.cts +46 -0
- package/dist/contract-DhQ4JjGG.d.mts +71 -0
- package/dist/contract-T1kcZNdG.d.mts +177 -0
- package/dist/contract-lETlIuXo.d.cts +30 -0
- package/dist/contract-lETlIuXo.d.mts +30 -0
- package/dist/core-CMpnmI5Q.mjs +1605 -0
- package/dist/core-CMpnmI5Q.mjs.map +1 -0
- package/dist/core-DT4ppWh8.d.mts +502 -0
- package/dist/core-KJawHjFF.d.cts +502 -0
- package/dist/core-ZGhH6Vs2.cjs +1790 -0
- package/dist/core-ZGhH6Vs2.cjs.map +1 -0
- package/dist/core.cjs +8 -0
- package/dist/core.d.cts +2 -0
- package/dist/core.d.mts +2 -0
- package/dist/core.mjs +2 -0
- package/dist/create-fetch-handler-BIdk9P30.mjs +1724 -0
- package/dist/create-fetch-handler-BIdk9P30.mjs.map +1 -0
- package/dist/create-fetch-handler-CmooujQo.cjs +1771 -0
- package/dist/create-fetch-handler-CmooujQo.cjs.map +1 -0
- package/dist/create-fetch-handler-Dlkhustu.d.cts +162 -0
- package/dist/create-fetch-handler-jy3hy5nZ.d.mts +162 -0
- package/dist/dispatcher-B0xTEHt1.cjs +212 -0
- package/dist/dispatcher-B0xTEHt1.cjs.map +1 -0
- package/dist/dispatcher-Coubwrka.mjs +196 -0
- package/dist/dispatcher-Coubwrka.mjs.map +1 -0
- package/dist/entry-auth-basic.cjs +5 -0
- package/dist/entry-auth-basic.d.cts +83 -0
- package/dist/entry-auth-basic.d.mts +83 -0
- package/dist/entry-auth-basic.mjs +2 -0
- package/dist/entry-auth-delegated.cjs +28 -0
- package/dist/entry-auth-delegated.cjs.map +1 -0
- package/dist/entry-auth-delegated.d.cts +36 -0
- package/dist/entry-auth-delegated.d.mts +36 -0
- package/dist/entry-auth-delegated.mjs +27 -0
- package/dist/entry-auth-delegated.mjs.map +1 -0
- package/dist/entry-auth-none.cjs +4 -0
- package/dist/entry-auth-none.d.cts +25 -0
- package/dist/entry-auth-none.d.mts +25 -0
- package/dist/entry-auth-none.mjs +2 -0
- package/dist/entry-authorization-delegated.cjs +27 -0
- package/dist/entry-authorization-delegated.cjs.map +1 -0
- package/dist/entry-authorization-delegated.d.cts +31 -0
- package/dist/entry-authorization-delegated.d.mts +31 -0
- package/dist/entry-authorization-delegated.mjs +26 -0
- package/dist/entry-authorization-delegated.mjs.map +1 -0
- package/dist/entry-authorization-none.cjs +3 -0
- package/dist/entry-authorization-none.d.cts +18 -0
- package/dist/entry-authorization-none.d.mts +18 -0
- package/dist/entry-authorization-none.mjs +2 -0
- package/dist/entry-authorization-roles.cjs +6 -0
- package/dist/entry-authorization-roles.d.cts +65 -0
- package/dist/entry-authorization-roles.d.mts +65 -0
- package/dist/entry-authorization-roles.mjs +2 -0
- package/dist/entry-bun.cjs +24 -0
- package/dist/entry-bun.cjs.map +1 -0
- package/dist/entry-bun.d.cts +8 -0
- package/dist/entry-bun.d.mts +8 -0
- package/dist/entry-bun.mjs +23 -0
- package/dist/entry-bun.mjs.map +1 -0
- package/dist/entry-drizzle-mysql.cjs +20 -0
- package/dist/entry-drizzle-mysql.cjs.map +1 -0
- package/dist/entry-drizzle-mysql.d.cts +27 -0
- package/dist/entry-drizzle-mysql.d.mts +27 -0
- package/dist/entry-drizzle-mysql.mjs +19 -0
- package/dist/entry-drizzle-mysql.mjs.map +1 -0
- package/dist/entry-drizzle-pg.cjs +21 -0
- package/dist/entry-drizzle-pg.cjs.map +1 -0
- package/dist/entry-drizzle-pg.d.cts +26 -0
- package/dist/entry-drizzle-pg.d.mts +26 -0
- package/dist/entry-drizzle-pg.mjs +20 -0
- package/dist/entry-drizzle-pg.mjs.map +1 -0
- package/dist/entry-drizzle-sqlite.cjs +21 -0
- package/dist/entry-drizzle-sqlite.cjs.map +1 -0
- package/dist/entry-drizzle-sqlite.d.cts +23 -0
- package/dist/entry-drizzle-sqlite.d.mts +23 -0
- package/dist/entry-drizzle-sqlite.mjs +20 -0
- package/dist/entry-drizzle-sqlite.mjs.map +1 -0
- package/dist/entry-elysia.cjs +125 -0
- package/dist/entry-elysia.cjs.map +1 -0
- package/dist/entry-elysia.d.cts +1017 -0
- package/dist/entry-elysia.d.mts +1017 -0
- package/dist/entry-elysia.mjs +123 -0
- package/dist/entry-elysia.mjs.map +1 -0
- package/dist/entry-express.cjs +57 -0
- package/dist/entry-express.cjs.map +1 -0
- package/dist/entry-express.d.cts +15 -0
- package/dist/entry-express.d.mts +15 -0
- package/dist/entry-express.mjs +56 -0
- package/dist/entry-express.mjs.map +1 -0
- package/dist/entry-hono.cjs +35 -0
- package/dist/entry-hono.cjs.map +1 -0
- package/dist/entry-hono.d.cts +16 -0
- package/dist/entry-hono.d.mts +16 -0
- package/dist/entry-hono.mjs +34 -0
- package/dist/entry-hono.mjs.map +1 -0
- package/dist/entry-hooks-log.cjs +22 -0
- package/dist/entry-hooks-log.cjs.map +1 -0
- package/dist/entry-hooks-log.d.cts +23 -0
- package/dist/entry-hooks-log.d.mts +23 -0
- package/dist/entry-hooks-log.mjs +21 -0
- package/dist/entry-hooks-log.mjs.map +1 -0
- package/dist/entry-storage-cloudflare-kv.cjs +47 -0
- package/dist/entry-storage-cloudflare-kv.cjs.map +1 -0
- package/dist/entry-storage-cloudflare-kv.d.cts +42 -0
- package/dist/entry-storage-cloudflare-kv.d.mts +42 -0
- package/dist/entry-storage-cloudflare-kv.mjs +46 -0
- package/dist/entry-storage-cloudflare-kv.mjs.map +1 -0
- package/dist/entry-storage-drizzle.cjs +78 -0
- package/dist/entry-storage-drizzle.cjs.map +1 -0
- package/dist/entry-storage-drizzle.d.cts +30 -0
- package/dist/entry-storage-drizzle.d.mts +30 -0
- package/dist/entry-storage-drizzle.mjs +77 -0
- package/dist/entry-storage-drizzle.mjs.map +1 -0
- package/dist/entry-storage-file.cjs +4 -0
- package/dist/entry-storage-file.d.cts +30 -0
- package/dist/entry-storage-file.d.mts +30 -0
- package/dist/entry-storage-file.mjs +2 -0
- package/dist/entry-storage-libsql.cjs +3 -0
- package/dist/entry-storage-libsql.d.cts +48 -0
- package/dist/entry-storage-libsql.d.mts +48 -0
- package/dist/entry-storage-libsql.mjs +2 -0
- package/dist/entry-storage-memory.cjs +3 -0
- package/dist/entry-storage-memory.d.cts +2 -0
- package/dist/entry-storage-memory.d.mts +2 -0
- package/dist/entry-storage-memory.mjs +2 -0
- package/dist/entry-storage-mongodb.cjs +3 -0
- package/dist/entry-storage-mongodb.d.cts +55 -0
- package/dist/entry-storage-mongodb.d.mts +55 -0
- package/dist/entry-storage-mongodb.mjs +2 -0
- package/dist/entry-storage-postgres.cjs +3 -0
- package/dist/entry-storage-postgres.d.cts +62 -0
- package/dist/entry-storage-postgres.d.mts +62 -0
- package/dist/entry-storage-postgres.mjs +2 -0
- package/dist/entry-storage-redis.cjs +4 -0
- package/dist/entry-storage-redis.d.cts +77 -0
- package/dist/entry-storage-redis.d.mts +77 -0
- package/dist/entry-storage-redis.mjs +2 -0
- package/dist/entry-storage-sqlite.cjs +3 -0
- package/dist/entry-storage-sqlite.d.cts +36 -0
- package/dist/entry-storage-sqlite.d.mts +36 -0
- package/dist/entry-storage-sqlite.mjs +2 -0
- package/dist/entry-storage-unstorage.cjs +42 -0
- package/dist/entry-storage-unstorage.cjs.map +1 -0
- package/dist/entry-storage-unstorage.d.cts +29 -0
- package/dist/entry-storage-unstorage.d.mts +29 -0
- package/dist/entry-storage-unstorage.mjs +41 -0
- package/dist/entry-storage-unstorage.mjs.map +1 -0
- package/dist/file-COBYZA4Q.cjs +148 -0
- package/dist/file-COBYZA4Q.cjs.map +1 -0
- package/dist/file-fi02eFHk.mjs +131 -0
- package/dist/file-fi02eFHk.mjs.map +1 -0
- package/dist/index.cjs +123 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +368 -0
- package/dist/index.d.mts +366 -0
- package/dist/index.mjs +61 -0
- package/dist/index.mjs.map +1 -0
- package/dist/keys-Byyj4quQ.mjs +111 -0
- package/dist/keys-Byyj4quQ.mjs.map +1 -0
- package/dist/keys-FiKpaVHX.cjs +302 -0
- package/dist/keys-FiKpaVHX.cjs.map +1 -0
- package/dist/libsql-bpVi0bXN.mjs +113 -0
- package/dist/libsql-bpVi0bXN.mjs.map +1 -0
- package/dist/libsql-pPJEo1e4.cjs +124 -0
- package/dist/libsql-pPJEo1e4.cjs.map +1 -0
- package/dist/memory-8Ef-PL5a.cjs +137 -0
- package/dist/memory-8Ef-PL5a.cjs.map +1 -0
- package/dist/memory-BMsSSwqn.mjs +127 -0
- package/dist/memory-BMsSSwqn.mjs.map +1 -0
- package/dist/memory-FnMJWCmB.d.cts +28 -0
- package/dist/memory-qIvANEs_.d.mts +28 -0
- package/dist/mongodb-Cy8yo0uk.cjs +108 -0
- package/dist/mongodb-Cy8yo0uk.cjs.map +1 -0
- package/dist/mongodb-Ddaq9mml.mjs +97 -0
- package/dist/mongodb-Ddaq9mml.mjs.map +1 -0
- package/dist/none-BnZtaGNJ.mjs +23 -0
- package/dist/none-BnZtaGNJ.mjs.map +1 -0
- package/dist/none-CAsxCOWN.cjs +49 -0
- package/dist/none-CAsxCOWN.cjs.map +1 -0
- package/dist/none-CZVrfnmF.cjs +33 -0
- package/dist/none-CZVrfnmF.cjs.map +1 -0
- package/dist/none-GhVIoh_s.mjs +33 -0
- package/dist/none-GhVIoh_s.mjs.map +1 -0
- package/dist/postgres-C8WbchFa.cjs +134 -0
- package/dist/postgres-C8WbchFa.cjs.map +1 -0
- package/dist/postgres-c3pAhmhr.mjs +123 -0
- package/dist/postgres-c3pAhmhr.mjs.map +1 -0
- package/dist/react.css +1 -0
- package/dist/react.js +31465 -0
- package/dist/receiver.cjs +43 -0
- package/dist/receiver.cjs.map +1 -0
- package/dist/receiver.d.cts +36 -0
- package/dist/receiver.d.mts +36 -0
- package/dist/receiver.mjs +40 -0
- package/dist/receiver.mjs.map +1 -0
- package/dist/redis-CFJkuSgB.cjs +270 -0
- package/dist/redis-CFJkuSgB.cjs.map +1 -0
- package/dist/redis-CvLi0KF7.mjs +254 -0
- package/dist/redis-CvLi0KF7.mjs.map +1 -0
- package/dist/roles-D0G9XqBq.cjs +128 -0
- package/dist/roles-D0G9XqBq.cjs.map +1 -0
- package/dist/roles-vp361lTk.mjs +99 -0
- package/dist/roles-vp361lTk.mjs.map +1 -0
- package/dist/schema-mo__wv4P.d.cts +233 -0
- package/dist/schema-mo__wv4P.d.mts +233 -0
- package/dist/schema.cjs +13 -0
- package/dist/schema.cjs.map +1 -0
- package/dist/schema.d.cts +2 -0
- package/dist/schema.d.mts +2 -0
- package/dist/schema.mjs +11 -0
- package/dist/schema.mjs.map +1 -0
- package/dist/signing.cjs +162 -0
- package/dist/signing.cjs.map +1 -0
- package/dist/signing.d.cts +73 -0
- package/dist/signing.d.mts +73 -0
- package/dist/signing.mjs +156 -0
- package/dist/signing.mjs.map +1 -0
- package/dist/sqlite-Cmqnrjes.mjs +67 -0
- package/dist/sqlite-Cmqnrjes.mjs.map +1 -0
- package/dist/sqlite-Dcufk0x3.cjs +78 -0
- package/dist/sqlite-Dcufk0x3.cjs.map +1 -0
- package/dist/table-Ce3Tzwqs.d.cts +11 -0
- package/dist/table-Ce3Tzwqs.d.mts +11 -0
- package/dist/testing.cjs +134 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +80 -0
- package/dist/testing.d.mts +80 -0
- package/dist/testing.mjs +131 -0
- package/dist/testing.mjs.map +1 -0
- package/dist/types-react/react.d.ts +98 -0
- package/dist/types-react/schema.d.ts +229 -0
- package/dist/types-react/ui/App.d.ts +22 -0
- package/dist/types-react/ui/api.d.ts +97 -0
- package/dist/types-react/ui/components/JsonCodeEditor.d.ts +12 -0
- package/dist/types-react/ui/components/ThemeToggle.d.ts +2 -0
- package/dist/types-react/ui/components/Toast.d.ts +16 -0
- package/dist/types-react/ui/components/primitives.d.ts +50 -0
- package/dist/types-react/ui/components/ui-bits.d.ts +22 -0
- package/dist/types-react/ui/components/webhook-bits.d.ts +51 -0
- package/dist/types-react/ui/lib/format.d.ts +39 -0
- package/dist/types-react/ui/lib/nav-guard.d.ts +20 -0
- package/dist/types-react/ui/lib/utils.d.ts +3 -0
- package/dist/types-react/ui/theme.d.ts +12 -0
- package/dist/types-react/ui/types.d.ts +80 -0
- package/dist/types-react/ui/views/AuditView.d.ts +6 -0
- package/dist/types-react/ui/views/DeliveriesView.d.ts +12 -0
- package/dist/types-react/ui/views/EndpointsView.d.ts +11 -0
- package/dist/types-react/ui/views/EventTypesView.d.ts +11 -0
- package/dist/types-react/ui/views/MessagesView.d.ts +10 -0
- package/dist/types-react/ui/views/OverviewView.d.ts +12 -0
- package/dist/ui/assets/index-B0eoQX2U.css +1 -0
- package/dist/ui/assets/index-S5t_CLOe.js +209 -0
- package/dist/ui/index.html +14 -0
- package/package.json +487 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
//#region src/auth/none.ts
|
|
2
|
+
var none_exports = /* @__PURE__ */ require("./keys-FiKpaVHX.cjs").__exportAll({
|
|
3
|
+
ANONYMOUS_PRINCIPAL: () => ANONYMOUS_PRINCIPAL,
|
|
4
|
+
noAuth: () => noAuth
|
|
5
|
+
});
|
|
6
|
+
/** The fixed principal returned by {@link noAuth}. */
|
|
7
|
+
const ANONYMOUS_PRINCIPAL = { id: "anonymous" };
|
|
8
|
+
/**
|
|
9
|
+
* Create an {@link AuthProvider} that performs no authentication and resolves
|
|
10
|
+
* every request to the shared {@link ANONYMOUS_PRINCIPAL}.
|
|
11
|
+
*
|
|
12
|
+
* Because it never returns `null`, the request is always "authenticated" — use
|
|
13
|
+
* an {@link AuthorizationProvider} to control what the anonymous principal may
|
|
14
|
+
* actually do.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { noAuth } from "@xtandard/webhooks/auth/none";
|
|
19
|
+
*
|
|
20
|
+
* const auth = noAuth();
|
|
21
|
+
* await auth.authenticate(request); // → { id: "anonymous" }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
function noAuth() {
|
|
25
|
+
return { async authenticate(_request) {
|
|
26
|
+
return ANONYMOUS_PRINCIPAL;
|
|
27
|
+
} };
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
Object.defineProperty(exports, "ANONYMOUS_PRINCIPAL", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
get: function() {
|
|
33
|
+
return ANONYMOUS_PRINCIPAL;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
Object.defineProperty(exports, "noAuth", {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
get: function() {
|
|
39
|
+
return noAuth;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
Object.defineProperty(exports, "none_exports", {
|
|
43
|
+
enumerable: true,
|
|
44
|
+
get: function() {
|
|
45
|
+
return none_exports;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
//# sourceMappingURL=none-CAsxCOWN.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"none-CAsxCOWN.cjs","names":[],"sources":["../src/auth/none.ts"],"sourcesContent":["/**\n * The \"no authentication\" {@link AuthProvider}. Treats every request as a single\n * anonymous principal.\n *\n * This does **not** mean \"reject everyone\" — it means the server performs no\n * credential checks at all. A fixed `{ id: \"anonymous\" }` principal is returned\n * for every request so that downstream {@link AuthorizationProvider authorization}\n * can still run (and, for example, deny mutating actions in readonly mode).\n *\n * Suitable for embedded usage, local development, or deployments fronted by an\n * external auth layer (a gateway, mTLS, a VPN, etc.). Pair it with\n * `noAuthorization()` to allow everything, or with `rolesAuthorization()` to\n * still gate actions.\n *\n * @module\n */\n\nimport type { AuthProvider, Principal } from \"./contract.ts\";\n\n/** The fixed principal returned by {@link noAuth}. */\nexport const ANONYMOUS_PRINCIPAL: Principal = { id: \"anonymous\" };\n\n/**\n * Create an {@link AuthProvider} that performs no authentication and resolves\n * every request to the shared {@link ANONYMOUS_PRINCIPAL}.\n *\n * Because it never returns `null`, the request is always \"authenticated\" — use\n * an {@link AuthorizationProvider} to control what the anonymous principal may\n * actually do.\n *\n * @example\n * ```ts\n * import { noAuth } from \"@xtandard/webhooks/auth/none\";\n *\n * const auth = noAuth();\n * await auth.authenticate(request); // → { id: \"anonymous\" }\n * ```\n */\nexport function noAuth(): AuthProvider {\n return {\n async authenticate(_request: Request): Promise<Principal | null> {\n return ANONYMOUS_PRINCIPAL;\n },\n };\n}\n"],"mappings":";;;;;;AAoBA,MAAa,sBAAiC,EAAE,IAAI,YAAY;;;;;;;;;;;;;;;;;AAkBhE,SAAgB,SAAuB;CACrC,OAAO,EACL,MAAM,aAAa,UAA8C;EAC/D,OAAO;CACT,EACF;AACF"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/authorization/none.ts
|
|
2
|
+
var none_exports = /* @__PURE__ */ require("./keys-FiKpaVHX.cjs").__exportAll({ noAuthorization: () => noAuthorization });
|
|
3
|
+
/**
|
|
4
|
+
* Create an {@link AuthorizationProvider} that authorizes everything.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { noAuthorization } from "@xtandard/webhooks/authorization/none";
|
|
9
|
+
*
|
|
10
|
+
* const authz = noAuthorization();
|
|
11
|
+
* await authz.authorize(input); // → true, always
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
function noAuthorization() {
|
|
15
|
+
return { async authorize(_input) {
|
|
16
|
+
return true;
|
|
17
|
+
} };
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
Object.defineProperty(exports, "noAuthorization", {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
get: function() {
|
|
23
|
+
return noAuthorization;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
Object.defineProperty(exports, "none_exports", {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
get: function() {
|
|
29
|
+
return none_exports;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=none-CZVrfnmF.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"none-CZVrfnmF.cjs","names":[],"sources":["../src/authorization/none.ts"],"sourcesContent":["/**\n * The \"no authorization\" {@link AuthorizationProvider}. Every action is allowed.\n *\n * This grants unconditional access regardless of the principal (even `null`) or\n * the action/resource. It is the right choice for embedded usage and local\n * development where the admin API is not exposed to untrusted callers — commonly\n * paired with `noAuth()`.\n *\n * Do **not** use it for a network-exposed admin surface; reach for\n * `rolesAuthorization()` (or a delegated provider) instead.\n *\n * @module\n */\n\nimport type { AuthorizationProvider, AuthorizeInput } from \"./contract.ts\";\n\n/**\n * Create an {@link AuthorizationProvider} that authorizes everything.\n *\n * @example\n * ```ts\n * import { noAuthorization } from \"@xtandard/webhooks/authorization/none\";\n *\n * const authz = noAuthorization();\n * await authz.authorize(input); // → true, always\n * ```\n */\nexport function noAuthorization(): AuthorizationProvider {\n return {\n async authorize(_input: AuthorizeInput): Promise<boolean> {\n return true;\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;AA2BA,SAAgB,kBAAyC;CACvD,OAAO,EACL,MAAM,UAAU,QAA0C;EACxD,OAAO;CACT,EACF;AACF"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-D7D4PA-g.mjs";
|
|
2
|
+
//#region src/auth/none.ts
|
|
3
|
+
var none_exports = /* @__PURE__ */ __exportAll({
|
|
4
|
+
ANONYMOUS_PRINCIPAL: () => ANONYMOUS_PRINCIPAL,
|
|
5
|
+
noAuth: () => noAuth
|
|
6
|
+
});
|
|
7
|
+
/** The fixed principal returned by {@link noAuth}. */
|
|
8
|
+
const ANONYMOUS_PRINCIPAL = { id: "anonymous" };
|
|
9
|
+
/**
|
|
10
|
+
* Create an {@link AuthProvider} that performs no authentication and resolves
|
|
11
|
+
* every request to the shared {@link ANONYMOUS_PRINCIPAL}.
|
|
12
|
+
*
|
|
13
|
+
* Because it never returns `null`, the request is always "authenticated" — use
|
|
14
|
+
* an {@link AuthorizationProvider} to control what the anonymous principal may
|
|
15
|
+
* actually do.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { noAuth } from "@xtandard/webhooks/auth/none";
|
|
20
|
+
*
|
|
21
|
+
* const auth = noAuth();
|
|
22
|
+
* await auth.authenticate(request); // → { id: "anonymous" }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
function noAuth() {
|
|
26
|
+
return { async authenticate(_request) {
|
|
27
|
+
return ANONYMOUS_PRINCIPAL;
|
|
28
|
+
} };
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { noAuth as n, none_exports as r, ANONYMOUS_PRINCIPAL as t };
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=none-GhVIoh_s.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"none-GhVIoh_s.mjs","names":[],"sources":["../src/auth/none.ts"],"sourcesContent":["/**\n * The \"no authentication\" {@link AuthProvider}. Treats every request as a single\n * anonymous principal.\n *\n * This does **not** mean \"reject everyone\" — it means the server performs no\n * credential checks at all. A fixed `{ id: \"anonymous\" }` principal is returned\n * for every request so that downstream {@link AuthorizationProvider authorization}\n * can still run (and, for example, deny mutating actions in readonly mode).\n *\n * Suitable for embedded usage, local development, or deployments fronted by an\n * external auth layer (a gateway, mTLS, a VPN, etc.). Pair it with\n * `noAuthorization()` to allow everything, or with `rolesAuthorization()` to\n * still gate actions.\n *\n * @module\n */\n\nimport type { AuthProvider, Principal } from \"./contract.ts\";\n\n/** The fixed principal returned by {@link noAuth}. */\nexport const ANONYMOUS_PRINCIPAL: Principal = { id: \"anonymous\" };\n\n/**\n * Create an {@link AuthProvider} that performs no authentication and resolves\n * every request to the shared {@link ANONYMOUS_PRINCIPAL}.\n *\n * Because it never returns `null`, the request is always \"authenticated\" — use\n * an {@link AuthorizationProvider} to control what the anonymous principal may\n * actually do.\n *\n * @example\n * ```ts\n * import { noAuth } from \"@xtandard/webhooks/auth/none\";\n *\n * const auth = noAuth();\n * await auth.authenticate(request); // → { id: \"anonymous\" }\n * ```\n */\nexport function noAuth(): AuthProvider {\n return {\n async authenticate(_request: Request): Promise<Principal | null> {\n return ANONYMOUS_PRINCIPAL;\n },\n };\n}\n"],"mappings":";;;;;;;AAoBA,MAAa,sBAAiC,EAAE,IAAI,YAAY;;;;;;;;;;;;;;;;;AAkBhE,SAAgB,SAAuB;CACrC,OAAO,EACL,MAAM,aAAa,UAA8C;EAC/D,OAAO;CACT,EACF;AACF"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
const require_keys = require("./keys-FiKpaVHX.cjs");
|
|
2
|
+
const require_contract = require("./contract-Bf1qguwt.cjs");
|
|
3
|
+
//#region src/storage/postgres.ts
|
|
4
|
+
/**
|
|
5
|
+
* Postgres storage adapter backed by a single key/value table
|
|
6
|
+
* (`key text PRIMARY KEY, value jsonb`). It works with any client exposing a
|
|
7
|
+
* `query(text, params?)` method that resolves to `{ rows }` — this covers
|
|
8
|
+
* [`pg`](https://github.com/brianc/node-postgres) (`Pool`/`Client`) and the
|
|
9
|
+
* in-process [`@electric-sql/pglite`](https://github.com/electric-sql/pglite)
|
|
10
|
+
* alike. You can pass a pre-built `client`, or a `connectionString`/`url` to
|
|
11
|
+
* lazily create a `pg` `Pool` on first use.
|
|
12
|
+
*
|
|
13
|
+
* The table is created on demand (`CREATE TABLE IF NOT EXISTS`) the first time
|
|
14
|
+
* any operation runs, guarded by a single promise so concurrent callers only
|
|
15
|
+
* issue the DDL once. Values are stored as `jsonb`; both `pg` and `pglite`
|
|
16
|
+
* return `jsonb` already parsed to JS, but a string is JSON-parsed defensively
|
|
17
|
+
* so either driver works.
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
var postgres_exports = /* @__PURE__ */ require_keys.__exportAll({ createPostgresStorage: () => createPostgresStorage });
|
|
22
|
+
/** Identifiers we are willing to interpolate into DDL/queries unquoted. */
|
|
23
|
+
const SAFE_IDENTIFIER = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
24
|
+
/**
|
|
25
|
+
* Escape LIKE wildcards (`%`, `_`) and the escape char itself in a literal
|
|
26
|
+
* prefix so `getKeys` matches the prefix verbatim. Paired with `ESCAPE '\'`.
|
|
27
|
+
*/
|
|
28
|
+
const escapeLike = (literal) => literal.replace(/[\\%_]/g, (c) => `\\${c}`);
|
|
29
|
+
/**
|
|
30
|
+
* Create a Postgres-backed {@link PostgresWebhooksStorage}. The table is created
|
|
31
|
+
* lazily on first use; connection (when using `connectionString`/`url`) is also
|
|
32
|
+
* lazy — the `pg` `Pool` is imported and constructed on the first operation and
|
|
33
|
+
* reused thereafter.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { createPostgresStorage } from "@xtandard/webhooks/storage/postgres";
|
|
38
|
+
*
|
|
39
|
+
* // Via connection string (lazy `pg` Pool):
|
|
40
|
+
* const storage = createPostgresStorage({
|
|
41
|
+
* connectionString: process.env.DATABASE_URL,
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
* // Or with a pre-built pg Pool / PGlite client:
|
|
45
|
+
* // import { PGlite } from "@electric-sql/pglite";
|
|
46
|
+
* // const storage = createPostgresStorage({ client: new PGlite() });
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
function createPostgresStorage(options) {
|
|
50
|
+
const table = options.table ?? "xtandard_webhooks";
|
|
51
|
+
if (!SAFE_IDENTIFIER.test(table)) throw new Error(`Invalid table name ${JSON.stringify(table)}: must match ${SAFE_IDENTIFIER.source}`);
|
|
52
|
+
const connectionString = options.connectionString ?? options.url;
|
|
53
|
+
const ownsClient = !options.client;
|
|
54
|
+
let client = options.client;
|
|
55
|
+
let connecting;
|
|
56
|
+
let ensured;
|
|
57
|
+
/** Resolve a client, creating a `pg` `Pool` on first use when needed. */
|
|
58
|
+
async function getClient() {
|
|
59
|
+
if (client) return client;
|
|
60
|
+
connecting ??= (async () => {
|
|
61
|
+
let Pool;
|
|
62
|
+
try {
|
|
63
|
+
({Pool} = await import("pg"));
|
|
64
|
+
} catch {
|
|
65
|
+
require_contract.requirePeer("pg", "storage/postgres");
|
|
66
|
+
}
|
|
67
|
+
client = new Pool({ connectionString });
|
|
68
|
+
return client;
|
|
69
|
+
})();
|
|
70
|
+
try {
|
|
71
|
+
return await connecting;
|
|
72
|
+
} finally {
|
|
73
|
+
connecting = void 0;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/** Create the backing table once, before the first operation. */
|
|
77
|
+
async function ensureTable() {
|
|
78
|
+
const c = await getClient();
|
|
79
|
+
ensured ??= (async () => {
|
|
80
|
+
await c.query(`CREATE TABLE IF NOT EXISTS ${table} (key text PRIMARY KEY, value jsonb NOT NULL)`);
|
|
81
|
+
})();
|
|
82
|
+
await ensured;
|
|
83
|
+
return c;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Normalise a `jsonb` column value. Both `pg` and `pglite` typically return
|
|
87
|
+
* it already parsed, but parse a string defensively so either driver works.
|
|
88
|
+
*/
|
|
89
|
+
const parseValue = (value) => {
|
|
90
|
+
if (typeof value === "string") try {
|
|
91
|
+
return JSON.parse(value);
|
|
92
|
+
} catch {
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
return value;
|
|
96
|
+
};
|
|
97
|
+
return {
|
|
98
|
+
async getItem(key) {
|
|
99
|
+
const { rows } = await (await ensureTable()).query(`SELECT value FROM ${table} WHERE key = $1`, [key]);
|
|
100
|
+
const row = rows[0];
|
|
101
|
+
if (row === void 0 || row.value === null || row.value === void 0) return null;
|
|
102
|
+
return parseValue(row.value);
|
|
103
|
+
},
|
|
104
|
+
async setItem(key, value) {
|
|
105
|
+
await (await ensureTable()).query(`INSERT INTO ${table} (key, value) VALUES ($1, $2::jsonb)
|
|
106
|
+
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value`, [key, JSON.stringify(value)]);
|
|
107
|
+
},
|
|
108
|
+
async removeItem(key) {
|
|
109
|
+
await (await ensureTable()).query(`DELETE FROM ${table} WHERE key = $1`, [key]);
|
|
110
|
+
},
|
|
111
|
+
async getKeys(prefix) {
|
|
112
|
+
const { rows } = await (await ensureTable()).query(`SELECT key FROM ${table} WHERE key LIKE $1 ESCAPE '\\'`, [`${escapeLike(prefix)}%`]);
|
|
113
|
+
return rows.map((row) => String(row.key));
|
|
114
|
+
},
|
|
115
|
+
async close() {
|
|
116
|
+
if (ownsClient && client?.end) await client.end();
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
//#endregion
|
|
121
|
+
Object.defineProperty(exports, "createPostgresStorage", {
|
|
122
|
+
enumerable: true,
|
|
123
|
+
get: function() {
|
|
124
|
+
return createPostgresStorage;
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
Object.defineProperty(exports, "postgres_exports", {
|
|
128
|
+
enumerable: true,
|
|
129
|
+
get: function() {
|
|
130
|
+
return postgres_exports;
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
//# sourceMappingURL=postgres-C8WbchFa.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-C8WbchFa.cjs","names":[],"sources":["../src/storage/postgres.ts"],"sourcesContent":["/**\n * Postgres storage adapter backed by a single key/value table\n * (`key text PRIMARY KEY, value jsonb`). It works with any client exposing a\n * `query(text, params?)` method that resolves to `{ rows }` — this covers\n * [`pg`](https://github.com/brianc/node-postgres) (`Pool`/`Client`) and the\n * in-process [`@electric-sql/pglite`](https://github.com/electric-sql/pglite)\n * alike. You can pass a pre-built `client`, or a `connectionString`/`url` to\n * lazily create a `pg` `Pool` on first use.\n *\n * The table is created on demand (`CREATE TABLE IF NOT EXISTS`) the first time\n * any operation runs, guarded by a single promise so concurrent callers only\n * issue the DDL once. Values are stored as `jsonb`; both `pg` and `pglite`\n * return `jsonb` already parsed to JS, but a string is JSON-parsed defensively\n * so either driver works.\n *\n * @module\n */\n\nimport { requirePeer } from \"./contract.ts\";\nimport type { WebhooksStorage } from \"./contract.ts\";\n\n/**\n * Minimal structural view of a SQL client. Both `pg`'s `Pool`/`Client` and\n * `@electric-sql/pglite`'s `PGlite` satisfy this shape.\n */\nexport interface SqlClient {\n query(text: string, params?: unknown[]): Promise<{ rows: Array<Record<string, unknown>> }>;\n}\n\n/** A client this adapter can also shut down (e.g. a `pg` `Pool`). */\ninterface ClosableSqlClient extends SqlClient {\n end?(): Promise<unknown>;\n}\n\n/** Options for {@link createPostgresStorage}. */\nexport interface PostgresStorageOptions {\n /**\n * A pre-built client exposing `query(text, params?) => Promise<{ rows }>`.\n * Both a `pg` `Pool`/`Client` and `@electric-sql/pglite` satisfy this.\n */\n client?: SqlClient;\n /**\n * Connection string used to lazily create a `pg` `Pool` (via dynamic import)\n * when no `client` is supplied.\n */\n connectionString?: string;\n /** Alias for {@link PostgresStorageOptions.connectionString}. */\n url?: string;\n /** Table name (default `\"xtandard_webhooks\"`). Must be a safe SQL identifier. */\n table?: string;\n}\n\n/**\n * A {@link WebhooksStorage} backed by Postgres, plus a `close()` method that\n * ends the underlying pool — but only the one this adapter created. A client\n * you passed in is left for you to manage.\n */\nexport interface PostgresWebhooksStorage extends WebhooksStorage {\n /** End the underlying pool if this adapter created it. No-op otherwise. */\n close(): Promise<void>;\n}\n\n/** Identifiers we are willing to interpolate into DDL/queries unquoted. */\nconst SAFE_IDENTIFIER = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\n\n/**\n * Escape LIKE wildcards (`%`, `_`) and the escape char itself in a literal\n * prefix so `getKeys` matches the prefix verbatim. Paired with `ESCAPE '\\'`.\n */\nconst escapeLike = (literal: string): string => literal.replace(/[\\\\%_]/g, (c) => `\\\\${c}`);\n\n/**\n * Create a Postgres-backed {@link PostgresWebhooksStorage}. The table is created\n * lazily on first use; connection (when using `connectionString`/`url`) is also\n * lazy — the `pg` `Pool` is imported and constructed on the first operation and\n * reused thereafter.\n *\n * @example\n * ```ts\n * import { createPostgresStorage } from \"@xtandard/webhooks/storage/postgres\";\n *\n * // Via connection string (lazy `pg` Pool):\n * const storage = createPostgresStorage({\n * connectionString: process.env.DATABASE_URL,\n * });\n *\n * // Or with a pre-built pg Pool / PGlite client:\n * // import { PGlite } from \"@electric-sql/pglite\";\n * // const storage = createPostgresStorage({ client: new PGlite() });\n * ```\n */\nexport function createPostgresStorage(options: PostgresStorageOptions): PostgresWebhooksStorage {\n const table = options.table ?? \"xtandard_webhooks\";\n if (!SAFE_IDENTIFIER.test(table)) {\n throw new Error(\n `Invalid table name ${JSON.stringify(table)}: must match ${SAFE_IDENTIFIER.source}`,\n );\n }\n const connectionString = options.connectionString ?? options.url;\n const ownsClient = !options.client;\n\n let client: ClosableSqlClient | undefined = options.client;\n let connecting: Promise<ClosableSqlClient> | undefined;\n let ensured: Promise<void> | undefined;\n\n /** Resolve a client, creating a `pg` `Pool` on first use when needed. */\n async function getClient(): Promise<ClosableSqlClient> {\n if (client) return client;\n connecting ??= (async () => {\n let Pool: new (config: { connectionString?: string }) => ClosableSqlClient;\n try {\n ({ Pool } = (await import(\"pg\")) as unknown as {\n Pool: new (config: { connectionString?: string }) => ClosableSqlClient;\n });\n } catch {\n requirePeer(\"pg\", \"storage/postgres\");\n }\n client = new Pool({ connectionString });\n return client;\n })();\n try {\n return await connecting;\n } finally {\n connecting = undefined;\n }\n }\n\n /** Create the backing table once, before the first operation. */\n async function ensureTable(): Promise<ClosableSqlClient> {\n const c = await getClient();\n ensured ??= (async () => {\n await c.query(\n `CREATE TABLE IF NOT EXISTS ${table} (key text PRIMARY KEY, value jsonb NOT NULL)`,\n );\n })();\n await ensured;\n return c;\n }\n\n /**\n * Normalise a `jsonb` column value. Both `pg` and `pglite` typically return\n * it already parsed, but parse a string defensively so either driver works.\n */\n const parseValue = <T>(value: unknown): T => {\n if (typeof value === \"string\") {\n try {\n return JSON.parse(value) as T;\n } catch {\n return value as T;\n }\n }\n return value as T;\n };\n\n return {\n async getItem<T>(key: string): Promise<T | null> {\n const c = await ensureTable();\n const { rows } = await c.query(`SELECT value FROM ${table} WHERE key = $1`, [key]);\n const row = rows[0];\n if (row === undefined || row.value === null || row.value === undefined) return null;\n return parseValue<T>(row.value);\n },\n\n async setItem<T>(key: string, value: T): Promise<void> {\n const c = await ensureTable();\n await c.query(\n `INSERT INTO ${table} (key, value) VALUES ($1, $2::jsonb)\n ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value`,\n [key, JSON.stringify(value)],\n );\n },\n\n async removeItem(key: string): Promise<void> {\n const c = await ensureTable();\n await c.query(`DELETE FROM ${table} WHERE key = $1`, [key]);\n },\n\n async getKeys(prefix: string): Promise<string[]> {\n const c = await ensureTable();\n const { rows } = await c.query(`SELECT key FROM ${table} WHERE key LIKE $1 ESCAPE '\\\\'`, [\n `${escapeLike(prefix)}%`,\n ]);\n return rows.map((row) => String(row.key));\n },\n\n async close(): Promise<void> {\n if (ownsClient && client?.end) await client.end();\n },\n } satisfies PostgresWebhooksStorage;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA+DA,MAAM,kBAAkB;;;;;AAMxB,MAAM,cAAc,YAA4B,QAAQ,QAAQ,YAAY,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;;AAsB1F,SAAgB,sBAAsB,SAA0D;CAC9F,MAAM,QAAQ,QAAQ,SAAS;CAC/B,IAAI,CAAC,gBAAgB,KAAK,KAAK,GAC7B,MAAM,IAAI,MACR,sBAAsB,KAAK,UAAU,KAAK,EAAE,eAAe,gBAAgB,QAC7E;CAEF,MAAM,mBAAmB,QAAQ,oBAAoB,QAAQ;CAC7D,MAAM,aAAa,CAAC,QAAQ;CAE5B,IAAI,SAAwC,QAAQ;CACpD,IAAI;CACJ,IAAI;;CAGJ,eAAe,YAAwC;EACrD,IAAI,QAAQ,OAAO;EACnB,gBAAgB,YAAY;GAC1B,IAAI;GACJ,IAAI;IACF,CAAC,CAAE,QAAU,MAAM,OAAO;GAG5B,QAAQ;IACN,iBAAA,YAAY,MAAM,kBAAkB;GACtC;GACA,SAAS,IAAI,KAAK,EAAE,iBAAiB,CAAC;GACtC,OAAO;EACT,GAAG;EACH,IAAI;GACF,OAAO,MAAM;EACf,UAAU;GACR,aAAa,KAAA;EACf;CACF;;CAGA,eAAe,cAA0C;EACvD,MAAM,IAAI,MAAM,UAAU;EAC1B,aAAa,YAAY;GACvB,MAAM,EAAE,MACN,8BAA8B,MAAM,8CACtC;EACF,GAAG;EACH,MAAM;EACN,OAAO;CACT;;;;;CAMA,MAAM,cAAiB,UAAsB;EAC3C,IAAI,OAAO,UAAU,UACnB,IAAI;GACF,OAAO,KAAK,MAAM,KAAK;EACzB,QAAQ;GACN,OAAO;EACT;EAEF,OAAO;CACT;CAEA,OAAO;EACL,MAAM,QAAW,KAAgC;GAE/C,MAAM,EAAE,SAAS,OAAM,MADP,YAAY,GACH,MAAM,qBAAqB,MAAM,kBAAkB,CAAC,GAAG,CAAC;GACjF,MAAM,MAAM,KAAK;GACjB,IAAI,QAAQ,KAAA,KAAa,IAAI,UAAU,QAAQ,IAAI,UAAU,KAAA,GAAW,OAAO;GAC/E,OAAO,WAAc,IAAI,KAAK;EAChC;EAEA,MAAM,QAAW,KAAa,OAAyB;GAErD,OAAM,MADU,YAAY,GACpB,MACN,eAAe,MAAM;kEAErB,CAAC,KAAK,KAAK,UAAU,KAAK,CAAC,CAC7B;EACF;EAEA,MAAM,WAAW,KAA4B;GAE3C,OAAM,MADU,YAAY,GACpB,MAAM,eAAe,MAAM,kBAAkB,CAAC,GAAG,CAAC;EAC5D;EAEA,MAAM,QAAQ,QAAmC;GAE/C,MAAM,EAAE,SAAS,OAAM,MADP,YAAY,GACH,MAAM,mBAAmB,MAAM,iCAAiC,CACvF,GAAG,WAAW,MAAM,EAAE,EACxB,CAAC;GACD,OAAO,KAAK,KAAK,QAAQ,OAAO,IAAI,GAAG,CAAC;EAC1C;EAEA,MAAM,QAAuB;GAC3B,IAAI,cAAc,QAAQ,KAAK,MAAM,OAAO,IAAI;EAClD;CACF;AACF"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-D7D4PA-g.mjs";
|
|
2
|
+
import { a as requirePeer } from "./contract-BEhDcd_5.mjs";
|
|
3
|
+
//#region src/storage/postgres.ts
|
|
4
|
+
/**
|
|
5
|
+
* Postgres storage adapter backed by a single key/value table
|
|
6
|
+
* (`key text PRIMARY KEY, value jsonb`). It works with any client exposing a
|
|
7
|
+
* `query(text, params?)` method that resolves to `{ rows }` — this covers
|
|
8
|
+
* [`pg`](https://github.com/brianc/node-postgres) (`Pool`/`Client`) and the
|
|
9
|
+
* in-process [`@electric-sql/pglite`](https://github.com/electric-sql/pglite)
|
|
10
|
+
* alike. You can pass a pre-built `client`, or a `connectionString`/`url` to
|
|
11
|
+
* lazily create a `pg` `Pool` on first use.
|
|
12
|
+
*
|
|
13
|
+
* The table is created on demand (`CREATE TABLE IF NOT EXISTS`) the first time
|
|
14
|
+
* any operation runs, guarded by a single promise so concurrent callers only
|
|
15
|
+
* issue the DDL once. Values are stored as `jsonb`; both `pg` and `pglite`
|
|
16
|
+
* return `jsonb` already parsed to JS, but a string is JSON-parsed defensively
|
|
17
|
+
* so either driver works.
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
var postgres_exports = /* @__PURE__ */ __exportAll({ createPostgresStorage: () => createPostgresStorage });
|
|
22
|
+
/** Identifiers we are willing to interpolate into DDL/queries unquoted. */
|
|
23
|
+
const SAFE_IDENTIFIER = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
24
|
+
/**
|
|
25
|
+
* Escape LIKE wildcards (`%`, `_`) and the escape char itself in a literal
|
|
26
|
+
* prefix so `getKeys` matches the prefix verbatim. Paired with `ESCAPE '\'`.
|
|
27
|
+
*/
|
|
28
|
+
const escapeLike = (literal) => literal.replace(/[\\%_]/g, (c) => `\\${c}`);
|
|
29
|
+
/**
|
|
30
|
+
* Create a Postgres-backed {@link PostgresWebhooksStorage}. The table is created
|
|
31
|
+
* lazily on first use; connection (when using `connectionString`/`url`) is also
|
|
32
|
+
* lazy — the `pg` `Pool` is imported and constructed on the first operation and
|
|
33
|
+
* reused thereafter.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { createPostgresStorage } from "@xtandard/webhooks/storage/postgres";
|
|
38
|
+
*
|
|
39
|
+
* // Via connection string (lazy `pg` Pool):
|
|
40
|
+
* const storage = createPostgresStorage({
|
|
41
|
+
* connectionString: process.env.DATABASE_URL,
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
* // Or with a pre-built pg Pool / PGlite client:
|
|
45
|
+
* // import { PGlite } from "@electric-sql/pglite";
|
|
46
|
+
* // const storage = createPostgresStorage({ client: new PGlite() });
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
function createPostgresStorage(options) {
|
|
50
|
+
const table = options.table ?? "xtandard_webhooks";
|
|
51
|
+
if (!SAFE_IDENTIFIER.test(table)) throw new Error(`Invalid table name ${JSON.stringify(table)}: must match ${SAFE_IDENTIFIER.source}`);
|
|
52
|
+
const connectionString = options.connectionString ?? options.url;
|
|
53
|
+
const ownsClient = !options.client;
|
|
54
|
+
let client = options.client;
|
|
55
|
+
let connecting;
|
|
56
|
+
let ensured;
|
|
57
|
+
/** Resolve a client, creating a `pg` `Pool` on first use when needed. */
|
|
58
|
+
async function getClient() {
|
|
59
|
+
if (client) return client;
|
|
60
|
+
connecting ??= (async () => {
|
|
61
|
+
let Pool;
|
|
62
|
+
try {
|
|
63
|
+
({Pool} = await import("pg"));
|
|
64
|
+
} catch {
|
|
65
|
+
requirePeer("pg", "storage/postgres");
|
|
66
|
+
}
|
|
67
|
+
client = new Pool({ connectionString });
|
|
68
|
+
return client;
|
|
69
|
+
})();
|
|
70
|
+
try {
|
|
71
|
+
return await connecting;
|
|
72
|
+
} finally {
|
|
73
|
+
connecting = void 0;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/** Create the backing table once, before the first operation. */
|
|
77
|
+
async function ensureTable() {
|
|
78
|
+
const c = await getClient();
|
|
79
|
+
ensured ??= (async () => {
|
|
80
|
+
await c.query(`CREATE TABLE IF NOT EXISTS ${table} (key text PRIMARY KEY, value jsonb NOT NULL)`);
|
|
81
|
+
})();
|
|
82
|
+
await ensured;
|
|
83
|
+
return c;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Normalise a `jsonb` column value. Both `pg` and `pglite` typically return
|
|
87
|
+
* it already parsed, but parse a string defensively so either driver works.
|
|
88
|
+
*/
|
|
89
|
+
const parseValue = (value) => {
|
|
90
|
+
if (typeof value === "string") try {
|
|
91
|
+
return JSON.parse(value);
|
|
92
|
+
} catch {
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
return value;
|
|
96
|
+
};
|
|
97
|
+
return {
|
|
98
|
+
async getItem(key) {
|
|
99
|
+
const { rows } = await (await ensureTable()).query(`SELECT value FROM ${table} WHERE key = $1`, [key]);
|
|
100
|
+
const row = rows[0];
|
|
101
|
+
if (row === void 0 || row.value === null || row.value === void 0) return null;
|
|
102
|
+
return parseValue(row.value);
|
|
103
|
+
},
|
|
104
|
+
async setItem(key, value) {
|
|
105
|
+
await (await ensureTable()).query(`INSERT INTO ${table} (key, value) VALUES ($1, $2::jsonb)
|
|
106
|
+
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value`, [key, JSON.stringify(value)]);
|
|
107
|
+
},
|
|
108
|
+
async removeItem(key) {
|
|
109
|
+
await (await ensureTable()).query(`DELETE FROM ${table} WHERE key = $1`, [key]);
|
|
110
|
+
},
|
|
111
|
+
async getKeys(prefix) {
|
|
112
|
+
const { rows } = await (await ensureTable()).query(`SELECT key FROM ${table} WHERE key LIKE $1 ESCAPE '\\'`, [`${escapeLike(prefix)}%`]);
|
|
113
|
+
return rows.map((row) => String(row.key));
|
|
114
|
+
},
|
|
115
|
+
async close() {
|
|
116
|
+
if (ownsClient && client?.end) await client.end();
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
//#endregion
|
|
121
|
+
export { postgres_exports as n, createPostgresStorage as t };
|
|
122
|
+
|
|
123
|
+
//# sourceMappingURL=postgres-c3pAhmhr.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-c3pAhmhr.mjs","names":[],"sources":["../src/storage/postgres.ts"],"sourcesContent":["/**\n * Postgres storage adapter backed by a single key/value table\n * (`key text PRIMARY KEY, value jsonb`). It works with any client exposing a\n * `query(text, params?)` method that resolves to `{ rows }` — this covers\n * [`pg`](https://github.com/brianc/node-postgres) (`Pool`/`Client`) and the\n * in-process [`@electric-sql/pglite`](https://github.com/electric-sql/pglite)\n * alike. You can pass a pre-built `client`, or a `connectionString`/`url` to\n * lazily create a `pg` `Pool` on first use.\n *\n * The table is created on demand (`CREATE TABLE IF NOT EXISTS`) the first time\n * any operation runs, guarded by a single promise so concurrent callers only\n * issue the DDL once. Values are stored as `jsonb`; both `pg` and `pglite`\n * return `jsonb` already parsed to JS, but a string is JSON-parsed defensively\n * so either driver works.\n *\n * @module\n */\n\nimport { requirePeer } from \"./contract.ts\";\nimport type { WebhooksStorage } from \"./contract.ts\";\n\n/**\n * Minimal structural view of a SQL client. Both `pg`'s `Pool`/`Client` and\n * `@electric-sql/pglite`'s `PGlite` satisfy this shape.\n */\nexport interface SqlClient {\n query(text: string, params?: unknown[]): Promise<{ rows: Array<Record<string, unknown>> }>;\n}\n\n/** A client this adapter can also shut down (e.g. a `pg` `Pool`). */\ninterface ClosableSqlClient extends SqlClient {\n end?(): Promise<unknown>;\n}\n\n/** Options for {@link createPostgresStorage}. */\nexport interface PostgresStorageOptions {\n /**\n * A pre-built client exposing `query(text, params?) => Promise<{ rows }>`.\n * Both a `pg` `Pool`/`Client` and `@electric-sql/pglite` satisfy this.\n */\n client?: SqlClient;\n /**\n * Connection string used to lazily create a `pg` `Pool` (via dynamic import)\n * when no `client` is supplied.\n */\n connectionString?: string;\n /** Alias for {@link PostgresStorageOptions.connectionString}. */\n url?: string;\n /** Table name (default `\"xtandard_webhooks\"`). Must be a safe SQL identifier. */\n table?: string;\n}\n\n/**\n * A {@link WebhooksStorage} backed by Postgres, plus a `close()` method that\n * ends the underlying pool — but only the one this adapter created. A client\n * you passed in is left for you to manage.\n */\nexport interface PostgresWebhooksStorage extends WebhooksStorage {\n /** End the underlying pool if this adapter created it. No-op otherwise. */\n close(): Promise<void>;\n}\n\n/** Identifiers we are willing to interpolate into DDL/queries unquoted. */\nconst SAFE_IDENTIFIER = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\n\n/**\n * Escape LIKE wildcards (`%`, `_`) and the escape char itself in a literal\n * prefix so `getKeys` matches the prefix verbatim. Paired with `ESCAPE '\\'`.\n */\nconst escapeLike = (literal: string): string => literal.replace(/[\\\\%_]/g, (c) => `\\\\${c}`);\n\n/**\n * Create a Postgres-backed {@link PostgresWebhooksStorage}. The table is created\n * lazily on first use; connection (when using `connectionString`/`url`) is also\n * lazy — the `pg` `Pool` is imported and constructed on the first operation and\n * reused thereafter.\n *\n * @example\n * ```ts\n * import { createPostgresStorage } from \"@xtandard/webhooks/storage/postgres\";\n *\n * // Via connection string (lazy `pg` Pool):\n * const storage = createPostgresStorage({\n * connectionString: process.env.DATABASE_URL,\n * });\n *\n * // Or with a pre-built pg Pool / PGlite client:\n * // import { PGlite } from \"@electric-sql/pglite\";\n * // const storage = createPostgresStorage({ client: new PGlite() });\n * ```\n */\nexport function createPostgresStorage(options: PostgresStorageOptions): PostgresWebhooksStorage {\n const table = options.table ?? \"xtandard_webhooks\";\n if (!SAFE_IDENTIFIER.test(table)) {\n throw new Error(\n `Invalid table name ${JSON.stringify(table)}: must match ${SAFE_IDENTIFIER.source}`,\n );\n }\n const connectionString = options.connectionString ?? options.url;\n const ownsClient = !options.client;\n\n let client: ClosableSqlClient | undefined = options.client;\n let connecting: Promise<ClosableSqlClient> | undefined;\n let ensured: Promise<void> | undefined;\n\n /** Resolve a client, creating a `pg` `Pool` on first use when needed. */\n async function getClient(): Promise<ClosableSqlClient> {\n if (client) return client;\n connecting ??= (async () => {\n let Pool: new (config: { connectionString?: string }) => ClosableSqlClient;\n try {\n ({ Pool } = (await import(\"pg\")) as unknown as {\n Pool: new (config: { connectionString?: string }) => ClosableSqlClient;\n });\n } catch {\n requirePeer(\"pg\", \"storage/postgres\");\n }\n client = new Pool({ connectionString });\n return client;\n })();\n try {\n return await connecting;\n } finally {\n connecting = undefined;\n }\n }\n\n /** Create the backing table once, before the first operation. */\n async function ensureTable(): Promise<ClosableSqlClient> {\n const c = await getClient();\n ensured ??= (async () => {\n await c.query(\n `CREATE TABLE IF NOT EXISTS ${table} (key text PRIMARY KEY, value jsonb NOT NULL)`,\n );\n })();\n await ensured;\n return c;\n }\n\n /**\n * Normalise a `jsonb` column value. Both `pg` and `pglite` typically return\n * it already parsed, but parse a string defensively so either driver works.\n */\n const parseValue = <T>(value: unknown): T => {\n if (typeof value === \"string\") {\n try {\n return JSON.parse(value) as T;\n } catch {\n return value as T;\n }\n }\n return value as T;\n };\n\n return {\n async getItem<T>(key: string): Promise<T | null> {\n const c = await ensureTable();\n const { rows } = await c.query(`SELECT value FROM ${table} WHERE key = $1`, [key]);\n const row = rows[0];\n if (row === undefined || row.value === null || row.value === undefined) return null;\n return parseValue<T>(row.value);\n },\n\n async setItem<T>(key: string, value: T): Promise<void> {\n const c = await ensureTable();\n await c.query(\n `INSERT INTO ${table} (key, value) VALUES ($1, $2::jsonb)\n ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value`,\n [key, JSON.stringify(value)],\n );\n },\n\n async removeItem(key: string): Promise<void> {\n const c = await ensureTable();\n await c.query(`DELETE FROM ${table} WHERE key = $1`, [key]);\n },\n\n async getKeys(prefix: string): Promise<string[]> {\n const c = await ensureTable();\n const { rows } = await c.query(`SELECT key FROM ${table} WHERE key LIKE $1 ESCAPE '\\\\'`, [\n `${escapeLike(prefix)}%`,\n ]);\n return rows.map((row) => String(row.key));\n },\n\n async close(): Promise<void> {\n if (ownsClient && client?.end) await client.end();\n },\n } satisfies PostgresWebhooksStorage;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA+DA,MAAM,kBAAkB;;;;;AAMxB,MAAM,cAAc,YAA4B,QAAQ,QAAQ,YAAY,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;;AAsB1F,SAAgB,sBAAsB,SAA0D;CAC9F,MAAM,QAAQ,QAAQ,SAAS;CAC/B,IAAI,CAAC,gBAAgB,KAAK,KAAK,GAC7B,MAAM,IAAI,MACR,sBAAsB,KAAK,UAAU,KAAK,EAAE,eAAe,gBAAgB,QAC7E;CAEF,MAAM,mBAAmB,QAAQ,oBAAoB,QAAQ;CAC7D,MAAM,aAAa,CAAC,QAAQ;CAE5B,IAAI,SAAwC,QAAQ;CACpD,IAAI;CACJ,IAAI;;CAGJ,eAAe,YAAwC;EACrD,IAAI,QAAQ,OAAO;EACnB,gBAAgB,YAAY;GAC1B,IAAI;GACJ,IAAI;IACF,CAAC,CAAE,QAAU,MAAM,OAAO;GAG5B,QAAQ;IACN,YAAY,MAAM,kBAAkB;GACtC;GACA,SAAS,IAAI,KAAK,EAAE,iBAAiB,CAAC;GACtC,OAAO;EACT,GAAG;EACH,IAAI;GACF,OAAO,MAAM;EACf,UAAU;GACR,aAAa,KAAA;EACf;CACF;;CAGA,eAAe,cAA0C;EACvD,MAAM,IAAI,MAAM,UAAU;EAC1B,aAAa,YAAY;GACvB,MAAM,EAAE,MACN,8BAA8B,MAAM,8CACtC;EACF,GAAG;EACH,MAAM;EACN,OAAO;CACT;;;;;CAMA,MAAM,cAAiB,UAAsB;EAC3C,IAAI,OAAO,UAAU,UACnB,IAAI;GACF,OAAO,KAAK,MAAM,KAAK;EACzB,QAAQ;GACN,OAAO;EACT;EAEF,OAAO;CACT;CAEA,OAAO;EACL,MAAM,QAAW,KAAgC;GAE/C,MAAM,EAAE,SAAS,OAAM,MADP,YAAY,GACH,MAAM,qBAAqB,MAAM,kBAAkB,CAAC,GAAG,CAAC;GACjF,MAAM,MAAM,KAAK;GACjB,IAAI,QAAQ,KAAA,KAAa,IAAI,UAAU,QAAQ,IAAI,UAAU,KAAA,GAAW,OAAO;GAC/E,OAAO,WAAc,IAAI,KAAK;EAChC;EAEA,MAAM,QAAW,KAAa,OAAyB;GAErD,OAAM,MADU,YAAY,GACpB,MACN,eAAe,MAAM;kEAErB,CAAC,KAAK,KAAK,UAAU,KAAK,CAAC,CAC7B;EACF;EAEA,MAAM,WAAW,KAA4B;GAE3C,OAAM,MADU,YAAY,GACpB,MAAM,eAAe,MAAM,kBAAkB,CAAC,GAAG,CAAC;EAC5D;EAEA,MAAM,QAAQ,QAAmC;GAE/C,MAAM,EAAE,SAAS,OAAM,MADP,YAAY,GACH,MAAM,mBAAmB,MAAM,iCAAiC,CACvF,GAAG,WAAW,MAAM,EAAE,EACxB,CAAC;GACD,OAAO,KAAK,KAAK,QAAQ,OAAO,IAAI,GAAG,CAAC;EAC1C;EAEA,MAAM,QAAuB;GAC3B,IAAI,cAAc,QAAQ,KAAK,MAAM,OAAO,IAAI;EAClD;CACF;AACF"}
|
package/dist/react.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-ease:initial;--tw-content:"";--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;--color-black:#000;--spacing:.25rem;--container-sm:24rem;--container-md:28rem;--container-2xl:42rem;--container-6xl:72rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--font-weight-medium:500;--font-weight-semibold:600;--tracking-tight:-.025em;--tracking-wide:.025em;--tracking-wider:.05em;--leading-snug:1.375;--leading-relaxed:1.625;--ease-out:cubic-bezier(0, 0, .2, 1);--animate-spin:spin 1s linear infinite;--blur-sm:8px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;--default-mono-font-family:"JetBrains Mono", "SFMono-Regular", "Cascadia Code", ui-monospace, monospace}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}*,:before,:after{box-sizing:border-box;border-color:var(--border)}html,body,#root{height:100%;margin:0;padding:0}body{background-color:var(--background);color:var(--foreground);font-family:var(--font-sans);letter-spacing:-.006em;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:14px;line-height:1.5}:focus-visible{outline:2px solid var(--ring);outline-offset:2px}}@layer components;@layer utilities{.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.top-0{top:0}.top-1\.5{top:calc(var(--spacing) * 1.5)}.top-1\/2{top:50%}.right-6{right:calc(var(--spacing) * 6)}.bottom-6{bottom:calc(var(--spacing) * 6)}.left-1\/2{left:50%}.left-2{left:calc(var(--spacing) * 2)}.z-40{z-index:40}.z-50{z-index:50}.z-\[9999\]{z-index:9999}.order-42{order:42}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.m-0{margin:0}.mx-auto{margin-inline:auto}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mb-1{margin-bottom:var(--spacing)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.ml-auto{margin-left:auto}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-flex{display:inline-flex}.table{display:table}.size-2{width:calc(var(--spacing) * 2);height:calc(var(--spacing) * 2)}.size-2\.5{width:calc(var(--spacing) * 2.5);height:calc(var(--spacing) * 2.5)}.size-3{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.size-3\.5{width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-6{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-14{height:calc(var(--spacing) * 14)}.h-screen{height:100vh}.max-h-32{max-height:calc(var(--spacing) * 32)}.max-h-64{max-height:calc(var(--spacing) * 64)}.max-h-\[85vh\]{max-height:85vh}.max-h-\[min\(20rem\,var\(--available-height\)\)\]{max-height:min(20rem,var(--available-height))}.min-h-0{min-height:0}.w-4{width:calc(var(--spacing) * 4)}.w-7{width:calc(var(--spacing) * 7)}.w-8{width:calc(var(--spacing) * 8)}.w-9{width:calc(var(--spacing) * 9)}.w-28{width:calc(var(--spacing) * 28)}.w-44{width:calc(var(--spacing) * 44)}.w-48{width:calc(var(--spacing) * 48)}.w-64{width:calc(var(--spacing) * 64)}.w-72{width:calc(var(--spacing) * 72)}.w-\[max\(var\(--anchor-width\)\,13rem\)\]{width:max(var(--anchor-width),13rem)}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-6xl{max-width:var(--container-6xl)}.max-w-\[240px\]{max-width:240px}.max-w-\[320px\]{max-width:320px}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.min-w-0{min-width:0}.min-w-\[280px\]{min-width:280px}.min-w-\[var\(--anchor-width\)\]{min-width:var(--anchor-width)}.flex-1{flex:1}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.border-collapse{border-collapse:collapse}.origin-\[var\(--transform-origin\)\]{transform-origin:var(--transform-origin)}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-x-0\.5{--tw-translate-x:calc(var(--spacing) * .5);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-spin{animation:var(--animate-spin)}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-5{gap:calc(var(--spacing) * 5)}.gap-6{gap:calc(var(--spacing) * 6)}.gap-x-8{column-gap:calc(var(--spacing) * 8)}.gap-y-2{row-gap:calc(var(--spacing) * 2)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-border>:not(:last-child)){border-color:var(--border)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-\[5px\]{border-radius:5px}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-sm{border-radius:calc(var(--radius) - 4px)}.rounded-xl{border-radius:calc(var(--radius) + 4px)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-l-\[3px\]{border-left-style:var(--tw-border-style);border-left-width:3px}.border-accent,.border-accent\/20{border-color:var(--accent)}@supports (color:color-mix(in lab,red,red)){.border-accent\/20{border-color:color-mix(in oklab,var(--accent) 20%,transparent)}}.border-accent\/30{border-color:var(--accent)}@supports (color:color-mix(in lab,red,red)){.border-accent\/30{border-color:color-mix(in oklab,var(--accent) 30%,transparent)}}.border-accent\/40{border-color:var(--accent)}@supports (color:color-mix(in lab,red,red)){.border-accent\/40{border-color:color-mix(in oklab,var(--accent) 40%,transparent)}}.border-border{border-color:var(--border)}.border-card{border-color:var(--card)}.border-chart-2\/30{border-color:var(--chart-2)}@supports (color:color-mix(in lab,red,red)){.border-chart-2\/30{border-color:color-mix(in oklab,var(--chart-2) 30%,transparent)}}.border-destructive\/20{border-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.border-destructive\/20{border-color:color-mix(in oklab,var(--destructive) 20%,transparent)}}.border-destructive\/30{border-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.border-destructive\/30{border-color:color-mix(in oklab,var(--destructive) 30%,transparent)}}.border-input{border-color:var(--input)}.border-success\/20{border-color:var(--success)}@supports (color:color-mix(in lab,red,red)){.border-success\/20{border-color:color-mix(in oklab,var(--success) 20%,transparent)}}.border-success\/30{border-color:var(--success)}@supports (color:color-mix(in lab,red,red)){.border-success\/30{border-color:color-mix(in oklab,var(--success) 30%,transparent)}}.border-transparent{border-color:#0000}.border-warning\/20{border-color:var(--warning)}@supports (color:color-mix(in lab,red,red)){.border-warning\/20{border-color:color-mix(in oklab,var(--warning) 20%,transparent)}}.border-warning\/30{border-color:var(--warning)}@supports (color:color-mix(in lab,red,red)){.border-warning\/30{border-color:color-mix(in oklab,var(--warning) 30%,transparent)}}.border-l-\[var\(--accent\)\]{border-left-color:var(--accent)}.border-l-\[var\(--destructive\)\]{border-left-color:var(--destructive)}.border-l-\[var\(--success\)\]{border-left-color:var(--success)}.border-l-\[var\(--warning\)\]{border-left-color:var(--warning)}.bg-accent,.bg-accent\/10{background-color:var(--accent)}@supports (color:color-mix(in lab,red,red)){.bg-accent\/10{background-color:color-mix(in oklab,var(--accent) 10%,transparent)}}.bg-accent\/\[0\.06\]{background-color:var(--accent)}@supports (color:color-mix(in lab,red,red)){.bg-accent\/\[0\.06\]{background-color:color-mix(in oklab,var(--accent) 6%,transparent)}}.bg-background,.bg-background\/80{background-color:var(--background)}@supports (color:color-mix(in lab,red,red)){.bg-background\/80{background-color:color-mix(in oklab,var(--background) 80%,transparent)}}.bg-black\/50{background-color:#00000080}@supports (color:color-mix(in lab,red,red)){.bg-black\/50{background-color:color-mix(in oklab,var(--color-black) 50%,transparent)}}.bg-card{background-color:var(--card)}.bg-chart-2\/10{background-color:var(--chart-2)}@supports (color:color-mix(in lab,red,red)){.bg-chart-2\/10{background-color:color-mix(in oklab,var(--chart-2) 10%,transparent)}}.bg-destructive,.bg-destructive\/10{background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.bg-destructive\/10{background-color:color-mix(in oklab,var(--destructive) 10%,transparent)}}.bg-input{background-color:var(--input)}.bg-muted-foreground\/40{background-color:var(--muted-foreground)}@supports (color:color-mix(in lab,red,red)){.bg-muted-foreground\/40{background-color:color-mix(in oklab,var(--muted-foreground) 40%,transparent)}}.bg-popover{background-color:var(--popover)}.bg-primary{background-color:var(--primary)}.bg-secondary,.bg-secondary\/30{background-color:var(--secondary)}@supports (color:color-mix(in lab,red,red)){.bg-secondary\/30{background-color:color-mix(in oklab,var(--secondary) 30%,transparent)}}.bg-secondary\/40{background-color:var(--secondary)}@supports (color:color-mix(in lab,red,red)){.bg-secondary\/40{background-color:color-mix(in oklab,var(--secondary) 40%,transparent)}}.bg-secondary\/50{background-color:var(--secondary)}@supports (color:color-mix(in lab,red,red)){.bg-secondary\/50{background-color:color-mix(in oklab,var(--secondary) 50%,transparent)}}.bg-secondary\/60{background-color:var(--secondary)}@supports (color:color-mix(in lab,red,red)){.bg-secondary\/60{background-color:color-mix(in oklab,var(--secondary) 60%,transparent)}}.bg-success,.bg-success\/10{background-color:var(--success)}@supports (color:color-mix(in lab,red,red)){.bg-success\/10{background-color:color-mix(in oklab,var(--success) 10%,transparent)}}.bg-transparent{background-color:#0000}.bg-warning,.bg-warning\/10{background-color:var(--warning)}@supports (color:color-mix(in lab,red,red)){.bg-warning\/10{background-color:color-mix(in oklab,var(--warning) 10%,transparent)}}.object-contain{object-fit:contain}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-1{padding:var(--spacing)}.p-1\.5{padding:calc(var(--spacing) * 1.5)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-3\.5{padding-block:calc(var(--spacing) * 3.5)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-16{padding-block:calc(var(--spacing) * 16)}.pt-0\.5{padding-top:calc(var(--spacing) * .5)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pl-2{padding-left:calc(var(--spacing) * 2)}.pl-8{padding-left:calc(var(--spacing) * 8)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:JetBrains Mono,SFMono-Regular,Cascadia Code,ui-monospace,monospace}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[15px\]{font-size:15px}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.break-all{word-break:break-all}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-accent{color:var(--accent)}.text-border{color:var(--border)}.text-chart-1{color:var(--chart-1)}.text-chart-2{color:var(--chart-2)}.text-destructive{color:var(--destructive)}.text-foreground{color:var(--foreground)}.text-muted-foreground,.text-muted-foreground\/50{color:var(--muted-foreground)}@supports (color:color-mix(in lab,red,red)){.text-muted-foreground\/50{color:color-mix(in oklab,var(--muted-foreground) 50%,transparent)}}.text-muted-foreground\/60{color:var(--muted-foreground)}@supports (color:color-mix(in lab,red,red)){.text-muted-foreground\/60{color:color-mix(in oklab,var(--muted-foreground) 60%,transparent)}}.text-muted-foreground\/70{color:var(--muted-foreground)}@supports (color:color-mix(in lab,red,red)){.text-muted-foreground\/70{color:color-mix(in oklab,var(--muted-foreground) 70%,transparent)}}.text-popover-foreground{color:var(--popover-foreground)}.text-primary-foreground{color:var(--primary-foreground)}.text-success{color:var(--success)}.text-warning{color:var(--warning)}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.ordinal{--tw-ordinal:ordinal;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.accent-\[var\(--accent\)\]{accent-color:var(--accent)}.opacity-60{opacity:.6}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-1{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-border{--tw-ring-color:var(--border)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur{--tw-backdrop-blur:blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[transform\,opacity\]{transition-property:transform,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.outline-none{--tw-outline-style:none;outline-style:none}.select-all{-webkit-user-select:all;user-select:all}.select-none{-webkit-user-select:none;user-select:none}@media(hover:hover){.group-hover\:translate-x-0\.5:is(:where(.group):hover *){--tw-translate-x:calc(var(--spacing) * .5);translate:var(--tw-translate-x) var(--tw-translate-y)}.group-hover\:text-muted-foreground:is(:where(.group):hover *){color:var(--muted-foreground)}}.placeholder\:text-muted-foreground::placeholder{color:var(--muted-foreground)}.before\:absolute:before{content:var(--tw-content);position:absolute}.before\:top-2:before{content:var(--tw-content);top:calc(var(--spacing) * 2)}.before\:bottom-1:before{content:var(--tw-content);bottom:var(--spacing)}.before\:left-\[13px\]:before{content:var(--tw-content);left:13px}.before\:w-px:before{content:var(--tw-content);width:1px}.before\:bg-border:before{content:var(--tw-content);background-color:var(--border)}.after\:absolute:after{content:var(--tw-content);position:absolute}.after\:inset-x-3:after{content:var(--tw-content);inset-inline:calc(var(--spacing) * 3)}.after\:-bottom-px:after{content:var(--tw-content);bottom:-1px}.after\:h-0\.5:after{content:var(--tw-content);height:calc(var(--spacing) * .5)}.after\:rounded-full:after{content:var(--tw-content);border-radius:3.40282e38px}.after\:bg-foreground:after{content:var(--tw-content);background-color:var(--foreground)}@media(hover:hover){.hover\:bg-destructive\/10:hover{background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-destructive\/10:hover{background-color:color-mix(in oklab,var(--destructive) 10%,transparent)}}.hover\:bg-primary\/90:hover{background-color:var(--primary)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab,var(--primary) 90%,transparent)}}.hover\:bg-secondary:hover,.hover\:bg-secondary\/30:hover{background-color:var(--secondary)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-secondary\/30:hover{background-color:color-mix(in oklab,var(--secondary) 30%,transparent)}}.hover\:bg-secondary\/60:hover{background-color:var(--secondary)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-secondary\/60:hover{background-color:color-mix(in oklab,var(--secondary) 60%,transparent)}}.hover\:bg-secondary\/70:hover{background-color:var(--secondary)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-secondary\/70:hover{background-color:color-mix(in oklab,var(--secondary) 70%,transparent)}}.hover\:text-destructive:hover{color:var(--destructive)}.hover\:text-foreground:hover{color:var(--foreground)}.hover\:underline:hover{text-decoration-line:underline}}.focus-visible\:border-ring:focus-visible{border-color:var(--ring)}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color:var(--ring)}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.focus-visible\:ring-offset-background:focus-visible{--tw-ring-offset-color:var(--background)}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.data-\[checked\]\:translate-x-\[18px\][data-checked]{--tw-translate-x:18px;translate:var(--tw-translate-x) var(--tw-translate-y)}.data-\[checked\]\:bg-success[data-checked]{background-color:var(--success)}.data-\[ending-style\]\:scale-95[data-ending-style]{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}.data-\[ending-style\]\:opacity-0[data-ending-style]{opacity:0}.data-\[highlighted\]\:bg-accent\/15[data-highlighted]{background-color:var(--accent)}@supports (color:color-mix(in lab,red,red)){.data-\[highlighted\]\:bg-accent\/15[data-highlighted]{background-color:color-mix(in oklab,var(--accent) 15%,transparent)}}.data-\[highlighted\]\:text-foreground[data-highlighted]{color:var(--foreground)}.data-\[popup-open\]\:border-ring[data-popup-open]{border-color:var(--ring)}.data-\[pressed\]\:bg-card[data-pressed]{background-color:var(--card)}.data-\[pressed\]\:text-foreground[data-pressed]{color:var(--foreground)}.data-\[pressed\]\:shadow-sm[data-pressed]{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.data-\[starting-style\]\:scale-95[data-starting-style]{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}.data-\[starting-style\]\:opacity-0[data-starting-style]{opacity:0}@media(min-width:40rem){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:px-4{padding-inline:calc(var(--spacing) * 4)}.sm\:px-6{padding-inline:calc(var(--spacing) * 6)}}@media(min-width:64rem){.lg\:flex{display:flex}}}:root{color-scheme:light;--radius:.625rem;--background:oklch(99% .002 285);--foreground:oklch(21% .01 285);--card:oklch(100% 0 0);--card-foreground:oklch(21% .01 285);--popover:oklch(100% 0 0);--popover-foreground:oklch(21% .01 285);--primary:oklch(24% .01 285);--primary-foreground:oklch(98% 0 0);--secondary:oklch(96.5% .003 285);--secondary-foreground:oklch(24% .01 285);--muted:oklch(96.5% .003 285);--muted-foreground:oklch(50% .012 285);--accent:oklch(55% .2 256);--accent-foreground:oklch(99% 0 0);--success:oklch(60% .15 152);--warning:oklch(70% .15 78);--info:oklch(55% .2 256);--destructive:oklch(58% .21 24);--border:oklch(21% .01 285/.11);--input:oklch(21% .01 285/.14);--ring:oklch(55% .2 256);--chart-1:oklch(55% .2 256);--chart-2:oklch(60% .15 152);--chart-3:oklch(70% .15 78);--chart-4:oklch(60% .2 16);--chart-5:oklch(62% .16 300);--shadow-sm:0 1px 2px oklch(20% .02 285/.06);--shadow-md:0 2px 4px oklch(20% .02 285/.05), 0 8px 20px oklch(20% .02 285/.08);--shadow-lg:0 16px 40px oklch(20% .02 285/.16)}:root[data-theme=dark]{color-scheme:dark;--background:oklch(16% .004 285);--foreground:oklch(97% 0 0);--card:oklch(20.5% .004 285);--card-foreground:oklch(97% 0 0);--popover:oklch(22% .004 285);--popover-foreground:oklch(97% 0 0);--primary:oklch(97% 0 0);--primary-foreground:oklch(20% .01 285);--secondary:oklch(27% .004 285);--secondary-foreground:oklch(97% 0 0);--muted:oklch(27% .004 285);--muted-foreground:oklch(66% .005 285);--accent:oklch(62% .19 256);--accent-foreground:oklch(99% 0 0);--success:oklch(72% .18 152);--warning:oklch(78% .15 78);--info:oklch(62% .19 256);--destructive:oklch(62% .21 24);--border:oklch(100% 0 0/.11);--input:oklch(100% 0 0/.14);--ring:oklch(62% .19 256);--chart-1:oklch(62% .19 256);--chart-2:oklch(72% .18 152);--chart-3:oklch(78% .15 78);--chart-4:oklch(66% .2 16);--chart-5:oklch(70% .16 300);--shadow-sm:0 1px 2px oklch(0% 0 0/.3);--shadow-md:0 2px 4px oklch(0% 0 0/.3), 0 10px 28px oklch(0% 0 0/.45);--shadow-lg:0 18px 48px oklch(0% 0 0/.55)}*{scrollbar-width:thin;scrollbar-color:var(--border) transparent}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-thumb{background:var(--muted-foreground)}@supports (color:color-mix(in lab,red,red)){::-webkit-scrollbar-thumb{background:color-mix(in oklab,var(--muted-foreground) 35%,transparent)}}::-webkit-scrollbar-thumb{background-clip:content-box;border:2px solid #0000;border-radius:4px}::-webkit-scrollbar-track{background:0 0}@media(prefers-reduced-motion:reduce){*,:before,:after{transition-duration:.01ms!important;animation-duration:.01ms!important}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@keyframes spin{to{transform:rotate(360deg)}}
|