@typokit/core 0.1.4

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.
Files changed (51) hide show
  1. package/dist/adapters/database.d.ts +28 -0
  2. package/dist/adapters/database.d.ts.map +1 -0
  3. package/dist/adapters/database.js +2 -0
  4. package/dist/adapters/database.js.map +1 -0
  5. package/dist/adapters/server.d.ts +35 -0
  6. package/dist/adapters/server.d.ts.map +1 -0
  7. package/dist/adapters/server.js +2 -0
  8. package/dist/adapters/server.js.map +1 -0
  9. package/dist/app.d.ts +36 -0
  10. package/dist/app.d.ts.map +1 -0
  11. package/dist/app.js +55 -0
  12. package/dist/app.js.map +1 -0
  13. package/dist/error-middleware.d.ts +17 -0
  14. package/dist/error-middleware.d.ts.map +1 -0
  15. package/dist/error-middleware.js +138 -0
  16. package/dist/error-middleware.js.map +1 -0
  17. package/dist/handler.d.ts +41 -0
  18. package/dist/handler.d.ts.map +1 -0
  19. package/dist/handler.js +22 -0
  20. package/dist/handler.js.map +1 -0
  21. package/dist/hooks.d.ts +48 -0
  22. package/dist/hooks.d.ts.map +1 -0
  23. package/dist/hooks.js +64 -0
  24. package/dist/hooks.js.map +1 -0
  25. package/dist/index.d.ts +9 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +6 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/middleware.d.ts +35 -0
  30. package/dist/middleware.d.ts.map +1 -0
  31. package/dist/middleware.js +54 -0
  32. package/dist/middleware.js.map +1 -0
  33. package/dist/plugin.d.ts +74 -0
  34. package/dist/plugin.d.ts.map +1 -0
  35. package/dist/plugin.js +3 -0
  36. package/dist/plugin.js.map +1 -0
  37. package/package.json +29 -0
  38. package/src/adapters/database.ts +37 -0
  39. package/src/adapters/server.ts +55 -0
  40. package/src/app.test.ts +438 -0
  41. package/src/app.ts +118 -0
  42. package/src/error-middleware.test.ts +263 -0
  43. package/src/error-middleware.ts +186 -0
  44. package/src/handler.test.ts +346 -0
  45. package/src/handler.ts +64 -0
  46. package/src/hooks.test.ts +419 -0
  47. package/src/hooks.ts +114 -0
  48. package/src/index.ts +51 -0
  49. package/src/middleware.test.ts +253 -0
  50. package/src/middleware.ts +100 -0
  51. package/src/plugin.ts +108 -0
@@ -0,0 +1,54 @@
1
+ // @typokit/core — Middleware System
2
+ import { createAppError } from "@typokit/errors";
3
+ /**
4
+ * Define a typed middleware that receives request properties and returns
5
+ * additional context properties. Supports context type narrowing.
6
+ */
7
+ export function defineMiddleware(handler) {
8
+ return { handler };
9
+ }
10
+ /** Create a no-op placeholder logger (actual implementation in observability phase) */
11
+ export function createPlaceholderLogger() {
12
+ const noop = () => { };
13
+ return {
14
+ trace: noop,
15
+ debug: noop,
16
+ info: noop,
17
+ warn: noop,
18
+ error: noop,
19
+ fatal: noop,
20
+ };
21
+ }
22
+ /** Create a RequestContext with ctx.fail() and ctx.log placeholder */
23
+ export function createRequestContext(overrides) {
24
+ return {
25
+ log: createPlaceholderLogger(),
26
+ fail(status, code, message, details) {
27
+ throw createAppError(status, code, message, details);
28
+ },
29
+ services: {},
30
+ requestId: Math.random().toString(36).slice(2) + Math.random().toString(36).slice(2),
31
+ ...overrides,
32
+ };
33
+ }
34
+ /**
35
+ * Execute a middleware chain in priority order (lower priority runs first).
36
+ * Each middleware's returned properties are accumulated onto the context.
37
+ * Middleware can short-circuit by throwing an error.
38
+ */
39
+ export async function executeMiddlewareChain(req, ctx, entries) {
40
+ const sorted = [...entries].sort((a, b) => (a.priority ?? 0) - (b.priority ?? 0));
41
+ let currentCtx = ctx;
42
+ for (const entry of sorted) {
43
+ const added = await entry.middleware.handler({
44
+ headers: req.headers,
45
+ body: req.body,
46
+ query: req.query,
47
+ params: req.params,
48
+ ctx: currentCtx,
49
+ });
50
+ currentCtx = { ...currentCtx, ...added };
51
+ }
52
+ return currentCtx;
53
+ }
54
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,oCAAoC;AAGpC,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAyBjD;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAoD;IAEpD,OAAO,EAAE,OAAO,EAAE,CAAC;AACrB,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,uBAAuB;IACrC,MAAM,IAAI,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;IACtB,OAAO;QACL,KAAK,EAAE,IAAI;QACX,KAAK,EAAE,IAAI;QACX,IAAI,EAAE,IAAI;QACV,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,IAAI;QACX,KAAK,EAAE,IAAI;KACZ,CAAC;AACJ,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,oBAAoB,CAClC,SAAmC;IAEnC,OAAO;QACL,GAAG,EAAE,uBAAuB,EAAE;QAC9B,IAAI,CACF,MAAc,EACd,IAAY,EACZ,OAAe,EACf,OAAiC;YAEjC,MAAM,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACvD,CAAC;QACD,QAAQ,EAAE,EAAE;QACZ,SAAS,EACP,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3E,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,GAAmB,EACnB,GAAmB,EACnB,OAA0B;IAE1B,MAAM,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAChD,CAAC;IAEF,IAAI,UAAU,GAAG,GAAG,CAAC;IACrB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC;YAC3C,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,GAAG,EAAE,UAAU;SAChB,CAAC,CAAC;QACH,UAAU,GAAG,EAAE,GAAG,UAAU,EAAE,GAAG,KAAK,EAAoB,CAAC;IAC7D,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC"}
@@ -0,0 +1,74 @@
1
+ import type { BuildContext, BuildResult, CompiledRouteTable, GeneratedOutput, RequestContext, SchemaChange, SchemaTypeMap } from "@typokit/types";
2
+ import type { AppError } from "@typokit/errors";
3
+ /** Tapable-style async series hook — plugins tap in, calls run in series */
4
+ export interface AsyncSeriesHook<T extends unknown[]> {
5
+ tap(name: string, fn: (...args: T) => void | Promise<void>): void;
6
+ call(...args: T): Promise<void>;
7
+ }
8
+ /** Tapable build pipeline — plugins hook into build phases via onBuild() */
9
+ export interface BuildPipeline {
10
+ hooks: {
11
+ /** Runs before any transforms — plugins can register additional type sources */
12
+ beforeTransform: AsyncSeriesHook<[BuildContext]>;
13
+ /** Runs after types are parsed — plugins can inspect/modify the type map */
14
+ afterTypeParse: AsyncSeriesHook<[SchemaTypeMap, BuildContext]>;
15
+ /** Runs after validators are generated — plugins can add custom validators */
16
+ afterValidators: AsyncSeriesHook<[GeneratedOutput[], BuildContext]>;
17
+ /** Runs after the route table is compiled */
18
+ afterRouteTable: AsyncSeriesHook<[CompiledRouteTable, BuildContext]>;
19
+ /** Runs after all generation — plugins emit their own artifacts */
20
+ emit: AsyncSeriesHook<[GeneratedOutput[], BuildContext]>;
21
+ /** Runs after build completes — cleanup, reporting */
22
+ done: AsyncSeriesHook<[BuildResult]>;
23
+ };
24
+ }
25
+ /** A CLI subcommand exposed by a plugin */
26
+ export interface CliCommand {
27
+ name: string;
28
+ description: string;
29
+ options?: Array<{
30
+ name: string;
31
+ description: string;
32
+ required?: boolean;
33
+ }>;
34
+ run(args: Record<string, unknown>): Promise<void>;
35
+ }
36
+ /** An introspection endpoint exposed by a plugin for the debug sidecar */
37
+ export interface InspectEndpoint {
38
+ path: string;
39
+ description: string;
40
+ handler(): Promise<unknown>;
41
+ }
42
+ /** Represents the running application instance passed to plugin lifecycle hooks */
43
+ export interface AppInstance {
44
+ /** Application name */
45
+ name: string;
46
+ /** Registered plugins */
47
+ plugins: TypoKitPlugin[];
48
+ /** Service container for dependency injection */
49
+ services: Record<string, unknown>;
50
+ }
51
+ /** Plugin contract — hooks into both build-time and runtime lifecycle events */
52
+ export interface TypoKitPlugin {
53
+ name: string;
54
+ /** Hook into the build pipeline — tap into specific build phases */
55
+ onBuild?(pipeline: BuildPipeline): void;
56
+ /** Hook into server startup — register middleware, services, resources */
57
+ onStart?(app: AppInstance): Promise<void>;
58
+ /** Fires after all routes are registered and the server is listening.
59
+ * Use for service discovery, health check readiness, warmup. */
60
+ onReady?(app: AppInstance): Promise<void>;
61
+ /** Observe unhandled errors — reporting, transformation (e.g. Sentry).
62
+ * Called after the framework's error middleware serializes the response. */
63
+ onError?(error: AppError, ctx: RequestContext): void;
64
+ /** Hook into server shutdown — cleanup connections, flush buffers */
65
+ onStop?(app: AppInstance): Promise<void>;
66
+ /** Dev mode only — fires when schema types change and the build regenerates.
67
+ * Use to refresh cached state (e.g. debug sidecar route map). */
68
+ onSchemaChange?(changes: SchemaChange[]): void;
69
+ /** Expose CLI subcommands */
70
+ commands?(): CliCommand[];
71
+ /** Expose introspection endpoints for the debug sidecar */
72
+ inspect?(): InspectEndpoint[];
73
+ }
74
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
package/dist/plugin.js ADDED
@@ -0,0 +1,3 @@
1
+ // @typokit/core — Plugin Interface & Build Pipeline
2
+ export {};
3
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,oDAAoD"}
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@typokit/core",
3
+ "exports": {
4
+ ".": {
5
+ "import": "./dist/index.js",
6
+ "types": "./dist/index.d.ts"
7
+ }
8
+ },
9
+ "version": "0.1.4",
10
+ "type": "module",
11
+ "files": [
12
+ "dist",
13
+ "src"
14
+ ],
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "dependencies": {
18
+ "@typokit/errors": "0.1.4",
19
+ "@typokit/types": "0.1.4"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/KyleBastien/typokit",
24
+ "directory": "packages/core"
25
+ },
26
+ "scripts": {
27
+ "test": "rstest run --passWithNoTests"
28
+ }
29
+ }
@@ -0,0 +1,37 @@
1
+ import type {
2
+ GeneratedOutput,
3
+ MigrationDraft,
4
+ SchemaTypeMap,
5
+ } from "@typokit/types";
6
+
7
+ /**
8
+ * Represents the current state of a database schema,
9
+ * used by adapters to compute diffs against TypoKit types.
10
+ */
11
+ export interface DatabaseState {
12
+ tables: Record<string, TableState>;
13
+ }
14
+
15
+ export interface TableState {
16
+ columns: Record<string, ColumnState>;
17
+ }
18
+
19
+ export interface ColumnState {
20
+ type: string;
21
+ nullable: boolean;
22
+ }
23
+
24
+ /**
25
+ * Every database adapter implements this interface.
26
+ * See typokit-arch.md Section 7.3.
27
+ */
28
+ export interface DatabaseAdapter {
29
+ /** Generate DB schema artifacts from TypoKit types */
30
+ generate(types: SchemaTypeMap): GeneratedOutput[];
31
+
32
+ /** Diff current DB state against types, produce migration draft */
33
+ diff(types: SchemaTypeMap, currentState: DatabaseState): MigrationDraft;
34
+
35
+ /** Generate typed repository helpers (optional — adapters can skip this) */
36
+ generateRepositories?(types: SchemaTypeMap): GeneratedOutput[];
37
+ }
@@ -0,0 +1,55 @@
1
+ import type {
2
+ CompiledRouteTable,
3
+ HandlerMap,
4
+ MiddlewareChain,
5
+ SerializerMap,
6
+ ServerHandle,
7
+ TypoKitRequest,
8
+ TypoKitResponse,
9
+ ValidatorMap,
10
+ } from "@typokit/types";
11
+
12
+ export interface ServerAdapter {
13
+ /** Adapter name for logging and diagnostics */
14
+ name: string;
15
+
16
+ /**
17
+ * Register TypoKit's compiled routes into the server framework.
18
+ * The adapter translates the route table into framework-native registrations.
19
+ * Each route handler receives a normalized TypoKitRequest and must return
20
+ * a TypoKitResponse.
21
+ */
22
+ registerRoutes(
23
+ routeTable: CompiledRouteTable,
24
+ handlerMap: HandlerMap,
25
+ middlewareChain: MiddlewareChain,
26
+ validatorMap?: ValidatorMap,
27
+ serializerMap?: SerializerMap,
28
+ ): void;
29
+
30
+ /**
31
+ * Start the server. Returns a handle for shutdown.
32
+ */
33
+ listen(port: number): Promise<ServerHandle>;
34
+
35
+ /**
36
+ * Normalize the framework's native request into TypoKit's standard format.
37
+ * This is where Fastify's `req`, Hono's `c`, or raw `http.IncomingMessage`
38
+ * get normalized into a consistent shape for TypoKit's validation/handler
39
+ * pipeline.
40
+ */
41
+ normalizeRequest(raw: unknown): TypoKitRequest;
42
+
43
+ /**
44
+ * Write TypoKit's response back through the framework's native response
45
+ * mechanism.
46
+ */
47
+ writeResponse(raw: unknown, response: TypoKitResponse): void;
48
+
49
+ /**
50
+ * Optional: expose the underlying framework instance for escape hatches.
51
+ * e.g., the raw Fastify instance so users can register Fastify-native plugins.
52
+ * Returns `unknown` — consumers cast to the specific framework type.
53
+ */
54
+ getNativeServer?(): unknown;
55
+ }