honertia 0.1.9 → 0.1.10

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/README.md CHANGED
@@ -511,10 +511,11 @@ const input = yield* validateRequest(
511
511
  S.Struct({ name: requiredString, description: S.optional(S.String) }),
512
512
  { errorComponent: 'Projects/Create' }
513
513
  )
514
- // input is fully typed: { name: string, description?: string }
514
+ // input is Validated<{ name: string, description?: string }>
515
515
  ```
516
516
 
517
517
  On validation failure, re-renders `errorComponent` with field-level errors.
518
+ `validateRequest` returns a branded `Validated<T>` value that you can require for writes.
518
519
 
519
520
  #### `DatabaseService` - Database Access
520
521
 
@@ -552,7 +553,9 @@ import { Effect, Schema as S } from 'effect'
552
553
  import {
553
554
  action,
554
555
  authorize,
556
+ asTrusted,
555
557
  validateRequest,
558
+ dbMutation,
556
559
  DatabaseService,
557
560
  redirect,
558
561
  requiredString,
@@ -575,12 +578,12 @@ export const createProject = action(
575
578
 
576
579
  // 3. Database - perform the mutation
577
580
  const db = yield* DatabaseService
578
- yield* Effect.tryPromise(() =>
579
- db.insert(projects).values({
581
+ yield* dbMutation(db, async (db) => {
582
+ await db.insert(projects).values(asTrusted({
580
583
  ...input,
581
584
  userId: auth.user.id,
582
- })
583
- )
585
+ }))
586
+ })
584
587
 
585
588
  // 4. Response - redirect on success
586
589
  return yield* redirect('/projects')
@@ -656,23 +659,63 @@ export const searchProjects = action(
656
659
 
657
660
  ### Helper Utilities
658
661
 
662
+ #### `dbMutation` - Safe Writes
663
+
664
+ Use `dbMutation` for writes that require validated or trusted input:
665
+
666
+ ```typescript
667
+ import { DatabaseService, dbMutation, validateRequest, asTrusted, authorize } from 'honertia/effect'
668
+
669
+ const auth = yield* authorize()
670
+ const input = yield* validateRequest(CreateProjectSchema)
671
+ const values = asTrusted({ userId: auth.user.id, ...input })
672
+ const db = yield* DatabaseService
673
+
674
+ yield* dbMutation(db, async (db) => {
675
+ await db.insert(projects).values(values)
676
+ })
677
+ ```
678
+
679
+ Use `asTrusted` for server-derived values like audit logs or usage meters, or when combining validated input with server-only fields.
680
+ `dbMutation` also wraps `execute`/`run` params to require validated or trusted inputs.
681
+
682
+ Why this design: we intentionally use nominal brands that do not survive spreads or merges. That means any modified or combined object must be explicitly re-branded with `asTrusted`, which makes trust boundaries visible and prevents accidental writes of unvalidated data.
683
+
684
+ ```typescript
685
+ const input = yield* validateRequest(CreateProjectSchema)
686
+
687
+ // This fails typechecking because the brand is dropped by the merge
688
+ const merged = { ...input, userId: auth.user.id }
689
+ // await db.insert(projects).values(merged)
690
+
691
+ // Explicitly re-brand after adding server data
692
+ const values = asTrusted({ ...input, userId: auth.user.id })
693
+ await db.insert(projects).values(values)
694
+ ```
695
+
696
+ For multi-step writes, use `dbTransaction` so writes require validated or trusted input.
697
+
659
698
  #### `dbTransaction` - Database Transactions
660
699
 
661
700
  Run multiple database operations in a transaction with automatic rollback on failure. The database instance is passed explicitly to keep the dependency visible and consistent with other service patterns:
662
701
 
663
702
  ```typescript
664
- import { DatabaseService, dbTransaction } from 'honertia/effect'
703
+ import { DatabaseService, dbTransaction, asTrusted } from 'honertia/effect'
665
704
 
666
705
  const db = yield* DatabaseService
706
+ const user = asTrusted({ name: 'Alice', email: 'alice@example.com' })
707
+ const balanceUpdate = asTrusted({ balance: 100 })
667
708
 
668
709
  yield* dbTransaction(db, async (tx) => {
669
- await tx.insert(users).values({ name: 'Alice', email: 'alice@example.com' })
670
- await tx.update(accounts).set({ balance: 100 }).where(eq(accounts.userId, id))
710
+ await tx.insert(users).values(user)
711
+ await tx.update(accounts).set(balanceUpdate).where(eq(accounts.userId, id))
671
712
  // If any operation fails, the entire transaction rolls back
672
713
  return { success: true }
673
714
  })
674
715
  ```
675
716
 
717
+ `dbTransaction` wraps `insert`, `update`, and `execute`/`run` params; `delete` has no payload, so build its conditions from validated or trusted values.
718
+
676
719
  ## Core Concepts
677
720
 
678
721
  ### Effect-Based Handlers
@@ -684,7 +727,9 @@ import { Effect } from 'effect'
684
727
  import {
685
728
  action,
686
729
  authorize,
730
+ asTrusted,
687
731
  validateRequest,
732
+ dbMutation,
688
733
  DatabaseService,
689
734
  render,
690
735
  redirect,
@@ -716,12 +761,12 @@ export const createProject = action(
716
761
  })
717
762
  const db = yield* DatabaseService
718
763
 
719
- yield* Effect.tryPromise(() =>
720
- db.insert(schema.projects).values({
764
+ yield* dbMutation(db, async (db) => {
765
+ await db.insert(schema.projects).values(asTrusted({
721
766
  ...input,
722
767
  userId: auth.user.id,
723
- })
724
- )
768
+ }))
769
+ })
725
770
 
726
771
  return yield* redirect('/projects')
727
772
  })
@@ -892,7 +937,7 @@ export const createProject = Effect.gen(function* () {
892
937
  errorComponent: 'Projects/Create', // Re-render with errors on validation failure
893
938
  })
894
939
 
895
- // input is fully typed: { name: string, description: string | null }
940
+ // input is Validated<{ name: string, description: string | null }>
896
941
  yield* insertProject(input)
897
942
 
898
943
  return yield* redirect('/projects')
@@ -7,6 +7,7 @@
7
7
  import { Effect } from 'effect';
8
8
  import { type AuthUser } from './services.js';
9
9
  import { UnauthorizedError, ForbiddenError, Redirect } from './errors.js';
10
+ import { type Validated, type Trusted } from './validation.js';
10
11
  /**
11
12
  * Semantic wrapper for Effect actions.
12
13
  *
@@ -25,8 +26,8 @@ import { UnauthorizedError, ForbiddenError, Redirect } from './errors.js';
25
26
  * // Opt-in to database
26
27
  * const db = yield* DatabaseService
27
28
  *
28
- * yield* Effect.tryPromise(() =>
29
- * db.insert(projects).values({ ...input, userId: auth.user.id })
29
+ * yield* dbMutation(db, input, (db, input) =>
30
+ * db.insert(projects).values(asTrusted({ ...input, userId: auth.user.id }))
30
31
  * )
31
32
  * return new Redirect({ url: '/projects', status: 303 })
32
33
  * })
@@ -52,19 +53,75 @@ export declare function action<R, E>(handler: Effect.Effect<Response | Redirect,
52
53
  * const auth = yield* authorize((a) => a.user.id === project.userId)
53
54
  */
54
55
  export declare function authorize(check?: (user: AuthUser) => boolean): Effect.Effect<AuthUser, UnauthorizedError | ForbiddenError, never>;
56
+ /**
57
+ * Run a database mutation with a safe wrapper.
58
+ * Writes only accept validated or trusted inputs for insert/update/execute params.
59
+ *
60
+ * @example
61
+ * const input = yield* validateRequest(CreateProjectSchema)
62
+ * const db = yield* DatabaseService
63
+ * yield* dbMutation(db, async (db) => {
64
+ * await db.insert(projects).values(asTrusted({ ...input, userId: auth.user.id }))
65
+ * })
66
+ */
67
+ export declare function dbMutation<DB, T>(db: DB, operation: (db: SafeTx<DB>) => Promise<T>): Effect.Effect<T, Error>;
68
+ type SafeInput<A> = Validated<A> | Trusted<A>;
69
+ type SafeValues<V> = V extends Array<infer E> ? Array<SafeInput<E>> | SafeInput<V> : V extends ReadonlyArray<infer E> ? ReadonlyArray<SafeInput<E>> | SafeInput<V> : SafeInput<V>;
70
+ type SafeParam<P> = P extends ReadonlyArray<any> ? SafeValues<P> : P extends Array<any> ? SafeValues<P> : P extends Record<string, unknown> ? SafeInput<P> : P;
71
+ type WrapExecuteArgs<A extends unknown[]> = A extends [infer Q, infer P, ...infer Rest] ? [Q, SafeParam<P>, ...Rest] : A;
72
+ type WrapSecondArg<A extends unknown[]> = A extends [infer First, infer Second, ...infer Rest] ? [First, SafeParam<Second>, ...Rest] : A;
73
+ type WrapMethod<I, K extends string> = I extends Record<K, (...args: infer A) => infer R> ? Omit<I, K> & {
74
+ [P in K]: (...args: WrapExecuteArgs<A>) => R;
75
+ } : I;
76
+ type WrapBuilder<I> = WrapMethod<WrapMethod<WrapMethod<I, 'execute'>, 'run'>, 'query'>;
77
+ type WrapValues<I> = I extends {
78
+ values: (values: infer V) => infer R;
79
+ } ? WrapBuilder<Omit<I, 'values'> & {
80
+ values: (values: SafeValues<V>) => R;
81
+ }> : WrapBuilder<I>;
82
+ type WrapSet<I> = I extends {
83
+ set: (values: infer V) => infer R;
84
+ } ? WrapBuilder<Omit<I, 'set'> & {
85
+ set: (values: SafeValues<V>) => R;
86
+ }> : WrapBuilder<I>;
87
+ type SafeInsert<Tx> = Tx extends {
88
+ insert: (...args: infer A) => infer I;
89
+ } ? Omit<Tx, 'insert'> & {
90
+ insert: (...args: WrapSecondArg<A>) => WrapValues<I>;
91
+ } : Tx;
92
+ type SafeUpdate<Tx> = Tx extends {
93
+ update: (...args: infer A) => infer I;
94
+ } ? Omit<Tx, 'update'> & {
95
+ update: (...args: WrapSecondArg<A>) => WrapSet<I>;
96
+ } : Tx;
97
+ type SafeDelete<Tx> = Tx extends {
98
+ delete: (...args: infer A) => infer I;
99
+ } ? Omit<Tx, 'delete'> & {
100
+ delete: (...args: WrapSecondArg<A>) => WrapBuilder<I>;
101
+ } : Tx;
102
+ export type SafeTx<Tx> = WrapBuilder<SafeDelete<SafeUpdate<SafeInsert<Tx>>>>;
103
+ type TransactionClient<DB> = DB extends {
104
+ transaction: (fn: (tx: infer Tx) => Promise<any>) => Promise<any>;
105
+ } ? Tx : never;
55
106
  /**
56
107
  * Run multiple database operations in a transaction.
57
108
  * Automatically rolls back on any failure.
58
109
  *
110
+ * The transaction client is wrapped as `SafeTx` so writes only accept
111
+ * validated or trusted inputs for insert/update/execute params.
112
+ *
59
113
  * @example
114
+ * const input = yield* validateRequest(CreateUserSchema)
115
+ * const balanceUpdate = asTrusted({ balance: 100 })
60
116
  * const db = yield* DatabaseService
61
117
  * yield* dbTransaction(db, async (tx) => {
62
- * await tx.insert(users).values({ name: 'Alice' })
63
- * await tx.update(accounts).set({ balance: 100 }).where(eq(accounts.userId, id))
118
+ * await tx.insert(users).values(input)
119
+ * await tx.update(accounts).set(balanceUpdate).where(eq(accounts.userId, id))
64
120
  * return { success: true }
65
121
  * })
66
122
  */
67
123
  export declare function dbTransaction<DB extends {
68
- transaction: (fn: (tx: unknown) => Promise<T>) => Promise<T>;
69
- }, T>(db: DB, operations: (tx: unknown) => Promise<T>): Effect.Effect<T, Error>;
124
+ transaction: (fn: (tx: any) => Promise<any>) => Promise<any>;
125
+ }, T>(db: DB, operations: (tx: SafeTx<TransactionClient<DB>>) => Promise<T>): Effect.Effect<T, Error>;
126
+ export {};
70
127
  //# sourceMappingURL=action.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../../src/effect/action.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAA;AACvC,OAAO,EAGL,KAAK,QAAQ,EACd,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAEzE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,CAAC,EACzB,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,GAAG,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,GAChD,MAAM,CAAC,MAAM,CAAC,QAAQ,GAAG,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAE1C;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,CACvB,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,OAAO,GAClC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,iBAAiB,GAAG,cAAc,EAAE,KAAK,CAAC,CAoBpE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,EAAE,SAAS;IAAE,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAA;CAAE,EAAE,CAAC,EAC1G,EAAE,EAAE,EAAE,EACN,UAAU,EAAE,CAAC,EAAE,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,GACtC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,CAKzB"}
1
+ {"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../../src/effect/action.ts"],"names":[],"mappings":"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"}
@@ -25,8 +25,8 @@ import { UnauthorizedError, ForbiddenError } from './errors.js';
25
25
  * // Opt-in to database
26
26
  * const db = yield* DatabaseService
27
27
  *
28
- * yield* Effect.tryPromise(() =>
29
- * db.insert(projects).values({ ...input, userId: auth.user.id })
28
+ * yield* dbMutation(db, input, (db, input) =>
29
+ * db.insert(projects).values(asTrusted({ ...input, userId: auth.user.id }))
30
30
  * )
31
31
  * return new Redirect({ url: '/projects', status: 303 })
32
32
  * })
@@ -69,21 +69,43 @@ export function authorize(check) {
69
69
  return user;
70
70
  });
71
71
  }
72
+ /**
73
+ * Run a database mutation with a safe wrapper.
74
+ * Writes only accept validated or trusted inputs for insert/update/execute params.
75
+ *
76
+ * @example
77
+ * const input = yield* validateRequest(CreateProjectSchema)
78
+ * const db = yield* DatabaseService
79
+ * yield* dbMutation(db, async (db) => {
80
+ * await db.insert(projects).values(asTrusted({ ...input, userId: auth.user.id }))
81
+ * })
82
+ */
83
+ export function dbMutation(db, operation) {
84
+ return Effect.tryPromise({
85
+ try: () => operation(db),
86
+ catch: (error) => error instanceof Error ? error : new Error(String(error)),
87
+ });
88
+ }
72
89
  /**
73
90
  * Run multiple database operations in a transaction.
74
91
  * Automatically rolls back on any failure.
75
92
  *
93
+ * The transaction client is wrapped as `SafeTx` so writes only accept
94
+ * validated or trusted inputs for insert/update/execute params.
95
+ *
76
96
  * @example
97
+ * const input = yield* validateRequest(CreateUserSchema)
98
+ * const balanceUpdate = asTrusted({ balance: 100 })
77
99
  * const db = yield* DatabaseService
78
100
  * yield* dbTransaction(db, async (tx) => {
79
- * await tx.insert(users).values({ name: 'Alice' })
80
- * await tx.update(accounts).set({ balance: 100 }).where(eq(accounts.userId, id))
101
+ * await tx.insert(users).values(input)
102
+ * await tx.update(accounts).set(balanceUpdate).where(eq(accounts.userId, id))
81
103
  * return { success: true }
82
104
  * })
83
105
  */
84
106
  export function dbTransaction(db, operations) {
85
107
  return Effect.tryPromise({
86
- try: () => db.transaction(operations),
108
+ try: () => db.transaction((tx) => operations(tx)),
87
109
  catch: (error) => error instanceof Error ? error : new Error(String(error)),
88
110
  });
89
111
  }
@@ -6,10 +6,10 @@
6
6
  export { DatabaseService, AuthService, AuthUserService, HonertiaService, RequestService, ResponseFactoryService, type AuthUser, type HonertiaRenderer, type RequestContext, type ResponseFactory, type HonertiaDatabaseType, type HonertiaAuthType, } from './services.js';
7
7
  export { ValidationError, UnauthorizedError, NotFoundError, ForbiddenError, HttpError, Redirect, type AppError, } from './errors.js';
8
8
  export * from './schema.js';
9
- export { getValidationData, formatSchemaErrors, validate, validateRequest, } from './validation.js';
9
+ export { getValidationData, formatSchemaErrors, validate, validateRequest, asValidated, asTrusted, type Validated, type Trusted, } from './validation.js';
10
10
  export { effectBridge, buildContextLayer, getEffectRuntime, type EffectBridgeConfig, } from './bridge.js';
11
11
  export { effectHandler, effect, handle, errorToResponse, } from './handler.js';
12
- export { action, authorize, dbTransaction, } from './action.js';
12
+ export { action, authorize, dbMutation, dbTransaction, type SafeTx, } from './action.js';
13
13
  export { redirect, render, renderWithErrors, json, text, notFound, forbidden, httpError, prefersJson, jsonOrRender, share, } from './responses.js';
14
14
  export { EffectRouteBuilder, effectRoutes, type EffectHandler, type BaseServices, } from './routing.js';
15
15
  export { RequireAuthLayer, RequireGuestLayer, isAuthenticated, currentUser, requireAuth, requireGuest, shareAuth, shareAuthMiddleware, effectAuthRoutes, betterAuthFormAction, betterAuthLogoutAction, loadUser, type AuthRoutesConfig, type BetterAuthFormActionConfig, type BetterAuthLogoutConfig, type BetterAuthActionResult, } from './auth.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/effect/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,eAAe,EACf,WAAW,EACX,eAAe,EACf,eAAe,EACf,cAAc,EACd,sBAAsB,EACtB,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,GACtB,MAAM,eAAe,CAAA;AAGtB,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,SAAS,EACT,QAAQ,EACR,KAAK,QAAQ,GACd,MAAM,aAAa,CAAA;AAGpB,cAAc,aAAa,CAAA;AAG3B,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,QAAQ,EACR,eAAe,GAChB,MAAM,iBAAiB,CAAA;AAGxB,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,kBAAkB,GACxB,MAAM,aAAa,CAAA;AAGpB,OAAO,EACL,aAAa,EACb,MAAM,EACN,MAAM,EACN,eAAe,GAChB,MAAM,cAAc,CAAA;AAGrB,OAAO,EACL,MAAM,EACN,SAAS,EACT,aAAa,GACd,MAAM,aAAa,CAAA;AAGpB,OAAO,EACL,QAAQ,EACR,MAAM,EACN,gBAAgB,EAChB,IAAI,EACJ,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,SAAS,EACT,WAAW,EACX,YAAY,EACZ,KAAK,GACN,MAAM,gBAAgB,CAAA;AAGvB,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,KAAK,aAAa,EAClB,KAAK,YAAY,GAClB,MAAM,cAAc,CAAA;AAGrB,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,WAAW,EACX,WAAW,EACX,YAAY,EACZ,SAAS,EACT,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,EACpB,sBAAsB,EACtB,QAAQ,EACR,KAAK,gBAAgB,EACrB,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,GAC5B,MAAM,WAAW,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/effect/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,eAAe,EACf,WAAW,EACX,eAAe,EACf,eAAe,EACf,cAAc,EACd,sBAAsB,EACtB,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,GACtB,MAAM,eAAe,CAAA;AAGtB,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,SAAS,EACT,QAAQ,EACR,KAAK,QAAQ,GACd,MAAM,aAAa,CAAA;AAGpB,cAAc,aAAa,CAAA;AAG3B,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,QAAQ,EACR,eAAe,EACf,WAAW,EACX,SAAS,EACT,KAAK,SAAS,EACd,KAAK,OAAO,GACb,MAAM,iBAAiB,CAAA;AAGxB,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,kBAAkB,GACxB,MAAM,aAAa,CAAA;AAGpB,OAAO,EACL,aAAa,EACb,MAAM,EACN,MAAM,EACN,eAAe,GAChB,MAAM,cAAc,CAAA;AAGrB,OAAO,EACL,MAAM,EACN,SAAS,EACT,UAAU,EACV,aAAa,EACb,KAAK,MAAM,GACZ,MAAM,aAAa,CAAA;AAGpB,OAAO,EACL,QAAQ,EACR,MAAM,EACN,gBAAgB,EAChB,IAAI,EACJ,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,SAAS,EACT,WAAW,EACX,YAAY,EACZ,KAAK,GACN,MAAM,gBAAgB,CAAA;AAGvB,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,KAAK,aAAa,EAClB,KAAK,YAAY,GAClB,MAAM,cAAc,CAAA;AAGrB,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,WAAW,EACX,WAAW,EACX,YAAY,EACZ,SAAS,EACT,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,EACpB,sBAAsB,EACtB,QAAQ,EACR,KAAK,gBAAgB,EACrB,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,GAC5B,MAAM,WAAW,CAAA"}
@@ -10,13 +10,13 @@ export { ValidationError, UnauthorizedError, NotFoundError, ForbiddenError, Http
10
10
  // Schema Validators
11
11
  export * from './schema.js';
12
12
  // Validation Helpers
13
- export { getValidationData, formatSchemaErrors, validate, validateRequest, } from './validation.js';
13
+ export { getValidationData, formatSchemaErrors, validate, validateRequest, asValidated, asTrusted, } from './validation.js';
14
14
  // Bridge
15
15
  export { effectBridge, buildContextLayer, getEffectRuntime, } from './bridge.js';
16
16
  // Handler
17
17
  export { effectHandler, effect, handle, errorToResponse, } from './handler.js';
18
18
  // Action Composables
19
- export { action, authorize, dbTransaction, } from './action.js';
19
+ export { action, authorize, dbMutation, dbTransaction, } from './action.js';
20
20
  // Response Helpers
21
21
  export { redirect, render, renderWithErrors, json, text, notFound, forbidden, httpError, prefersJson, jsonOrRender, share, } from './responses.js';
22
22
  // Routing
@@ -15,6 +15,30 @@ export declare const getValidationData: Effect.Effect<Record<string, unknown>, V
15
15
  * Format Effect Schema parse errors into field-level validation errors.
16
16
  */
17
17
  export declare function formatSchemaErrors(error: ParseResult.ParseError, messages?: Record<string, string>, attributes?: Record<string, string>): Record<string, string>;
18
+ /**
19
+ * Nominal brand marker for validated data.
20
+ * Private field prevents the brand from surviving object spreads.
21
+ */
22
+ declare class ValidatedBrand {
23
+ private readonly __validatedBrand;
24
+ }
25
+ export type Validated<A> = A & ValidatedBrand;
26
+ /**
27
+ * Mark data as validated (type-level only).
28
+ */
29
+ export declare const asValidated: <A>(input: A) => Validated<A>;
30
+ /**
31
+ * Nominal brand marker for trusted (server-derived) data.
32
+ * Private field prevents the brand from surviving object spreads.
33
+ */
34
+ declare class TrustedBrand {
35
+ private readonly __trustedBrand;
36
+ }
37
+ export type Trusted<A> = A & TrustedBrand;
38
+ /**
39
+ * Mark data as trusted (type-level only).
40
+ */
41
+ export declare const asTrusted: <A>(input: A) => Trusted<A>;
18
42
  /**
19
43
  * Options for validation functions.
20
44
  */
@@ -51,10 +75,11 @@ export interface ValidateOptions {
51
75
  * Validate data against a schema.
52
76
  * Returns validated data or fails with ValidationError.
53
77
  */
54
- export declare function validate<A, I>(schema: S.Schema<A, I>, data: unknown, options?: ValidateOptions): Effect.Effect<A, ValidationError, never>;
78
+ export declare function validate<A, I>(schema: S.Schema<A, I>, data: unknown, options?: ValidateOptions): Effect.Effect<Validated<A>, ValidationError, never>;
55
79
  /**
56
80
  * Validate request data against a schema.
57
81
  * Extracts data from request and validates in one step.
58
82
  */
59
- export declare function validateRequest<A, I>(schema: S.Schema<A, I>, options?: ValidateOptions): Effect.Effect<A, ValidationError, RequestService>;
83
+ export declare function validateRequest<A, I>(schema: S.Schema<A, I>, options?: ValidateOptions): Effect.Effect<Validated<A>, ValidationError, RequestService>;
84
+ export {};
60
85
  //# sourceMappingURL=validation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/effect/validation.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAA;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE7C;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,CAC3C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvB,eAAe,EACf,cAAc,CA0Bd,CAAA;AAEF;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,CAAC,UAAU,EAC7B,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACrC,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACtC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAgBxB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEjC;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEnC;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,CAAC,EAC3B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EACtB,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,eAAoB,GAC5B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,eAAe,EAAE,KAAK,CAAC,CAS1C;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,CAAC,EAClC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EACtB,OAAO,GAAE,eAAoB,GAC5B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,eAAe,EAAE,cAAc,CAAC,CAKnD"}
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/effect/validation.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAA;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE7C;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,CAC3C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvB,eAAe,EACf,cAAc,CA0Bd,CAAA;AAEF;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,CAAC,UAAU,EAC7B,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACrC,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACtC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAgBxB;AAED;;;GAGG;AACH,OAAO,OAAO,cAAc;IAC1B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAM;CACxC;AAED,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,cAAc,CAAA;AAE7C;;GAEG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,EAAE,OAAO,CAAC,KAAG,SAAS,CAAC,CAAC,CAC9B,CAAA;AAEvB;;;GAGG;AACH,OAAO,OAAO,YAAY;IACxB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAM;CACtC;AAED,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,YAAY,CAAA;AAEzC;;GAEG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,EAAE,OAAO,CAAC,KAAG,OAAO,CAAC,CAAC,CAC5B,CAAA;AAErB;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEjC;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEnC;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,CAAC,EAC3B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EACtB,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,eAAoB,GAC5B,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,KAAK,CAAC,CAUrD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,CAAC,EAClC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EACtB,OAAO,GAAE,eAAoB,GAC5B,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,cAAc,CAAC,CAK9D"}
@@ -41,6 +41,14 @@ export function formatSchemaErrors(error, messages = {}, attributes = {}) {
41
41
  }
42
42
  return errors;
43
43
  }
44
+ /**
45
+ * Mark data as validated (type-level only).
46
+ */
47
+ export const asValidated = (input) => input;
48
+ /**
49
+ * Mark data as trusted (type-level only).
50
+ */
51
+ export const asTrusted = (input) => input;
44
52
  /**
45
53
  * Validate data against a schema.
46
54
  * Returns validated data or fails with ValidationError.
@@ -49,7 +57,7 @@ export function validate(schema, data, options = {}) {
49
57
  return S.decodeUnknown(schema)(data).pipe(Effect.mapError((error) => new ValidationError({
50
58
  errors: formatSchemaErrors(error, options.messages, options.attributes),
51
59
  component: options.errorComponent,
52
- })));
60
+ })), Effect.map(asValidated));
53
61
  }
54
62
  /**
55
63
  * Validate request data against a schema.
package/dist/schema.d.ts CHANGED
@@ -5,5 +5,5 @@
5
5
  * Import from 'honertia/schema' for validation functionality.
6
6
  */
7
7
  export { S, trimmed, nullableString, optionalString, requiredString, required, alpha, alphaDash, alphaNum, startsWith, endsWith, lowercase, uppercase, coercedNumber, positiveInt, nonNegativeInt, parsePositiveInt, between, digits, digitsBetween, gt, gte, lt, lte, multipleOf, coercedBoolean, checkbox, accepted, declined, coercedDate, nullableDate, after, afterOrEqual, before, beforeOrEqual, ensureArray, distinct, minItems, maxItems, inArray, notIn, email, nullableEmail, url, nullableUrl, uuid, nullableUuid, ip, ipv4, ipv6, macAddress, jsonString, confirmed, size, min, max, password, nullable, filled, excludeIf, } from './effect/schema.js';
8
- export { getValidationData, formatSchemaErrors, validate, validateRequest, } from './effect/validation.js';
8
+ export { getValidationData, formatSchemaErrors, validate, validateRequest, asValidated, asTrusted, type Validated, type Trusted, } from './effect/validation.js';
9
9
  //# sourceMappingURL=schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAEL,CAAC,EAED,OAAO,EACP,cAAc,EACd,cAAc,EACd,cAAc,EACd,QAAQ,EACR,KAAK,EACL,SAAS,EACT,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,SAAS,EACT,SAAS,EAET,aAAa,EACb,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,OAAO,EACP,MAAM,EACN,aAAa,EACb,EAAE,EACF,GAAG,EACH,EAAE,EACF,GAAG,EACH,UAAU,EAEV,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,QAAQ,EAER,WAAW,EACX,YAAY,EACZ,KAAK,EACL,YAAY,EACZ,MAAM,EACN,aAAa,EAEb,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,QAAQ,EAER,OAAO,EACP,KAAK,EAEL,KAAK,EACL,aAAa,EACb,GAAG,EACH,WAAW,EACX,IAAI,EACJ,YAAY,EACZ,EAAE,EACF,IAAI,EACJ,IAAI,EACJ,UAAU,EACV,UAAU,EAEV,SAAS,EAET,IAAI,EACJ,GAAG,EACH,GAAG,EAEH,QAAQ,EAER,QAAQ,EACR,MAAM,EACN,SAAS,GACV,MAAM,oBAAoB,CAAA;AAG3B,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,QAAQ,EACR,eAAe,GAChB,MAAM,wBAAwB,CAAA"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAEL,CAAC,EAED,OAAO,EACP,cAAc,EACd,cAAc,EACd,cAAc,EACd,QAAQ,EACR,KAAK,EACL,SAAS,EACT,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,SAAS,EACT,SAAS,EAET,aAAa,EACb,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,OAAO,EACP,MAAM,EACN,aAAa,EACb,EAAE,EACF,GAAG,EACH,EAAE,EACF,GAAG,EACH,UAAU,EAEV,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,QAAQ,EAER,WAAW,EACX,YAAY,EACZ,KAAK,EACL,YAAY,EACZ,MAAM,EACN,aAAa,EAEb,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,QAAQ,EAER,OAAO,EACP,KAAK,EAEL,KAAK,EACL,aAAa,EACb,GAAG,EACH,WAAW,EACX,IAAI,EACJ,YAAY,EACZ,EAAE,EACF,IAAI,EACJ,IAAI,EACJ,UAAU,EACV,UAAU,EAEV,SAAS,EAET,IAAI,EACJ,GAAG,EACH,GAAG,EAEH,QAAQ,EAER,QAAQ,EACR,MAAM,EACN,SAAS,GACV,MAAM,oBAAoB,CAAA;AAG3B,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,QAAQ,EACR,eAAe,EACf,WAAW,EACX,SAAS,EACT,KAAK,SAAS,EACd,KAAK,OAAO,GACb,MAAM,wBAAwB,CAAA"}
package/dist/schema.js CHANGED
@@ -31,4 +31,4 @@ password,
31
31
  // Utility
32
32
  nullable, filled, excludeIf, } from './effect/schema.js';
33
33
  // Validation Helpers
34
- export { getValidationData, formatSchemaErrors, validate, validateRequest, } from './effect/validation.js';
34
+ export { getValidationData, formatSchemaErrors, validate, validateRequest, asValidated, asTrusted, } from './effect/validation.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "honertia",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "Inertia.js-style server-driven SPA adapter for Hono",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",