@develit-io/backend-sdk 7.0.0 → 7.0.2
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/dist/index.d.mts +4 -16
- package/dist/index.d.ts +4 -16
- package/dist/index.mjs +121 -430
- package/dist/middlewares.d.mts +15 -0
- package/dist/middlewares.d.ts +15 -0
- package/dist/middlewares.mjs +230 -0
- package/dist/shared/backend-sdk.CgM_2r0b.mjs +98 -0
- package/package.json +6 -1
package/dist/index.d.mts
CHANGED
|
@@ -2,7 +2,6 @@ import * as drizzle_orm from 'drizzle-orm';
|
|
|
2
2
|
import { ExtractTablesWithRelations, DBQueryConfig, BuildQueryResult, AnyColumn } from 'drizzle-orm';
|
|
3
3
|
import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
|
|
4
4
|
import { AnySQLiteTable } from 'drizzle-orm/sqlite-core';
|
|
5
|
-
import { MiddlewareHandler } from 'hono/types';
|
|
6
5
|
import { z as z$1 } from 'zod';
|
|
7
6
|
import * as z from 'zod/v4/core';
|
|
8
7
|
import { ContentfulStatusCode, SuccessStatusCode } from 'hono/utils/http-status';
|
|
@@ -35,7 +34,7 @@ declare const bankAccount: {
|
|
|
35
34
|
swiftBic: drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"swift_bic", [string, ...string[]], number | undefined>;
|
|
36
35
|
bicCor: drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"bic_cor", [string, ...string[]], number | undefined>;
|
|
37
36
|
currency: drizzle_orm.NotNull<drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"currency", ["CZK" | "EUR" | "USD" | "PLN" | "RON" | "GBP" | "RUB" | "HUF" | "CHF" | "DKK" | "SEK" | "HRK" | "NOK" | "BGN" | "TRY" | "AUD" | "CAD" | "JPY" | "CNY" | "INR" | "BRL" | "MXN" | "ZAR" | "SGD" | "HKD" | "KRW" | "MYR" | "THB" | "IDR" | "PHP" | "AED" | "SAR" | "ILS" | "EGP" | "NGN" | "PKR" | "COP" | "CLP" | "PEN" | "VND" | "KZT" | "UAH" | "BTC" | "ETH" | "ADA" | "DOT" | "ATOM" | "XRP" | "LTC" | "SOL" | "DOGE" | "MATIC" | "AVAX", ...("CZK" | "EUR" | "USD" | "PLN" | "RON" | "GBP" | "RUB" | "HUF" | "CHF" | "DKK" | "SEK" | "HRK" | "NOK" | "BGN" | "TRY" | "AUD" | "CAD" | "JPY" | "CNY" | "INR" | "BRL" | "MXN" | "ZAR" | "SGD" | "HKD" | "KRW" | "MYR" | "THB" | "IDR" | "PHP" | "AED" | "SAR" | "ILS" | "EGP" | "NGN" | "PKR" | "COP" | "CLP" | "PEN" | "VND" | "KZT" | "UAH" | "BTC" | "ETH" | "ADA" | "DOT" | "ATOM" | "XRP" | "LTC" | "SOL" | "DOGE" | "MATIC" | "AVAX")[]], number | undefined>>;
|
|
38
|
-
countryCode: drizzle_orm.NotNull<drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"country_code", ["AF" | "AL" | "DZ" | "AS" | "AD" | "AO" | "AG" | "AR" | "AM" | "AW" | "AU" | "AT" | "AZ" | "BS" | "BH" | "BD" | "BB" | "BY" | "BE" | "BZ" | "BJ" | "BO" | "BQ" | "BA" | "BW" | "BR" | "IO" | "VG" | "BG" | "BF" | "BI" | "KH" | "CM" | "CA" | "CV" | "CF" | "TD" | "CL" | "CN" | "CO" | "KM" | "CK" | "CR" | "HR" | "CW" | "CY" | "CZ" | "CD" | "DK" | "DJ" | "DM" | "DO" | "TL" | "
|
|
37
|
+
countryCode: drizzle_orm.NotNull<drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"country_code", ["EC" | "AF" | "AL" | "DZ" | "AS" | "AD" | "AO" | "AG" | "AR" | "AM" | "AW" | "AU" | "AT" | "AZ" | "BS" | "BH" | "BD" | "BB" | "BY" | "BE" | "BZ" | "BJ" | "BO" | "BQ" | "BA" | "BW" | "BR" | "IO" | "VG" | "BG" | "BF" | "BI" | "KH" | "CM" | "CA" | "CV" | "CF" | "TD" | "CL" | "CN" | "CO" | "KM" | "CK" | "CR" | "HR" | "CW" | "CY" | "CZ" | "CD" | "DK" | "DJ" | "DM" | "DO" | "TL" | "EG" | "SV" | "GQ" | "ER" | "EE" | "ET" | "FO" | "FJ" | "FI" | "FR" | "GF" | "PF" | "GA" | "GM" | "GE" | "DE" | "GH" | "GR" | "GD" | "GP" | "GU" | "GT" | "GN" | "GW" | "GY" | "HT" | "HN" | "HU" | "IS" | "IN" | "ID" | "IR" | "IQ" | "IE" | "IM" | "IL" | "IT" | "CI" | "JM" | "JP" | "JE" | "JO" | "KZ" | "KE" | "KI" | "XK" | "KW" | "KG" | "LA" | "LV" | "LB" | "LS" | "LR" | "LI" | "LT" | "LU" | "MK" | "MG" | "MW" | "MY" | "MV" | "ML" | "MT" | "MQ" | "MR" | "MU" | "MX" | "FM" | "MD" | "MC" | "MN" | "ME" | "MS" | "MA" | "MZ" | "NA" | "NP" | "NL" | "NZ" | "NI" | "NE" | "NG" | "NU" | "NF" | "KP" | "NO" | "OM" | "PK" | "PS" | "PA" | "PG" | "PY" | "PE" | "PH" | "PL" | "PT" | "PR" | "QA" | "CG" | "RE" | "RO" | "RU" | "RW" | "BL" | "KN" | "LC" | "MF" | "VC" | "WS" | "SM" | "SA" | "SN" | "RS" | "SC" | "SL" | "SG" | "SX" | "SK" | "SI" | "SO" | "ZA" | "KR" | "SS" | "ES" | "LK" | "SD" | "SR" | "SJ" | "SZ" | "SE" | "CH" | "TW" | "TJ" | "TZ" | "TH" | "TG" | "TO" | "TT" | "TN" | "TR" | "TM" | "UM" | "VI" | "UG" | "UA" | "AE" | "GB" | "UZ" | "VU" | "VE" | "VN" | "WF" | "EH" | "YE" | "ZM" | "ZW", ...("EC" | "AF" | "AL" | "DZ" | "AS" | "AD" | "AO" | "AG" | "AR" | "AM" | "AW" | "AU" | "AT" | "AZ" | "BS" | "BH" | "BD" | "BB" | "BY" | "BE" | "BZ" | "BJ" | "BO" | "BQ" | "BA" | "BW" | "BR" | "IO" | "VG" | "BG" | "BF" | "BI" | "KH" | "CM" | "CA" | "CV" | "CF" | "TD" | "CL" | "CN" | "CO" | "KM" | "CK" | "CR" | "HR" | "CW" | "CY" | "CZ" | "CD" | "DK" | "DJ" | "DM" | "DO" | "TL" | "EG" | "SV" | "GQ" | "ER" | "EE" | "ET" | "FO" | "FJ" | "FI" | "FR" | "GF" | "PF" | "GA" | "GM" | "GE" | "DE" | "GH" | "GR" | "GD" | "GP" | "GU" | "GT" | "GN" | "GW" | "GY" | "HT" | "HN" | "HU" | "IS" | "IN" | "ID" | "IR" | "IQ" | "IE" | "IM" | "IL" | "IT" | "CI" | "JM" | "JP" | "JE" | "JO" | "KZ" | "KE" | "KI" | "XK" | "KW" | "KG" | "LA" | "LV" | "LB" | "LS" | "LR" | "LI" | "LT" | "LU" | "MK" | "MG" | "MW" | "MY" | "MV" | "ML" | "MT" | "MQ" | "MR" | "MU" | "MX" | "FM" | "MD" | "MC" | "MN" | "ME" | "MS" | "MA" | "MZ" | "NA" | "NP" | "NL" | "NZ" | "NI" | "NE" | "NG" | "NU" | "NF" | "KP" | "NO" | "OM" | "PK" | "PS" | "PA" | "PG" | "PY" | "PE" | "PH" | "PL" | "PT" | "PR" | "QA" | "CG" | "RE" | "RO" | "RU" | "RW" | "BL" | "KN" | "LC" | "MF" | "VC" | "WS" | "SM" | "SA" | "SN" | "RS" | "SC" | "SL" | "SG" | "SX" | "SK" | "SI" | "SO" | "ZA" | "KR" | "SS" | "ES" | "LK" | "SD" | "SR" | "SJ" | "SZ" | "SE" | "CH" | "TW" | "TJ" | "TZ" | "TH" | "TG" | "TO" | "TT" | "TN" | "TR" | "TM" | "UM" | "VI" | "UG" | "UA" | "AE" | "GB" | "UZ" | "VU" | "VE" | "VN" | "WF" | "EH" | "YE" | "ZM" | "ZW")[]], number | undefined>>;
|
|
39
38
|
routingNumber: drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"routing_number", [string, ...string[]], number | undefined>;
|
|
40
39
|
sortCode: drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"sort_code", [string, ...string[]], number | undefined>;
|
|
41
40
|
clabe: drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"clabe", [string, ...string[]], number | undefined>;
|
|
@@ -67,18 +66,6 @@ declare const composeWranglerBase: ({ project, name, }: {
|
|
|
67
66
|
keep_vars: boolean;
|
|
68
67
|
};
|
|
69
68
|
|
|
70
|
-
declare const idempotency: <T extends {
|
|
71
|
-
IDEMPOTENCY_KV: KVNamespace;
|
|
72
|
-
}>() => MiddlewareHandler;
|
|
73
|
-
|
|
74
|
-
declare const jwt: <TAuthService, TJwtPayload>() => MiddlewareHandler;
|
|
75
|
-
|
|
76
|
-
declare const ip: <TOrganizationService, TJwtPayload>() => MiddlewareHandler;
|
|
77
|
-
|
|
78
|
-
declare const logger: () => MiddlewareHandler;
|
|
79
|
-
|
|
80
|
-
declare const signature: <TOrganizationService, TJwtPayload>() => MiddlewareHandler;
|
|
81
|
-
|
|
82
69
|
interface AuditLogPayload<T> {
|
|
83
70
|
action: T;
|
|
84
71
|
actorId: string;
|
|
@@ -208,6 +195,7 @@ declare const bankAccountMetadataSchema: z$1.ZodObject<{
|
|
|
208
195
|
AVAX: "AVAX";
|
|
209
196
|
}>>;
|
|
210
197
|
country: z$1.ZodOptional<z$1.ZodEnum<{
|
|
198
|
+
EC: "EC";
|
|
211
199
|
AF: "AF";
|
|
212
200
|
AL: "AL";
|
|
213
201
|
DZ: "DZ";
|
|
@@ -261,7 +249,6 @@ declare const bankAccountMetadataSchema: z$1.ZodObject<{
|
|
|
261
249
|
DM: "DM";
|
|
262
250
|
DO: "DO";
|
|
263
251
|
TL: "TL";
|
|
264
|
-
EC: "EC";
|
|
265
252
|
EG: "EG";
|
|
266
253
|
SV: "SV";
|
|
267
254
|
GQ: "GQ";
|
|
@@ -687,6 +674,7 @@ type BuildSearchOptions = {
|
|
|
687
674
|
declare const buildSearchConditions: (search: string | undefined | null, columns: ReadonlyArray<AnyColumn>, opts?: BuildSearchOptions) => drizzle_orm.SQL<unknown> | undefined;
|
|
688
675
|
declare const buildMultiFilterConditions: <T>(column: drizzle_orm.Column, value: T | T[] | undefined) => drizzle_orm.SQL<unknown> | undefined;
|
|
689
676
|
declare const buildRangeFilterConditions: <T>(column: drizzle_orm.Column, minValue: T | undefined, maxValue: T | undefined) => drizzle_orm.SQL<unknown> | undefined;
|
|
677
|
+
declare const resolveColumn: <T extends object, K extends Extract<keyof T, string>>(table: T, column: string | undefined, fallback?: K) => AnyColumn;
|
|
690
678
|
|
|
691
679
|
interface Command<TAuditAction = string> {
|
|
692
680
|
handler: (db: DrizzleD1Database<Record<string, unknown>>) => CommandItem<TAuditAction>;
|
|
@@ -834,5 +822,5 @@ interface WithRetryCounterOptions {
|
|
|
834
822
|
type AsyncMethod<TArgs extends unknown[] = unknown[], TResult = unknown> = (...args: TArgs) => Promise<TResult>;
|
|
835
823
|
declare function cloudflareQueue<TArgs extends unknown[] = unknown[], TResult = unknown>(options: WithRetryCounterOptions): (target: unknown, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<AsyncMethod<TArgs, TResult>>) => void;
|
|
836
824
|
|
|
837
|
-
export { DatabaseTransaction, ENVIRONMENT, RPCResponse, USER_ROLES, action, bankAccount, bankAccountMetadataSchema, base, bicSchema, buildMultiFilterConditions, buildRangeFilterConditions, buildSearchConditions, calculateExponentialBackoff, cloudflareQueue, composeWranglerBase, createAuditLogWriter, createInternalError, createSignatureKeyPair, defineCommand, derivePortFromId, develitWorker, durableObjectNamespaceIdFromName, first, firstOrError, getD1Credentials, getD1DatabaseIdFromWrangler, getDrizzleD1Config, getSecret, handleAction, handleActionResponse, ibanSchema,
|
|
825
|
+
export { DatabaseTransaction, ENVIRONMENT, RPCResponse, USER_ROLES, action, bankAccount, bankAccountMetadataSchema, base, bicSchema, buildMultiFilterConditions, buildRangeFilterConditions, buildSearchConditions, calculateExponentialBackoff, cloudflareQueue, composeWranglerBase, createAuditLogWriter, createInternalError, createSignatureKeyPair, defineCommand, derivePortFromId, develitWorker, durableObjectNamespaceIdFromName, first, firstOrError, getD1Credentials, getD1DatabaseIdFromWrangler, getDrizzleD1Config, getSecret, handleAction, handleActionResponse, ibanSchema, isInternalError, paginationQuerySchema, paginationSchema, resolveColumn, service, signPayload, useFetch, useResult, useResultSync, uuidv4, verifyPayloadSignature };
|
|
838
826
|
export type { ActionExecution, ActionHandlerOptions, AuditLogWriter, AuthUser, BankAccountMetadata, BaseEvent, BuildSearchOptions, Command, CommandLogPayload, DevelitWorkerMethods, Environment, GatewayResponse, IRPCResponse, IdempotencyVariables, IncludeRelation, InferResultType, InternalError, InternalErrorResponseStatus, Project, UserRole, UserVariables, ValidatedInput };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ import * as drizzle_orm from 'drizzle-orm';
|
|
|
2
2
|
import { ExtractTablesWithRelations, DBQueryConfig, BuildQueryResult, AnyColumn } from 'drizzle-orm';
|
|
3
3
|
import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
|
|
4
4
|
import { AnySQLiteTable } from 'drizzle-orm/sqlite-core';
|
|
5
|
-
import { MiddlewareHandler } from 'hono/types';
|
|
6
5
|
import { z as z$1 } from 'zod';
|
|
7
6
|
import * as z from 'zod/v4/core';
|
|
8
7
|
import { ContentfulStatusCode, SuccessStatusCode } from 'hono/utils/http-status';
|
|
@@ -35,7 +34,7 @@ declare const bankAccount: {
|
|
|
35
34
|
swiftBic: drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"swift_bic", [string, ...string[]], number | undefined>;
|
|
36
35
|
bicCor: drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"bic_cor", [string, ...string[]], number | undefined>;
|
|
37
36
|
currency: drizzle_orm.NotNull<drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"currency", ["CZK" | "EUR" | "USD" | "PLN" | "RON" | "GBP" | "RUB" | "HUF" | "CHF" | "DKK" | "SEK" | "HRK" | "NOK" | "BGN" | "TRY" | "AUD" | "CAD" | "JPY" | "CNY" | "INR" | "BRL" | "MXN" | "ZAR" | "SGD" | "HKD" | "KRW" | "MYR" | "THB" | "IDR" | "PHP" | "AED" | "SAR" | "ILS" | "EGP" | "NGN" | "PKR" | "COP" | "CLP" | "PEN" | "VND" | "KZT" | "UAH" | "BTC" | "ETH" | "ADA" | "DOT" | "ATOM" | "XRP" | "LTC" | "SOL" | "DOGE" | "MATIC" | "AVAX", ...("CZK" | "EUR" | "USD" | "PLN" | "RON" | "GBP" | "RUB" | "HUF" | "CHF" | "DKK" | "SEK" | "HRK" | "NOK" | "BGN" | "TRY" | "AUD" | "CAD" | "JPY" | "CNY" | "INR" | "BRL" | "MXN" | "ZAR" | "SGD" | "HKD" | "KRW" | "MYR" | "THB" | "IDR" | "PHP" | "AED" | "SAR" | "ILS" | "EGP" | "NGN" | "PKR" | "COP" | "CLP" | "PEN" | "VND" | "KZT" | "UAH" | "BTC" | "ETH" | "ADA" | "DOT" | "ATOM" | "XRP" | "LTC" | "SOL" | "DOGE" | "MATIC" | "AVAX")[]], number | undefined>>;
|
|
38
|
-
countryCode: drizzle_orm.NotNull<drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"country_code", ["AF" | "AL" | "DZ" | "AS" | "AD" | "AO" | "AG" | "AR" | "AM" | "AW" | "AU" | "AT" | "AZ" | "BS" | "BH" | "BD" | "BB" | "BY" | "BE" | "BZ" | "BJ" | "BO" | "BQ" | "BA" | "BW" | "BR" | "IO" | "VG" | "BG" | "BF" | "BI" | "KH" | "CM" | "CA" | "CV" | "CF" | "TD" | "CL" | "CN" | "CO" | "KM" | "CK" | "CR" | "HR" | "CW" | "CY" | "CZ" | "CD" | "DK" | "DJ" | "DM" | "DO" | "TL" | "
|
|
37
|
+
countryCode: drizzle_orm.NotNull<drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"country_code", ["EC" | "AF" | "AL" | "DZ" | "AS" | "AD" | "AO" | "AG" | "AR" | "AM" | "AW" | "AU" | "AT" | "AZ" | "BS" | "BH" | "BD" | "BB" | "BY" | "BE" | "BZ" | "BJ" | "BO" | "BQ" | "BA" | "BW" | "BR" | "IO" | "VG" | "BG" | "BF" | "BI" | "KH" | "CM" | "CA" | "CV" | "CF" | "TD" | "CL" | "CN" | "CO" | "KM" | "CK" | "CR" | "HR" | "CW" | "CY" | "CZ" | "CD" | "DK" | "DJ" | "DM" | "DO" | "TL" | "EG" | "SV" | "GQ" | "ER" | "EE" | "ET" | "FO" | "FJ" | "FI" | "FR" | "GF" | "PF" | "GA" | "GM" | "GE" | "DE" | "GH" | "GR" | "GD" | "GP" | "GU" | "GT" | "GN" | "GW" | "GY" | "HT" | "HN" | "HU" | "IS" | "IN" | "ID" | "IR" | "IQ" | "IE" | "IM" | "IL" | "IT" | "CI" | "JM" | "JP" | "JE" | "JO" | "KZ" | "KE" | "KI" | "XK" | "KW" | "KG" | "LA" | "LV" | "LB" | "LS" | "LR" | "LI" | "LT" | "LU" | "MK" | "MG" | "MW" | "MY" | "MV" | "ML" | "MT" | "MQ" | "MR" | "MU" | "MX" | "FM" | "MD" | "MC" | "MN" | "ME" | "MS" | "MA" | "MZ" | "NA" | "NP" | "NL" | "NZ" | "NI" | "NE" | "NG" | "NU" | "NF" | "KP" | "NO" | "OM" | "PK" | "PS" | "PA" | "PG" | "PY" | "PE" | "PH" | "PL" | "PT" | "PR" | "QA" | "CG" | "RE" | "RO" | "RU" | "RW" | "BL" | "KN" | "LC" | "MF" | "VC" | "WS" | "SM" | "SA" | "SN" | "RS" | "SC" | "SL" | "SG" | "SX" | "SK" | "SI" | "SO" | "ZA" | "KR" | "SS" | "ES" | "LK" | "SD" | "SR" | "SJ" | "SZ" | "SE" | "CH" | "TW" | "TJ" | "TZ" | "TH" | "TG" | "TO" | "TT" | "TN" | "TR" | "TM" | "UM" | "VI" | "UG" | "UA" | "AE" | "GB" | "UZ" | "VU" | "VE" | "VN" | "WF" | "EH" | "YE" | "ZM" | "ZW", ...("EC" | "AF" | "AL" | "DZ" | "AS" | "AD" | "AO" | "AG" | "AR" | "AM" | "AW" | "AU" | "AT" | "AZ" | "BS" | "BH" | "BD" | "BB" | "BY" | "BE" | "BZ" | "BJ" | "BO" | "BQ" | "BA" | "BW" | "BR" | "IO" | "VG" | "BG" | "BF" | "BI" | "KH" | "CM" | "CA" | "CV" | "CF" | "TD" | "CL" | "CN" | "CO" | "KM" | "CK" | "CR" | "HR" | "CW" | "CY" | "CZ" | "CD" | "DK" | "DJ" | "DM" | "DO" | "TL" | "EG" | "SV" | "GQ" | "ER" | "EE" | "ET" | "FO" | "FJ" | "FI" | "FR" | "GF" | "PF" | "GA" | "GM" | "GE" | "DE" | "GH" | "GR" | "GD" | "GP" | "GU" | "GT" | "GN" | "GW" | "GY" | "HT" | "HN" | "HU" | "IS" | "IN" | "ID" | "IR" | "IQ" | "IE" | "IM" | "IL" | "IT" | "CI" | "JM" | "JP" | "JE" | "JO" | "KZ" | "KE" | "KI" | "XK" | "KW" | "KG" | "LA" | "LV" | "LB" | "LS" | "LR" | "LI" | "LT" | "LU" | "MK" | "MG" | "MW" | "MY" | "MV" | "ML" | "MT" | "MQ" | "MR" | "MU" | "MX" | "FM" | "MD" | "MC" | "MN" | "ME" | "MS" | "MA" | "MZ" | "NA" | "NP" | "NL" | "NZ" | "NI" | "NE" | "NG" | "NU" | "NF" | "KP" | "NO" | "OM" | "PK" | "PS" | "PA" | "PG" | "PY" | "PE" | "PH" | "PL" | "PT" | "PR" | "QA" | "CG" | "RE" | "RO" | "RU" | "RW" | "BL" | "KN" | "LC" | "MF" | "VC" | "WS" | "SM" | "SA" | "SN" | "RS" | "SC" | "SL" | "SG" | "SX" | "SK" | "SI" | "SO" | "ZA" | "KR" | "SS" | "ES" | "LK" | "SD" | "SR" | "SJ" | "SZ" | "SE" | "CH" | "TW" | "TJ" | "TZ" | "TH" | "TG" | "TO" | "TT" | "TN" | "TR" | "TM" | "UM" | "VI" | "UG" | "UA" | "AE" | "GB" | "UZ" | "VU" | "VE" | "VN" | "WF" | "EH" | "YE" | "ZM" | "ZW")[]], number | undefined>>;
|
|
39
38
|
routingNumber: drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"routing_number", [string, ...string[]], number | undefined>;
|
|
40
39
|
sortCode: drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"sort_code", [string, ...string[]], number | undefined>;
|
|
41
40
|
clabe: drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"clabe", [string, ...string[]], number | undefined>;
|
|
@@ -67,18 +66,6 @@ declare const composeWranglerBase: ({ project, name, }: {
|
|
|
67
66
|
keep_vars: boolean;
|
|
68
67
|
};
|
|
69
68
|
|
|
70
|
-
declare const idempotency: <T extends {
|
|
71
|
-
IDEMPOTENCY_KV: KVNamespace;
|
|
72
|
-
}>() => MiddlewareHandler;
|
|
73
|
-
|
|
74
|
-
declare const jwt: <TAuthService, TJwtPayload>() => MiddlewareHandler;
|
|
75
|
-
|
|
76
|
-
declare const ip: <TOrganizationService, TJwtPayload>() => MiddlewareHandler;
|
|
77
|
-
|
|
78
|
-
declare const logger: () => MiddlewareHandler;
|
|
79
|
-
|
|
80
|
-
declare const signature: <TOrganizationService, TJwtPayload>() => MiddlewareHandler;
|
|
81
|
-
|
|
82
69
|
interface AuditLogPayload<T> {
|
|
83
70
|
action: T;
|
|
84
71
|
actorId: string;
|
|
@@ -208,6 +195,7 @@ declare const bankAccountMetadataSchema: z$1.ZodObject<{
|
|
|
208
195
|
AVAX: "AVAX";
|
|
209
196
|
}>>;
|
|
210
197
|
country: z$1.ZodOptional<z$1.ZodEnum<{
|
|
198
|
+
EC: "EC";
|
|
211
199
|
AF: "AF";
|
|
212
200
|
AL: "AL";
|
|
213
201
|
DZ: "DZ";
|
|
@@ -261,7 +249,6 @@ declare const bankAccountMetadataSchema: z$1.ZodObject<{
|
|
|
261
249
|
DM: "DM";
|
|
262
250
|
DO: "DO";
|
|
263
251
|
TL: "TL";
|
|
264
|
-
EC: "EC";
|
|
265
252
|
EG: "EG";
|
|
266
253
|
SV: "SV";
|
|
267
254
|
GQ: "GQ";
|
|
@@ -687,6 +674,7 @@ type BuildSearchOptions = {
|
|
|
687
674
|
declare const buildSearchConditions: (search: string | undefined | null, columns: ReadonlyArray<AnyColumn>, opts?: BuildSearchOptions) => drizzle_orm.SQL<unknown> | undefined;
|
|
688
675
|
declare const buildMultiFilterConditions: <T>(column: drizzle_orm.Column, value: T | T[] | undefined) => drizzle_orm.SQL<unknown> | undefined;
|
|
689
676
|
declare const buildRangeFilterConditions: <T>(column: drizzle_orm.Column, minValue: T | undefined, maxValue: T | undefined) => drizzle_orm.SQL<unknown> | undefined;
|
|
677
|
+
declare const resolveColumn: <T extends object, K extends Extract<keyof T, string>>(table: T, column: string | undefined, fallback?: K) => AnyColumn;
|
|
690
678
|
|
|
691
679
|
interface Command<TAuditAction = string> {
|
|
692
680
|
handler: (db: DrizzleD1Database<Record<string, unknown>>) => CommandItem<TAuditAction>;
|
|
@@ -834,5 +822,5 @@ interface WithRetryCounterOptions {
|
|
|
834
822
|
type AsyncMethod<TArgs extends unknown[] = unknown[], TResult = unknown> = (...args: TArgs) => Promise<TResult>;
|
|
835
823
|
declare function cloudflareQueue<TArgs extends unknown[] = unknown[], TResult = unknown>(options: WithRetryCounterOptions): (target: unknown, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<AsyncMethod<TArgs, TResult>>) => void;
|
|
836
824
|
|
|
837
|
-
export { DatabaseTransaction, ENVIRONMENT, RPCResponse, USER_ROLES, action, bankAccount, bankAccountMetadataSchema, base, bicSchema, buildMultiFilterConditions, buildRangeFilterConditions, buildSearchConditions, calculateExponentialBackoff, cloudflareQueue, composeWranglerBase, createAuditLogWriter, createInternalError, createSignatureKeyPair, defineCommand, derivePortFromId, develitWorker, durableObjectNamespaceIdFromName, first, firstOrError, getD1Credentials, getD1DatabaseIdFromWrangler, getDrizzleD1Config, getSecret, handleAction, handleActionResponse, ibanSchema,
|
|
825
|
+
export { DatabaseTransaction, ENVIRONMENT, RPCResponse, USER_ROLES, action, bankAccount, bankAccountMetadataSchema, base, bicSchema, buildMultiFilterConditions, buildRangeFilterConditions, buildSearchConditions, calculateExponentialBackoff, cloudflareQueue, composeWranglerBase, createAuditLogWriter, createInternalError, createSignatureKeyPair, defineCommand, derivePortFromId, develitWorker, durableObjectNamespaceIdFromName, first, firstOrError, getD1Credentials, getD1DatabaseIdFromWrangler, getDrizzleD1Config, getSecret, handleAction, handleActionResponse, ibanSchema, isInternalError, paginationQuerySchema, paginationSchema, resolveColumn, service, signPayload, useFetch, useResult, useResultSync, uuidv4, verifyPayloadSignature };
|
|
838
826
|
export type { ActionExecution, ActionHandlerOptions, AuditLogWriter, AuthUser, BankAccountMetadata, BaseEvent, BuildSearchOptions, Command, CommandLogPayload, DevelitWorkerMethods, Environment, GatewayResponse, IRPCResponse, IdempotencyVariables, IncludeRelation, InferResultType, InternalError, InternalErrorResponseStatus, Project, UserRole, UserVariables, ValidatedInput };
|
package/dist/index.mjs
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import { sql, or, inArray, eq, gte, lte, and } from 'drizzle-orm';
|
|
2
2
|
import { integer, text } from 'drizzle-orm/sqlite-core';
|
|
3
3
|
import { COUNTRY_CODES_2, CURRENCY_CODES, BANK_CODES } from '@develit-io/general-codes';
|
|
4
|
-
import { createMiddleware } from 'hono/factory';
|
|
5
|
-
import { HTTPException } from 'hono/http-exception';
|
|
6
|
-
import { createError } from 'h3';
|
|
7
4
|
import { z as z$1 } from 'zod';
|
|
5
|
+
import * as z from 'zod/v4/core';
|
|
6
|
+
import { createError } from 'h3';
|
|
8
7
|
import 'cloudflare';
|
|
9
8
|
import fs from 'node:fs';
|
|
10
|
-
import crypto$1
|
|
9
|
+
import crypto$1 from 'node:crypto';
|
|
11
10
|
import path from 'node:path';
|
|
12
11
|
import { parse } from 'comment-json';
|
|
13
|
-
|
|
12
|
+
export { c as createSignatureKeyPair, s as signPayload, v as verifyPayloadSignature } from './shared/backend-sdk.CgM_2r0b.mjs';
|
|
14
13
|
import superjson from 'superjson';
|
|
15
14
|
|
|
16
15
|
const ENVIRONMENT = ["dev", "test", "staging", "production"];
|
|
@@ -76,34 +75,119 @@ const composeWranglerBase = ({
|
|
|
76
75
|
};
|
|
77
76
|
};
|
|
78
77
|
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
78
|
+
const ibanSchema = z$1.string().min(1).regex(/^[A-Z]{2}[0-9]{2}[A-Z0-9]{11,30}$/, {
|
|
79
|
+
message: "Invalid IBAN format"
|
|
80
|
+
});
|
|
81
|
+
const bicSchema = z$1.string().min(1).regex(/^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$/, {
|
|
82
|
+
message: "Invalid SWIFT/BIC format"
|
|
83
|
+
});
|
|
84
|
+
const bankAccountMetadataSchema = z$1.object({
|
|
85
|
+
id: z$1.string().optional(),
|
|
86
|
+
number: z$1.string().optional(),
|
|
87
|
+
bankCode: z$1.enum(BANK_CODES).optional(),
|
|
88
|
+
holderName: z$1.string().optional(),
|
|
89
|
+
iban: ibanSchema.optional(),
|
|
90
|
+
address: z$1.string().optional(),
|
|
91
|
+
swiftBic: bicSchema.optional(),
|
|
92
|
+
bicCor: bicSchema.optional(),
|
|
93
|
+
currency: z$1.enum(CURRENCY_CODES).optional(),
|
|
94
|
+
country: z$1.enum(COUNTRY_CODES_2).optional(),
|
|
95
|
+
routingNumber: z$1.string().optional(),
|
|
96
|
+
// US
|
|
97
|
+
sortCode: z$1.string().optional(),
|
|
98
|
+
// UK
|
|
99
|
+
clabe: z$1.string().optional(),
|
|
100
|
+
// Mexico
|
|
101
|
+
bsb: z$1.string().optional(),
|
|
102
|
+
// Australia
|
|
103
|
+
brBankNumber: z$1.string().optional()
|
|
104
|
+
// Brazil
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const paginationQuerySchema = new z.$ZodObject({
|
|
108
|
+
type: "object",
|
|
109
|
+
shape: {
|
|
110
|
+
page: new z.$ZodDefault({
|
|
111
|
+
type: "default",
|
|
112
|
+
innerType: new z.$ZodNumber({
|
|
113
|
+
type: "number",
|
|
114
|
+
coerce: true
|
|
115
|
+
}),
|
|
116
|
+
defaultValue: () => 1
|
|
117
|
+
}),
|
|
118
|
+
limit: new z.$ZodDefault({
|
|
119
|
+
type: "default",
|
|
120
|
+
innerType: new z.$ZodNumber({
|
|
121
|
+
type: "number",
|
|
122
|
+
coerce: true
|
|
123
|
+
}),
|
|
124
|
+
defaultValue: () => 20
|
|
125
|
+
}),
|
|
126
|
+
sort: new z.$ZodDefault({
|
|
127
|
+
type: "default",
|
|
128
|
+
innerType: new z.$ZodObject({
|
|
129
|
+
type: "object",
|
|
130
|
+
shape: {
|
|
131
|
+
column: new z.$ZodDefault({
|
|
132
|
+
type: "default",
|
|
133
|
+
innerType: new z.$ZodEnum({
|
|
134
|
+
type: "enum",
|
|
135
|
+
entries: {
|
|
136
|
+
createdAt: "createdAt",
|
|
137
|
+
updatedAt: "updatedAt",
|
|
138
|
+
deletedAt: "deletedAt"
|
|
139
|
+
}
|
|
140
|
+
}),
|
|
141
|
+
defaultValue: () => "updatedAt"
|
|
142
|
+
}),
|
|
143
|
+
direction: new z.$ZodDefault({
|
|
144
|
+
type: "default",
|
|
145
|
+
innerType: new z.$ZodEnum({
|
|
146
|
+
type: "enum",
|
|
147
|
+
entries: {
|
|
148
|
+
asc: "asc",
|
|
149
|
+
desc: "desc"
|
|
150
|
+
}
|
|
151
|
+
}),
|
|
152
|
+
defaultValue: () => "desc"
|
|
153
|
+
})
|
|
154
|
+
}
|
|
155
|
+
}),
|
|
156
|
+
defaultValue: () => ({ column: "updatedAt", direction: "desc" })
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
const paginationSchema = new z.$ZodObject({
|
|
161
|
+
type: "object",
|
|
162
|
+
shape: {
|
|
163
|
+
page: new z.$ZodNumber({
|
|
164
|
+
type: "number"
|
|
165
|
+
}),
|
|
166
|
+
limit: new z.$ZodNumber({
|
|
167
|
+
type: "number"
|
|
168
|
+
}),
|
|
169
|
+
sort: new z.$ZodObject({
|
|
170
|
+
type: "object",
|
|
171
|
+
shape: {
|
|
172
|
+
column: new z.$ZodEnum({
|
|
173
|
+
type: "enum",
|
|
174
|
+
entries: {
|
|
175
|
+
createdAt: "createdAt",
|
|
176
|
+
updatedAt: "updatedAt",
|
|
177
|
+
deletedAt: "deletedAt"
|
|
178
|
+
}
|
|
179
|
+
}),
|
|
180
|
+
direction: new z.$ZodEnum({
|
|
181
|
+
type: "enum",
|
|
182
|
+
entries: {
|
|
183
|
+
asc: "asc",
|
|
184
|
+
desc: "desc"
|
|
185
|
+
}
|
|
186
|
+
})
|
|
99
187
|
}
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
});
|
|
104
|
-
await next();
|
|
105
|
-
});
|
|
106
|
-
};
|
|
188
|
+
})
|
|
189
|
+
}
|
|
190
|
+
});
|
|
107
191
|
|
|
108
192
|
const handleActionResponse = ({
|
|
109
193
|
error,
|
|
@@ -263,16 +347,6 @@ function createAuditLogWriter(table) {
|
|
|
263
347
|
};
|
|
264
348
|
}
|
|
265
349
|
|
|
266
|
-
const validateBearerScheme = (header) => {
|
|
267
|
-
return header.startsWith("Bearer ") && header.length > 7 && !header.slice(7).includes(" ");
|
|
268
|
-
};
|
|
269
|
-
const extractBearerToken = (header) => {
|
|
270
|
-
return header.slice(7).trim();
|
|
271
|
-
};
|
|
272
|
-
const validateBearerToken = (bearerToken) => {
|
|
273
|
-
return z$1.jwt().safeParse(bearerToken).success;
|
|
274
|
-
};
|
|
275
|
-
|
|
276
350
|
function first(rows) {
|
|
277
351
|
return rows.length > 0 ? rows[0] : void 0;
|
|
278
352
|
}
|
|
@@ -413,6 +487,10 @@ const buildRangeFilterConditions = (column, minValue, maxValue) => {
|
|
|
413
487
|
if (conditions.length === 1) return conditions[0];
|
|
414
488
|
return and(...conditions);
|
|
415
489
|
};
|
|
490
|
+
const resolveColumn = (table, column, fallback = "updatedAt") => {
|
|
491
|
+
const key = column && column in table ? column : fallback;
|
|
492
|
+
return table[key];
|
|
493
|
+
};
|
|
416
494
|
|
|
417
495
|
class DatabaseTransaction {
|
|
418
496
|
constructor(db, serviceName, auditLogWriter) {
|
|
@@ -509,108 +587,6 @@ async function useFetch(url, { parseAs = "json", ...options } = {}) {
|
|
|
509
587
|
return [body, null];
|
|
510
588
|
}
|
|
511
589
|
|
|
512
|
-
const logRequest = (log) => {
|
|
513
|
-
console.log("REQUEST | An incoming request has been recorded.", log);
|
|
514
|
-
};
|
|
515
|
-
const logResponse = (log) => {
|
|
516
|
-
console.log(`RESPONSE | An outgoing response has been recorded.`, log);
|
|
517
|
-
};
|
|
518
|
-
|
|
519
|
-
const createSignatureKeyPair = async () => {
|
|
520
|
-
const { publicKey, privateKey } = await subtle.generateKey(
|
|
521
|
-
{
|
|
522
|
-
name: "RSASSA-PKCS1-v1_5",
|
|
523
|
-
modulusLength: 4096,
|
|
524
|
-
publicExponent: new Uint8Array([1, 0, 1]),
|
|
525
|
-
hash: "SHA-256"
|
|
526
|
-
},
|
|
527
|
-
true,
|
|
528
|
-
["sign", "verify"]
|
|
529
|
-
);
|
|
530
|
-
const exportedPublicKey = await subtle.exportKey("spki", publicKey);
|
|
531
|
-
const exportedPrivateKey = await subtle.exportKey("pkcs8", privateKey);
|
|
532
|
-
return {
|
|
533
|
-
publicKey: Buffer.from(exportedPublicKey).toString("base64"),
|
|
534
|
-
privateKey: Buffer.from(exportedPrivateKey).toString("base64")
|
|
535
|
-
};
|
|
536
|
-
};
|
|
537
|
-
const signPayload = async ({
|
|
538
|
-
payload,
|
|
539
|
-
privateKey
|
|
540
|
-
}) => {
|
|
541
|
-
const binaryPrivateKey = Uint8Array.from(
|
|
542
|
-
atob(privateKey),
|
|
543
|
-
(c) => c.charCodeAt(0)
|
|
544
|
-
);
|
|
545
|
-
const importedPrivateKey = await crypto.subtle.importKey(
|
|
546
|
-
"pkcs8",
|
|
547
|
-
binaryPrivateKey,
|
|
548
|
-
{
|
|
549
|
-
name: "RSASSA-PKCS1-v1_5",
|
|
550
|
-
hash: "SHA-256"
|
|
551
|
-
},
|
|
552
|
-
false,
|
|
553
|
-
["sign"]
|
|
554
|
-
);
|
|
555
|
-
const encodedPayload = new TextEncoder().encode(payload);
|
|
556
|
-
const signature = await crypto.subtle.sign(
|
|
557
|
-
{
|
|
558
|
-
name: "RSASSA-PKCS1-v1_5"
|
|
559
|
-
},
|
|
560
|
-
importedPrivateKey,
|
|
561
|
-
encodedPayload
|
|
562
|
-
);
|
|
563
|
-
const base64Signature = btoa(
|
|
564
|
-
String.fromCharCode(...new Uint8Array(signature))
|
|
565
|
-
);
|
|
566
|
-
return base64Signature;
|
|
567
|
-
};
|
|
568
|
-
const algParams = {
|
|
569
|
-
RSA: {
|
|
570
|
-
name: "RSASSA-PKCS1-v1_5",
|
|
571
|
-
hash: { name: "SHA-256" }
|
|
572
|
-
},
|
|
573
|
-
EC: {
|
|
574
|
-
name: "ECDSA",
|
|
575
|
-
namedCurve: "P-256"
|
|
576
|
-
},
|
|
577
|
-
HMAC: {
|
|
578
|
-
name: "HMAC",
|
|
579
|
-
hash: { name: "SHA-256" }
|
|
580
|
-
}
|
|
581
|
-
};
|
|
582
|
-
const verifyPayloadSignature = async ({
|
|
583
|
-
signature,
|
|
584
|
-
data,
|
|
585
|
-
publicKey,
|
|
586
|
-
algorithm = "RSA"
|
|
587
|
-
}) => {
|
|
588
|
-
const binaryPublicKey = Uint8Array.from(
|
|
589
|
-
atob(publicKey),
|
|
590
|
-
(c) => c.charCodeAt(0)
|
|
591
|
-
);
|
|
592
|
-
const format = algorithm === "HMAC" ? "raw" : "spki";
|
|
593
|
-
const importedPublicKey = await crypto.subtle.importKey(
|
|
594
|
-
format,
|
|
595
|
-
binaryPublicKey,
|
|
596
|
-
algParams[algorithm],
|
|
597
|
-
false,
|
|
598
|
-
["verify"]
|
|
599
|
-
);
|
|
600
|
-
const encodedPayload = new TextEncoder().encode(data);
|
|
601
|
-
const decodedSignature = Uint8Array.from(
|
|
602
|
-
atob(signature),
|
|
603
|
-
(c) => c.charCodeAt(0)
|
|
604
|
-
);
|
|
605
|
-
const isValid = await crypto.subtle.verify(
|
|
606
|
-
algParams[algorithm],
|
|
607
|
-
importedPublicKey,
|
|
608
|
-
decodedSignature,
|
|
609
|
-
encodedPayload
|
|
610
|
-
);
|
|
611
|
-
return isValid;
|
|
612
|
-
};
|
|
613
|
-
|
|
614
590
|
const calculateExponentialBackoff = (attempts, baseDelaySeconds) => {
|
|
615
591
|
return baseDelaySeconds ** attempts;
|
|
616
592
|
};
|
|
@@ -627,291 +603,6 @@ const getSecret = async (secretName, env) => {
|
|
|
627
603
|
return await secret.get();
|
|
628
604
|
};
|
|
629
605
|
|
|
630
|
-
const jwt = () => {
|
|
631
|
-
return createMiddleware(async (context, next) => {
|
|
632
|
-
const authorizationHeader = context.req.header("Authorization");
|
|
633
|
-
if (!authorizationHeader) {
|
|
634
|
-
throw new HTTPException(401, {
|
|
635
|
-
message: `The 'Authorization' header must exist and must have a value.`
|
|
636
|
-
});
|
|
637
|
-
}
|
|
638
|
-
if (!validateBearerScheme(authorizationHeader)) {
|
|
639
|
-
throw new HTTPException(401, {
|
|
640
|
-
message: `The 'Authorization' header value must use the Bearer scheme.`
|
|
641
|
-
});
|
|
642
|
-
}
|
|
643
|
-
const bearerToken = extractBearerToken(authorizationHeader);
|
|
644
|
-
if (!validateBearerToken(bearerToken)) {
|
|
645
|
-
throw new HTTPException(401, {
|
|
646
|
-
message: `The Bearer token in the 'Authorization' header value must be a JWT.`
|
|
647
|
-
});
|
|
648
|
-
}
|
|
649
|
-
const authService = context.env.AUTH_SERVICE;
|
|
650
|
-
const { data, error } = await authService.verifyAccessToken({
|
|
651
|
-
accessToken: bearerToken
|
|
652
|
-
});
|
|
653
|
-
if (!data || error) {
|
|
654
|
-
throw new HTTPException(401, {
|
|
655
|
-
message: "The JWT must contain valid user information."
|
|
656
|
-
});
|
|
657
|
-
}
|
|
658
|
-
const rawUserMetaDataString = data.payload.user.rawUserMetaData;
|
|
659
|
-
const rawUserMetaData = rawUserMetaDataString ? JSON.parse(rawUserMetaDataString) : null;
|
|
660
|
-
const organizationId = rawUserMetaData?.organizationId ?? null;
|
|
661
|
-
if (!organizationId) {
|
|
662
|
-
throw new HTTPException(422, {
|
|
663
|
-
message: "User data integrity check failed."
|
|
664
|
-
});
|
|
665
|
-
}
|
|
666
|
-
context.set("user", {
|
|
667
|
-
email: data.payload.user.email,
|
|
668
|
-
role: data.payload.user.role,
|
|
669
|
-
organizationId
|
|
670
|
-
});
|
|
671
|
-
context.set("jwt", data.payload);
|
|
672
|
-
await next();
|
|
673
|
-
});
|
|
674
|
-
};
|
|
675
|
-
|
|
676
|
-
const ip = () => {
|
|
677
|
-
return createMiddleware(async (context, next) => {
|
|
678
|
-
if (!["localhost", "dev"].includes(context.env.ENVIRONMENT)) {
|
|
679
|
-
const requestIp = context.req.header("cf-connecting-ip") || context.req.header("x-forwarded-for");
|
|
680
|
-
if (!requestIp) {
|
|
681
|
-
throw new HTTPException(401, {
|
|
682
|
-
message: "Failed to retrieve request IP address."
|
|
683
|
-
});
|
|
684
|
-
}
|
|
685
|
-
const user = context.get("user");
|
|
686
|
-
if (!user.organizationId) {
|
|
687
|
-
throw new HTTPException(401, {
|
|
688
|
-
message: "Failed to retrieve request organization ID."
|
|
689
|
-
});
|
|
690
|
-
}
|
|
691
|
-
const organizationService = context.env.ORGANIZATION_SERVICE;
|
|
692
|
-
const { data: organization, error } = await organizationService.getOrganization({
|
|
693
|
-
organizationId: user.organizationId
|
|
694
|
-
});
|
|
695
|
-
if (!organization || error) {
|
|
696
|
-
throw new HTTPException(404, {
|
|
697
|
-
message: "Failed to retrieve organization."
|
|
698
|
-
});
|
|
699
|
-
}
|
|
700
|
-
if (organization.ipAuthorization) {
|
|
701
|
-
if (!organization.authorizedIps.map((ip2) => ip2.ip).includes(requestIp)) {
|
|
702
|
-
throw new HTTPException(404, {
|
|
703
|
-
message: "Forbidden"
|
|
704
|
-
});
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
await next();
|
|
709
|
-
});
|
|
710
|
-
};
|
|
711
|
-
|
|
712
|
-
const composeRequestLog = async (request) => {
|
|
713
|
-
return {
|
|
714
|
-
method: request.method,
|
|
715
|
-
path: request.path,
|
|
716
|
-
query: request.query(),
|
|
717
|
-
headers: request.header(),
|
|
718
|
-
body: await request.json().catch(() => null)
|
|
719
|
-
};
|
|
720
|
-
};
|
|
721
|
-
const composeResponseLog = async (response, method, path) => {
|
|
722
|
-
return {
|
|
723
|
-
method,
|
|
724
|
-
path,
|
|
725
|
-
status: response.status,
|
|
726
|
-
statusText: response.statusText,
|
|
727
|
-
headers: Object.fromEntries(response.headers.entries()),
|
|
728
|
-
body: await response.json().catch(() => null)
|
|
729
|
-
};
|
|
730
|
-
};
|
|
731
|
-
|
|
732
|
-
const logger = () => {
|
|
733
|
-
return createMiddleware(async (context, next) => {
|
|
734
|
-
const requestLog = await composeRequestLog(context.req);
|
|
735
|
-
logRequest(requestLog);
|
|
736
|
-
await next();
|
|
737
|
-
const response = context.res.clone();
|
|
738
|
-
const responseLog = await composeResponseLog(
|
|
739
|
-
response,
|
|
740
|
-
context.req.method,
|
|
741
|
-
context.req.url
|
|
742
|
-
);
|
|
743
|
-
logResponse(responseLog);
|
|
744
|
-
});
|
|
745
|
-
};
|
|
746
|
-
|
|
747
|
-
const signature = () => {
|
|
748
|
-
return createMiddleware(async (context, next) => {
|
|
749
|
-
if (!["localhost", "dev"].includes(context.env.ENVIRONMENT)) {
|
|
750
|
-
const signatureHeader = context.req.header("X-Signature");
|
|
751
|
-
if (!signatureHeader) {
|
|
752
|
-
throw new HTTPException(401, {
|
|
753
|
-
message: `The 'X-Signature' header must exist and must have a value.`
|
|
754
|
-
});
|
|
755
|
-
}
|
|
756
|
-
const signatureKeyHeader = context.req.header("X-Signature-Key");
|
|
757
|
-
if (!signatureKeyHeader) {
|
|
758
|
-
throw new HTTPException(401, {
|
|
759
|
-
message: `The 'X-Signature-Key' header must exist and must have a value.`
|
|
760
|
-
});
|
|
761
|
-
}
|
|
762
|
-
const payload = JSON.stringify(await context.req.json().catch(() => null));
|
|
763
|
-
const user = context.get("user");
|
|
764
|
-
if (!user.organizationId) {
|
|
765
|
-
throw new HTTPException(401, {
|
|
766
|
-
message: "Failed to retrieve request organization ID."
|
|
767
|
-
});
|
|
768
|
-
}
|
|
769
|
-
const organizationService = context.env.ORGANIZATION_SERVICE;
|
|
770
|
-
const { data: organization, error } = await organizationService.getOrganization({
|
|
771
|
-
organizationId: user.organizationId
|
|
772
|
-
});
|
|
773
|
-
if (!organization || error) {
|
|
774
|
-
throw new HTTPException(404, {
|
|
775
|
-
message: "Failed to retrieve organization."
|
|
776
|
-
});
|
|
777
|
-
}
|
|
778
|
-
const signatureKey = organization.signatureKeys.filter(
|
|
779
|
-
(signatureKey2) => signatureKey2.name === signatureKeyHeader
|
|
780
|
-
)[0];
|
|
781
|
-
if (!signatureKey) {
|
|
782
|
-
throw new HTTPException(404, {
|
|
783
|
-
message: "Signature key not found."
|
|
784
|
-
});
|
|
785
|
-
}
|
|
786
|
-
const isVerified = await verifyPayloadSignature({
|
|
787
|
-
signature: signatureHeader,
|
|
788
|
-
publicKey: signatureKey.publicKey,
|
|
789
|
-
data: payload
|
|
790
|
-
});
|
|
791
|
-
if (!isVerified) {
|
|
792
|
-
throw new HTTPException(401, {
|
|
793
|
-
message: "Invalid signature key or signature."
|
|
794
|
-
});
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
await next();
|
|
798
|
-
});
|
|
799
|
-
};
|
|
800
|
-
|
|
801
|
-
const ibanSchema = z$1.string().min(1).regex(/^[A-Z]{2}[0-9]{2}[A-Z0-9]{11,30}$/, {
|
|
802
|
-
message: "Invalid IBAN format"
|
|
803
|
-
});
|
|
804
|
-
const bicSchema = z$1.string().min(1).regex(/^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$/, {
|
|
805
|
-
message: "Invalid SWIFT/BIC format"
|
|
806
|
-
});
|
|
807
|
-
const bankAccountMetadataSchema = z$1.object({
|
|
808
|
-
id: z$1.string().optional(),
|
|
809
|
-
number: z$1.string().optional(),
|
|
810
|
-
bankCode: z$1.enum(BANK_CODES).optional(),
|
|
811
|
-
holderName: z$1.string().optional(),
|
|
812
|
-
iban: ibanSchema.optional(),
|
|
813
|
-
address: z$1.string().optional(),
|
|
814
|
-
swiftBic: bicSchema.optional(),
|
|
815
|
-
bicCor: bicSchema.optional(),
|
|
816
|
-
currency: z$1.enum(CURRENCY_CODES).optional(),
|
|
817
|
-
country: z$1.enum(COUNTRY_CODES_2).optional(),
|
|
818
|
-
routingNumber: z$1.string().optional(),
|
|
819
|
-
// US
|
|
820
|
-
sortCode: z$1.string().optional(),
|
|
821
|
-
// UK
|
|
822
|
-
clabe: z$1.string().optional(),
|
|
823
|
-
// Mexico
|
|
824
|
-
bsb: z$1.string().optional(),
|
|
825
|
-
// Australia
|
|
826
|
-
brBankNumber: z$1.string().optional()
|
|
827
|
-
// Brazil
|
|
828
|
-
});
|
|
829
|
-
|
|
830
|
-
const paginationQuerySchema = new z.$ZodObject({
|
|
831
|
-
type: "object",
|
|
832
|
-
shape: {
|
|
833
|
-
page: new z.$ZodDefault({
|
|
834
|
-
type: "default",
|
|
835
|
-
innerType: new z.$ZodNumber({
|
|
836
|
-
type: "number",
|
|
837
|
-
coerce: true
|
|
838
|
-
}),
|
|
839
|
-
defaultValue: () => 1
|
|
840
|
-
}),
|
|
841
|
-
limit: new z.$ZodDefault({
|
|
842
|
-
type: "default",
|
|
843
|
-
innerType: new z.$ZodNumber({
|
|
844
|
-
type: "number",
|
|
845
|
-
coerce: true
|
|
846
|
-
}),
|
|
847
|
-
defaultValue: () => 20
|
|
848
|
-
}),
|
|
849
|
-
sort: new z.$ZodDefault({
|
|
850
|
-
type: "default",
|
|
851
|
-
innerType: new z.$ZodObject({
|
|
852
|
-
type: "object",
|
|
853
|
-
shape: {
|
|
854
|
-
column: new z.$ZodDefault({
|
|
855
|
-
type: "default",
|
|
856
|
-
innerType: new z.$ZodEnum({
|
|
857
|
-
type: "enum",
|
|
858
|
-
entries: {
|
|
859
|
-
createdAt: "createdAt",
|
|
860
|
-
updatedAt: "updatedAt",
|
|
861
|
-
deletedAt: "deletedAt"
|
|
862
|
-
}
|
|
863
|
-
}),
|
|
864
|
-
defaultValue: () => "updatedAt"
|
|
865
|
-
}),
|
|
866
|
-
direction: new z.$ZodDefault({
|
|
867
|
-
type: "default",
|
|
868
|
-
innerType: new z.$ZodEnum({
|
|
869
|
-
type: "enum",
|
|
870
|
-
entries: {
|
|
871
|
-
asc: "asc",
|
|
872
|
-
desc: "desc"
|
|
873
|
-
}
|
|
874
|
-
}),
|
|
875
|
-
defaultValue: () => "desc"
|
|
876
|
-
})
|
|
877
|
-
}
|
|
878
|
-
}),
|
|
879
|
-
defaultValue: () => ({ column: "updatedAt", direction: "desc" })
|
|
880
|
-
})
|
|
881
|
-
}
|
|
882
|
-
});
|
|
883
|
-
const paginationSchema = new z.$ZodObject({
|
|
884
|
-
type: "object",
|
|
885
|
-
shape: {
|
|
886
|
-
page: new z.$ZodNumber({
|
|
887
|
-
type: "number"
|
|
888
|
-
}),
|
|
889
|
-
limit: new z.$ZodNumber({
|
|
890
|
-
type: "number"
|
|
891
|
-
}),
|
|
892
|
-
sort: new z.$ZodObject({
|
|
893
|
-
type: "object",
|
|
894
|
-
shape: {
|
|
895
|
-
column: new z.$ZodEnum({
|
|
896
|
-
type: "enum",
|
|
897
|
-
entries: {
|
|
898
|
-
createdAt: "createdAt",
|
|
899
|
-
updatedAt: "updatedAt",
|
|
900
|
-
deletedAt: "deletedAt"
|
|
901
|
-
}
|
|
902
|
-
}),
|
|
903
|
-
direction: new z.$ZodEnum({
|
|
904
|
-
type: "enum",
|
|
905
|
-
entries: {
|
|
906
|
-
asc: "asc",
|
|
907
|
-
desc: "desc"
|
|
908
|
-
}
|
|
909
|
-
})
|
|
910
|
-
}
|
|
911
|
-
})
|
|
912
|
-
}
|
|
913
|
-
});
|
|
914
|
-
|
|
915
606
|
const service = (serviceName) => {
|
|
916
607
|
return function(constructor) {
|
|
917
608
|
return class extends constructor {
|
|
@@ -1052,4 +743,4 @@ function develitWorker(Worker) {
|
|
|
1052
743
|
return DevelitWorker;
|
|
1053
744
|
}
|
|
1054
745
|
|
|
1055
|
-
export { DatabaseTransaction, ENVIRONMENT, RPCResponse, USER_ROLES, action, bankAccount, bankAccountMetadataSchema, base, bicSchema, buildMultiFilterConditions, buildRangeFilterConditions, buildSearchConditions, calculateExponentialBackoff, cloudflareQueue, composeWranglerBase, createAuditLogWriter, createInternalError,
|
|
746
|
+
export { DatabaseTransaction, ENVIRONMENT, RPCResponse, USER_ROLES, action, bankAccount, bankAccountMetadataSchema, base, bicSchema, buildMultiFilterConditions, buildRangeFilterConditions, buildSearchConditions, calculateExponentialBackoff, cloudflareQueue, composeWranglerBase, createAuditLogWriter, createInternalError, defineCommand, derivePortFromId, develitWorker, durableObjectNamespaceIdFromName, first, firstOrError, getD1Credentials, getD1DatabaseIdFromWrangler, getDrizzleD1Config, getSecret, handleAction, handleActionResponse, ibanSchema, isInternalError, paginationQuerySchema, paginationSchema, resolveColumn, service, useFetch, useResult, useResultSync, uuidv4 };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { MiddlewareHandler } from 'hono/types';
|
|
2
|
+
|
|
3
|
+
declare const idempotency: <T extends {
|
|
4
|
+
IDEMPOTENCY_KV: KVNamespace;
|
|
5
|
+
}>() => MiddlewareHandler;
|
|
6
|
+
|
|
7
|
+
declare const jwt: <TAuthService, TJwtPayload>() => MiddlewareHandler;
|
|
8
|
+
|
|
9
|
+
declare const ip: <TOrganizationService, TJwtPayload>() => MiddlewareHandler;
|
|
10
|
+
|
|
11
|
+
declare const logger: () => MiddlewareHandler;
|
|
12
|
+
|
|
13
|
+
declare const signature: <TOrganizationService, TJwtPayload>() => MiddlewareHandler;
|
|
14
|
+
|
|
15
|
+
export { idempotency, ip, jwt, logger, signature };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { MiddlewareHandler } from 'hono/types';
|
|
2
|
+
|
|
3
|
+
declare const idempotency: <T extends {
|
|
4
|
+
IDEMPOTENCY_KV: KVNamespace;
|
|
5
|
+
}>() => MiddlewareHandler;
|
|
6
|
+
|
|
7
|
+
declare const jwt: <TAuthService, TJwtPayload>() => MiddlewareHandler;
|
|
8
|
+
|
|
9
|
+
declare const ip: <TOrganizationService, TJwtPayload>() => MiddlewareHandler;
|
|
10
|
+
|
|
11
|
+
declare const logger: () => MiddlewareHandler;
|
|
12
|
+
|
|
13
|
+
declare const signature: <TOrganizationService, TJwtPayload>() => MiddlewareHandler;
|
|
14
|
+
|
|
15
|
+
export { idempotency, ip, jwt, logger, signature };
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { createMiddleware } from 'hono/factory';
|
|
2
|
+
import { HTTPException } from 'hono/http-exception';
|
|
3
|
+
import 'h3';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import 'cloudflare';
|
|
6
|
+
import 'node:fs';
|
|
7
|
+
import 'node:crypto';
|
|
8
|
+
import 'node:path';
|
|
9
|
+
import 'comment-json';
|
|
10
|
+
import 'drizzle-orm';
|
|
11
|
+
import { v as verifyPayloadSignature } from './shared/backend-sdk.CgM_2r0b.mjs';
|
|
12
|
+
|
|
13
|
+
const validateBearerScheme = (header) => {
|
|
14
|
+
return header.startsWith("Bearer ") && header.length > 7 && !header.slice(7).includes(" ");
|
|
15
|
+
};
|
|
16
|
+
const extractBearerToken = (header) => {
|
|
17
|
+
return header.slice(7).trim();
|
|
18
|
+
};
|
|
19
|
+
const validateBearerToken = (bearerToken) => {
|
|
20
|
+
return z.jwt().safeParse(bearerToken).success;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const logRequest = (log) => {
|
|
24
|
+
console.log("REQUEST | An incoming request has been recorded.", log);
|
|
25
|
+
};
|
|
26
|
+
const logResponse = (log) => {
|
|
27
|
+
console.log(`RESPONSE | An outgoing response has been recorded.`, log);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const idempotency = () => {
|
|
31
|
+
return createMiddleware(async (context, next) => {
|
|
32
|
+
const idempotencyKeyHeader = context.req.header("X-Idempotency-Key");
|
|
33
|
+
if (!idempotencyKeyHeader) {
|
|
34
|
+
throw new HTTPException(401, {
|
|
35
|
+
message: `The 'X-Idempotency-Key' header must exist and must have a value.`
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
const existingIdempotencyRecord = await context.env.IDEMPOTENCY_KV.get(idempotencyKeyHeader);
|
|
39
|
+
if (existingIdempotencyRecord) {
|
|
40
|
+
throw new HTTPException(409, {
|
|
41
|
+
message: "The identical request has already been processed. The idempotency key is not unique."
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
await context.env.IDEMPOTENCY_KV.put(
|
|
45
|
+
idempotencyKeyHeader,
|
|
46
|
+
idempotencyKeyHeader,
|
|
47
|
+
{
|
|
48
|
+
expirationTtl: 60 * 60 * 24 * 3
|
|
49
|
+
// 3 days
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
context.set("idempotency", {
|
|
53
|
+
key: idempotencyKeyHeader
|
|
54
|
+
});
|
|
55
|
+
await next();
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const jwt = () => {
|
|
60
|
+
return createMiddleware(async (context, next) => {
|
|
61
|
+
const authorizationHeader = context.req.header("Authorization");
|
|
62
|
+
if (!authorizationHeader) {
|
|
63
|
+
throw new HTTPException(401, {
|
|
64
|
+
message: `The 'Authorization' header must exist and must have a value.`
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (!validateBearerScheme(authorizationHeader)) {
|
|
68
|
+
throw new HTTPException(401, {
|
|
69
|
+
message: `The 'Authorization' header value must use the Bearer scheme.`
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
const bearerToken = extractBearerToken(authorizationHeader);
|
|
73
|
+
if (!validateBearerToken(bearerToken)) {
|
|
74
|
+
throw new HTTPException(401, {
|
|
75
|
+
message: `The Bearer token in the 'Authorization' header value must be a JWT.`
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
const authService = context.env.AUTH_SERVICE;
|
|
79
|
+
const { data, error } = await authService.verifyAccessToken({
|
|
80
|
+
accessToken: bearerToken
|
|
81
|
+
});
|
|
82
|
+
if (!data || error) {
|
|
83
|
+
throw new HTTPException(401, {
|
|
84
|
+
message: "The JWT must contain valid user information."
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
const rawUserMetaDataString = data.payload.user.rawUserMetaData;
|
|
88
|
+
const rawUserMetaData = rawUserMetaDataString ? JSON.parse(rawUserMetaDataString) : null;
|
|
89
|
+
const organizationId = rawUserMetaData?.organizationId ?? null;
|
|
90
|
+
if (!organizationId) {
|
|
91
|
+
throw new HTTPException(422, {
|
|
92
|
+
message: "User data integrity check failed."
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
context.set("user", {
|
|
96
|
+
email: data.payload.user.email,
|
|
97
|
+
role: data.payload.user.role,
|
|
98
|
+
organizationId
|
|
99
|
+
});
|
|
100
|
+
context.set("jwt", data.payload);
|
|
101
|
+
await next();
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const ip = () => {
|
|
106
|
+
return createMiddleware(async (context, next) => {
|
|
107
|
+
if (!["localhost", "dev"].includes(context.env.ENVIRONMENT)) {
|
|
108
|
+
const requestIp = context.req.header("cf-connecting-ip") || context.req.header("x-forwarded-for");
|
|
109
|
+
if (!requestIp) {
|
|
110
|
+
throw new HTTPException(401, {
|
|
111
|
+
message: "Failed to retrieve request IP address."
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
const user = context.get("user");
|
|
115
|
+
if (!user.organizationId) {
|
|
116
|
+
throw new HTTPException(401, {
|
|
117
|
+
message: "Failed to retrieve request organization ID."
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
const organizationService = context.env.ORGANIZATION_SERVICE;
|
|
121
|
+
const { data: organization, error } = await organizationService.getOrganization({
|
|
122
|
+
organizationId: user.organizationId
|
|
123
|
+
});
|
|
124
|
+
if (!organization || error) {
|
|
125
|
+
throw new HTTPException(404, {
|
|
126
|
+
message: "Failed to retrieve organization."
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (organization.ipAuthorization) {
|
|
130
|
+
if (!organization.authorizedIps.map((ip2) => ip2.ip).includes(requestIp)) {
|
|
131
|
+
throw new HTTPException(404, {
|
|
132
|
+
message: "Forbidden"
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
await next();
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const composeRequestLog = async (request) => {
|
|
142
|
+
return {
|
|
143
|
+
method: request.method,
|
|
144
|
+
path: request.path,
|
|
145
|
+
query: request.query(),
|
|
146
|
+
headers: request.header(),
|
|
147
|
+
body: await request.json().catch(() => null)
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
const composeResponseLog = async (response, method, path) => {
|
|
151
|
+
return {
|
|
152
|
+
method,
|
|
153
|
+
path,
|
|
154
|
+
status: response.status,
|
|
155
|
+
statusText: response.statusText,
|
|
156
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
157
|
+
body: await response.json().catch(() => null)
|
|
158
|
+
};
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const logger = () => {
|
|
162
|
+
return createMiddleware(async (context, next) => {
|
|
163
|
+
const requestLog = await composeRequestLog(context.req);
|
|
164
|
+
logRequest(requestLog);
|
|
165
|
+
await next();
|
|
166
|
+
const response = context.res.clone();
|
|
167
|
+
const responseLog = await composeResponseLog(
|
|
168
|
+
response,
|
|
169
|
+
context.req.method,
|
|
170
|
+
context.req.url
|
|
171
|
+
);
|
|
172
|
+
logResponse(responseLog);
|
|
173
|
+
});
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const signature = () => {
|
|
177
|
+
return createMiddleware(async (context, next) => {
|
|
178
|
+
if (!["localhost", "dev"].includes(context.env.ENVIRONMENT)) {
|
|
179
|
+
const signatureHeader = context.req.header("X-Signature");
|
|
180
|
+
if (!signatureHeader) {
|
|
181
|
+
throw new HTTPException(401, {
|
|
182
|
+
message: `The 'X-Signature' header must exist and must have a value.`
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
const signatureKeyHeader = context.req.header("X-Signature-Key");
|
|
186
|
+
if (!signatureKeyHeader) {
|
|
187
|
+
throw new HTTPException(401, {
|
|
188
|
+
message: `The 'X-Signature-Key' header must exist and must have a value.`
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
const payload = JSON.stringify(await context.req.json().catch(() => null));
|
|
192
|
+
const user = context.get("user");
|
|
193
|
+
if (!user.organizationId) {
|
|
194
|
+
throw new HTTPException(401, {
|
|
195
|
+
message: "Failed to retrieve request organization ID."
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
const organizationService = context.env.ORGANIZATION_SERVICE;
|
|
199
|
+
const { data: organization, error } = await organizationService.getOrganization({
|
|
200
|
+
organizationId: user.organizationId
|
|
201
|
+
});
|
|
202
|
+
if (!organization || error) {
|
|
203
|
+
throw new HTTPException(404, {
|
|
204
|
+
message: "Failed to retrieve organization."
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
const signatureKey = organization.signatureKeys.filter(
|
|
208
|
+
(signatureKey2) => signatureKey2.name === signatureKeyHeader
|
|
209
|
+
)[0];
|
|
210
|
+
if (!signatureKey) {
|
|
211
|
+
throw new HTTPException(404, {
|
|
212
|
+
message: "Signature key not found."
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
const isVerified = await verifyPayloadSignature({
|
|
216
|
+
signature: signatureHeader,
|
|
217
|
+
publicKey: signatureKey.publicKey,
|
|
218
|
+
data: payload
|
|
219
|
+
});
|
|
220
|
+
if (!isVerified) {
|
|
221
|
+
throw new HTTPException(401, {
|
|
222
|
+
message: "Invalid signature key or signature."
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
await next();
|
|
227
|
+
});
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
export { idempotency, ip, jwt, logger, signature };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { subtle } from 'node:crypto';
|
|
2
|
+
|
|
3
|
+
const createSignatureKeyPair = async () => {
|
|
4
|
+
const { publicKey, privateKey } = await subtle.generateKey(
|
|
5
|
+
{
|
|
6
|
+
name: "RSASSA-PKCS1-v1_5",
|
|
7
|
+
modulusLength: 4096,
|
|
8
|
+
publicExponent: new Uint8Array([1, 0, 1]),
|
|
9
|
+
hash: "SHA-256"
|
|
10
|
+
},
|
|
11
|
+
true,
|
|
12
|
+
["sign", "verify"]
|
|
13
|
+
);
|
|
14
|
+
const exportedPublicKey = await subtle.exportKey("spki", publicKey);
|
|
15
|
+
const exportedPrivateKey = await subtle.exportKey("pkcs8", privateKey);
|
|
16
|
+
return {
|
|
17
|
+
publicKey: Buffer.from(exportedPublicKey).toString("base64"),
|
|
18
|
+
privateKey: Buffer.from(exportedPrivateKey).toString("base64")
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
const signPayload = async ({
|
|
22
|
+
payload,
|
|
23
|
+
privateKey
|
|
24
|
+
}) => {
|
|
25
|
+
const binaryPrivateKey = Uint8Array.from(
|
|
26
|
+
atob(privateKey),
|
|
27
|
+
(c) => c.charCodeAt(0)
|
|
28
|
+
);
|
|
29
|
+
const importedPrivateKey = await crypto.subtle.importKey(
|
|
30
|
+
"pkcs8",
|
|
31
|
+
binaryPrivateKey,
|
|
32
|
+
{
|
|
33
|
+
name: "RSASSA-PKCS1-v1_5",
|
|
34
|
+
hash: "SHA-256"
|
|
35
|
+
},
|
|
36
|
+
false,
|
|
37
|
+
["sign"]
|
|
38
|
+
);
|
|
39
|
+
const encodedPayload = new TextEncoder().encode(payload);
|
|
40
|
+
const signature = await crypto.subtle.sign(
|
|
41
|
+
{
|
|
42
|
+
name: "RSASSA-PKCS1-v1_5"
|
|
43
|
+
},
|
|
44
|
+
importedPrivateKey,
|
|
45
|
+
encodedPayload
|
|
46
|
+
);
|
|
47
|
+
const base64Signature = btoa(
|
|
48
|
+
String.fromCharCode(...new Uint8Array(signature))
|
|
49
|
+
);
|
|
50
|
+
return base64Signature;
|
|
51
|
+
};
|
|
52
|
+
const algParams = {
|
|
53
|
+
RSA: {
|
|
54
|
+
name: "RSASSA-PKCS1-v1_5",
|
|
55
|
+
hash: { name: "SHA-256" }
|
|
56
|
+
},
|
|
57
|
+
EC: {
|
|
58
|
+
name: "ECDSA",
|
|
59
|
+
namedCurve: "P-256"
|
|
60
|
+
},
|
|
61
|
+
HMAC: {
|
|
62
|
+
name: "HMAC",
|
|
63
|
+
hash: { name: "SHA-256" }
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
const verifyPayloadSignature = async ({
|
|
67
|
+
signature,
|
|
68
|
+
data,
|
|
69
|
+
publicKey,
|
|
70
|
+
algorithm = "RSA"
|
|
71
|
+
}) => {
|
|
72
|
+
const binaryPublicKey = Uint8Array.from(
|
|
73
|
+
atob(publicKey),
|
|
74
|
+
(c) => c.charCodeAt(0)
|
|
75
|
+
);
|
|
76
|
+
const format = algorithm === "HMAC" ? "raw" : "spki";
|
|
77
|
+
const importedPublicKey = await crypto.subtle.importKey(
|
|
78
|
+
format,
|
|
79
|
+
binaryPublicKey,
|
|
80
|
+
algParams[algorithm],
|
|
81
|
+
false,
|
|
82
|
+
["verify"]
|
|
83
|
+
);
|
|
84
|
+
const encodedPayload = new TextEncoder().encode(data);
|
|
85
|
+
const decodedSignature = Uint8Array.from(
|
|
86
|
+
atob(signature),
|
|
87
|
+
(c) => c.charCodeAt(0)
|
|
88
|
+
);
|
|
89
|
+
const isValid = await crypto.subtle.verify(
|
|
90
|
+
algParams[algorithm],
|
|
91
|
+
importedPublicKey,
|
|
92
|
+
decodedSignature,
|
|
93
|
+
encodedPayload
|
|
94
|
+
);
|
|
95
|
+
return isValid;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export { createSignatureKeyPair as c, signPayload as s, verifyPayloadSignature as v };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@develit-io/backend-sdk",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.2",
|
|
4
4
|
"description": "Develit Backend SDK",
|
|
5
5
|
"author": "Develit.io",
|
|
6
6
|
"license": "ISC",
|
|
@@ -22,6 +22,11 @@
|
|
|
22
22
|
"import": "./dist/index.mjs",
|
|
23
23
|
"default": "./dist/index.mjs"
|
|
24
24
|
},
|
|
25
|
+
"./middlewares": {
|
|
26
|
+
"types": "./dist/middlewares.d.ts",
|
|
27
|
+
"import": "./dist/middlewares.mjs",
|
|
28
|
+
"default": "./dist/middlewares.mjs"
|
|
29
|
+
},
|
|
25
30
|
"./package.json": "./package.json"
|
|
26
31
|
},
|
|
27
32
|
"files": [
|