@kunk/server 3.0.4 → 3.0.5

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,142 +0,0 @@
1
- import { eq, type InferInsertModel, type InferSelectModel, type SQL, type Table } from "drizzle-orm";
2
- import { drizzle } from "drizzle-orm/bun-sql";
3
- import type { BunSQLDatabase } from "drizzle-orm/bun-sql/postgres/driver";
4
- import { SERVER_ERROR } from "@/utils/+";
5
- import { Database } from "@/contracts/+";
6
- import type { ContextData } from "@kunk/api";
7
- import type { IndexColumn, PgColumn } from "drizzle-orm/pg-core";
8
-
9
- export class DizzleDatabase extends Database {
10
-
11
- private released: boolean = false
12
-
13
- private constructor(
14
- private readonly sql: BunSQLDatabase,
15
- private readonly session: Bun.ReservedSQL
16
- ) {
17
- super()
18
- }
19
-
20
- static async create(sql: Bun.SQL, contextData: ContextData): Promise<DizzleDatabase> {
21
- const session = await sql.reserve()
22
- if (contextData.tenantId) {
23
- await session`SELECT set_config('app.tenant_id', ${contextData.tenantId}, false);`
24
- }
25
- return new DizzleDatabase(drizzle({ client: session }), session)
26
- }
27
-
28
- override async create<T extends Table, V extends InferInsertModel<T> | InferInsertModel<T>[]>(
29
- entity: T,
30
- values: V
31
- ): Promise<
32
- V extends InferInsertModel<T>[]
33
- ? { [K in keyof V]: NonNullable<InferSelectModel<T>> }
34
- : NonNullable<InferSelectModel<T>>
35
- > {
36
- const table = entity as any
37
- const result = await this.sql.insert(table).values(values).returning()
38
-
39
- const length = Array.isArray(values) ? values.length : 1
40
- if (result.length !== length) {
41
- throw SERVER_ERROR.UNEXPECTED("FAILED_TO_INSERT_ENTITY", {})
42
- }
43
-
44
- if (Array.isArray(values)) {
45
- return result as any
46
- }
47
-
48
- return result[0] as any
49
- }
50
-
51
- async update<T extends Table>(
52
- entity: T,
53
- id: string,
54
- values: Partial<InferInsertModel<T>>
55
- ): Promise<InferSelectModel<T>> {
56
- const table = entity as any
57
- const [result] = await this.sql.update(table)
58
- .set(values)
59
- .where(eq(table.id, id))
60
- .returning()
61
-
62
- if (!result) {
63
- throw SERVER_ERROR.UNEXPECTED("FAILED_TO_UPDATE_ENTITY", { })
64
- }
65
-
66
- return result as InferSelectModel<T>
67
- }
68
-
69
- async upsert<T extends Table>(entity: T, options: {
70
- target: IndexColumn | IndexColumn[],
71
- values: InferInsertModel<T>
72
- }): Promise<InferSelectModel<T>> {
73
- const table = entity as any
74
- const [result] = await this.sql.insert(table).values(options.values).onConflictDoUpdate({
75
- target: options.target,
76
- set: options.values,
77
- }).returning()
78
-
79
- if (!result) {
80
- throw SERVER_ERROR.UNEXPECTED("FAILED_TO_UPSERT_ENTITY", {})
81
- }
82
-
83
- return result as InferSelectModel<T>
84
- }
85
-
86
- async findMany<T extends Table>(entity: T, options?: {
87
- where?: SQL,
88
- limit?: number,
89
- offset?: number,
90
- orderBy?: (PgColumn | SQL | SQL.Aliased)[],
91
- }): Promise<InferSelectModel<T>[]> {
92
- const table = entity as any
93
- const result = await this.sql.select().from(table)
94
- .where(options?.where)
95
- .limit(options?.limit ?? 1000)
96
- .offset(options?.offset ?? 0)
97
- .orderBy(...(options?.orderBy ?? []))
98
- .execute()
99
-
100
- if (!result) {
101
- throw SERVER_ERROR.UNEXPECTED("FAILED_TO_GET_MANY_ENTITIES", {})
102
- }
103
-
104
- return result as InferSelectModel<T>[]
105
- }
106
-
107
- async findOne<T extends Table>(entity: T, options?: {
108
- where?: SQL,
109
- }): Promise<InferSelectModel<T> | null> {
110
- const table = entity as any
111
- const [result] = await this.sql.select().from(table).where(options?.where).limit(1).execute()
112
-
113
- if (!result) {
114
- return null
115
- }
116
-
117
- return result as InferSelectModel<T>
118
- }
119
-
120
- async get<T extends Table>(entity: T, id: string): Promise<InferSelectModel<T>> {
121
- const table = entity as any
122
- const [result] = await this.sql.select().from(table).where(eq(table.id, id)).limit(1).execute()
123
-
124
- if (!result) {
125
- throw SERVER_ERROR.GET_ENTITY_NOT_FOUND(table, id)
126
- }
127
-
128
- return result as InferSelectModel<T>
129
- }
130
-
131
- async delete<T extends Table>(entity: T, id: string): Promise<void> {
132
- const table = entity as any
133
- await this.sql.delete(table).where(eq(table.id, id))
134
- }
135
-
136
- async commit(): Promise<void> {
137
- if (!this.released) {
138
- this.released = true
139
- this.session.release()
140
- }
141
- }
142
- }
@@ -1 +0,0 @@
1
- export * as DrizzleQuery from "drizzle-orm/sql/expressions";
@@ -1,36 +0,0 @@
1
- import { Logger } from "@kunk/api"
2
- import pino from "pino"
3
-
4
- const rootLogger = pino({
5
- name: 'app',
6
- transport: {
7
- target: 'pino-pretty',
8
- options: {
9
- colorize: true,
10
- translateTime: 'SYS:standard',
11
- ignore: 'pid,hostname'
12
- }
13
- }
14
- })
15
-
16
- export class PinoLogger implements Logger {
17
-
18
- constructor(private logger: pino.Logger = rootLogger) {}
19
-
20
- info(message: string): void {
21
- this.logger.info(message)
22
- }
23
-
24
- warn(message: string): void {
25
- this.logger.warn(message)
26
- }
27
-
28
- error(error: any): void {
29
- this.logger.error(error)
30
- }
31
-
32
- fork(name: string): Logger {
33
- return new PinoLogger(this.logger.child({ name }))
34
- }
35
-
36
- }
package/src/setup.ts DELETED
@@ -1,26 +0,0 @@
1
- import * as Contracts from "@/contracts/+";
2
- import * as Services from "@/services/+";
3
- import { registry } from "@/registry";
4
- import { DizzleDatabase } from "@/services/+";
5
- import { DatabaseConfig } from "@/configs/+";
6
-
7
-
8
- registry.bind(Contracts.Logger).to(Services.PinoLogger)
9
- registry.bind(Contracts.Generator).to(Services.BunGenerator)
10
-
11
- registry.bind(Bun.SQL).toDynamicValue(() => {
12
- const config = DatabaseConfig.get()
13
- return new Bun.SQL({
14
- url: config.uri,
15
- max: config.maxPoolSize,
16
- idleTimeout: config.idleTimeout,
17
- connectionTimeout: config.connectionTimeout
18
- })
19
- }).inSingletonScope()
20
-
21
- registry.bind(Contracts.Database).toDynamicValue(async (container) => {
22
- return await DizzleDatabase.create(
23
- container.get(Bun.SQL),
24
- container.get(Contracts.ContextData)
25
- )
26
- }).inRequestScope()
package/src/utils/+.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from "./SERVER_ERROR"
2
- export * from "./config"
@@ -1,41 +0,0 @@
1
- import type { StandardSchemaV1 } from "@standard-schema/spec"
2
- import { Throwable, type IThrowable } from "@kunk/api"
3
- import { getTableUniqueName, Table } from "drizzle-orm"
4
-
5
- export namespace SERVER_ERROR {
6
-
7
- export function RESOURCE_ID_NOT_FOUND(resource: string, id: string) {
8
- return Throwable.create("RESOURCE_ID_NOT_FOUND", 404, { resource, id })
9
- }
10
-
11
- export function RESOURCE_NOT_FOUND(resource: string) {
12
- return Throwable.create("RESOURCE_NOT_FOUND", 404, { resource })
13
- }
14
-
15
- export function BAD_REQUEST(type: string, args: Record<string, any>) {
16
- return Throwable.create(type, 400, args)
17
- }
18
-
19
- export function RESOURCE_ID_ALREADY_EXISTS(resource: string, id: string) {
20
- return Throwable.create("RESOURCE_ID_ALREADY_EXISTS", 400, { resource, id })
21
- }
22
-
23
- export function VALIDATION(...issues: IThrowable[]) {
24
- return Throwable.create("VALIDATION_ERROR", 422, { issues })
25
- }
26
-
27
- export function SCHEMA_VALIDATION(issues: readonly StandardSchemaV1.Issue[]) {
28
- return Throwable.create("SCHEMA_VALIDATION_ERROR", 422, { issues })
29
- }
30
-
31
- export function UNEXPECTED(type: string, args: Record<string, any>) {
32
- return Throwable.create(type, 500, args)
33
- }
34
-
35
- export const FORWARD = Throwable.forward
36
-
37
- export function GET_ENTITY_NOT_FOUND<T extends Table>(entity: T, id: string) {
38
- return SERVER_ERROR.RESOURCE_ID_NOT_FOUND(getTableUniqueName(entity), id)
39
- }
40
-
41
- }
@@ -1,70 +0,0 @@
1
- import { SERVER_ERROR } from "./SERVER_ERROR";
2
- import type { StandardSchemaV1 } from "@standard-schema/spec";
3
- import type { I } from "@kunk/api";
4
- import * as path from "path";
5
-
6
- function interpolateEnvVars<T>(obj: T): T {
7
- if (typeof obj === 'string') {
8
- return obj.replace(
9
- /\${([^:-]+)(?:-([^}]+))?}/g,
10
- (_, key, defaultValue) => Bun.env[key] || defaultValue || ''
11
- ) as T;
12
- }
13
-
14
- if (typeof obj === 'object' && obj !== null) {
15
- const result = (Array.isArray(obj) ? [] : {}) as T;
16
- for (const key in obj) {
17
- result[key] = interpolateEnvVars(obj[key]);
18
- }
19
- return result;
20
- }
21
-
22
- return obj;
23
- }
24
-
25
- async function loadFromFile<T extends StandardSchemaV1>(name: string, schema: T): Promise<I.Output<T>> {
26
- let rawConfig = {}
27
- const filePath = path.resolve(process.cwd(), `./config/${name}.yaml`)
28
-
29
- if (await Bun.file(filePath).exists()) {
30
- rawConfig = await import(filePath).then(module => module.default?.[Bun.env.NODE_ENV || "local"]);
31
- }
32
-
33
- const validated = await schema["~standard"].validate(rawConfig);
34
- if (validated.issues) {
35
- throw SERVER_ERROR.SCHEMA_VALIDATION(validated.issues)
36
- }
37
- return interpolateEnvVars(validated.value) as I.Output<T>;
38
- }
39
-
40
-
41
- export class Config<T extends StandardSchemaV1> {
42
-
43
- private constructor(
44
- private readonly schema: T,
45
- private values: I.Output<T>
46
- ) {}
47
-
48
-
49
- public get() {
50
- return this.values;
51
- }
52
-
53
- public async set(values: I.Input<T>): Promise<void> {
54
- const validated = await this.schema["~standard"].validate(values);
55
- if (validated.issues) {
56
- throw SERVER_ERROR.SCHEMA_VALIDATION(validated.issues)
57
- }
58
- this.values = validated.value as I.Output<T>;
59
- }
60
-
61
- static async create<T extends StandardSchemaV1>(options: { name: string, schema: T }) {
62
- const values = await loadFromFile(options.name, options.schema);
63
- return new Config(options.schema, values as I.Output<T>);
64
- }
65
-
66
- public static set<T extends StandardSchemaV1>(config: Config<T>, values: I.Input<T>) {
67
- config.set(values);
68
- }
69
-
70
- }
package/tsconfig.json DELETED
@@ -1,19 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "rootDir": ".",
4
- "baseUrl": ".",
5
- "paths": {
6
- "@/*": ["./src/*"]
7
- },
8
- "strict": true,
9
- "module": "Preserve",
10
- "target": "ESNext"
11
- },
12
- "include": [
13
- "src/**/*.ts"
14
- ],
15
- "exclude": [
16
- "node_modules",
17
- "dist"
18
- ]
19
- }
package/tsdown.config.ts DELETED
@@ -1,15 +0,0 @@
1
- import { defineConfig } from 'tsdown'
2
-
3
- export default defineConfig({
4
- entry: [
5
- './src/index.ts'
6
- ],
7
- external: [
8
- "drizzle-orm",
9
- "drizzle-sdk",
10
- ],
11
- dts: true,
12
- minify: {
13
- mangle: true,
14
- }
15
- })