@tablecraft/adapter-elysia 0.1.0-beta.1

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 ADDED
@@ -0,0 +1,27 @@
1
+ # @tablecraft/adapter-elysia
2
+
3
+ Elysia (Bun) adapter for [TableCraft](https://github.com/your-org/tablecraft).
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ bun add @tablecraft/engine @tablecraft/adapter-elysia
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```ts
14
+ import { Elysia } from 'elysia';
15
+ import { createElysiaPlugin } from '@tablecraft/adapter-elysia';
16
+
17
+ const app = new Elysia()
18
+ .use(createElysiaPlugin({
19
+ db,
20
+ schema,
21
+ configs,
22
+ getContext: ({ request }) => ({
23
+ tenantId: request.headers.get('x-tenant-id'),
24
+ }),
25
+ }))
26
+ .listen(3000);
27
+ ```
@@ -0,0 +1,130 @@
1
+ import { Elysia } from 'elysia';
2
+ import { TableConfig, ConfigInput, EngineContext } from '@tablecraft/engine';
3
+ export interface ElysiaAdapterOptions {
4
+ db: unknown;
5
+ schema: Record<string, unknown>;
6
+ configs: ConfigInput[] | Record<string, ConfigInput>;
7
+ /**
8
+ * Extract context from the Elysia context.
9
+ * Access headers, store, etc.
10
+ */
11
+ getContext?: (ctx: {
12
+ request: Request;
13
+ store: Record<string, unknown>;
14
+ }) => EngineContext | Promise<EngineContext>;
15
+ /**
16
+ * Override built-in access check with your own logic.
17
+ */
18
+ checkAccess?: (config: TableConfig, context: EngineContext, request: Request) => boolean | Promise<boolean>;
19
+ }
20
+ /**
21
+ * Creates an Elysia plugin with a `/:table` route.
22
+ */
23
+ export declare function createElysiaPlugin(options: ElysiaAdapterOptions): Elysia<"/api/data", {
24
+ decorator: {};
25
+ store: {};
26
+ derive: {};
27
+ resolve: {};
28
+ }, {
29
+ typebox: {};
30
+ error: {};
31
+ }, {
32
+ schema: {};
33
+ standaloneSchema: {};
34
+ macro: {};
35
+ macroFn: {};
36
+ parser: {};
37
+ response: {};
38
+ }, {
39
+ api: {
40
+ data: {
41
+ ":table": {
42
+ _meta: {
43
+ get: {
44
+ body: unknown;
45
+ params: {
46
+ table: string;
47
+ } & {};
48
+ query: any;
49
+ headers: any;
50
+ response: {
51
+ 200: import("@tablecraft/engine").TableMetadata | {
52
+ error: string;
53
+ };
54
+ 422: {
55
+ type: "validation";
56
+ on: string;
57
+ summary?: string;
58
+ message?: string;
59
+ found?: unknown;
60
+ property?: string;
61
+ expected?: string;
62
+ };
63
+ };
64
+ };
65
+ };
66
+ };
67
+ };
68
+ };
69
+ } & {
70
+ api: {
71
+ data: {
72
+ ":table": {
73
+ get: {
74
+ body: unknown;
75
+ params: {
76
+ table: string;
77
+ } & {};
78
+ query: any;
79
+ headers: any;
80
+ response: {
81
+ 200: string | import("@tablecraft/engine").EngineResult<Record<string, unknown>> | {
82
+ error: string;
83
+ };
84
+ 422: {
85
+ type: "validation";
86
+ on: string;
87
+ summary?: string;
88
+ message?: string;
89
+ found?: unknown;
90
+ property?: string;
91
+ expected?: string;
92
+ };
93
+ };
94
+ };
95
+ };
96
+ };
97
+ };
98
+ }, {
99
+ derive: {};
100
+ resolve: {};
101
+ schema: {};
102
+ standaloneSchema: {};
103
+ response: {};
104
+ }, {
105
+ derive: {};
106
+ resolve: {};
107
+ schema: {};
108
+ standaloneSchema: {};
109
+ response: {};
110
+ }>;
111
+ /**
112
+ * Creates an Elysia handler for a single table.
113
+ */
114
+ export declare function createElysiaHandler(options: {
115
+ db: unknown;
116
+ schema: Record<string, unknown>;
117
+ config: ConfigInput;
118
+ getContext?: (ctx: {
119
+ request: Request;
120
+ store: Record<string, unknown>;
121
+ }) => EngineContext | Promise<EngineContext>;
122
+ checkAccess?: (config: TableConfig, context: EngineContext, request: Request) => boolean | Promise<boolean>;
123
+ }): ({ request, store, set }: {
124
+ request: Request;
125
+ store: Record<string, unknown>;
126
+ set: any;
127
+ }) => Promise<string | import("@tablecraft/engine").EngineResult<Record<string, unknown>> | {
128
+ error: string;
129
+ }>;
130
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAML,WAAW,EACX,WAAW,EACX,aAAa,EACd,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACrD;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,KAAK,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACnH;;OAEG;IACH,WAAW,CAAC,EAAE,CACZ,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,OAAO,KACb,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACjC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4E/D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IAC3C,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,KAAK,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACnH,WAAW,CAAC,EAAE,CACZ,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,OAAO,KACb,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACjC,IAIe,yBAAyB;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,GAAG,EAAE,GAAG,CAAA;CAAE;;GAqCtG"}
package/dist/index.js ADDED
@@ -0,0 +1,100 @@
1
+ import { Elysia } from 'elysia';
2
+ import { createEngines, createTableEngine, parseRequest, checkAccess as defaultCheckAccess, getExportMeta, } from '@tablecraft/engine';
3
+ /**
4
+ * Creates an Elysia plugin with a `/:table` route.
5
+ */
6
+ export function createElysiaPlugin(options) {
7
+ const engines = createEngines({
8
+ db: options.db,
9
+ schema: options.schema,
10
+ configs: options.configs,
11
+ });
12
+ return new Elysia({ prefix: '/api/data' }).get('/:table/_meta', async ({ params, request, store, set }) => {
13
+ const tableName = params.table;
14
+ const engine = engines[tableName];
15
+ if (!engine) {
16
+ set.status = 404;
17
+ return { error: `Unknown resource '${tableName}'` };
18
+ }
19
+ const context = options.getContext
20
+ ? await options.getContext({ request, store: store })
21
+ : {};
22
+ return engine.getMetadata(context);
23
+ }).get('/:table', async ({ params, request, store, set }) => {
24
+ const tableName = params.table;
25
+ const engine = engines[tableName];
26
+ if (!engine) {
27
+ set.status = 404;
28
+ return { error: `Unknown resource '${tableName}'` };
29
+ }
30
+ const config = engine.getConfig();
31
+ const context = options.getContext
32
+ ? await options.getContext({ request, store: store })
33
+ : {};
34
+ const hasAccess = options.checkAccess
35
+ ? await options.checkAccess(config, context, request)
36
+ : defaultCheckAccess(config, context);
37
+ if (!hasAccess) {
38
+ set.status = 403;
39
+ return { error: 'Forbidden' };
40
+ }
41
+ const url = new URL(request.url);
42
+ const reqParams = parseRequest(url.searchParams);
43
+ // Export
44
+ if (reqParams.export) {
45
+ const allowed = config.export?.formats ?? ['csv', 'json'];
46
+ const enabled = config.export?.enabled ?? true;
47
+ if (!enabled || !allowed.includes(reqParams.export)) {
48
+ set.status = 400;
49
+ return { error: `Export format '${reqParams.export}' not allowed` };
50
+ }
51
+ const body = await engine.exportData(reqParams, context);
52
+ const { contentType, filename } = getExportMeta(tableName, reqParams.export);
53
+ set.headers['Content-Type'] = contentType;
54
+ set.headers['Content-Disposition'] = `attachment; filename="${filename}"`;
55
+ return body;
56
+ }
57
+ // Query
58
+ const result = await engine.query(reqParams, context);
59
+ set.headers['X-Total-Count'] = String(result.meta.total);
60
+ return result;
61
+ });
62
+ }
63
+ /**
64
+ * Creates an Elysia handler for a single table.
65
+ */
66
+ export function createElysiaHandler(options) {
67
+ const { db, schema, config, getContext, checkAccess } = options;
68
+ const engine = createTableEngine({ db, schema, config });
69
+ return async ({ request, store, set }) => {
70
+ const context = getContext
71
+ ? await getContext({ request, store })
72
+ : {};
73
+ const actualConfig = engine.getConfig();
74
+ const hasAccess = checkAccess
75
+ ? await checkAccess(actualConfig, context, request)
76
+ : defaultCheckAccess(actualConfig, context);
77
+ if (!hasAccess) {
78
+ set.status = 403;
79
+ return { error: 'Forbidden' };
80
+ }
81
+ const url = new URL(request.url);
82
+ const params = parseRequest(url.searchParams);
83
+ if (params.export) {
84
+ const allowed = actualConfig.export?.formats ?? ['csv', 'json'];
85
+ if (!(actualConfig.export?.enabled ?? true) || !allowed.includes(params.export)) {
86
+ set.status = 400;
87
+ return { error: `Export format '${params.export}' not allowed` };
88
+ }
89
+ const body = await engine.exportData(params, context);
90
+ const { contentType, filename } = getExportMeta(actualConfig.name, params.export);
91
+ set.headers['Content-Type'] = contentType;
92
+ set.headers['Content-Disposition'] = `attachment; filename="${filename}"`;
93
+ return body;
94
+ }
95
+ const result = await engine.query(params, context);
96
+ set.headers['X-Total-Count'] = String(result.meta.total);
97
+ return result;
98
+ };
99
+ }
100
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@tablecraft/adapter-elysia",
3
+ "version": "0.1.0-beta.1",
4
+ "description": "Elysia (Bun) adapter for TableCraft",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "bun run --bun tsc",
19
+ "dev": "bun run --bun tsc --watch",
20
+ "test": "vitest",
21
+ "typecheck": "bun run --bun tsc --noEmit"
22
+ },
23
+ "peerDependencies": {
24
+ "@tablecraft/engine": ">=0.1.0-beta.1",
25
+ "elysia": ">=1.0.0"
26
+ },
27
+ "devDependencies": {
28
+ "@tablecraft/engine": "workspace:*",
29
+ "elysia": "^1.2.0",
30
+ "typescript": "^5.3.3",
31
+ "vitest": "^1.2.0"
32
+ },
33
+ "keywords": [
34
+ "tablecraft",
35
+ "elysia",
36
+ "bun",
37
+ "adapter"
38
+ ],
39
+ "license": "MIT"
40
+ }