@nubase/backend 0.1.34 → 0.1.37
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 +245 -3
- package/dist/index.d.ts +245 -3
- package/dist/index.js +848 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +848 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as hono from 'hono';
|
|
2
2
|
import { Context, Hono } from 'hono';
|
|
3
|
-
import { RequestSchema, InferRequestParams, InferRequestBody, InferResponseBody } from '@nubase/core';
|
|
3
|
+
import { RequestSchema, InferRequestParams, InferRequestBody, InferResponseBody, BaseSchema, ObjectSchema } from '@nubase/core';
|
|
4
4
|
import { ContentfulStatusCode } from 'hono/utils/http-status';
|
|
5
|
+
import { StringReference, ExpressionBuilder, ExpressionWrapper, SqlBool } from 'kysely';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Represents an authenticated user on the backend.
|
|
@@ -318,6 +319,47 @@ declare function getUser<TUser extends BackendUser = BackendUser>(c: Context): T
|
|
|
318
319
|
*/
|
|
319
320
|
declare function getAuthController<TUser extends BackendUser = BackendUser>(c: Context): BackendAuthController<TUser>;
|
|
320
321
|
|
|
322
|
+
/**
|
|
323
|
+
* Configuration for the auth section of {@link NubaseBackendConfig}.
|
|
324
|
+
* Consumed by `BackendAuthController` implementations to derive JWT and
|
|
325
|
+
* cookie behaviour.
|
|
326
|
+
*/
|
|
327
|
+
interface NubaseBackendAuthConfig {
|
|
328
|
+
/** Secret used to sign and verify session JWTs. */
|
|
329
|
+
jwtSecret: string;
|
|
330
|
+
/**
|
|
331
|
+
* Lifetime of the session, in seconds. Applied to both the JWT `exp`
|
|
332
|
+
* claim and the session cookie's `Max-Age`.
|
|
333
|
+
*/
|
|
334
|
+
sessionMaxAgeSeconds: number;
|
|
335
|
+
/** Name of the HttpOnly cookie that carries the session JWT. */
|
|
336
|
+
cookieName: string;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Backend application configuration for a Nubase app.
|
|
340
|
+
*
|
|
341
|
+
* An app declares this in `src/backend/backend-config.ts` and the wiring
|
|
342
|
+
* code (controller singletons, middleware factories) reads it. The type
|
|
343
|
+
* lives in the framework so all Nubase apps share one shape; apps may
|
|
344
|
+
* extend it with their own sections by intersecting with this type.
|
|
345
|
+
*
|
|
346
|
+
* @example
|
|
347
|
+
* ```ts
|
|
348
|
+
* import type { NubaseBackendConfig } from "@nubase/backend";
|
|
349
|
+
*
|
|
350
|
+
* export const config: NubaseBackendConfig = {
|
|
351
|
+
* auth: {
|
|
352
|
+
* jwtSecret: process.env.JWT_SECRET ?? "dev-secret",
|
|
353
|
+
* sessionMaxAgeSeconds: 60 * 60 * 24 * 30,
|
|
354
|
+
* cookieName: "nubase_auth",
|
|
355
|
+
* },
|
|
356
|
+
* };
|
|
357
|
+
* ```
|
|
358
|
+
*/
|
|
359
|
+
interface NubaseBackendConfig {
|
|
360
|
+
auth: NubaseBackendAuthConfig;
|
|
361
|
+
}
|
|
362
|
+
|
|
321
363
|
/**
|
|
322
364
|
* Custom HTTP error class that allows handlers to throw errors with specific status codes.
|
|
323
365
|
* Use this to return proper HTTP error responses instead of generic 500 errors.
|
|
@@ -329,7 +371,19 @@ declare function getAuthController<TUser extends BackendUser = BackendUser>(c: C
|
|
|
329
371
|
*/
|
|
330
372
|
declare class HttpError extends Error {
|
|
331
373
|
statusCode: ContentfulStatusCode;
|
|
332
|
-
|
|
374
|
+
/**
|
|
375
|
+
* Optional structured payload merged into the JSON response body under
|
|
376
|
+
* the `error` key. Use when the caller needs machine-readable details
|
|
377
|
+
* (error code, field, line/column, etc.) beyond the human message.
|
|
378
|
+
*/
|
|
379
|
+
payload?: Record<string, unknown> | undefined;
|
|
380
|
+
constructor(statusCode: ContentfulStatusCode, message: string,
|
|
381
|
+
/**
|
|
382
|
+
* Optional structured payload merged into the JSON response body under
|
|
383
|
+
* the `error` key. Use when the caller needs machine-readable details
|
|
384
|
+
* (error code, field, line/column, etc.) beyond the human message.
|
|
385
|
+
*/
|
|
386
|
+
payload?: Record<string, unknown> | undefined);
|
|
333
387
|
}
|
|
334
388
|
/**
|
|
335
389
|
* URL Parameter Coercion System (Backend)
|
|
@@ -565,6 +619,194 @@ type EndpointSelector<TEndpoints extends Record<string, RequestSchema>, T extend
|
|
|
565
619
|
*/
|
|
566
620
|
declare function createHandlerFactory<TEndpoints extends Record<string, RequestSchema>, TUser extends BackendUser = BackendUser>(config: HandlerFactoryConfig<TEndpoints>): <TSelector extends (endpoints: TEndpoints) => RequestSchema, TAuth extends AuthLevel = "none">(selector: TSelector, options: FactoryHandlerOptions<ReturnType<TSelector>, TAuth, TUser>) => HttpHandler;
|
|
567
621
|
|
|
622
|
+
type ShapeOf = Record<string, BaseSchema<any>>;
|
|
623
|
+
/**
|
|
624
|
+
* Runtime shape of an NQL field-to-column map. Keys are schema field names;
|
|
625
|
+
* values are Kysely column references (e.g. `"tickets.title"`).
|
|
626
|
+
*
|
|
627
|
+
* This type is intentionally loose at runtime. The strong typing is applied
|
|
628
|
+
* at binding-creation time via {@link createNqlBindings}, which constrains
|
|
629
|
+
* keys to the schema's shape and values to the Kysely `StringReference`
|
|
630
|
+
* union. Once built, the bindings object is carried through the NQL
|
|
631
|
+
* pipeline as a plain `Record<string, string>`.
|
|
632
|
+
*/
|
|
633
|
+
type FieldBindings = Record<string, string>;
|
|
634
|
+
/**
|
|
635
|
+
* Curry a bindings factory for a specific Kysely DB type.
|
|
636
|
+
*
|
|
637
|
+
* The outer call pins `DB` (the generated Kysely database interface). The
|
|
638
|
+
* inner call takes the NQL schema and a map whose keys are checked against
|
|
639
|
+
* the schema's shape and whose values are checked against the Kysely
|
|
640
|
+
* `StringReference<DB, TB>` union — so a typo in either half is a compile
|
|
641
|
+
* error, and referencing a table you haven't joined in the current query
|
|
642
|
+
* is caught when the resulting bindings are passed to `compileNql`.
|
|
643
|
+
*
|
|
644
|
+
* @example
|
|
645
|
+
* ```ts
|
|
646
|
+
* import type { DB } from "./db-types";
|
|
647
|
+
* const ticketBindings = createNqlBindings<DB>()(ticketListSchema, {
|
|
648
|
+
* id: "tickets.id",
|
|
649
|
+
* title: "tickets.title",
|
|
650
|
+
* assigneeName: "users.displayName", // cross-table, only valid if joined
|
|
651
|
+
* });
|
|
652
|
+
* ```
|
|
653
|
+
*/
|
|
654
|
+
declare function createNqlBindings<DB>(): <TShape extends ShapeOf, TB extends keyof DB>(schema: ObjectSchema<TShape>, mapping: Partial<Record<keyof TShape & string, StringReference<DB, TB>>>) => FieldBindings;
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Source position tracking. `line` and `column` are 1-based to match
|
|
658
|
+
* how most editors report positions. `offset` is a 0-based character
|
|
659
|
+
* offset into the original source string.
|
|
660
|
+
*/
|
|
661
|
+
interface SourceSpan {
|
|
662
|
+
line: number;
|
|
663
|
+
column: number;
|
|
664
|
+
offset: number;
|
|
665
|
+
length: number;
|
|
666
|
+
}
|
|
667
|
+
type NqlErrorCode = "TOKENIZE" | "PARSE" | "VALIDATE";
|
|
668
|
+
interface NqlError {
|
|
669
|
+
code: NqlErrorCode;
|
|
670
|
+
message: string;
|
|
671
|
+
line: number;
|
|
672
|
+
column: number;
|
|
673
|
+
length?: number;
|
|
674
|
+
}
|
|
675
|
+
type Result<T, E> = {
|
|
676
|
+
ok: true;
|
|
677
|
+
value: T;
|
|
678
|
+
} | {
|
|
679
|
+
ok: false;
|
|
680
|
+
error: E;
|
|
681
|
+
};
|
|
682
|
+
type ComparisonOp = "=" | "!=" | "<" | "<=" | ">" | ">=" | "CONTAINS" | "STARTS_WITH" | "ENDS_WITH";
|
|
683
|
+
interface IdentifierRef {
|
|
684
|
+
raw: string;
|
|
685
|
+
span: SourceSpan;
|
|
686
|
+
}
|
|
687
|
+
interface StringLit {
|
|
688
|
+
kind: "string";
|
|
689
|
+
value: string;
|
|
690
|
+
span: SourceSpan;
|
|
691
|
+
}
|
|
692
|
+
interface NumberLit {
|
|
693
|
+
kind: "number";
|
|
694
|
+
value: number;
|
|
695
|
+
span: SourceSpan;
|
|
696
|
+
}
|
|
697
|
+
interface BoolLit {
|
|
698
|
+
kind: "boolean";
|
|
699
|
+
value: boolean;
|
|
700
|
+
span: SourceSpan;
|
|
701
|
+
}
|
|
702
|
+
interface NullLit {
|
|
703
|
+
kind: "null";
|
|
704
|
+
span: SourceSpan;
|
|
705
|
+
}
|
|
706
|
+
type Literal = StringLit | NumberLit | BoolLit | NullLit;
|
|
707
|
+
interface ComparisonNode {
|
|
708
|
+
type: "comparison";
|
|
709
|
+
field: IdentifierRef;
|
|
710
|
+
op: ComparisonOp;
|
|
711
|
+
value: Literal;
|
|
712
|
+
span: SourceSpan;
|
|
713
|
+
}
|
|
714
|
+
interface NullCheckNode {
|
|
715
|
+
type: "nullCheck";
|
|
716
|
+
field: IdentifierRef;
|
|
717
|
+
negated: boolean;
|
|
718
|
+
span: SourceSpan;
|
|
719
|
+
}
|
|
720
|
+
interface InNode {
|
|
721
|
+
type: "in";
|
|
722
|
+
field: IdentifierRef;
|
|
723
|
+
negated: boolean;
|
|
724
|
+
values: Literal[];
|
|
725
|
+
span: SourceSpan;
|
|
726
|
+
}
|
|
727
|
+
interface LogicalNode {
|
|
728
|
+
type: "logical";
|
|
729
|
+
op: "AND" | "OR" | "NOT";
|
|
730
|
+
children: ParsedNode[];
|
|
731
|
+
span: SourceSpan;
|
|
732
|
+
}
|
|
733
|
+
type ParsedNode = ComparisonNode | NullCheckNode | InNode | LogicalNode;
|
|
734
|
+
type ValidFieldType = "string" | "number" | "boolean";
|
|
735
|
+
interface ValidFieldRef {
|
|
736
|
+
/** Canonical name from the schema (not the raw source text). */
|
|
737
|
+
name: string;
|
|
738
|
+
baseType: ValidFieldType;
|
|
739
|
+
/** True if the schema wraps this field in OptionalSchema. */
|
|
740
|
+
optional: boolean;
|
|
741
|
+
span: SourceSpan;
|
|
742
|
+
}
|
|
743
|
+
interface ValidComparisonNode {
|
|
744
|
+
type: "comparison";
|
|
745
|
+
field: ValidFieldRef;
|
|
746
|
+
op: ComparisonOp;
|
|
747
|
+
value: Literal;
|
|
748
|
+
span: SourceSpan;
|
|
749
|
+
}
|
|
750
|
+
interface ValidNullCheckNode {
|
|
751
|
+
type: "nullCheck";
|
|
752
|
+
field: ValidFieldRef;
|
|
753
|
+
negated: boolean;
|
|
754
|
+
span: SourceSpan;
|
|
755
|
+
}
|
|
756
|
+
interface ValidInNode {
|
|
757
|
+
type: "in";
|
|
758
|
+
field: ValidFieldRef;
|
|
759
|
+
negated: boolean;
|
|
760
|
+
values: Literal[];
|
|
761
|
+
span: SourceSpan;
|
|
762
|
+
}
|
|
763
|
+
interface ValidLogicalNode {
|
|
764
|
+
type: "logical";
|
|
765
|
+
op: "AND" | "OR" | "NOT";
|
|
766
|
+
children: ValidNode[];
|
|
767
|
+
span: SourceSpan;
|
|
768
|
+
}
|
|
769
|
+
type ValidNode = ValidComparisonNode | ValidNullCheckNode | ValidInNode | ValidLogicalNode;
|
|
770
|
+
|
|
771
|
+
/**
|
|
772
|
+
* A compiled NQL expression, ready to be passed to Kysely's `.where(...)`.
|
|
773
|
+
* Calling it with an `ExpressionBuilder` yields a boolean `ExpressionWrapper`
|
|
774
|
+
* usable directly as a WHERE clause.
|
|
775
|
+
*/
|
|
776
|
+
type CompiledNql = (eb: ExpressionBuilder<any, any>) => ExpressionWrapper<any, any, SqlBool>;
|
|
777
|
+
interface CompileNqlOptions {
|
|
778
|
+
/**
|
|
779
|
+
* Bindings map declaring which schema fields are queryable via NQL, and
|
|
780
|
+
* the Kysely column reference each one resolves to. Only fields whose
|
|
781
|
+
* keys appear here are queryable; anything else in the schema is
|
|
782
|
+
* rejected as an unknown field at validate time.
|
|
783
|
+
*
|
|
784
|
+
* Build this with {@link createNqlBindings} to get end-to-end type
|
|
785
|
+
* safety (schema keys on the key side, Kysely DB columns on the value
|
|
786
|
+
* side).
|
|
787
|
+
*/
|
|
788
|
+
fields: FieldBindings;
|
|
789
|
+
}
|
|
790
|
+
/**
|
|
791
|
+
* End-to-end pipeline: tokenize → parse → validate → compile.
|
|
792
|
+
*
|
|
793
|
+
* Returns a discriminated-union Result. On success the `value` is a function
|
|
794
|
+
* that can be handed directly to `query.where(...)`. On failure the `error`
|
|
795
|
+
* carries a `code` identifying the stage (`TOKENIZE`, `PARSE`, `VALIDATE`)
|
|
796
|
+
* and a 1-based `line`/`column` for surfacing back to the user.
|
|
797
|
+
*/
|
|
798
|
+
declare function compileNql(source: string, schema: ObjectSchema<any>, options: CompileNqlOptions): Result<CompiledNql, NqlError>;
|
|
799
|
+
|
|
800
|
+
interface CompileOptions {
|
|
801
|
+
/**
|
|
802
|
+
* Map of schema field name to Kysely column reference (e.g. `"tickets.title"`
|
|
803
|
+
* or `"users.displayName"`). Values here are trusted to be valid Kysely
|
|
804
|
+
* refs — type safety is enforced at binding-creation time, usually via
|
|
805
|
+
* {@link createNqlBindings}.
|
|
806
|
+
*/
|
|
807
|
+
fields: FieldBindings;
|
|
808
|
+
}
|
|
809
|
+
|
|
568
810
|
/**
|
|
569
811
|
* Parse a cookie header string into a key-value object.
|
|
570
812
|
*
|
|
@@ -608,4 +850,4 @@ interface ValidateEnvironmentOptions {
|
|
|
608
850
|
*/
|
|
609
851
|
declare function validateEnvironment(options?: ValidateEnvironmentOptions): Promise<void>;
|
|
610
852
|
|
|
611
|
-
export { AUTH_CONTROLLER_KEY, AUTH_USER_KEY, type AuthHandlers, type AuthLevel, type AuthMiddlewareOptions, type AuthVariables, type BackendAuthController, type BackendUser, type CreateAuthHandlersOptions, type CreateHttpHandlerOptions, type EndpointSelector, type FactoryHandlerOptions, type HandlerFactoryConfig, HttpError, type HttpHandler, type HttpHandlers, type TokenPayload, type TypedHandler, type TypedHandlerContext, type TypedRouteDefinition, type TypedRoutes, type ValidateEnvironmentOptions, type VerifyTokenResult, createAuthHandlers, createAuthMiddleware, createHandlerFactory, createHttpHandler, createTypedHandler, createTypedRoutes, getAuthController, getCookie, getUser, parseCookies, registerHandlers, requireAuth, validateEnvironment };
|
|
853
|
+
export { AUTH_CONTROLLER_KEY, AUTH_USER_KEY, type AuthHandlers, type AuthLevel, type AuthMiddlewareOptions, type AuthVariables, type BackendAuthController, type BackendUser, type CompileNqlOptions, type CompileOptions, type CompiledNql, type CreateAuthHandlersOptions, type CreateHttpHandlerOptions, type EndpointSelector, type FactoryHandlerOptions, type FieldBindings, type HandlerFactoryConfig, HttpError, type HttpHandler, type HttpHandlers, type NqlError, type NqlErrorCode, type NubaseBackendAuthConfig, type NubaseBackendConfig, type ParsedNode, type Result, type SourceSpan, type TokenPayload, type TypedHandler, type TypedHandlerContext, type TypedRouteDefinition, type TypedRoutes, type ValidFieldRef, type ValidFieldType, type ValidNode, type ValidateEnvironmentOptions, type VerifyTokenResult, compileNql, createAuthHandlers, createAuthMiddleware, createHandlerFactory, createHttpHandler, createNqlBindings, createTypedHandler, createTypedRoutes, getAuthController, getCookie, getUser, parseCookies, registerHandlers, requireAuth, validateEnvironment };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as hono from 'hono';
|
|
2
2
|
import { Context, Hono } from 'hono';
|
|
3
|
-
import { RequestSchema, InferRequestParams, InferRequestBody, InferResponseBody } from '@nubase/core';
|
|
3
|
+
import { RequestSchema, InferRequestParams, InferRequestBody, InferResponseBody, BaseSchema, ObjectSchema } from '@nubase/core';
|
|
4
4
|
import { ContentfulStatusCode } from 'hono/utils/http-status';
|
|
5
|
+
import { StringReference, ExpressionBuilder, ExpressionWrapper, SqlBool } from 'kysely';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Represents an authenticated user on the backend.
|
|
@@ -318,6 +319,47 @@ declare function getUser<TUser extends BackendUser = BackendUser>(c: Context): T
|
|
|
318
319
|
*/
|
|
319
320
|
declare function getAuthController<TUser extends BackendUser = BackendUser>(c: Context): BackendAuthController<TUser>;
|
|
320
321
|
|
|
322
|
+
/**
|
|
323
|
+
* Configuration for the auth section of {@link NubaseBackendConfig}.
|
|
324
|
+
* Consumed by `BackendAuthController` implementations to derive JWT and
|
|
325
|
+
* cookie behaviour.
|
|
326
|
+
*/
|
|
327
|
+
interface NubaseBackendAuthConfig {
|
|
328
|
+
/** Secret used to sign and verify session JWTs. */
|
|
329
|
+
jwtSecret: string;
|
|
330
|
+
/**
|
|
331
|
+
* Lifetime of the session, in seconds. Applied to both the JWT `exp`
|
|
332
|
+
* claim and the session cookie's `Max-Age`.
|
|
333
|
+
*/
|
|
334
|
+
sessionMaxAgeSeconds: number;
|
|
335
|
+
/** Name of the HttpOnly cookie that carries the session JWT. */
|
|
336
|
+
cookieName: string;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Backend application configuration for a Nubase app.
|
|
340
|
+
*
|
|
341
|
+
* An app declares this in `src/backend/backend-config.ts` and the wiring
|
|
342
|
+
* code (controller singletons, middleware factories) reads it. The type
|
|
343
|
+
* lives in the framework so all Nubase apps share one shape; apps may
|
|
344
|
+
* extend it with their own sections by intersecting with this type.
|
|
345
|
+
*
|
|
346
|
+
* @example
|
|
347
|
+
* ```ts
|
|
348
|
+
* import type { NubaseBackendConfig } from "@nubase/backend";
|
|
349
|
+
*
|
|
350
|
+
* export const config: NubaseBackendConfig = {
|
|
351
|
+
* auth: {
|
|
352
|
+
* jwtSecret: process.env.JWT_SECRET ?? "dev-secret",
|
|
353
|
+
* sessionMaxAgeSeconds: 60 * 60 * 24 * 30,
|
|
354
|
+
* cookieName: "nubase_auth",
|
|
355
|
+
* },
|
|
356
|
+
* };
|
|
357
|
+
* ```
|
|
358
|
+
*/
|
|
359
|
+
interface NubaseBackendConfig {
|
|
360
|
+
auth: NubaseBackendAuthConfig;
|
|
361
|
+
}
|
|
362
|
+
|
|
321
363
|
/**
|
|
322
364
|
* Custom HTTP error class that allows handlers to throw errors with specific status codes.
|
|
323
365
|
* Use this to return proper HTTP error responses instead of generic 500 errors.
|
|
@@ -329,7 +371,19 @@ declare function getAuthController<TUser extends BackendUser = BackendUser>(c: C
|
|
|
329
371
|
*/
|
|
330
372
|
declare class HttpError extends Error {
|
|
331
373
|
statusCode: ContentfulStatusCode;
|
|
332
|
-
|
|
374
|
+
/**
|
|
375
|
+
* Optional structured payload merged into the JSON response body under
|
|
376
|
+
* the `error` key. Use when the caller needs machine-readable details
|
|
377
|
+
* (error code, field, line/column, etc.) beyond the human message.
|
|
378
|
+
*/
|
|
379
|
+
payload?: Record<string, unknown> | undefined;
|
|
380
|
+
constructor(statusCode: ContentfulStatusCode, message: string,
|
|
381
|
+
/**
|
|
382
|
+
* Optional structured payload merged into the JSON response body under
|
|
383
|
+
* the `error` key. Use when the caller needs machine-readable details
|
|
384
|
+
* (error code, field, line/column, etc.) beyond the human message.
|
|
385
|
+
*/
|
|
386
|
+
payload?: Record<string, unknown> | undefined);
|
|
333
387
|
}
|
|
334
388
|
/**
|
|
335
389
|
* URL Parameter Coercion System (Backend)
|
|
@@ -565,6 +619,194 @@ type EndpointSelector<TEndpoints extends Record<string, RequestSchema>, T extend
|
|
|
565
619
|
*/
|
|
566
620
|
declare function createHandlerFactory<TEndpoints extends Record<string, RequestSchema>, TUser extends BackendUser = BackendUser>(config: HandlerFactoryConfig<TEndpoints>): <TSelector extends (endpoints: TEndpoints) => RequestSchema, TAuth extends AuthLevel = "none">(selector: TSelector, options: FactoryHandlerOptions<ReturnType<TSelector>, TAuth, TUser>) => HttpHandler;
|
|
567
621
|
|
|
622
|
+
type ShapeOf = Record<string, BaseSchema<any>>;
|
|
623
|
+
/**
|
|
624
|
+
* Runtime shape of an NQL field-to-column map. Keys are schema field names;
|
|
625
|
+
* values are Kysely column references (e.g. `"tickets.title"`).
|
|
626
|
+
*
|
|
627
|
+
* This type is intentionally loose at runtime. The strong typing is applied
|
|
628
|
+
* at binding-creation time via {@link createNqlBindings}, which constrains
|
|
629
|
+
* keys to the schema's shape and values to the Kysely `StringReference`
|
|
630
|
+
* union. Once built, the bindings object is carried through the NQL
|
|
631
|
+
* pipeline as a plain `Record<string, string>`.
|
|
632
|
+
*/
|
|
633
|
+
type FieldBindings = Record<string, string>;
|
|
634
|
+
/**
|
|
635
|
+
* Curry a bindings factory for a specific Kysely DB type.
|
|
636
|
+
*
|
|
637
|
+
* The outer call pins `DB` (the generated Kysely database interface). The
|
|
638
|
+
* inner call takes the NQL schema and a map whose keys are checked against
|
|
639
|
+
* the schema's shape and whose values are checked against the Kysely
|
|
640
|
+
* `StringReference<DB, TB>` union — so a typo in either half is a compile
|
|
641
|
+
* error, and referencing a table you haven't joined in the current query
|
|
642
|
+
* is caught when the resulting bindings are passed to `compileNql`.
|
|
643
|
+
*
|
|
644
|
+
* @example
|
|
645
|
+
* ```ts
|
|
646
|
+
* import type { DB } from "./db-types";
|
|
647
|
+
* const ticketBindings = createNqlBindings<DB>()(ticketListSchema, {
|
|
648
|
+
* id: "tickets.id",
|
|
649
|
+
* title: "tickets.title",
|
|
650
|
+
* assigneeName: "users.displayName", // cross-table, only valid if joined
|
|
651
|
+
* });
|
|
652
|
+
* ```
|
|
653
|
+
*/
|
|
654
|
+
declare function createNqlBindings<DB>(): <TShape extends ShapeOf, TB extends keyof DB>(schema: ObjectSchema<TShape>, mapping: Partial<Record<keyof TShape & string, StringReference<DB, TB>>>) => FieldBindings;
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Source position tracking. `line` and `column` are 1-based to match
|
|
658
|
+
* how most editors report positions. `offset` is a 0-based character
|
|
659
|
+
* offset into the original source string.
|
|
660
|
+
*/
|
|
661
|
+
interface SourceSpan {
|
|
662
|
+
line: number;
|
|
663
|
+
column: number;
|
|
664
|
+
offset: number;
|
|
665
|
+
length: number;
|
|
666
|
+
}
|
|
667
|
+
type NqlErrorCode = "TOKENIZE" | "PARSE" | "VALIDATE";
|
|
668
|
+
interface NqlError {
|
|
669
|
+
code: NqlErrorCode;
|
|
670
|
+
message: string;
|
|
671
|
+
line: number;
|
|
672
|
+
column: number;
|
|
673
|
+
length?: number;
|
|
674
|
+
}
|
|
675
|
+
type Result<T, E> = {
|
|
676
|
+
ok: true;
|
|
677
|
+
value: T;
|
|
678
|
+
} | {
|
|
679
|
+
ok: false;
|
|
680
|
+
error: E;
|
|
681
|
+
};
|
|
682
|
+
type ComparisonOp = "=" | "!=" | "<" | "<=" | ">" | ">=" | "CONTAINS" | "STARTS_WITH" | "ENDS_WITH";
|
|
683
|
+
interface IdentifierRef {
|
|
684
|
+
raw: string;
|
|
685
|
+
span: SourceSpan;
|
|
686
|
+
}
|
|
687
|
+
interface StringLit {
|
|
688
|
+
kind: "string";
|
|
689
|
+
value: string;
|
|
690
|
+
span: SourceSpan;
|
|
691
|
+
}
|
|
692
|
+
interface NumberLit {
|
|
693
|
+
kind: "number";
|
|
694
|
+
value: number;
|
|
695
|
+
span: SourceSpan;
|
|
696
|
+
}
|
|
697
|
+
interface BoolLit {
|
|
698
|
+
kind: "boolean";
|
|
699
|
+
value: boolean;
|
|
700
|
+
span: SourceSpan;
|
|
701
|
+
}
|
|
702
|
+
interface NullLit {
|
|
703
|
+
kind: "null";
|
|
704
|
+
span: SourceSpan;
|
|
705
|
+
}
|
|
706
|
+
type Literal = StringLit | NumberLit | BoolLit | NullLit;
|
|
707
|
+
interface ComparisonNode {
|
|
708
|
+
type: "comparison";
|
|
709
|
+
field: IdentifierRef;
|
|
710
|
+
op: ComparisonOp;
|
|
711
|
+
value: Literal;
|
|
712
|
+
span: SourceSpan;
|
|
713
|
+
}
|
|
714
|
+
interface NullCheckNode {
|
|
715
|
+
type: "nullCheck";
|
|
716
|
+
field: IdentifierRef;
|
|
717
|
+
negated: boolean;
|
|
718
|
+
span: SourceSpan;
|
|
719
|
+
}
|
|
720
|
+
interface InNode {
|
|
721
|
+
type: "in";
|
|
722
|
+
field: IdentifierRef;
|
|
723
|
+
negated: boolean;
|
|
724
|
+
values: Literal[];
|
|
725
|
+
span: SourceSpan;
|
|
726
|
+
}
|
|
727
|
+
interface LogicalNode {
|
|
728
|
+
type: "logical";
|
|
729
|
+
op: "AND" | "OR" | "NOT";
|
|
730
|
+
children: ParsedNode[];
|
|
731
|
+
span: SourceSpan;
|
|
732
|
+
}
|
|
733
|
+
type ParsedNode = ComparisonNode | NullCheckNode | InNode | LogicalNode;
|
|
734
|
+
type ValidFieldType = "string" | "number" | "boolean";
|
|
735
|
+
interface ValidFieldRef {
|
|
736
|
+
/** Canonical name from the schema (not the raw source text). */
|
|
737
|
+
name: string;
|
|
738
|
+
baseType: ValidFieldType;
|
|
739
|
+
/** True if the schema wraps this field in OptionalSchema. */
|
|
740
|
+
optional: boolean;
|
|
741
|
+
span: SourceSpan;
|
|
742
|
+
}
|
|
743
|
+
interface ValidComparisonNode {
|
|
744
|
+
type: "comparison";
|
|
745
|
+
field: ValidFieldRef;
|
|
746
|
+
op: ComparisonOp;
|
|
747
|
+
value: Literal;
|
|
748
|
+
span: SourceSpan;
|
|
749
|
+
}
|
|
750
|
+
interface ValidNullCheckNode {
|
|
751
|
+
type: "nullCheck";
|
|
752
|
+
field: ValidFieldRef;
|
|
753
|
+
negated: boolean;
|
|
754
|
+
span: SourceSpan;
|
|
755
|
+
}
|
|
756
|
+
interface ValidInNode {
|
|
757
|
+
type: "in";
|
|
758
|
+
field: ValidFieldRef;
|
|
759
|
+
negated: boolean;
|
|
760
|
+
values: Literal[];
|
|
761
|
+
span: SourceSpan;
|
|
762
|
+
}
|
|
763
|
+
interface ValidLogicalNode {
|
|
764
|
+
type: "logical";
|
|
765
|
+
op: "AND" | "OR" | "NOT";
|
|
766
|
+
children: ValidNode[];
|
|
767
|
+
span: SourceSpan;
|
|
768
|
+
}
|
|
769
|
+
type ValidNode = ValidComparisonNode | ValidNullCheckNode | ValidInNode | ValidLogicalNode;
|
|
770
|
+
|
|
771
|
+
/**
|
|
772
|
+
* A compiled NQL expression, ready to be passed to Kysely's `.where(...)`.
|
|
773
|
+
* Calling it with an `ExpressionBuilder` yields a boolean `ExpressionWrapper`
|
|
774
|
+
* usable directly as a WHERE clause.
|
|
775
|
+
*/
|
|
776
|
+
type CompiledNql = (eb: ExpressionBuilder<any, any>) => ExpressionWrapper<any, any, SqlBool>;
|
|
777
|
+
interface CompileNqlOptions {
|
|
778
|
+
/**
|
|
779
|
+
* Bindings map declaring which schema fields are queryable via NQL, and
|
|
780
|
+
* the Kysely column reference each one resolves to. Only fields whose
|
|
781
|
+
* keys appear here are queryable; anything else in the schema is
|
|
782
|
+
* rejected as an unknown field at validate time.
|
|
783
|
+
*
|
|
784
|
+
* Build this with {@link createNqlBindings} to get end-to-end type
|
|
785
|
+
* safety (schema keys on the key side, Kysely DB columns on the value
|
|
786
|
+
* side).
|
|
787
|
+
*/
|
|
788
|
+
fields: FieldBindings;
|
|
789
|
+
}
|
|
790
|
+
/**
|
|
791
|
+
* End-to-end pipeline: tokenize → parse → validate → compile.
|
|
792
|
+
*
|
|
793
|
+
* Returns a discriminated-union Result. On success the `value` is a function
|
|
794
|
+
* that can be handed directly to `query.where(...)`. On failure the `error`
|
|
795
|
+
* carries a `code` identifying the stage (`TOKENIZE`, `PARSE`, `VALIDATE`)
|
|
796
|
+
* and a 1-based `line`/`column` for surfacing back to the user.
|
|
797
|
+
*/
|
|
798
|
+
declare function compileNql(source: string, schema: ObjectSchema<any>, options: CompileNqlOptions): Result<CompiledNql, NqlError>;
|
|
799
|
+
|
|
800
|
+
interface CompileOptions {
|
|
801
|
+
/**
|
|
802
|
+
* Map of schema field name to Kysely column reference (e.g. `"tickets.title"`
|
|
803
|
+
* or `"users.displayName"`). Values here are trusted to be valid Kysely
|
|
804
|
+
* refs — type safety is enforced at binding-creation time, usually via
|
|
805
|
+
* {@link createNqlBindings}.
|
|
806
|
+
*/
|
|
807
|
+
fields: FieldBindings;
|
|
808
|
+
}
|
|
809
|
+
|
|
568
810
|
/**
|
|
569
811
|
* Parse a cookie header string into a key-value object.
|
|
570
812
|
*
|
|
@@ -608,4 +850,4 @@ interface ValidateEnvironmentOptions {
|
|
|
608
850
|
*/
|
|
609
851
|
declare function validateEnvironment(options?: ValidateEnvironmentOptions): Promise<void>;
|
|
610
852
|
|
|
611
|
-
export { AUTH_CONTROLLER_KEY, AUTH_USER_KEY, type AuthHandlers, type AuthLevel, type AuthMiddlewareOptions, type AuthVariables, type BackendAuthController, type BackendUser, type CreateAuthHandlersOptions, type CreateHttpHandlerOptions, type EndpointSelector, type FactoryHandlerOptions, type HandlerFactoryConfig, HttpError, type HttpHandler, type HttpHandlers, type TokenPayload, type TypedHandler, type TypedHandlerContext, type TypedRouteDefinition, type TypedRoutes, type ValidateEnvironmentOptions, type VerifyTokenResult, createAuthHandlers, createAuthMiddleware, createHandlerFactory, createHttpHandler, createTypedHandler, createTypedRoutes, getAuthController, getCookie, getUser, parseCookies, registerHandlers, requireAuth, validateEnvironment };
|
|
853
|
+
export { AUTH_CONTROLLER_KEY, AUTH_USER_KEY, type AuthHandlers, type AuthLevel, type AuthMiddlewareOptions, type AuthVariables, type BackendAuthController, type BackendUser, type CompileNqlOptions, type CompileOptions, type CompiledNql, type CreateAuthHandlersOptions, type CreateHttpHandlerOptions, type EndpointSelector, type FactoryHandlerOptions, type FieldBindings, type HandlerFactoryConfig, HttpError, type HttpHandler, type HttpHandlers, type NqlError, type NqlErrorCode, type NubaseBackendAuthConfig, type NubaseBackendConfig, type ParsedNode, type Result, type SourceSpan, type TokenPayload, type TypedHandler, type TypedHandlerContext, type TypedRouteDefinition, type TypedRoutes, type ValidFieldRef, type ValidFieldType, type ValidNode, type ValidateEnvironmentOptions, type VerifyTokenResult, compileNql, createAuthHandlers, createAuthMiddleware, createHandlerFactory, createHttpHandler, createNqlBindings, createTypedHandler, createTypedRoutes, getAuthController, getCookie, getUser, parseCookies, registerHandlers, requireAuth, validateEnvironment };
|