@open-mercato/shared 0.4.6-canary-c3811b08ec → 0.4.6-canary-8ae94de818

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/i18n/context.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport { createContext, useContext, useMemo, type ReactNode } from 'react'\nimport type { Locale } from './config'\n\nexport type Dict = Record<string, string>\n\nexport type TranslateParams = Record<string, string | number>\n\nexport type TranslateFn = (\n key: string,\n fallbackOrParams?: string | TranslateParams,\n params?: TranslateParams\n) => string\n\nexport type I18nContextValue = {\n locale: Locale\n t: TranslateFn\n}\n\nconst I18nContext = createContext<I18nContextValue | null>(null)\n\nfunction format(template: string, params?: TranslateParams) {\n if (!params) return template\n return template.replace(/\\{\\{(\\w+)\\}\\}|\\{(\\w+)\\}/g, (_, doubleKey, singleKey) => {\n const key = doubleKey ?? singleKey\n if (!key) return _\n const value = params[key]\n if (value === undefined) {\n return doubleKey ? `{{${key}}}` : `{${key}}`\n }\n return String(value)\n })\n}\n\nexport function I18nProvider({ children, locale, dict }: { children: ReactNode; locale: Locale; dict: Dict }) {\n const value = useMemo<I18nContextValue>(() => ({\n locale,\n t: (key, fallbackOrParams, params) => {\n let fallback: string | undefined\n let resolvedParams: TranslateParams | undefined\n\n if (typeof fallbackOrParams === 'string') {\n fallback = fallbackOrParams\n resolvedParams = params\n } else {\n resolvedParams = fallbackOrParams ?? params\n }\n\n const template = dict[key] ?? fallback ?? key\n return format(template, resolvedParams)\n },\n }), [locale, dict])\n return <I18nContext.Provider value={value}>{children}</I18nContext.Provider>\n}\n\nexport function useT() {\n const ctx = useContext(I18nContext)\n if (!ctx) throw new Error('useT must be used within I18nProvider')\n return ctx.t\n}\n\nexport function useLocale() {\n const ctx = useContext(I18nContext)\n if (!ctx) throw new Error('useLocale must be used within I18nProvider')\n return ctx.locale\n}\n"],
5
- "mappings": ";AAoDS;AAnDT,SAAS,eAAe,YAAY,eAA+B;AAkBnE,MAAM,cAAc,cAAuC,IAAI;AAE/D,SAAS,OAAO,UAAkB,QAA0B;AAC1D,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,SAAS,QAAQ,4BAA4B,CAAC,GAAG,WAAW,cAAc;AAC/E,UAAM,MAAM,aAAa;AACzB,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,QAAQ,OAAO,GAAG;AACxB,QAAI,UAAU,QAAW;AACvB,aAAO,YAAY,KAAK,GAAG,OAAO,IAAI,GAAG;AAAA,IAC3C;AACA,WAAO,OAAO,KAAK;AAAA,EACrB,CAAC;AACH;AAEO,SAAS,aAAa,EAAE,UAAU,QAAQ,KAAK,GAAwD;AAC5G,QAAM,QAAQ,QAA0B,OAAO;AAAA,IAC7C;AAAA,IACA,GAAG,CAAC,KAAK,kBAAkB,WAAW;AACpC,UAAI;AACJ,UAAI;AAEJ,UAAI,OAAO,qBAAqB,UAAU;AACxC,mBAAW;AACX,yBAAiB;AAAA,MACnB,OAAO;AACL,yBAAiB,oBAAoB;AAAA,MACvC;AAEA,YAAM,WAAW,KAAK,GAAG,KAAK,YAAY;AAC1C,aAAO,OAAO,UAAU,cAAc;AAAA,IACxC;AAAA,EACF,IAAI,CAAC,QAAQ,IAAI,CAAC;AAClB,SAAO,oBAAC,YAAY,UAAZ,EAAqB,OAAe,UAAS;AACvD;AAEO,SAAS,OAAO;AACrB,QAAM,MAAM,WAAW,WAAW;AAClC,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,uCAAuC;AACjE,SAAO,IAAI;AACb;AAEO,SAAS,YAAY;AAC1B,QAAM,MAAM,WAAW,WAAW;AAClC,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,4CAA4C;AACtE,SAAO,IAAI;AACb;",
4
+ "sourcesContent": ["\"use client\"\nimport React, { createContext, useContext, useMemo } from 'react'\nimport type { Locale } from './config'\n\nexport type Dict = Record<string, string>\n\nexport type TranslateParams = Record<string, string | number>\n\nexport type TranslateFn = (\n key: string,\n fallbackOrParams?: string | TranslateParams,\n params?: TranslateParams\n) => string\n\nexport type I18nContextValue = {\n locale: Locale\n t: TranslateFn\n}\n\nconst I18nContext = createContext<I18nContextValue | null>(null)\n\nfunction format(template: string, params?: TranslateParams) {\n if (!params) return template\n return template.replace(/\\{\\{(\\w+)\\}\\}|\\{(\\w+)\\}/g, (_, doubleKey, singleKey) => {\n const key = doubleKey ?? singleKey\n if (!key) return _\n const value = params[key]\n if (value === undefined) {\n return doubleKey ? `{{${key}}}` : `{${key}}`\n }\n return String(value)\n })\n}\n\nexport function I18nProvider({ children, locale, dict }: { children: React.ReactNode; locale: Locale; dict: Dict }) {\n const value = useMemo<I18nContextValue>(() => ({\n locale,\n t: (key, fallbackOrParams, params) => {\n let fallback: string | undefined\n let resolvedParams: TranslateParams | undefined\n\n if (typeof fallbackOrParams === 'string') {\n fallback = fallbackOrParams\n resolvedParams = params\n } else {\n resolvedParams = fallbackOrParams ?? params\n }\n\n const template = dict[key] ?? fallback ?? key\n return format(template, resolvedParams)\n },\n }), [locale, dict])\n return <I18nContext.Provider value={value}>{children}</I18nContext.Provider>\n}\n\nexport function useT() {\n const ctx = useContext(I18nContext)\n if (!ctx) throw new Error('useT must be used within I18nProvider')\n return ctx.t\n}\n\nexport function useLocale() {\n const ctx = useContext(I18nContext)\n if (!ctx) throw new Error('useLocale must be used within I18nProvider')\n return ctx.locale\n}\n"],
5
+ "mappings": ";AAoDS;AAnDT,SAAgB,eAAe,YAAY,eAAe;AAkB1D,MAAM,cAAc,cAAuC,IAAI;AAE/D,SAAS,OAAO,UAAkB,QAA0B;AAC1D,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,SAAS,QAAQ,4BAA4B,CAAC,GAAG,WAAW,cAAc;AAC/E,UAAM,MAAM,aAAa;AACzB,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,QAAQ,OAAO,GAAG;AACxB,QAAI,UAAU,QAAW;AACvB,aAAO,YAAY,KAAK,GAAG,OAAO,IAAI,GAAG;AAAA,IAC3C;AACA,WAAO,OAAO,KAAK;AAAA,EACrB,CAAC;AACH;AAEO,SAAS,aAAa,EAAE,UAAU,QAAQ,KAAK,GAA8D;AAClH,QAAM,QAAQ,QAA0B,OAAO;AAAA,IAC7C;AAAA,IACA,GAAG,CAAC,KAAK,kBAAkB,WAAW;AACpC,UAAI;AACJ,UAAI;AAEJ,UAAI,OAAO,qBAAqB,UAAU;AACxC,mBAAW;AACX,yBAAiB;AAAA,MACnB,OAAO;AACL,yBAAiB,oBAAoB;AAAA,MACvC;AAEA,YAAM,WAAW,KAAK,GAAG,KAAK,YAAY;AAC1C,aAAO,OAAO,UAAU,cAAc;AAAA,IACxC;AAAA,EACF,IAAI,CAAC,QAAQ,IAAI,CAAC;AAClB,SAAO,oBAAC,YAAY,UAAZ,EAAqB,OAAe,UAAS;AACvD;AAEO,SAAS,OAAO;AACrB,QAAM,MAAM,WAAW,WAAW;AAClC,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,uCAAuC;AACjE,SAAO,IAAI;AACb;AAEO,SAAS,YAAY;AAC1B,QAAM,MAAM,WAAW,WAAW;AAClC,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,4CAA4C;AACtE,SAAO,IAAI;AACb;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,34 @@
1
+ import crypto from "node:crypto";
2
+ function base64url(input) {
3
+ return (typeof input === "string" ? Buffer.from(input) : input).toString("base64").replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
4
+ }
5
+ function signJwt(payload, secret = process.env.JWT_SECRET, expiresInSec = 60 * 60 * 8) {
6
+ if (!secret) throw new Error("JWT_SECRET is not set");
7
+ const header = { alg: "HS256", typ: "JWT" };
8
+ const now = Math.floor(Date.now() / 1e3);
9
+ const body = { iat: now, exp: now + expiresInSec, ...payload };
10
+ const encHeader = base64url(JSON.stringify(header));
11
+ const encBody = base64url(JSON.stringify(body));
12
+ const data = `${encHeader}.${encBody}`;
13
+ const sig = crypto.createHmac("sha256", secret).update(data).digest();
14
+ const encSig = base64url(sig);
15
+ return `${data}.${encSig}`;
16
+ }
17
+ function verifyJwt(token, secret = process.env.JWT_SECRET) {
18
+ if (!secret) throw new Error("JWT_SECRET is not set");
19
+ const parts = token.split(".");
20
+ if (parts.length !== 3) return null;
21
+ const [h, p, s] = parts;
22
+ const data = `${h}.${p}`;
23
+ const expected = base64url(crypto.createHmac("sha256", secret).update(data).digest());
24
+ if (!crypto.timingSafeEqual(Buffer.from(s), Buffer.from(expected))) return null;
25
+ const payload = JSON.parse(Buffer.from(p, "base64").toString("utf8"));
26
+ const now = Math.floor(Date.now() / 1e3);
27
+ if (payload.exp && now > payload.exp) return null;
28
+ return payload;
29
+ }
30
+ export {
31
+ signJwt,
32
+ verifyJwt
33
+ };
34
+ //# sourceMappingURL=jwt.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/lib/lib/auth/jwt.ts"],
4
+ "sourcesContent": ["import crypto from 'node:crypto'\n\nfunction base64url(input: Buffer | string) {\n return (typeof input === 'string' ? Buffer.from(input) : input)\n .toString('base64')\n .replace(/=/g, '')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n}\n\nexport type JwtPayload = Record<string, any>\n\nexport function signJwt(payload: JwtPayload, secret = process.env.JWT_SECRET!, expiresInSec = 60 * 60 * 8) {\n if (!secret) throw new Error('JWT_SECRET is not set')\n const header = { alg: 'HS256', typ: 'JWT' }\n const now = Math.floor(Date.now() / 1000)\n const body = { iat: now, exp: now + expiresInSec, ...payload }\n const encHeader = base64url(JSON.stringify(header))\n const encBody = base64url(JSON.stringify(body))\n const data = `${encHeader}.${encBody}`\n const sig = crypto.createHmac('sha256', secret).update(data).digest()\n const encSig = base64url(sig)\n return `${data}.${encSig}`\n}\n\nexport function verifyJwt(token: string, secret = process.env.JWT_SECRET!) {\n if (!secret) throw new Error('JWT_SECRET is not set')\n const parts = token.split('.')\n if (parts.length !== 3) return null\n const [h, p, s] = parts\n const data = `${h}.${p}`\n const expected = base64url(crypto.createHmac('sha256', secret).update(data).digest())\n if (!crypto.timingSafeEqual(Buffer.from(s), Buffer.from(expected))) return null\n const payload = JSON.parse(Buffer.from(p, 'base64').toString('utf8'))\n const now = Math.floor(Date.now() / 1000)\n if (payload.exp && now > payload.exp) return null\n return payload\n}\n\n"],
5
+ "mappings": "AAAA,OAAO,YAAY;AAEnB,SAAS,UAAU,OAAwB;AACzC,UAAQ,OAAO,UAAU,WAAW,OAAO,KAAK,KAAK,IAAI,OACtD,SAAS,QAAQ,EACjB,QAAQ,MAAM,EAAE,EAChB,QAAQ,OAAO,GAAG,EAClB,QAAQ,OAAO,GAAG;AACvB;AAIO,SAAS,QAAQ,SAAqB,SAAS,QAAQ,IAAI,YAAa,eAAe,KAAK,KAAK,GAAG;AACzG,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,uBAAuB;AACpD,QAAM,SAAS,EAAE,KAAK,SAAS,KAAK,MAAM;AAC1C,QAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,QAAM,OAAO,EAAE,KAAK,KAAK,KAAK,MAAM,cAAc,GAAG,QAAQ;AAC7D,QAAM,YAAY,UAAU,KAAK,UAAU,MAAM,CAAC;AAClD,QAAM,UAAU,UAAU,KAAK,UAAU,IAAI,CAAC;AAC9C,QAAM,OAAO,GAAG,SAAS,IAAI,OAAO;AACpC,QAAM,MAAM,OAAO,WAAW,UAAU,MAAM,EAAE,OAAO,IAAI,EAAE,OAAO;AACpE,QAAM,SAAS,UAAU,GAAG;AAC5B,SAAO,GAAG,IAAI,IAAI,MAAM;AAC1B;AAEO,SAAS,UAAU,OAAe,SAAS,QAAQ,IAAI,YAAa;AACzE,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,uBAAuB;AACpD,QAAM,QAAQ,MAAM,MAAM,GAAG;AAC7B,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAM,CAAC,GAAG,GAAG,CAAC,IAAI;AAClB,QAAM,OAAO,GAAG,CAAC,IAAI,CAAC;AACtB,QAAM,WAAW,UAAU,OAAO,WAAW,UAAU,MAAM,EAAE,OAAO,IAAI,EAAE,OAAO,CAAC;AACpF,MAAI,CAAC,OAAO,gBAAgB,OAAO,KAAK,CAAC,GAAG,OAAO,KAAK,QAAQ,CAAC,EAAG,QAAO;AAC3E,QAAM,UAAU,KAAK,MAAM,OAAO,KAAK,GAAG,QAAQ,EAAE,SAAS,MAAM,CAAC;AACpE,QAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,MAAI,QAAQ,OAAO,MAAM,QAAQ,IAAK,QAAO;AAC7C,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,77 @@
1
+ import { cookies } from "next/headers";
2
+ import { verifyJwt } from "./jwt.js";
3
+ async function resolveApiKeyAuth(secret) {
4
+ if (!secret) return null;
5
+ try {
6
+ const { createRequestContainer } = await import("@open-mercato/shared/lib/di/container");
7
+ const container = await createRequestContainer();
8
+ const em = container.resolve("em");
9
+ const { findApiKeyBySecret } = await import("@open-mercato/core/modules/api_keys/services/apiKeyService");
10
+ const { Role } = await import("@open-mercato/core/modules/auth/data/entities");
11
+ const record = await findApiKeyBySecret(em, secret);
12
+ if (!record) return null;
13
+ const roleIds = Array.isArray(record.rolesJson) ? record.rolesJson : [];
14
+ const roles = roleIds.length ? await em.find(Role, { id: { $in: roleIds } }) : [];
15
+ const roleNames = roles.map((role) => role.name).filter((name) => typeof name === "string" && name.length > 0);
16
+ try {
17
+ record.lastUsedAt = /* @__PURE__ */ new Date();
18
+ await em.persistAndFlush(record);
19
+ } catch {
20
+ }
21
+ return {
22
+ sub: `api_key:${record.id}`,
23
+ tenantId: record.tenantId ?? null,
24
+ orgId: record.organizationId ?? null,
25
+ roles: roleNames,
26
+ isApiKey: true,
27
+ keyId: record.id,
28
+ keyName: record.name
29
+ };
30
+ } catch {
31
+ return null;
32
+ }
33
+ }
34
+ function extractApiKey(req) {
35
+ const header = (req.headers.get("x-api-key") || "").trim();
36
+ if (header) return header;
37
+ const authHeader = (req.headers.get("authorization") || "").trim();
38
+ if (authHeader.toLowerCase().startsWith("apikey ")) {
39
+ return authHeader.slice(7).trim();
40
+ }
41
+ return null;
42
+ }
43
+ async function getAuthFromCookies() {
44
+ const token = (await cookies()).get("auth_token")?.value;
45
+ if (!token) return null;
46
+ try {
47
+ const payload = verifyJwt(token);
48
+ return payload;
49
+ } catch {
50
+ return null;
51
+ }
52
+ }
53
+ async function getAuthFromRequest(req) {
54
+ const authHeader = (req.headers.get("authorization") || "").trim();
55
+ let token;
56
+ if (authHeader.toLowerCase().startsWith("bearer ")) token = authHeader.slice(7).trim();
57
+ if (!token) {
58
+ const cookie = req.headers.get("cookie") || "";
59
+ const match = cookie.match(/(?:^|;\s*)auth_token=([^;]+)/);
60
+ if (match) token = decodeURIComponent(match[1]);
61
+ }
62
+ if (token) {
63
+ try {
64
+ const payload = verifyJwt(token);
65
+ if (payload) return payload;
66
+ } catch {
67
+ }
68
+ }
69
+ const apiKey = extractApiKey(req);
70
+ if (!apiKey) return null;
71
+ return resolveApiKeyAuth(apiKey);
72
+ }
73
+ export {
74
+ getAuthFromCookies,
75
+ getAuthFromRequest
76
+ };
77
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/lib/lib/auth/server.ts"],
4
+ "sourcesContent": ["import { cookies } from 'next/headers'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { verifyJwt } from './jwt'\n\nexport type AuthContext = {\n sub: string\n tenantId: string | null\n orgId: string | null\n email?: string\n roles?: string[]\n isApiKey?: boolean\n keyId?: string\n keyName?: string\n [k: string]: any\n} | null\n\nasync function resolveApiKeyAuth(secret: string): Promise<AuthContext> {\n if (!secret) return null\n try {\n const { createRequestContainer } = await import('@open-mercato/shared/lib/di/container')\n const container = await createRequestContainer()\n const em = (container.resolve('em') as EntityManager)\n const { findApiKeyBySecret } = await import('@open-mercato/core/modules/api_keys/services/apiKeyService')\n const { Role } = await import('@open-mercato/core/modules/auth/data/entities')\n\n const record = await findApiKeyBySecret(em, secret)\n if (!record) return null\n\n const roleIds = Array.isArray(record.rolesJson) ? record.rolesJson : []\n const roles = roleIds.length\n ? await em.find(Role, { id: { $in: roleIds as any } } as any)\n : []\n const roleNames = roles.map((role) => role.name).filter((name): name is string => typeof name === 'string' && name.length > 0)\n\n try {\n record.lastUsedAt = new Date()\n await em.persistAndFlush(record)\n } catch {}\n\n return {\n sub: `api_key:${record.id}`,\n tenantId: record.tenantId ?? null,\n orgId: record.organizationId ?? null,\n roles: roleNames,\n isApiKey: true,\n keyId: record.id,\n keyName: record.name,\n }\n } catch {\n return null\n }\n}\n\nfunction extractApiKey(req: Request): string | null {\n const header = (req.headers.get('x-api-key') || '').trim()\n if (header) return header\n const authHeader = (req.headers.get('authorization') || '').trim()\n if (authHeader.toLowerCase().startsWith('apikey ')) {\n return authHeader.slice(7).trim()\n }\n return null\n}\n\nexport async function getAuthFromCookies(): Promise<AuthContext> {\n const token = (await cookies()).get('auth_token')?.value\n if (!token) return null\n try {\n const payload = verifyJwt(token)\n return payload\n } catch {\n return null\n }\n}\n\nexport async function getAuthFromRequest(req: Request): Promise<AuthContext> {\n const authHeader = (req.headers.get('authorization') || '').trim()\n let token: string | undefined\n if (authHeader.toLowerCase().startsWith('bearer ')) token = authHeader.slice(7).trim()\n if (!token) {\n const cookie = req.headers.get('cookie') || ''\n const match = cookie.match(/(?:^|;\\s*)auth_token=([^;]+)/)\n if (match) token = decodeURIComponent(match[1])\n }\n if (token) {\n try {\n const payload = verifyJwt(token)\n if (payload) return payload\n } catch {}\n }\n\n const apiKey = extractApiKey(req)\n if (!apiKey) return null\n return resolveApiKeyAuth(apiKey)\n}\n"],
5
+ "mappings": "AAAA,SAAS,eAAe;AAExB,SAAS,iBAAiB;AAc1B,eAAe,kBAAkB,QAAsC;AACrE,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI;AACF,UAAM,EAAE,uBAAuB,IAAI,MAAM,OAAO,uCAAuC;AACvF,UAAM,YAAY,MAAM,uBAAuB;AAC/C,UAAM,KAAM,UAAU,QAAQ,IAAI;AAClC,UAAM,EAAE,mBAAmB,IAAI,MAAM,OAAO,4DAA4D;AACxG,UAAM,EAAE,KAAK,IAAI,MAAM,OAAO,+CAA+C;AAE7E,UAAM,SAAS,MAAM,mBAAmB,IAAI,MAAM;AAClD,QAAI,CAAC,OAAQ,QAAO;AAEpB,UAAM,UAAU,MAAM,QAAQ,OAAO,SAAS,IAAI,OAAO,YAAY,CAAC;AACtE,UAAM,QAAQ,QAAQ,SAClB,MAAM,GAAG,KAAK,MAAM,EAAE,IAAI,EAAE,KAAK,QAAe,EAAE,CAAQ,IAC1D,CAAC;AACL,UAAM,YAAY,MAAM,IAAI,CAAC,SAAS,KAAK,IAAI,EAAE,OAAO,CAAC,SAAyB,OAAO,SAAS,YAAY,KAAK,SAAS,CAAC;AAE7H,QAAI;AACF,aAAO,aAAa,oBAAI,KAAK;AAC7B,YAAM,GAAG,gBAAgB,MAAM;AAAA,IACjC,QAAQ;AAAA,IAAC;AAET,WAAO;AAAA,MACL,KAAK,WAAW,OAAO,EAAE;AAAA,MACzB,UAAU,OAAO,YAAY;AAAA,MAC7B,OAAO,OAAO,kBAAkB;AAAA,MAChC,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO,OAAO;AAAA,MACd,SAAS,OAAO;AAAA,IAClB;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,cAAc,KAA6B;AAClD,QAAM,UAAU,IAAI,QAAQ,IAAI,WAAW,KAAK,IAAI,KAAK;AACzD,MAAI,OAAQ,QAAO;AACnB,QAAM,cAAc,IAAI,QAAQ,IAAI,eAAe,KAAK,IAAI,KAAK;AACjE,MAAI,WAAW,YAAY,EAAE,WAAW,SAAS,GAAG;AAClD,WAAO,WAAW,MAAM,CAAC,EAAE,KAAK;AAAA,EAClC;AACA,SAAO;AACT;AAEA,eAAsB,qBAA2C;AAC/D,QAAM,SAAS,MAAM,QAAQ,GAAG,IAAI,YAAY,GAAG;AACnD,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI;AACF,UAAM,UAAU,UAAU,KAAK;AAC/B,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,mBAAmB,KAAoC;AAC3E,QAAM,cAAc,IAAI,QAAQ,IAAI,eAAe,KAAK,IAAI,KAAK;AACjE,MAAI;AACJ,MAAI,WAAW,YAAY,EAAE,WAAW,SAAS,EAAG,SAAQ,WAAW,MAAM,CAAC,EAAE,KAAK;AACrF,MAAI,CAAC,OAAO;AACV,UAAM,SAAS,IAAI,QAAQ,IAAI,QAAQ,KAAK;AAC5C,UAAM,QAAQ,OAAO,MAAM,8BAA8B;AACzD,QAAI,MAAO,SAAQ,mBAAmB,MAAM,CAAC,CAAC;AAAA,EAChD;AACA,MAAI,OAAO;AACT,QAAI;AACF,YAAM,UAAU,UAAU,KAAK;AAC/B,UAAI,QAAS,QAAO;AAAA,IACtB,QAAQ;AAAA,IAAC;AAAA,EACX;AAEA,QAAM,SAAS,cAAc,GAAG;AAChC,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,kBAAkB,MAAM;AACjC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,26 @@
1
+ import { Resend } from "resend";
2
+ import { parseBooleanWithDefault } from "../../boolean.js";
3
+ async function sendEmail({ to, subject, react, from, replyTo }) {
4
+ const emailDisabled = parseBooleanWithDefault(process.env.OM_DISABLE_EMAIL_DELIVERY, false) || parseBooleanWithDefault(process.env.OM_TEST_MODE, false);
5
+ if (emailDisabled) return;
6
+ const apiKey = process.env.RESEND_API_KEY;
7
+ if (!apiKey) throw new Error("RESEND_API_KEY is not set");
8
+ const resend = new Resend(apiKey);
9
+ const fromAddr = from || process.env.EMAIL_FROM || "no-reply@localhost";
10
+ const payload = {
11
+ to,
12
+ subject,
13
+ from: fromAddr,
14
+ react,
15
+ ...replyTo ? { reply_to: replyTo } : {}
16
+ };
17
+ const result = await resend.emails.send(payload);
18
+ const errorMessage = typeof result?.error === "string" ? result.error : typeof result?.error?.message === "string" ? result.error.message : null;
19
+ if (errorMessage) {
20
+ throw new Error(`RESEND_SEND_FAILED: ${errorMessage}`);
21
+ }
22
+ }
23
+ export {
24
+ sendEmail
25
+ };
26
+ //# sourceMappingURL=send.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/lib/lib/email/send.ts"],
4
+ "sourcesContent": ["import { Resend } from 'resend'\nimport React from 'react'\nimport { parseBooleanWithDefault } from '../../boolean'\n\nexport type SendEmailOptions = {\n to: string\n subject: string\n react: React.ReactElement\n from?: string\n replyTo?: string\n}\n\nexport async function sendEmail({ to, subject, react, from, replyTo }: SendEmailOptions) {\n const emailDisabled =\n parseBooleanWithDefault(process.env.OM_DISABLE_EMAIL_DELIVERY, false) ||\n parseBooleanWithDefault(process.env.OM_TEST_MODE, false)\n if (emailDisabled) return\n\n const apiKey = process.env.RESEND_API_KEY\n if (!apiKey) throw new Error('RESEND_API_KEY is not set')\n const resend = new Resend(apiKey)\n const fromAddr = from || process.env.EMAIL_FROM || 'no-reply@localhost'\n const payload = {\n to,\n subject,\n from: fromAddr,\n react,\n ...(replyTo ? { reply_to: replyTo } : {}),\n }\n const result = await resend.emails.send(payload)\n const errorMessage =\n typeof (result as any)?.error === 'string'\n ? (result as any).error\n : typeof (result as any)?.error?.message === 'string'\n ? (result as any).error.message\n : null\n if (errorMessage) {\n throw new Error(`RESEND_SEND_FAILED: ${errorMessage}`)\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,cAAc;AAEvB,SAAS,+BAA+B;AAUxC,eAAsB,UAAU,EAAE,IAAI,SAAS,OAAO,MAAM,QAAQ,GAAqB;AACvF,QAAM,gBACJ,wBAAwB,QAAQ,IAAI,2BAA2B,KAAK,KACpE,wBAAwB,QAAQ,IAAI,cAAc,KAAK;AACzD,MAAI,cAAe;AAEnB,QAAM,SAAS,QAAQ,IAAI;AAC3B,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,2BAA2B;AACxD,QAAM,SAAS,IAAI,OAAO,MAAM;AAChC,QAAM,WAAW,QAAQ,QAAQ,IAAI,cAAc;AACnD,QAAM,UAAU;AAAA,IACd;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA,GAAI,UAAU,EAAE,UAAU,QAAQ,IAAI,CAAC;AAAA,EACzC;AACA,QAAM,SAAS,MAAM,OAAO,OAAO,KAAK,OAAO;AAC/C,QAAM,eACJ,OAAQ,QAAgB,UAAU,WAC7B,OAAe,QAChB,OAAQ,QAAgB,OAAO,YAAY,WACxC,OAAe,MAAM,UACtB;AACR,MAAI,cAAc;AAChB,UAAM,IAAI,MAAM,uBAAuB,YAAY,EAAE;AAAA,EACvD;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,7 @@
1
+ const locales = ["en", "pl", "es", "de"];
2
+ const defaultLocale = "en";
3
+ export {
4
+ defaultLocale,
5
+ locales
6
+ };
7
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/lib/lib/i18n/config.ts"],
4
+ "sourcesContent": ["export type Locale = 'en' | 'pl' | 'es' | 'de'\n\nexport const locales: Locale[] = ['en', 'pl', 'es', 'de']\nexport const defaultLocale: Locale = 'en'\n"],
5
+ "mappings": "AAEO,MAAM,UAAoB,CAAC,MAAM,MAAM,MAAM,IAAI;AACjD,MAAM,gBAAwB;",
6
+ "names": []
7
+ }
@@ -0,0 +1,31 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext, useMemo } from "react";
4
+ const I18nContext = createContext(null);
5
+ function format(template, params) {
6
+ if (!params) return template;
7
+ return template.replace(/\{(\w+)\}/g, (_, k) => String(params[k] ?? `{${k}}`));
8
+ }
9
+ function I18nProvider({ children, locale, dict }) {
10
+ const value = useMemo(() => ({
11
+ locale,
12
+ t: (key, params) => format(dict[key] ?? key, params)
13
+ }), [locale, dict]);
14
+ return /* @__PURE__ */ jsx(I18nContext.Provider, { value, children });
15
+ }
16
+ function useT() {
17
+ const ctx = useContext(I18nContext);
18
+ if (!ctx) throw new Error("useT must be used within I18nProvider");
19
+ return ctx.t;
20
+ }
21
+ function useLocale() {
22
+ const ctx = useContext(I18nContext);
23
+ if (!ctx) throw new Error("useLocale must be used within I18nProvider");
24
+ return ctx.locale;
25
+ }
26
+ export {
27
+ I18nProvider,
28
+ useLocale,
29
+ useT
30
+ };
31
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/lib/lib/i18n/context.tsx"],
4
+ "sourcesContent": ["\"use client\"\nimport React, { createContext, useContext, useMemo } from 'react'\nimport type { Locale } from './config'\n\nexport type Dict = Record<string, string>\n\nexport type I18nContextValue = {\n locale: Locale\n t: (key: string, params?: Record<string, string | number>) => string\n}\n\nconst I18nContext = createContext<I18nContextValue | null>(null)\n\nfunction format(template: string, params?: Record<string, string | number>) {\n if (!params) return template\n return template.replace(/\\{(\\w+)\\}/g, (_, k) => String(params[k] ?? `{${k}}`))\n}\n\nexport function I18nProvider({ children, locale, dict }: { children: React.ReactNode; locale: Locale; dict: Dict }) {\n const value = useMemo<I18nContextValue>(() => ({\n locale,\n t: (key, params) => format(dict[key] ?? key, params),\n }), [locale, dict])\n return <I18nContext.Provider value={value}>{children}</I18nContext.Provider>\n}\n\nexport function useT() {\n const ctx = useContext(I18nContext)\n if (!ctx) throw new Error('useT must be used within I18nProvider')\n return ctx.t\n}\n\nexport function useLocale() {\n const ctx = useContext(I18nContext)\n if (!ctx) throw new Error('useLocale must be used within I18nProvider')\n return ctx.locale\n}\n\n"],
5
+ "mappings": ";AAuBS;AAtBT,SAAgB,eAAe,YAAY,eAAe;AAU1D,MAAM,cAAc,cAAuC,IAAI;AAE/D,SAAS,OAAO,UAAkB,QAA0C;AAC1E,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,SAAS,QAAQ,cAAc,CAAC,GAAG,MAAM,OAAO,OAAO,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC;AAC/E;AAEO,SAAS,aAAa,EAAE,UAAU,QAAQ,KAAK,GAA8D;AAClH,QAAM,QAAQ,QAA0B,OAAO;AAAA,IAC7C;AAAA,IACA,GAAG,CAAC,KAAK,WAAW,OAAO,KAAK,GAAG,KAAK,KAAK,MAAM;AAAA,EACrD,IAAI,CAAC,QAAQ,IAAI,CAAC;AAClB,SAAO,oBAAC,YAAY,UAAZ,EAAqB,OAAe,UAAS;AACvD;AAEO,SAAS,OAAO;AACrB,QAAM,MAAM,WAAW,WAAW;AAClC,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,uCAAuC;AACjE,SAAO,IAAI;AACb;AAEO,SAAS,YAAY;AAC1B,QAAM,MAAM,WAAW,WAAW;AAClC,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,4CAA4C;AACtE,SAAO,IAAI;AACb;",
6
+ "names": []
7
+ }
@@ -0,0 +1,9 @@
1
+ import { clsx } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+ function cn(...inputs) {
4
+ return twMerge(clsx(inputs));
5
+ }
6
+ export {
7
+ cn
8
+ };
9
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/lib/utils.ts"],
4
+ "sourcesContent": ["import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n"],
5
+ "mappings": "AAAA,SAAS,YAA6B;AACtC,SAAS,eAAe;AAEjB,SAAS,MAAM,QAAsB;AAC1C,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;",
6
+ "names": []
7
+ }
@@ -1,4 +1,4 @@
1
- const APP_VERSION = "0.4.6-canary-c3811b08ec";
1
+ const APP_VERSION = "0.4.6-canary-8ae94de818";
2
2
  const appVersion = APP_VERSION;
3
3
  export {
4
4
  APP_VERSION,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/version.ts"],
4
- "sourcesContent": ["// Build-time generated version\nexport const APP_VERSION = '0.4.6-canary-c3811b08ec'\nexport const appVersion = APP_VERSION\n"],
4
+ "sourcesContent": ["// Build-time generated version\nexport const APP_VERSION = '0.4.6-canary-8ae94de818'\nexport const appVersion = APP_VERSION\n"],
5
5
  "mappings": "AACO,MAAM,cAAc;AACpB,MAAM,aAAa;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,2 @@
1
+ export * from "./types.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/modules/payment_gateways/index.ts"],
4
+ "sourcesContent": ["export * from './types'\n"],
5
+ "mappings": "AAAA,cAAc;",
6
+ "names": []
7
+ }
@@ -0,0 +1,59 @@
1
+ const adapterRegistry = /* @__PURE__ */ new Map();
2
+ const webhookHandlerRegistry = /* @__PURE__ */ new Map();
3
+ function adapterKey(providerKey, version) {
4
+ return version ? `${providerKey}:${version}` : providerKey;
5
+ }
6
+ function registerGatewayAdapter(adapter, options) {
7
+ const key = adapterKey(adapter.providerKey, options?.version);
8
+ adapterRegistry.set(key, adapter);
9
+ if (options?.version) {
10
+ if (!adapterRegistry.has(adapter.providerKey)) {
11
+ adapterRegistry.set(adapter.providerKey, adapter);
12
+ }
13
+ }
14
+ return () => {
15
+ adapterRegistry.delete(key);
16
+ };
17
+ }
18
+ function getGatewayAdapter(providerKey, version) {
19
+ if (version) {
20
+ return adapterRegistry.get(adapterKey(providerKey, version)) ?? adapterRegistry.get(providerKey);
21
+ }
22
+ return adapterRegistry.get(providerKey);
23
+ }
24
+ function listGatewayAdapters() {
25
+ const seen = /* @__PURE__ */ new Set();
26
+ const result = [];
27
+ for (const [key, adapter] of adapterRegistry) {
28
+ if (!key.includes(":") && !seen.has(adapter.providerKey)) {
29
+ seen.add(adapter.providerKey);
30
+ result.push(adapter);
31
+ }
32
+ }
33
+ return result;
34
+ }
35
+ function clearGatewayAdapters() {
36
+ adapterRegistry.clear();
37
+ }
38
+ function registerWebhookHandler(providerKey, handler, options) {
39
+ webhookHandlerRegistry.set(providerKey, { handler, queue: options?.queue });
40
+ return () => {
41
+ webhookHandlerRegistry.delete(providerKey);
42
+ };
43
+ }
44
+ function getWebhookHandler(providerKey) {
45
+ return webhookHandlerRegistry.get(providerKey);
46
+ }
47
+ function clearWebhookHandlers() {
48
+ webhookHandlerRegistry.clear();
49
+ }
50
+ export {
51
+ clearGatewayAdapters,
52
+ clearWebhookHandlers,
53
+ getGatewayAdapter,
54
+ getWebhookHandler,
55
+ listGatewayAdapters,
56
+ registerGatewayAdapter,
57
+ registerWebhookHandler
58
+ };
59
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/modules/payment_gateways/types.ts"],
4
+ "sourcesContent": ["// \u2500\u2500 Unified Payment Status \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type UnifiedPaymentStatus =\n | 'pending'\n | 'authorized'\n | 'captured'\n | 'partially_captured'\n | 'refunded'\n | 'partially_refunded'\n | 'cancelled'\n | 'failed'\n | 'expired'\n | 'unknown'\n\n// \u2500\u2500 GatewayAdapter Interface \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface GatewayAdapter {\n readonly providerKey: string\n\n /** Create a payment session / payment intent */\n createSession(input: CreateSessionInput): Promise<CreateSessionResult>\n\n /** Capture an authorized payment */\n capture(input: CaptureInput): Promise<CaptureResult>\n\n /** Refund a captured payment (full or partial) */\n refund(input: RefundInput): Promise<RefundResult>\n\n /** Cancel / void an authorized payment before capture */\n cancel(input: CancelInput): Promise<CancelResult>\n\n /** Get current payment status from provider */\n getStatus(input: GetStatusInput): Promise<GatewayPaymentStatus>\n\n /** Verify and parse an inbound webhook event */\n verifyWebhook(input: VerifyWebhookInput): Promise<WebhookEvent>\n\n /** Map provider status to unified status */\n mapStatus(providerStatus: string, eventType?: string): UnifiedPaymentStatus\n}\n\n// \u2500\u2500 Input / Output Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface CreateSessionInput {\n orderId?: string\n paymentId: string\n tenantId: string\n organizationId: string\n amount: number\n currencyCode: string\n captureMethod?: 'automatic' | 'manual'\n paymentTypes?: string[]\n description?: string\n successUrl?: string\n cancelUrl?: string\n metadata?: Record<string, unknown>\n credentials: Record<string, unknown>\n lineItems?: SessionLineItem[]\n}\n\nexport interface SessionLineItem {\n name: string\n quantity: number\n unitAmount: number\n currencyCode: string\n}\n\nexport interface CreateSessionResult {\n sessionId: string\n clientSecret?: string\n redirectUrl?: string\n status: UnifiedPaymentStatus\n providerData?: Record<string, unknown>\n}\n\nexport interface CaptureInput {\n sessionId: string\n amount?: number\n credentials: Record<string, unknown>\n metadata?: Record<string, unknown>\n}\n\nexport interface CaptureResult {\n status: UnifiedPaymentStatus\n capturedAmount: number\n providerData?: Record<string, unknown>\n}\n\nexport interface RefundInput {\n sessionId: string\n amount?: number\n reason?: string\n credentials: Record<string, unknown>\n metadata?: Record<string, unknown>\n}\n\nexport interface RefundResult {\n refundId: string\n status: UnifiedPaymentStatus\n refundedAmount: number\n providerData?: Record<string, unknown>\n}\n\nexport interface CancelInput {\n sessionId: string\n reason?: string\n credentials: Record<string, unknown>\n}\n\nexport interface CancelResult {\n status: UnifiedPaymentStatus\n providerData?: Record<string, unknown>\n}\n\nexport interface GetStatusInput {\n sessionId: string\n credentials: Record<string, unknown>\n}\n\nexport interface GatewayPaymentStatus {\n status: UnifiedPaymentStatus\n amount: number\n amountReceived: number\n currencyCode: string\n providerData?: Record<string, unknown>\n}\n\nexport interface VerifyWebhookInput {\n rawBody: string | Buffer\n headers: Record<string, string | string[] | undefined>\n credentials: Record<string, unknown>\n}\n\nexport interface WebhookEvent {\n eventType: string\n eventId: string\n data: Record<string, unknown>\n idempotencyKey: string\n timestamp: Date\n}\n\n// \u2500\u2500 Webhook Handler \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface WebhookHandlerRegistration {\n handler: (input: VerifyWebhookInput) => Promise<WebhookEvent>\n queue?: string\n}\n\n// \u2500\u2500 Adapter Registry Options \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface RegisterAdapterOptions {\n version?: string\n}\n\n// \u2500\u2500 Registries \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst adapterRegistry = new Map<string, GatewayAdapter>()\nconst webhookHandlerRegistry = new Map<string, WebhookHandlerRegistration>()\n\nfunction adapterKey(providerKey: string, version?: string): string {\n return version ? `${providerKey}:${version}` : providerKey\n}\n\nexport function registerGatewayAdapter(adapter: GatewayAdapter, options?: RegisterAdapterOptions): () => void {\n const key = adapterKey(adapter.providerKey, options?.version)\n adapterRegistry.set(key, adapter)\n if (options?.version) {\n // Also register as default if no default exists\n if (!adapterRegistry.has(adapter.providerKey)) {\n adapterRegistry.set(adapter.providerKey, adapter)\n }\n }\n return () => {\n adapterRegistry.delete(key)\n }\n}\n\nexport function getGatewayAdapter(providerKey: string, version?: string): GatewayAdapter | undefined {\n if (version) {\n return adapterRegistry.get(adapterKey(providerKey, version)) ?? adapterRegistry.get(providerKey)\n }\n return adapterRegistry.get(providerKey)\n}\n\nexport function listGatewayAdapters(): GatewayAdapter[] {\n const seen = new Set<string>()\n const result: GatewayAdapter[] = []\n for (const [key, adapter] of adapterRegistry) {\n if (!key.includes(':') && !seen.has(adapter.providerKey)) {\n seen.add(adapter.providerKey)\n result.push(adapter)\n }\n }\n return result\n}\n\nexport function clearGatewayAdapters(): void {\n adapterRegistry.clear()\n}\n\nexport function registerWebhookHandler(\n providerKey: string,\n handler: (input: VerifyWebhookInput) => Promise<WebhookEvent>,\n options?: { queue?: string },\n): () => void {\n webhookHandlerRegistry.set(providerKey, { handler, queue: options?.queue })\n return () => {\n webhookHandlerRegistry.delete(providerKey)\n }\n}\n\nexport function getWebhookHandler(providerKey: string): WebhookHandlerRegistration | undefined {\n return webhookHandlerRegistry.get(providerKey)\n}\n\nexport function clearWebhookHandlers(): void {\n webhookHandlerRegistry.clear()\n}\n"],
5
+ "mappings": "AA4JA,MAAM,kBAAkB,oBAAI,IAA4B;AACxD,MAAM,yBAAyB,oBAAI,IAAwC;AAE3E,SAAS,WAAW,aAAqB,SAA0B;AACjE,SAAO,UAAU,GAAG,WAAW,IAAI,OAAO,KAAK;AACjD;AAEO,SAAS,uBAAuB,SAAyB,SAA8C;AAC5G,QAAM,MAAM,WAAW,QAAQ,aAAa,SAAS,OAAO;AAC5D,kBAAgB,IAAI,KAAK,OAAO;AAChC,MAAI,SAAS,SAAS;AAEpB,QAAI,CAAC,gBAAgB,IAAI,QAAQ,WAAW,GAAG;AAC7C,sBAAgB,IAAI,QAAQ,aAAa,OAAO;AAAA,IAClD;AAAA,EACF;AACA,SAAO,MAAM;AACX,oBAAgB,OAAO,GAAG;AAAA,EAC5B;AACF;AAEO,SAAS,kBAAkB,aAAqB,SAA8C;AACnG,MAAI,SAAS;AACX,WAAO,gBAAgB,IAAI,WAAW,aAAa,OAAO,CAAC,KAAK,gBAAgB,IAAI,WAAW;AAAA,EACjG;AACA,SAAO,gBAAgB,IAAI,WAAW;AACxC;AAEO,SAAS,sBAAwC;AACtD,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,SAA2B,CAAC;AAClC,aAAW,CAAC,KAAK,OAAO,KAAK,iBAAiB;AAC5C,QAAI,CAAC,IAAI,SAAS,GAAG,KAAK,CAAC,KAAK,IAAI,QAAQ,WAAW,GAAG;AACxD,WAAK,IAAI,QAAQ,WAAW;AAC5B,aAAO,KAAK,OAAO;AAAA,IACrB;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,uBAA6B;AAC3C,kBAAgB,MAAM;AACxB;AAEO,SAAS,uBACd,aACA,SACA,SACY;AACZ,yBAAuB,IAAI,aAAa,EAAE,SAAS,OAAO,SAAS,MAAM,CAAC;AAC1E,SAAO,MAAM;AACX,2BAAuB,OAAO,WAAW;AAAA,EAC3C;AACF;AAEO,SAAS,kBAAkB,aAA6D;AAC7F,SAAO,uBAAuB,IAAI,WAAW;AAC/C;AAEO,SAAS,uBAA6B;AAC3C,yBAAuB,MAAM;AAC/B;",
6
+ "names": []
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/shared",
3
- "version": "0.4.6-canary-c3811b08ec",
3
+ "version": "0.4.6-canary-8ae94de818",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -1,5 +1,5 @@
1
1
  "use client"
2
- import { createContext, useContext, useMemo, type ReactNode } from 'react'
2
+ import React, { createContext, useContext, useMemo } from 'react'
3
3
  import type { Locale } from './config'
4
4
 
5
5
  export type Dict = Record<string, string>
@@ -32,7 +32,7 @@ function format(template: string, params?: TranslateParams) {
32
32
  })
33
33
  }
34
34
 
35
- export function I18nProvider({ children, locale, dict }: { children: ReactNode; locale: Locale; dict: Dict }) {
35
+ export function I18nProvider({ children, locale, dict }: { children: React.ReactNode; locale: Locale; dict: Dict }) {
36
36
  const value = useMemo<I18nContextValue>(() => ({
37
37
  locale,
38
38
  t: (key, fallbackOrParams, params) => {
@@ -0,0 +1,39 @@
1
+ import crypto from 'node:crypto'
2
+
3
+ function base64url(input: Buffer | string) {
4
+ return (typeof input === 'string' ? Buffer.from(input) : input)
5
+ .toString('base64')
6
+ .replace(/=/g, '')
7
+ .replace(/\+/g, '-')
8
+ .replace(/\//g, '_')
9
+ }
10
+
11
+ export type JwtPayload = Record<string, any>
12
+
13
+ export function signJwt(payload: JwtPayload, secret = process.env.JWT_SECRET!, expiresInSec = 60 * 60 * 8) {
14
+ if (!secret) throw new Error('JWT_SECRET is not set')
15
+ const header = { alg: 'HS256', typ: 'JWT' }
16
+ const now = Math.floor(Date.now() / 1000)
17
+ const body = { iat: now, exp: now + expiresInSec, ...payload }
18
+ const encHeader = base64url(JSON.stringify(header))
19
+ const encBody = base64url(JSON.stringify(body))
20
+ const data = `${encHeader}.${encBody}`
21
+ const sig = crypto.createHmac('sha256', secret).update(data).digest()
22
+ const encSig = base64url(sig)
23
+ return `${data}.${encSig}`
24
+ }
25
+
26
+ export function verifyJwt(token: string, secret = process.env.JWT_SECRET!) {
27
+ if (!secret) throw new Error('JWT_SECRET is not set')
28
+ const parts = token.split('.')
29
+ if (parts.length !== 3) return null
30
+ const [h, p, s] = parts
31
+ const data = `${h}.${p}`
32
+ const expected = base64url(crypto.createHmac('sha256', secret).update(data).digest())
33
+ if (!crypto.timingSafeEqual(Buffer.from(s), Buffer.from(expected))) return null
34
+ const payload = JSON.parse(Buffer.from(p, 'base64').toString('utf8'))
35
+ const now = Math.floor(Date.now() / 1000)
36
+ if (payload.exp && now > payload.exp) return null
37
+ return payload
38
+ }
39
+
@@ -0,0 +1,94 @@
1
+ import { cookies } from 'next/headers'
2
+ import type { EntityManager } from '@mikro-orm/postgresql'
3
+ import { verifyJwt } from './jwt'
4
+
5
+ export type AuthContext = {
6
+ sub: string
7
+ tenantId: string | null
8
+ orgId: string | null
9
+ email?: string
10
+ roles?: string[]
11
+ isApiKey?: boolean
12
+ keyId?: string
13
+ keyName?: string
14
+ [k: string]: any
15
+ } | null
16
+
17
+ async function resolveApiKeyAuth(secret: string): Promise<AuthContext> {
18
+ if (!secret) return null
19
+ try {
20
+ const { createRequestContainer } = await import('@open-mercato/shared/lib/di/container')
21
+ const container = await createRequestContainer()
22
+ const em = (container.resolve('em') as EntityManager)
23
+ const { findApiKeyBySecret } = await import('@open-mercato/core/modules/api_keys/services/apiKeyService')
24
+ const { Role } = await import('@open-mercato/core/modules/auth/data/entities')
25
+
26
+ const record = await findApiKeyBySecret(em, secret)
27
+ if (!record) return null
28
+
29
+ const roleIds = Array.isArray(record.rolesJson) ? record.rolesJson : []
30
+ const roles = roleIds.length
31
+ ? await em.find(Role, { id: { $in: roleIds as any } } as any)
32
+ : []
33
+ const roleNames = roles.map((role) => role.name).filter((name): name is string => typeof name === 'string' && name.length > 0)
34
+
35
+ try {
36
+ record.lastUsedAt = new Date()
37
+ await em.persistAndFlush(record)
38
+ } catch {}
39
+
40
+ return {
41
+ sub: `api_key:${record.id}`,
42
+ tenantId: record.tenantId ?? null,
43
+ orgId: record.organizationId ?? null,
44
+ roles: roleNames,
45
+ isApiKey: true,
46
+ keyId: record.id,
47
+ keyName: record.name,
48
+ }
49
+ } catch {
50
+ return null
51
+ }
52
+ }
53
+
54
+ function extractApiKey(req: Request): string | null {
55
+ const header = (req.headers.get('x-api-key') || '').trim()
56
+ if (header) return header
57
+ const authHeader = (req.headers.get('authorization') || '').trim()
58
+ if (authHeader.toLowerCase().startsWith('apikey ')) {
59
+ return authHeader.slice(7).trim()
60
+ }
61
+ return null
62
+ }
63
+
64
+ export async function getAuthFromCookies(): Promise<AuthContext> {
65
+ const token = (await cookies()).get('auth_token')?.value
66
+ if (!token) return null
67
+ try {
68
+ const payload = verifyJwt(token)
69
+ return payload
70
+ } catch {
71
+ return null
72
+ }
73
+ }
74
+
75
+ export async function getAuthFromRequest(req: Request): Promise<AuthContext> {
76
+ const authHeader = (req.headers.get('authorization') || '').trim()
77
+ let token: string | undefined
78
+ if (authHeader.toLowerCase().startsWith('bearer ')) token = authHeader.slice(7).trim()
79
+ if (!token) {
80
+ const cookie = req.headers.get('cookie') || ''
81
+ const match = cookie.match(/(?:^|;\s*)auth_token=([^;]+)/)
82
+ if (match) token = decodeURIComponent(match[1])
83
+ }
84
+ if (token) {
85
+ try {
86
+ const payload = verifyJwt(token)
87
+ if (payload) return payload
88
+ } catch {}
89
+ }
90
+
91
+ const apiKey = extractApiKey(req)
92
+ if (!apiKey) return null
93
+ return resolveApiKeyAuth(apiKey)
94
+ }
@@ -0,0 +1,40 @@
1
+ import { Resend } from 'resend'
2
+ import React from 'react'
3
+ import { parseBooleanWithDefault } from '../../boolean'
4
+
5
+ export type SendEmailOptions = {
6
+ to: string
7
+ subject: string
8
+ react: React.ReactElement
9
+ from?: string
10
+ replyTo?: string
11
+ }
12
+
13
+ export async function sendEmail({ to, subject, react, from, replyTo }: SendEmailOptions) {
14
+ const emailDisabled =
15
+ parseBooleanWithDefault(process.env.OM_DISABLE_EMAIL_DELIVERY, false) ||
16
+ parseBooleanWithDefault(process.env.OM_TEST_MODE, false)
17
+ if (emailDisabled) return
18
+
19
+ const apiKey = process.env.RESEND_API_KEY
20
+ if (!apiKey) throw new Error('RESEND_API_KEY is not set')
21
+ const resend = new Resend(apiKey)
22
+ const fromAddr = from || process.env.EMAIL_FROM || 'no-reply@localhost'
23
+ const payload = {
24
+ to,
25
+ subject,
26
+ from: fromAddr,
27
+ react,
28
+ ...(replyTo ? { reply_to: replyTo } : {}),
29
+ }
30
+ const result = await resend.emails.send(payload)
31
+ const errorMessage =
32
+ typeof (result as any)?.error === 'string'
33
+ ? (result as any).error
34
+ : typeof (result as any)?.error?.message === 'string'
35
+ ? (result as any).error.message
36
+ : null
37
+ if (errorMessage) {
38
+ throw new Error(`RESEND_SEND_FAILED: ${errorMessage}`)
39
+ }
40
+ }
@@ -0,0 +1,4 @@
1
+ export type Locale = 'en' | 'pl' | 'es' | 'de'
2
+
3
+ export const locales: Locale[] = ['en', 'pl', 'es', 'de']
4
+ export const defaultLocale: Locale = 'en'
@@ -0,0 +1,38 @@
1
+ "use client"
2
+ import React, { createContext, useContext, useMemo } from 'react'
3
+ import type { Locale } from './config'
4
+
5
+ export type Dict = Record<string, string>
6
+
7
+ export type I18nContextValue = {
8
+ locale: Locale
9
+ t: (key: string, params?: Record<string, string | number>) => string
10
+ }
11
+
12
+ const I18nContext = createContext<I18nContextValue | null>(null)
13
+
14
+ function format(template: string, params?: Record<string, string | number>) {
15
+ if (!params) return template
16
+ return template.replace(/\{(\w+)\}/g, (_, k) => String(params[k] ?? `{${k}}`))
17
+ }
18
+
19
+ export function I18nProvider({ children, locale, dict }: { children: React.ReactNode; locale: Locale; dict: Dict }) {
20
+ const value = useMemo<I18nContextValue>(() => ({
21
+ locale,
22
+ t: (key, params) => format(dict[key] ?? key, params),
23
+ }), [locale, dict])
24
+ return <I18nContext.Provider value={value}>{children}</I18nContext.Provider>
25
+ }
26
+
27
+ export function useT() {
28
+ const ctx = useContext(I18nContext)
29
+ if (!ctx) throw new Error('useT must be used within I18nProvider')
30
+ return ctx.t
31
+ }
32
+
33
+ export function useLocale() {
34
+ const ctx = useContext(I18nContext)
35
+ if (!ctx) throw new Error('useLocale must be used within I18nProvider')
36
+ return ctx.locale
37
+ }
38
+
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
@@ -0,0 +1 @@
1
+ export * from './types'
@@ -0,0 +1,218 @@
1
+ // ── Unified Payment Status ──────────────────────────────────────────────────
2
+
3
+ export type UnifiedPaymentStatus =
4
+ | 'pending'
5
+ | 'authorized'
6
+ | 'captured'
7
+ | 'partially_captured'
8
+ | 'refunded'
9
+ | 'partially_refunded'
10
+ | 'cancelled'
11
+ | 'failed'
12
+ | 'expired'
13
+ | 'unknown'
14
+
15
+ // ── GatewayAdapter Interface ────────────────────────────────────────────────
16
+
17
+ export interface GatewayAdapter {
18
+ readonly providerKey: string
19
+
20
+ /** Create a payment session / payment intent */
21
+ createSession(input: CreateSessionInput): Promise<CreateSessionResult>
22
+
23
+ /** Capture an authorized payment */
24
+ capture(input: CaptureInput): Promise<CaptureResult>
25
+
26
+ /** Refund a captured payment (full or partial) */
27
+ refund(input: RefundInput): Promise<RefundResult>
28
+
29
+ /** Cancel / void an authorized payment before capture */
30
+ cancel(input: CancelInput): Promise<CancelResult>
31
+
32
+ /** Get current payment status from provider */
33
+ getStatus(input: GetStatusInput): Promise<GatewayPaymentStatus>
34
+
35
+ /** Verify and parse an inbound webhook event */
36
+ verifyWebhook(input: VerifyWebhookInput): Promise<WebhookEvent>
37
+
38
+ /** Map provider status to unified status */
39
+ mapStatus(providerStatus: string, eventType?: string): UnifiedPaymentStatus
40
+ }
41
+
42
+ // ── Input / Output Types ────────────────────────────────────────────────────
43
+
44
+ export interface CreateSessionInput {
45
+ orderId?: string
46
+ paymentId: string
47
+ tenantId: string
48
+ organizationId: string
49
+ amount: number
50
+ currencyCode: string
51
+ captureMethod?: 'automatic' | 'manual'
52
+ paymentTypes?: string[]
53
+ description?: string
54
+ successUrl?: string
55
+ cancelUrl?: string
56
+ metadata?: Record<string, unknown>
57
+ credentials: Record<string, unknown>
58
+ lineItems?: SessionLineItem[]
59
+ }
60
+
61
+ export interface SessionLineItem {
62
+ name: string
63
+ quantity: number
64
+ unitAmount: number
65
+ currencyCode: string
66
+ }
67
+
68
+ export interface CreateSessionResult {
69
+ sessionId: string
70
+ clientSecret?: string
71
+ redirectUrl?: string
72
+ status: UnifiedPaymentStatus
73
+ providerData?: Record<string, unknown>
74
+ }
75
+
76
+ export interface CaptureInput {
77
+ sessionId: string
78
+ amount?: number
79
+ credentials: Record<string, unknown>
80
+ metadata?: Record<string, unknown>
81
+ }
82
+
83
+ export interface CaptureResult {
84
+ status: UnifiedPaymentStatus
85
+ capturedAmount: number
86
+ providerData?: Record<string, unknown>
87
+ }
88
+
89
+ export interface RefundInput {
90
+ sessionId: string
91
+ amount?: number
92
+ reason?: string
93
+ credentials: Record<string, unknown>
94
+ metadata?: Record<string, unknown>
95
+ }
96
+
97
+ export interface RefundResult {
98
+ refundId: string
99
+ status: UnifiedPaymentStatus
100
+ refundedAmount: number
101
+ providerData?: Record<string, unknown>
102
+ }
103
+
104
+ export interface CancelInput {
105
+ sessionId: string
106
+ reason?: string
107
+ credentials: Record<string, unknown>
108
+ }
109
+
110
+ export interface CancelResult {
111
+ status: UnifiedPaymentStatus
112
+ providerData?: Record<string, unknown>
113
+ }
114
+
115
+ export interface GetStatusInput {
116
+ sessionId: string
117
+ credentials: Record<string, unknown>
118
+ }
119
+
120
+ export interface GatewayPaymentStatus {
121
+ status: UnifiedPaymentStatus
122
+ amount: number
123
+ amountReceived: number
124
+ currencyCode: string
125
+ providerData?: Record<string, unknown>
126
+ }
127
+
128
+ export interface VerifyWebhookInput {
129
+ rawBody: string | Buffer
130
+ headers: Record<string, string | string[] | undefined>
131
+ credentials: Record<string, unknown>
132
+ }
133
+
134
+ export interface WebhookEvent {
135
+ eventType: string
136
+ eventId: string
137
+ data: Record<string, unknown>
138
+ idempotencyKey: string
139
+ timestamp: Date
140
+ }
141
+
142
+ // ── Webhook Handler ─────────────────────────────────────────────────────────
143
+
144
+ export interface WebhookHandlerRegistration {
145
+ handler: (input: VerifyWebhookInput) => Promise<WebhookEvent>
146
+ queue?: string
147
+ }
148
+
149
+ // ── Adapter Registry Options ────────────────────────────────────────────────
150
+
151
+ export interface RegisterAdapterOptions {
152
+ version?: string
153
+ }
154
+
155
+ // ── Registries ──────────────────────────────────────────────────────────────
156
+
157
+ const adapterRegistry = new Map<string, GatewayAdapter>()
158
+ const webhookHandlerRegistry = new Map<string, WebhookHandlerRegistration>()
159
+
160
+ function adapterKey(providerKey: string, version?: string): string {
161
+ return version ? `${providerKey}:${version}` : providerKey
162
+ }
163
+
164
+ export function registerGatewayAdapter(adapter: GatewayAdapter, options?: RegisterAdapterOptions): () => void {
165
+ const key = adapterKey(adapter.providerKey, options?.version)
166
+ adapterRegistry.set(key, adapter)
167
+ if (options?.version) {
168
+ // Also register as default if no default exists
169
+ if (!adapterRegistry.has(adapter.providerKey)) {
170
+ adapterRegistry.set(adapter.providerKey, adapter)
171
+ }
172
+ }
173
+ return () => {
174
+ adapterRegistry.delete(key)
175
+ }
176
+ }
177
+
178
+ export function getGatewayAdapter(providerKey: string, version?: string): GatewayAdapter | undefined {
179
+ if (version) {
180
+ return adapterRegistry.get(adapterKey(providerKey, version)) ?? adapterRegistry.get(providerKey)
181
+ }
182
+ return adapterRegistry.get(providerKey)
183
+ }
184
+
185
+ export function listGatewayAdapters(): GatewayAdapter[] {
186
+ const seen = new Set<string>()
187
+ const result: GatewayAdapter[] = []
188
+ for (const [key, adapter] of adapterRegistry) {
189
+ if (!key.includes(':') && !seen.has(adapter.providerKey)) {
190
+ seen.add(adapter.providerKey)
191
+ result.push(adapter)
192
+ }
193
+ }
194
+ return result
195
+ }
196
+
197
+ export function clearGatewayAdapters(): void {
198
+ adapterRegistry.clear()
199
+ }
200
+
201
+ export function registerWebhookHandler(
202
+ providerKey: string,
203
+ handler: (input: VerifyWebhookInput) => Promise<WebhookEvent>,
204
+ options?: { queue?: string },
205
+ ): () => void {
206
+ webhookHandlerRegistry.set(providerKey, { handler, queue: options?.queue })
207
+ return () => {
208
+ webhookHandlerRegistry.delete(providerKey)
209
+ }
210
+ }
211
+
212
+ export function getWebhookHandler(providerKey: string): WebhookHandlerRegistration | undefined {
213
+ return webhookHandlerRegistry.get(providerKey)
214
+ }
215
+
216
+ export function clearWebhookHandlers(): void {
217
+ webhookHandlerRegistry.clear()
218
+ }