fastify-auto-sqlapi 0.0.4 → 0.1.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.
Files changed (127) hide show
  1. package/AGENTS.md +15 -2
  2. package/AGENTS_BACKEND.md +160 -32
  3. package/AGENTS_FRONTEND.md +220 -49
  4. package/README.md +147 -27
  5. package/dist/bin/generate-schema.js +12 -29
  6. package/dist/bin/generate-tables.js +10 -33
  7. package/dist/bin/utils.d.ts +29 -1
  8. package/dist/bin/utils.d.ts.map +1 -1
  9. package/dist/bin/utils.js +71 -2
  10. package/dist/index.d.ts +1 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/lib/cli/load-dependency.d.ts +8 -0
  13. package/dist/lib/cli/load-dependency.d.ts.map +1 -0
  14. package/dist/lib/cli/load-dependency.js +21 -0
  15. package/dist/lib/cli/mysql-introspect.d.ts.map +1 -1
  16. package/dist/lib/cli/mysql-introspect.js +2 -11
  17. package/dist/lib/cli/pg-introspect.d.ts.map +1 -1
  18. package/dist/lib/cli/pg-introspect.js +2 -17
  19. package/dist/lib/cli/schema-codegen.d.ts +1 -1
  20. package/dist/lib/cli/schema-codegen.d.ts.map +1 -1
  21. package/dist/lib/cli/schema-codegen.js +11 -4
  22. package/dist/lib/cli/tables-codegen.d.ts.map +1 -1
  23. package/dist/lib/cli/tables-codegen.js +4 -3
  24. package/dist/lib/db.d.ts +1 -0
  25. package/dist/lib/db.d.ts.map +1 -1
  26. package/dist/lib/db.js +33 -49
  27. package/dist/lib/dialect.d.ts +17 -0
  28. package/dist/lib/dialect.d.ts.map +1 -1
  29. package/dist/lib/dialect.js +32 -0
  30. package/dist/lib/engine/bulk/bulk-upsert.d.ts.map +1 -1
  31. package/dist/lib/engine/bulk/bulk-upsert.js +26 -50
  32. package/dist/lib/engine/rest/delete.d.ts.map +1 -1
  33. package/dist/lib/engine/rest/delete.js +5 -10
  34. package/dist/lib/engine/rest/get.d.ts.map +1 -1
  35. package/dist/lib/engine/rest/get.js +4 -6
  36. package/dist/lib/engine/rest/insert.d.ts.map +1 -1
  37. package/dist/lib/engine/rest/insert.js +20 -39
  38. package/dist/lib/engine/rest/update.d.ts.map +1 -1
  39. package/dist/lib/engine/rest/update.js +35 -67
  40. package/dist/lib/engine/search/search.d.ts.map +1 -1
  41. package/dist/lib/engine/search/search.js +650 -130
  42. package/dist/lib/engine/write-helpers.d.ts +39 -2
  43. package/dist/lib/engine/write-helpers.d.ts.map +1 -1
  44. package/dist/lib/engine/write-helpers.js +58 -15
  45. package/dist/lib/errors.d.ts +11 -0
  46. package/dist/lib/errors.d.ts.map +1 -0
  47. package/dist/lib/errors.js +12 -0
  48. package/dist/lib/naming.d.ts +11 -2
  49. package/dist/lib/naming.d.ts.map +1 -1
  50. package/dist/lib/naming.js +33 -5
  51. package/dist/lib/schema/bulk-upsert.d.ts.map +1 -1
  52. package/dist/lib/schema/bulk-upsert.js +9 -25
  53. package/dist/lib/schema/helpers.d.ts +28 -1
  54. package/dist/lib/schema/helpers.d.ts.map +1 -1
  55. package/dist/lib/schema/helpers.js +38 -0
  56. package/dist/lib/schema/insert.d.ts.map +1 -1
  57. package/dist/lib/schema/insert.js +9 -19
  58. package/dist/lib/schema/search.d.ts.map +1 -1
  59. package/dist/lib/schema/search.js +147 -53
  60. package/dist/lib/schema/update.d.ts.map +1 -1
  61. package/dist/lib/schema/update.js +9 -25
  62. package/dist/lib/sql-api.d.ts +6 -6
  63. package/dist/lib/sql-api.d.ts.map +1 -1
  64. package/dist/lib/sql-api.js +8 -8
  65. package/dist/lib/table-helpers.d.ts +6 -1
  66. package/dist/lib/table-helpers.d.ts.map +1 -1
  67. package/dist/lib/table-helpers.js +51 -3
  68. package/dist/lib/tenant.d.ts +23 -0
  69. package/dist/lib/tenant.d.ts.map +1 -1
  70. package/dist/lib/tenant.js +57 -9
  71. package/dist/routes/auto/bulk-delete.routes.d.ts.map +1 -1
  72. package/dist/routes/auto/bulk-delete.routes.js +17 -23
  73. package/dist/routes/auto/bulk-upsert.routes.d.ts.map +1 -1
  74. package/dist/routes/auto/bulk-upsert.routes.js +16 -22
  75. package/dist/routes/auto/delete.routes.d.ts.map +1 -1
  76. package/dist/routes/auto/delete.routes.js +18 -24
  77. package/dist/routes/auto/get.routes.d.ts.map +1 -1
  78. package/dist/routes/auto/get.routes.js +16 -23
  79. package/dist/routes/auto/insert.routes.d.ts.map +1 -1
  80. package/dist/routes/auto/insert.routes.js +19 -26
  81. package/dist/routes/auto/route-helpers.d.ts +27 -2
  82. package/dist/routes/auto/route-helpers.d.ts.map +1 -1
  83. package/dist/routes/auto/route-helpers.js +39 -1
  84. package/dist/routes/auto/search.routes.d.ts.map +1 -1
  85. package/dist/routes/auto/search.routes.js +47 -47
  86. package/dist/routes/auto/update.routes.d.ts.map +1 -1
  87. package/dist/routes/auto/update.routes.js +20 -27
  88. package/dist/types/cli.d.ts +22 -0
  89. package/dist/types/cli.d.ts.map +1 -0
  90. package/dist/types/cli.js +1 -0
  91. package/dist/types/computed.d.ts +29 -0
  92. package/dist/types/computed.d.ts.map +1 -0
  93. package/dist/types/computed.js +1 -0
  94. package/dist/types/conditions.d.ts +16 -0
  95. package/dist/types/conditions.d.ts.map +1 -0
  96. package/dist/types/conditions.js +1 -0
  97. package/dist/types/db.d.ts +22 -0
  98. package/dist/types/db.d.ts.map +1 -0
  99. package/dist/types/db.js +1 -0
  100. package/dist/types/dml.d.ts +64 -0
  101. package/dist/types/dml.d.ts.map +1 -0
  102. package/dist/types/dml.js +1 -0
  103. package/dist/types/join.d.ts +44 -0
  104. package/dist/types/join.d.ts.map +1 -0
  105. package/dist/types/join.js +1 -0
  106. package/dist/types/plugin.d.ts +20 -0
  107. package/dist/types/plugin.d.ts.map +1 -0
  108. package/dist/types/plugin.js +1 -0
  109. package/dist/types/schema.d.ts +10 -0
  110. package/dist/types/schema.d.ts.map +1 -0
  111. package/dist/types/schema.js +1 -0
  112. package/dist/types/search.d.ts +45 -0
  113. package/dist/types/search.d.ts.map +1 -0
  114. package/dist/types/search.js +1 -0
  115. package/dist/types/table.d.ts +52 -0
  116. package/dist/types/table.d.ts.map +1 -0
  117. package/dist/types/table.js +7 -0
  118. package/dist/types/tenant.d.ts +19 -0
  119. package/dist/types/tenant.d.ts.map +1 -0
  120. package/dist/types/tenant.js +1 -0
  121. package/dist/types/validation.d.ts +21 -0
  122. package/dist/types/validation.d.ts.map +1 -0
  123. package/dist/types/validation.js +1 -0
  124. package/dist/types.d.ts +12 -258
  125. package/dist/types.d.ts.map +1 -1
  126. package/dist/types.js +12 -7
  127. package/package.json +8 -5
@@ -1,27 +1,21 @@
1
1
  import { BulkDeleteTableBody, BulkDeleteTableResponse } from '../../lib/schema/bulk-delete.js';
2
2
  import { primaryAsString } from '../../types.js';
3
- import { mergeOnRequests } from './route-helpers.js';
3
+ import { registerForAllTables } from './route-helpers.js';
4
4
  export default async function bulkDeleteRoutes(fastify, options) {
5
- const { DbTables } = options;
6
- for (const [tableName, tableConf] of Object.entries(DbTables)) {
7
- const bodySchema = BulkDeleteTableBody(DbTables, tableName);
8
- const responseSchema = BulkDeleteTableResponse(DbTables, tableName);
9
- fastify.route({
10
- method: 'POST',
11
- url: `/bulk/${tableConf.Schema.tableName}/delete`,
12
- schema: {
13
- body: bodySchema,
14
- response: { 200: responseSchema },
15
- tags: [`SqlAPI-${tableName}`],
16
- summary: `Bulk delete ${tableName}`,
17
- description: `Delete multiple records from ${tableName} by primary key`,
18
- },
19
- onRequest: mergeOnRequests(options, tableConf),
20
- handler: async (request, reply) => {
21
- const items = request.body;
22
- const ids = items.map((item) => item[primaryAsString(tableConf.primary)]);
23
- reply.send(await fastify.sqlApi.bulkDelete(tableName, ids, request));
24
- },
25
- });
26
- }
5
+ await registerForAllTables(fastify, options, {
6
+ method: 'POST',
7
+ url: (tc) => `/bulk/${tc.Schema.tableName}/delete`,
8
+ successStatus: 200,
9
+ schemas: (db, table) => ({
10
+ body: BulkDeleteTableBody(db, table),
11
+ response: BulkDeleteTableResponse(db, table),
12
+ }),
13
+ summary: 'Bulk delete',
14
+ description: (name) => `Delete multiple records from ${name} by primary key`,
15
+ handle: (fastify, tableName, tc, request) => {
16
+ const items = request.body;
17
+ const ids = items.map((item) => item[primaryAsString(tc.primary)]);
18
+ return fastify.sqlApi.bulkDelete(tableName, ids, request);
19
+ },
20
+ });
27
21
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bulk-upsert.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/bulk-upsert.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,mBAAmB,EAAkB,MAAM,gBAAgB,CAAC;AAE1E,wBAA8B,gBAAgB,CAC5C,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAwBf"}
1
+ {"version":3,"file":"bulk-upsert.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/bulk-upsert.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,mBAAmB,EAAkB,MAAM,gBAAgB,CAAC;AAE1E,wBAA8B,gBAAgB,CAC5C,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAgBf"}
@@ -1,25 +1,19 @@
1
1
  import { BulkUpsertTableBody, BulkUpsertTableResponse } from '../../lib/schema/bulk-upsert.js';
2
- import { mergeOnRequests, buildWriteDescription } from './route-helpers.js';
2
+ import { registerForAllTables, buildWriteDescription } from './route-helpers.js';
3
3
  export default async function bulkUpsertRoutes(fastify, options) {
4
- const { DbTables } = options;
5
- for (const [tableName, tableConf] of Object.entries(DbTables)) {
6
- const bodySchema = BulkUpsertTableBody(DbTables, tableName);
7
- const responseSchema = BulkUpsertTableResponse(DbTables, tableName);
8
- fastify.route({
9
- method: 'PUT',
10
- url: `/bulk/${tableConf.Schema.tableName}`,
11
- schema: {
12
- body: bodySchema,
13
- response: { 200: responseSchema },
14
- tags: [`SqlAPI-${tableName}`],
15
- summary: `Bulk upsert ${tableName}`,
16
- description: buildWriteDescription('Bulk upsert records in', tableName, tableConf),
17
- },
18
- onRequest: mergeOnRequests(options, tableConf),
19
- handler: async (request, reply) => {
20
- const items = request.body;
21
- reply.send(await fastify.sqlApi.bulkUpsert(tableName, items, request));
22
- },
23
- });
24
- }
4
+ await registerForAllTables(fastify, options, {
5
+ method: 'PUT',
6
+ url: (tc) => `/bulk/${tc.Schema.tableName}`,
7
+ successStatus: 200,
8
+ schemas: (db, table) => ({
9
+ body: BulkUpsertTableBody(db, table),
10
+ response: BulkUpsertTableResponse(db, table),
11
+ }),
12
+ summary: 'Bulk upsert',
13
+ description: (name, tc) => buildWriteDescription('Bulk upsert records in', name, tc),
14
+ handle: (fastify, tableName, _tc, request) => {
15
+ const items = request.body;
16
+ return fastify.sqlApi.bulkUpsert(tableName, items, request);
17
+ },
18
+ });
25
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"delete.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/delete.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAI/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,YAAY,CACxC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CA2Bf"}
1
+ {"version":3,"file":"delete.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/delete.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAI/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,YAAY,CACxC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAmBf"}
@@ -1,29 +1,23 @@
1
1
  import { Type } from '@sinclair/typebox';
2
2
  import { primaryAsString } from '../../types.js';
3
- import { mergeOnRequests } from './route-helpers.js';
3
+ import { registerForAllTables } from './route-helpers.js';
4
4
  export default async function deleteRoutes(fastify, options) {
5
- const { DbTables } = options;
6
- for (const [tableName, tableConf] of Object.entries(DbTables)) {
7
- const pkField = primaryAsString(tableConf.primary);
8
- const pkType = tableConf.Schema.fields[pkField];
9
- const responseSchema = Type.Object({
10
- main: Type.Object({ [pkField]: pkType }),
11
- });
12
- fastify.route({
13
- method: 'DELETE',
14
- url: `/rest/${tableConf.Schema.tableName}/:id`,
15
- schema: {
5
+ await registerForAllTables(fastify, options, {
6
+ method: 'DELETE',
7
+ url: (tc) => `/rest/${tc.Schema.tableName}/:id`,
8
+ successStatus: 200,
9
+ schemas: (_db, _table, tc) => {
10
+ const pkField = primaryAsString(tc.primary);
11
+ return {
16
12
  params: Type.Object({ id: Type.String() }),
17
- response: { 200: responseSchema },
18
- tags: [`SqlAPI-${tableName}`],
19
- summary: `Delete ${tableName}`,
20
- description: `Delete a record from ${tableName} by primary key`,
21
- },
22
- onRequest: mergeOnRequests(options, tableConf),
23
- handler: async (request, reply) => {
24
- const { id } = request.params;
25
- reply.send(await fastify.sqlApi.delete(tableName, id, request));
26
- },
27
- });
28
- }
13
+ response: Type.Object({ main: Type.Object({ [pkField]: tc.Schema.fields[pkField] }) }),
14
+ };
15
+ },
16
+ summary: 'Delete',
17
+ description: (name) => `Delete a record from ${name} by primary key`,
18
+ handle: (fastify, tableName, _tc, request) => {
19
+ const { id } = request.params;
20
+ return fastify.sqlApi.delete(tableName, id, request);
21
+ },
22
+ });
29
23
  }
@@ -1 +1 @@
1
- {"version":3,"file":"get.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/get.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,SAAS,CACrC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAyBf"}
1
+ {"version":3,"file":"get.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/get.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,SAAS,CACrC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAgBf"}
@@ -1,26 +1,19 @@
1
1
  import { Type } from '@sinclair/typebox';
2
- import { mergeOnRequests } from './route-helpers.js';
2
+ import { registerForAllTables } from './route-helpers.js';
3
3
  export default async function getRoutes(fastify, options) {
4
- const { DbTables } = options;
5
- for (const [tableName, tableConf] of Object.entries(DbTables)) {
6
- const responseSchema = Type.Object({
7
- main: Type.Partial(Type.Object(tableConf.Schema.fields)),
8
- });
9
- fastify.route({
10
- method: 'GET',
11
- url: `/rest/${tableConf.Schema.tableName}/:id`,
12
- schema: {
13
- params: Type.Object({ id: Type.String() }),
14
- response: { 200: responseSchema },
15
- tags: [`SqlAPI-${tableName}`],
16
- summary: `Get ${tableName}`,
17
- description: `Get a record from ${tableName} by primary key`,
18
- },
19
- onRequest: mergeOnRequests(options, tableConf),
20
- handler: async (request, reply) => {
21
- const { id } = request.params;
22
- reply.send(await fastify.sqlApi.get(tableName, id, request));
23
- },
24
- });
25
- }
4
+ await registerForAllTables(fastify, options, {
5
+ method: 'GET',
6
+ url: (tc) => `/rest/${tc.Schema.tableName}/:id`,
7
+ successStatus: 200,
8
+ schemas: (_db, _table, tc) => ({
9
+ params: Type.Object({ id: Type.String() }),
10
+ response: Type.Object({ main: Type.Partial(Type.Object(tc.Schema.fields)) }),
11
+ }),
12
+ summary: 'Get',
13
+ description: (name) => `Get a record from ${name} by primary key`,
14
+ handle: (fastify, tableName, _tc, request) => {
15
+ const { id } = request.params;
16
+ return fastify.sqlApi.get(tableName, id, request);
17
+ },
18
+ });
26
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"insert.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/insert.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,YAAY,CACxC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAiCf"}
1
+ {"version":3,"file":"insert.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/insert.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,YAAY,CACxC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAsBf"}
@@ -1,29 +1,22 @@
1
1
  import { InsertTableBody, InsertTableResponse } from '../../lib/schema/insert.js';
2
- import { mergeOnRequests, buildWriteDescription } from './route-helpers.js';
2
+ import { registerForAllTables, buildWriteDescription } from './route-helpers.js';
3
3
  export default async function insertRoutes(fastify, options) {
4
- const { DbTables } = options;
5
- for (const [tableName, tableConf] of Object.entries(DbTables)) {
6
- const bodySchema = InsertTableBody(DbTables, tableName);
7
- const responseSchema = InsertTableResponse(DbTables, tableName);
8
- fastify.route({
9
- method: 'POST',
10
- url: `/rest/${tableConf.Schema.tableName}`,
11
- schema: {
12
- body: bodySchema,
13
- response: { 201: responseSchema },
14
- tags: [`SqlAPI-${tableName}`],
15
- summary: `Insert ${tableName}`,
16
- description: buildWriteDescription('Insert a record into', tableName, tableConf),
17
- },
18
- onRequest: mergeOnRequests(options, tableConf),
19
- handler: async (request, reply) => {
20
- const body = request.body;
21
- const result = await fastify.sqlApi.insert(tableName, {
22
- record: body.main,
23
- secondaries: body.secondaries,
24
- }, request);
25
- reply.status(201).send(result);
26
- },
27
- });
28
- }
4
+ await registerForAllTables(fastify, options, {
5
+ method: 'POST',
6
+ url: (tc) => `/rest/${tc.Schema.tableName}`,
7
+ successStatus: 201,
8
+ schemas: (db, table) => ({
9
+ body: InsertTableBody(db, table),
10
+ response: InsertTableResponse(db, table),
11
+ }),
12
+ summary: 'Insert',
13
+ description: (name, tc) => buildWriteDescription('Insert a record into', name, tc),
14
+ handle: (fastify, tableName, _tc, request) => {
15
+ const body = request.body;
16
+ return fastify.sqlApi.insert(tableName, {
17
+ record: body.main,
18
+ secondaries: body.secondaries,
19
+ }, request);
20
+ },
21
+ });
29
22
  }
@@ -1,7 +1,32 @@
1
- import type { FastifyRequest, FastifyReply } from 'fastify';
2
- import type { ITable, SqlApiPluginOptions } from '../../types.js';
1
+ import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
2
+ import type { ITable, SqlApiPluginOptions, DbTables } from '../../types.js';
3
3
  type RequestHook = (request: FastifyRequest, reply: FastifyReply) => Promise<void | FastifyReply>;
4
4
  export declare function mergeOnRequests(options: SqlApiPluginOptions, tableConf: ITable): RequestHook[];
5
5
  export declare function buildWriteDescription(action: string, tableName: string, tableConf: ITable): string;
6
+ interface RouteSchema {
7
+ body?: any;
8
+ params?: any;
9
+ querystring?: any;
10
+ response?: any;
11
+ }
12
+ export interface AutoRouteSpec {
13
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE';
14
+ /** URL builder receiving the table configuration to read `Schema.tableName`. */
15
+ url: (tableConf: ITable) => string;
16
+ successStatus: 200 | 201;
17
+ /** Build per-table schemas (body, params, querystring, response). Response is wrapped with `{ [successStatus]: ... }` automatically. */
18
+ schemas: (dbTables: DbTables, tableName: string, tableConf: ITable) => RouteSchema;
19
+ summary: string;
20
+ description: (tableName: string, tableConf: ITable, schemas: RouteSchema) => string;
21
+ /** Translates the request to a sqlApi call. If it does not call reply.send/status itself,
22
+ * the registrar will reply.status(successStatus).send(returnValue). */
23
+ handle: (fastify: FastifyInstance, tableName: string, tableConf: ITable, request: FastifyRequest, reply: FastifyReply) => Promise<unknown>;
24
+ }
25
+ /**
26
+ * Iterates over every table in `options.DbTables` and registers one Fastify route for it
27
+ * following `spec`. Centralizes onRequest hook merging, tags, schema response wrapping,
28
+ * default reply when handler returns a value.
29
+ */
30
+ export declare function registerForAllTables(fastify: FastifyInstance, options: SqlApiPluginOptions, spec: AutoRouteSpec): Promise<void>;
6
31
  export {};
7
32
  //# sourceMappingURL=route-helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"route-helpers.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/route-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAElE,KAAK,WAAW,GAAG,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,GAAG,YAAY,CAAC,CAAC;AAElG,wBAAgB,eAAe,CAAC,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,GAAG,WAAW,EAAE,CAE9F;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQlG"}
1
+ {"version":3,"file":"route-helpers.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/route-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE5E,KAAK,WAAW,GAAG,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,GAAG,YAAY,CAAC,CAAC;AAElG,wBAAgB,eAAe,CAAC,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,GAAG,WAAW,EAAE,CAE9F;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQlG;AAED,UAAU,WAAW;IAEnB,IAAI,CAAC,EAAE,GAAG,CAAC;IAEX,MAAM,CAAC,EAAE,GAAG,CAAC;IAEb,WAAW,CAAC,EAAE,GAAG,CAAC;IAElB,QAAQ,CAAC,EAAE,GAAG,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;IAC1C,gFAAgF;IAChF,GAAG,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IACnC,aAAa,EAAE,GAAG,GAAG,GAAG,CAAC;IACzB,wIAAwI;IACxI,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,WAAW,CAAC;IACnF,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,KAAK,MAAM,CAAC;IACpF;2EACuE;IACvE,MAAM,EAAE,CACN,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,YAAY,KAChB,OAAO,CAAC,OAAO,CAAC,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,EAC5B,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,IAAI,CAAC,CA8Bf"}
@@ -3,10 +3,48 @@ export function mergeOnRequests(options, tableConf) {
3
3
  }
4
4
  export function buildWriteDescription(action, tableName, tableConf) {
5
5
  const joinList = tableConf.allowedWriteJoins
6
- ?.map(([joinSchema]) => joinSchema.tableName)
6
+ ?.map((j) => j.alias)
7
7
  .join(', ');
8
8
  return [
9
9
  `${action} ${tableName}`,
10
10
  joinList && `Available secondaries: ${joinList}`,
11
11
  ].filter(Boolean).join('. ');
12
12
  }
13
+ /**
14
+ * Iterates over every table in `options.DbTables` and registers one Fastify route for it
15
+ * following `spec`. Centralizes onRequest hook merging, tags, schema response wrapping,
16
+ * default reply when handler returns a value.
17
+ */
18
+ export async function registerForAllTables(fastify, options, spec) {
19
+ const { DbTables } = options;
20
+ for (const [tableName, tableConf] of Object.entries(DbTables)) {
21
+ const schemas = spec.schemas(DbTables, tableName, tableConf);
22
+ // Only include schema keys that are actually defined: Fastify checks for key
23
+ // *presence* (not undefined value) to decide whether to emit FSTWRN001.
24
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
+ const schema = {
26
+ tags: [`SqlAPI-${tableName}`],
27
+ summary: `${spec.summary} ${tableName}`,
28
+ description: spec.description(tableName, tableConf, schemas),
29
+ };
30
+ if (schemas.body !== undefined)
31
+ schema.body = schemas.body;
32
+ if (schemas.params !== undefined)
33
+ schema.params = schemas.params;
34
+ if (schemas.querystring !== undefined)
35
+ schema.querystring = schemas.querystring;
36
+ if (schemas.response !== undefined)
37
+ schema.response = { [spec.successStatus]: schemas.response };
38
+ fastify.route({
39
+ method: spec.method,
40
+ url: spec.url(tableConf),
41
+ schema,
42
+ onRequest: mergeOnRequests(options, tableConf),
43
+ handler: async (request, reply) => {
44
+ const result = await spec.handle(fastify, tableName, tableConf, request, reply);
45
+ if (!reply.sent)
46
+ reply.status(spec.successStatus).send(result);
47
+ },
48
+ });
49
+ }
50
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"search.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/search.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,YAAY,CACxC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAoDf"}
1
+ {"version":3,"file":"search.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/search.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,YAAY,CACxC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAiDf"}
@@ -1,50 +1,50 @@
1
1
  import { SearchTableBodyPost, SearchTableQueryString, SearchTableResponse } from '../../lib/schema/search.js';
2
- import { mergeOnRequests } from './route-helpers.js';
2
+ import { registerForAllTables } from './route-helpers.js';
3
3
  export default async function searchRoutes(fastify, options) {
4
- const { DbTables } = options;
5
- for (const [tableName, tableConf] of Object.entries(DbTables)) {
6
- const bodySchema = SearchTableBodyPost(DbTables, tableName);
7
- const responseSchema = SearchTableResponse(DbTables, tableName);
8
- const joinList = Object.keys(bodySchema.properties.joins?.properties || {}).join(', ');
9
- const description = [
10
- `Search records in ${tableName}`,
11
- joinList && `Available joins: ${joinList}`,
12
- ].filter(Boolean).join('. ');
13
- fastify.route({
14
- method: 'POST',
15
- url: `/search/${tableConf.Schema.tableName}`,
16
- schema: {
17
- body: bodySchema,
18
- querystring: SearchTableQueryString,
19
- response: { 200: responseSchema },
20
- tags: [`SqlAPI-${tableName}`],
21
- summary: `Search ${tableName}`,
22
- description,
23
- },
24
- onRequest: mergeOnRequests(options, tableConf),
25
- handler: async (request, reply) => {
26
- const body = request.body;
27
- const query = request.query;
28
- const result = await fastify.sqlApi.search(tableName, {
29
- filters: body.filters,
30
- conditions: body.conditions,
31
- joinFilters: body.joinFilters,
32
- joins: body.joins,
33
- joinGroups: body.joinGroups,
34
- orderBy: query.orderBy,
35
- paginator: (query.page || query.itemsPerPage)
36
- ? {
37
- page: query.page || 1,
38
- itemsPerPage: query.itemsPerPage || 500,
39
- }
40
- : undefined,
41
- computeMin: query.computeMin,
42
- computeMax: query.computeMax,
43
- computeSum: query.computeSum,
44
- computeAvg: query.computeAvg,
45
- }, request);
46
- reply.send({ table: tableConf.Schema.tableName, ...result });
47
- },
48
- });
49
- }
4
+ await registerForAllTables(fastify, options, {
5
+ method: 'POST',
6
+ url: (tc) => `/search/${tc.Schema.tableName}`,
7
+ successStatus: 200,
8
+ schemas: (db, table) => ({
9
+ body: SearchTableBodyPost(db, table),
10
+ querystring: SearchTableQueryString,
11
+ response: SearchTableResponse(db, table),
12
+ }),
13
+ summary: 'Search',
14
+ description: (name, _tc, schemas) => {
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
+ const body = schemas.body;
17
+ const multiAliases = Object.keys(body?.properties?.joinMultiple?.properties || {});
18
+ const leftAliases = Object.keys(body?.properties?.joinLeft?.properties || {});
19
+ return [
20
+ `Search records in ${name}`,
21
+ multiAliases.length && `Available joinMultiple/joinMustExist/joinGroup aliases: ${multiAliases.join(', ')}`,
22
+ leftAliases.length && `Available joinLeft aliases: ${leftAliases.join(', ')}`,
23
+ ].filter(Boolean).join('. ');
24
+ },
25
+ handle: async (fastify, tableName, tc, request) => {
26
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
+ const body = request.body;
28
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
+ const query = request.query;
30
+ const result = await fastify.sqlApi.search(tableName, {
31
+ filters: body.filters,
32
+ conditions: body.conditions,
33
+ joinMustExist: body.joinMustExist,
34
+ joinMultiple: body.joinMultiple,
35
+ joinGroup: body.joinGroup,
36
+ joinLeft: body.joinLeft,
37
+ selectComputed: body.selectComputed,
38
+ orderBy: query.orderBy,
39
+ paginator: (query.page || query.itemsPerPage)
40
+ ? { page: query.page || 1, itemsPerPage: query.itemsPerPage || 500 }
41
+ : undefined,
42
+ computeMin: query.computeMin,
43
+ computeMax: query.computeMax,
44
+ computeSum: query.computeSum,
45
+ computeAvg: query.computeAvg,
46
+ }, request);
47
+ return { table: tc.Schema.tableName, ...result };
48
+ },
49
+ });
50
50
  }
@@ -1 +1 @@
1
- {"version":3,"file":"update.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/update.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,YAAY,CACxC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAmCf"}
1
+ {"version":3,"file":"update.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/update.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,YAAY,CACxC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAwBf"}
@@ -1,30 +1,23 @@
1
1
  import { UpdateTableBody, UpdateTableResponse } from '../../lib/schema/update.js';
2
- import { mergeOnRequests, buildWriteDescription } from './route-helpers.js';
2
+ import { registerForAllTables, buildWriteDescription } from './route-helpers.js';
3
3
  export default async function updateRoutes(fastify, options) {
4
- const { DbTables } = options;
5
- for (const [tableName, tableConf] of Object.entries(DbTables)) {
6
- const bodySchema = UpdateTableBody(DbTables, tableName);
7
- const responseSchema = UpdateTableResponse(DbTables, tableName);
8
- fastify.route({
9
- method: 'PUT',
10
- url: `/rest/${tableConf.Schema.tableName}`,
11
- schema: {
12
- body: bodySchema,
13
- response: { 200: responseSchema },
14
- tags: [`SqlAPI-${tableName}`],
15
- summary: `Update ${tableName}`,
16
- description: buildWriteDescription('Update a record in', tableName, tableConf),
17
- },
18
- onRequest: mergeOnRequests(options, tableConf),
19
- handler: async (request, reply) => {
20
- const body = request.body;
21
- const result = await fastify.sqlApi.update(tableName, {
22
- record: body.main,
23
- secondaries: body.secondaries,
24
- deletions: body.deletions,
25
- }, request);
26
- reply.send(result);
27
- },
28
- });
29
- }
4
+ await registerForAllTables(fastify, options, {
5
+ method: 'PUT',
6
+ url: (tc) => `/rest/${tc.Schema.tableName}`,
7
+ successStatus: 200,
8
+ schemas: (db, table) => ({
9
+ body: UpdateTableBody(db, table),
10
+ response: UpdateTableResponse(db, table),
11
+ }),
12
+ summary: 'Update',
13
+ description: (name, tc) => buildWriteDescription('Update a record in', name, tc),
14
+ handle: (fastify, tableName, _tc, request) => {
15
+ const body = request.body;
16
+ return fastify.sqlApi.update(tableName, {
17
+ record: body.main,
18
+ secondaries: body.secondaries,
19
+ deletions: body.deletions,
20
+ }, request);
21
+ },
22
+ });
30
23
  }
@@ -0,0 +1,22 @@
1
+ import type { DialectName } from '../lib/dialect.js';
2
+ export interface SqlApiConfig {
3
+ outputDir: string;
4
+ schema?: string;
5
+ dialect?: DialectName;
6
+ envFile?: string;
7
+ }
8
+ export interface ColumnInfo {
9
+ table_name: string;
10
+ column_name: string;
11
+ udt_name: string;
12
+ column_default: string | null;
13
+ is_nullable: string;
14
+ }
15
+ export interface TableMap {
16
+ [schemaName: string]: {
17
+ name: string;
18
+ fields: Record<string, string>;
19
+ colMap: Record<string, string>;
20
+ };
21
+ }
22
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/types/cli.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,QAAQ;IACvB,CAAC,UAAU,EAAE,MAAM,GAAG;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAChC,CAAC;CACH"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,29 @@
1
+ import type { TSchema } from '@sinclair/typebox';
2
+ import type { QueryClient } from '../lib/db.js';
3
+ /**
4
+ * Context passed to ComputedFieldFn when the engine resolves a computed field.
5
+ * - `db` exposes dialect-aware helpers (qi, ph, dialectName, dateTrunc, ...).
6
+ * - `qiCol(field, opts?)` returns a quoted column reference, optionally
7
+ * prefixed by an alias qualifier — needed when the computed is embedded in
8
+ * a `LEFT JOIN <table> AS <alias>` (joinLeft).
9
+ */
10
+ export interface ComputedFieldContext {
11
+ db: QueryClient;
12
+ qiCol(field: string, opts?: {
13
+ qualifier?: string;
14
+ }): string;
15
+ }
16
+ /**
17
+ * Result returned by a ComputedFieldFn.
18
+ * - `expr`: SQL fragment usable as a scalar expression.
19
+ * - `values`: bound parameter values (always parameterized — never interpolate
20
+ * user-derived data into `expr`).
21
+ * - `type`: TypeBox schema for Swagger filters and main response (REQUIRED).
22
+ */
23
+ export interface ComputedFieldExpr {
24
+ expr: string;
25
+ values: unknown[];
26
+ type: TSchema;
27
+ }
28
+ export type ComputedFieldFn = (ctx: ComputedFieldContext) => ComputedFieldExpr;
29
+ //# sourceMappingURL=computed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computed.d.ts","sourceRoot":"","sources":["../../src/types/computed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,WAAW,CAAC;IAChB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC;CAC7D;AAED;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,MAAM,eAAe,GAAG,CAAC,GAAG,EAAE,oBAAoB,KAAK,iBAAiB,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ import type { ConditionBuilder as CB } from 'node-condition-builder';
2
+ type SingleValueMethods = 'isEqual' | 'isNotEqual' | 'isGreater' | 'isNotGreater' | 'isGreaterOrEqual' | 'isNotGreaterOrEqual' | 'isLess' | 'isNotLess' | 'isLessOrEqual' | 'isNotLessOrEqual' | 'isLike' | 'isNotLike' | 'isILike' | 'isNotILike';
3
+ type BetweenMethods = 'isBetween' | 'isNotBetween';
4
+ type InMethods = 'isIn' | 'isNotIn';
5
+ type NullMethods = 'isNull' | 'isNotNull';
6
+ export type ConditionMethod = SingleValueMethods | BetweenMethods | InMethods | NullMethods;
7
+ type ConditionParams<M extends ConditionMethod> = M extends SingleValueMethods ? [value: Parameters<CB[M]>[1]] : M extends BetweenMethods ? [from: Parameters<CB[M]>[1], to: Parameters<CB[M]>[2]] : M extends InMethods ? [values: Parameters<CB[M]>[1]] : M extends NullMethods ? [] : never;
8
+ export type SearchCondition<F extends string = string> = {
9
+ [M in ConditionMethod]: {
10
+ field: F;
11
+ method: M;
12
+ params: ConditionParams<M>;
13
+ };
14
+ }[ConditionMethod];
15
+ export {};
16
+ //# sourceMappingURL=conditions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conditions.d.ts","sourceRoot":"","sources":["../../src/types/conditions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,IAAI,EAAE,EAAE,MAAM,wBAAwB,CAAC;AAGrE,KAAK,kBAAkB,GACnB,SAAS,GAAG,YAAY,GACxB,WAAW,GAAG,cAAc,GAAG,kBAAkB,GAAG,qBAAqB,GACzE,QAAQ,GAAG,WAAW,GAAG,eAAe,GAAG,kBAAkB,GAC7D,QAAQ,GAAG,WAAW,GAAG,SAAS,GAAG,YAAY,CAAC;AAGtD,KAAK,cAAc,GAAG,WAAW,GAAG,cAAc,CAAC;AAGnD,KAAK,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AAGpC,KAAK,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE1C,MAAM,MAAM,eAAe,GAAG,kBAAkB,GAAG,cAAc,GAAG,SAAS,GAAG,WAAW,CAAC;AAG5F,KAAK,eAAe,CAAC,CAAC,SAAS,eAAe,IAC5C,CAAC,SAAS,kBAAkB,GAAG,CAAC,KAAK,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAC5D,CAAC,SAAS,cAAc,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GACjF,CAAC,SAAS,SAAS,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GACpD,CAAC,SAAS,WAAW,GAAG,EAAE,GAC1B,KAAK,CAAC;AAER,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI;KACtD,CAAC,IAAI,eAAe,GAAG;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,MAAM,EAAE,CAAC,CAAC;QAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,CAAA;KAAE;CAC5E,CAAC,eAAe,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};