@appweaver/core 1.0.0

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 (271) hide show
  1. package/LICENSE +1 -0
  2. package/README.md +7 -0
  3. package/app/application.d.ts +43 -0
  4. package/app/application.js +112 -0
  5. package/app/create-app.d.ts +32 -0
  6. package/app/create-app.js +38 -0
  7. package/app/index.d.ts +2 -0
  8. package/app/index.js +18 -0
  9. package/app/lifecycle-manager.d.ts +20 -0
  10. package/app/lifecycle-manager.js +42 -0
  11. package/app/load-modules.d.ts +10 -0
  12. package/app/load-modules.js +50 -0
  13. package/app/load-providers.d.ts +8 -0
  14. package/app/load-providers.js +33 -0
  15. package/cache/cache-service.d.ts +72 -0
  16. package/cache/cache-service.js +202 -0
  17. package/cache/cache.d.ts +12 -0
  18. package/cache/cache.js +184 -0
  19. package/cache/caching.d.ts +8 -0
  20. package/cache/caching.js +72 -0
  21. package/cache/eviction/eviction-index.d.ts +35 -0
  22. package/cache/eviction/eviction-index.js +2 -0
  23. package/cache/eviction/fifo-eviction-index.d.ts +7 -0
  24. package/cache/eviction/fifo-eviction-index.js +28 -0
  25. package/cache/eviction/index.d.ts +4 -0
  26. package/cache/eviction/index.js +20 -0
  27. package/cache/eviction/lfu-eviction-index.d.ts +8 -0
  28. package/cache/eviction/lfu-eviction-index.js +82 -0
  29. package/cache/eviction/lru-eviction-index.d.ts +8 -0
  30. package/cache/eviction/lru-eviction-index.js +81 -0
  31. package/cache/index.d.ts +2 -0
  32. package/cache/index.js +18 -0
  33. package/cache/memory-cache.d.ts +4 -0
  34. package/cache/memory-cache.js +12 -0
  35. package/cache/redis-cache.d.ts +4 -0
  36. package/cache/redis-cache.js +12 -0
  37. package/context/context.d.ts +2 -0
  38. package/context/context.js +13 -0
  39. package/context/dependency-injection.d.ts +98 -0
  40. package/context/dependency-injection.js +276 -0
  41. package/context/index.d.ts +2 -0
  42. package/context/index.js +18 -0
  43. package/database/create-client.d.ts +11 -0
  44. package/database/create-client.js +142 -0
  45. package/database/index.d.ts +1 -0
  46. package/database/index.js +17 -0
  47. package/database/prisma-database.d.ts +15 -0
  48. package/database/prisma-database.js +53 -0
  49. package/errors/error-handler.d.ts +3 -0
  50. package/errors/error-handler.js +24 -0
  51. package/errors/error-schema.d.ts +32 -0
  52. package/errors/error-schema.js +31 -0
  53. package/errors/http-error.d.ts +21 -0
  54. package/errors/http-error.js +33 -0
  55. package/errors/index.d.ts +3 -0
  56. package/errors/index.js +19 -0
  57. package/events/node-events.d.ts +7 -0
  58. package/events/node-events.js +39 -0
  59. package/export/export-service.d.ts +19 -0
  60. package/export/export-service.js +154 -0
  61. package/export/index.d.ts +1 -0
  62. package/export/index.js +17 -0
  63. package/factory/create-model.d.ts +2 -0
  64. package/factory/create-model.js +366 -0
  65. package/factory/create-policy.d.ts +2 -0
  66. package/factory/create-policy.js +16 -0
  67. package/factory/create-routes.d.ts +2 -0
  68. package/factory/create-routes.js +21 -0
  69. package/factory/create-service.d.ts +3 -0
  70. package/factory/create-service.js +97 -0
  71. package/factory/index.d.ts +4 -0
  72. package/factory/index.js +20 -0
  73. package/health/health-routes.d.ts +2 -0
  74. package/health/health-routes.js +36 -0
  75. package/health/health-schema.d.ts +45 -0
  76. package/health/health-schema.js +52 -0
  77. package/health/health-service.d.ts +38 -0
  78. package/health/health-service.js +82 -0
  79. package/health/index.d.ts +2 -0
  80. package/health/index.js +18 -0
  81. package/index.d.ts +15 -0
  82. package/index.js +31 -0
  83. package/mailer/email-service.d.ts +36 -0
  84. package/mailer/email-service.js +89 -0
  85. package/mailer/index.d.ts +1 -0
  86. package/mailer/index.js +17 -0
  87. package/mailer/json-mailer.d.ts +7 -0
  88. package/mailer/json-mailer.js +32 -0
  89. package/mailer/smtp-mailer.d.ts +7 -0
  90. package/mailer/smtp-mailer.js +43 -0
  91. package/memory/in-memory.d.ts +24 -0
  92. package/memory/in-memory.js +164 -0
  93. package/memory/redis.d.ts +26 -0
  94. package/memory/redis.js +158 -0
  95. package/package.json +68 -0
  96. package/prisma/client/browser.d.ts +34 -0
  97. package/prisma/client/browser.js +56 -0
  98. package/prisma/client/client.d.ts +53 -0
  99. package/prisma/client/client.js +70 -0
  100. package/prisma/client/commonInputTypes.d.ts +395 -0
  101. package/prisma/client/commonInputTypes.js +11 -0
  102. package/prisma/client/enums.d.ts +1 -0
  103. package/prisma/client/enums.js +11 -0
  104. package/prisma/client/internal/class.d.ts +187 -0
  105. package/prisma/client/internal/class.js +85 -0
  106. package/prisma/client/internal/prismaNamespace.d.ts +987 -0
  107. package/prisma/client/internal/prismaNamespace.js +193 -0
  108. package/prisma/client/internal/prismaNamespaceBrowser.d.ts +125 -0
  109. package/prisma/client/internal/prismaNamespaceBrowser.js +164 -0
  110. package/prisma/client/models/ApiKey.d.ts +1167 -0
  111. package/prisma/client/models/ApiKey.js +2 -0
  112. package/prisma/client/models/File.d.ts +1248 -0
  113. package/prisma/client/models/File.js +2 -0
  114. package/prisma/client/models/OneTimeToken.d.ts +1083 -0
  115. package/prisma/client/models/OneTimeToken.js +2 -0
  116. package/prisma/client/models/Permission.d.ts +1209 -0
  117. package/prisma/client/models/Permission.js +2 -0
  118. package/prisma/client/models/Role.d.ts +1209 -0
  119. package/prisma/client/models/Role.js +2 -0
  120. package/prisma/client/models/Seeder.d.ts +1023 -0
  121. package/prisma/client/models/Seeder.js +2 -0
  122. package/prisma/client/models.d.ts +7 -0
  123. package/prisma/client/models.js +2 -0
  124. package/queue/bull-queue.d.ts +37 -0
  125. package/queue/bull-queue.js +207 -0
  126. package/queue/memory-queue.d.ts +54 -0
  127. package/queue/memory-queue.js +283 -0
  128. package/resource/index.d.ts +4 -0
  129. package/resource/index.js +20 -0
  130. package/resource/resource-loader.d.ts +26 -0
  131. package/resource/resource-loader.js +161 -0
  132. package/resource/resource-routes.d.ts +3 -0
  133. package/resource/resource-routes.js +174 -0
  134. package/resource/resource-schema.d.ts +33 -0
  135. package/resource/resource-schema.js +186 -0
  136. package/resource/resource-service.d.ts +89 -0
  137. package/resource/resource-service.js +772 -0
  138. package/resources.d.ts +9 -0
  139. package/resources.js +24 -0
  140. package/scheduler/cron-scheduler.d.ts +12 -0
  141. package/scheduler/cron-scheduler.js +73 -0
  142. package/security/account/account-routes.d.ts +2 -0
  143. package/security/account/account-routes.js +104 -0
  144. package/security/account/account-schema.d.ts +290 -0
  145. package/security/account/account-schema.js +166 -0
  146. package/security/account/account-service.d.ts +88 -0
  147. package/security/account/account-service.js +218 -0
  148. package/security/account/index.d.ts +3 -0
  149. package/security/account/index.js +19 -0
  150. package/security/api-key/api-key-auth.d.ts +4 -0
  151. package/security/api-key/api-key-auth.js +66 -0
  152. package/security/api-key/index.d.ts +1 -0
  153. package/security/api-key/index.js +17 -0
  154. package/security/auth-routes.d.ts +2 -0
  155. package/security/auth-routes.js +80 -0
  156. package/security/auth-schema.d.ts +215 -0
  157. package/security/auth-schema.js +129 -0
  158. package/security/auth-service.d.ts +117 -0
  159. package/security/auth-service.js +272 -0
  160. package/security/auth.d.ts +3 -0
  161. package/security/auth.js +127 -0
  162. package/security/basic/basic-auth.d.ts +4 -0
  163. package/security/basic/basic-auth.js +32 -0
  164. package/security/basic/index.d.ts +1 -0
  165. package/security/basic/index.js +17 -0
  166. package/security/create-auth-resources.d.ts +6 -0
  167. package/security/create-auth-resources.js +129 -0
  168. package/security/helper.d.ts +127 -0
  169. package/security/helper.js +329 -0
  170. package/security/index.d.ts +4 -0
  171. package/security/index.js +20 -0
  172. package/security/jwt/index.d.ts +2 -0
  173. package/security/jwt/index.js +18 -0
  174. package/security/jwt/jwt-auth.d.ts +4 -0
  175. package/security/jwt/jwt-auth.js +57 -0
  176. package/security/jwt/jwt-keys.d.ts +7 -0
  177. package/security/jwt/jwt-keys.js +43 -0
  178. package/security/oauth2/create-oauth2-plugin.d.ts +17 -0
  179. package/security/oauth2/create-oauth2-plugin.js +85 -0
  180. package/security/oauth2/index.d.ts +3 -0
  181. package/security/oauth2/index.js +19 -0
  182. package/security/oauth2/oauth2-custom.d.ts +7 -0
  183. package/security/oauth2/oauth2-custom.js +40 -0
  184. package/security/oauth2/oauth2-facebook.d.ts +1 -0
  185. package/security/oauth2/oauth2-facebook.js +30 -0
  186. package/security/oauth2/oauth2-google.d.ts +1 -0
  187. package/security/oauth2/oauth2-google.js +28 -0
  188. package/security/oauth2/oauth2-schema.d.ts +10 -0
  189. package/security/oauth2/oauth2-schema.js +53 -0
  190. package/security/recaptcha/index.d.ts +2 -0
  191. package/security/recaptcha/index.js +18 -0
  192. package/security/recaptcha/recaptcha-verify.d.ts +1 -0
  193. package/security/recaptcha/recaptcha-verify.js +33 -0
  194. package/security/recaptcha/recaptcha.d.ts +2 -0
  195. package/security/recaptcha/recaptcha.js +22 -0
  196. package/security/resources/api-key/model.d.ts +2 -0
  197. package/security/resources/api-key/model.js +63 -0
  198. package/security/resources/api-key/policy.d.ts +2 -0
  199. package/security/resources/api-key/policy.js +26 -0
  200. package/security/resources/api-key/routes.d.ts +2 -0
  201. package/security/resources/api-key/routes.js +15 -0
  202. package/security/resources/api-key/service.d.ts +3 -0
  203. package/security/resources/api-key/service.js +33 -0
  204. package/security/resources/one-time-token/model.d.ts +2 -0
  205. package/security/resources/one-time-token/model.js +32 -0
  206. package/security/resources/permission/model.d.ts +2 -0
  207. package/security/resources/permission/model.js +16 -0
  208. package/security/resources/role/model.d.ts +2 -0
  209. package/security/resources/role/model.js +22 -0
  210. package/security/store/database-security-store.d.ts +5 -0
  211. package/security/store/database-security-store.js +51 -0
  212. package/security/store/redis-security-store.d.ts +5 -0
  213. package/security/store/redis-security-store.js +32 -0
  214. package/seeder/create-seeder.d.ts +21 -0
  215. package/seeder/create-seeder.js +17 -0
  216. package/seeder/index.d.ts +2 -0
  217. package/seeder/index.js +18 -0
  218. package/seeder/resources/seeder/model.d.ts +2 -0
  219. package/seeder/resources/seeder/model.js +38 -0
  220. package/seeder/seeder.d.ts +20 -0
  221. package/seeder/seeder.js +175 -0
  222. package/server/create-server.d.ts +20 -0
  223. package/server/create-server.js +160 -0
  224. package/server/index.d.ts +4 -0
  225. package/server/index.js +20 -0
  226. package/server/info-route.d.ts +2 -0
  227. package/server/info-route.js +18 -0
  228. package/server/info-schema.d.ts +37 -0
  229. package/server/info-schema.js +19 -0
  230. package/server/register-model.d.ts +2 -0
  231. package/server/register-model.js +12 -0
  232. package/server/register-plugin.d.ts +2 -0
  233. package/server/register-plugin.js +13 -0
  234. package/server/register-route.d.ts +3 -0
  235. package/server/register-route.js +74 -0
  236. package/server/schemas.d.ts +3 -0
  237. package/server/schemas.js +30 -0
  238. package/server/swagger.d.ts +3 -0
  239. package/server/swagger.js +122 -0
  240. package/storage/file-route.d.ts +2 -0
  241. package/storage/file-route.js +39 -0
  242. package/storage/file-schema.d.ts +9 -0
  243. package/storage/file-schema.js +42 -0
  244. package/storage/file-service.d.ts +81 -0
  245. package/storage/file-service.js +384 -0
  246. package/storage/filesystem-storage.d.ts +10 -0
  247. package/storage/filesystem-storage.js +128 -0
  248. package/storage/index.d.ts +2 -0
  249. package/storage/index.js +18 -0
  250. package/storage/resources/file/model.d.ts +2 -0
  251. package/storage/resources/file/model.js +75 -0
  252. package/types/application-context.d.ts +20 -0
  253. package/types/application-context.js +2 -0
  254. package/types/auth.d.ts +31 -0
  255. package/types/auth.js +2 -0
  256. package/types/fastify-extensions.d.ts +24 -0
  257. package/types/fastify-extensions.js +4 -0
  258. package/types/generated.d.ts +193 -0
  259. package/types/generated.js +3 -0
  260. package/types/index.d.ts +4 -0
  261. package/types/index.js +20 -0
  262. package/types/server.d.ts +4 -0
  263. package/types/server.js +2 -0
  264. package/utils/export-util.d.ts +8 -0
  265. package/utils/export-util.js +25 -0
  266. package/utils/file-util.d.ts +64 -0
  267. package/utils/file-util.js +141 -0
  268. package/utils/index.d.ts +3 -0
  269. package/utils/index.js +19 -0
  270. package/utils/schema-util.d.ts +20 -0
  271. package/utils/schema-util.js +37 -0
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.infoSchema = exports.InfoResponse = void 0;
4
+ const typebox_1 = require("@sinclair/typebox");
5
+ const errors_1 = require("../errors");
6
+ const utils_1 = require("../utils");
7
+ exports.InfoResponse = typebox_1.Type.Object({
8
+ name: typebox_1.Type.String(),
9
+ version: typebox_1.Type.String()
10
+ }, { $id: 'InfoResponse' });
11
+ exports.infoSchema = {
12
+ tags: ['Info'],
13
+ summary: 'Application info',
14
+ description: 'Application info',
15
+ response: {
16
+ 200: (0, utils_1.createSchemaModel)(exports.InfoResponse),
17
+ ...errors_1.AllErrorResponses
18
+ }
19
+ };
@@ -0,0 +1,2 @@
1
+ import { TObject } from '@sinclair/typebox';
2
+ export declare function registerModel(schema: TObject, name?: string): void;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerModel = registerModel;
4
+ const common_1 = require("@appweaver/common");
5
+ const utils_1 = require("../utils");
6
+ function registerModel(schema, name) {
7
+ const refType = (0, utils_1.createSchemaModel)(schema, {
8
+ name,
9
+ addToServer: false
10
+ });
11
+ common_1.logger.debug({ modelName: refType.$ref }, 'Registered model');
12
+ }
@@ -0,0 +1,2 @@
1
+ import { Server } from '../types';
2
+ export declare function registerPlugin(name: string, plugin: (server: Server) => void, dependencies?: string[]): void;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.registerPlugin = registerPlugin;
7
+ const fastify_plugin_1 = __importDefault(require("fastify-plugin"));
8
+ const common_1 = require("@appweaver/common");
9
+ const context_1 = require("../context");
10
+ function registerPlugin(name, plugin, dependencies = []) {
11
+ (0, context_1.define)((0, fastify_plugin_1.default)(plugin, { name, dependencies }), common_1.PLUGIN, 'append');
12
+ common_1.logger.debug({ plugin: name, dependencies }, 'Registered plugin');
13
+ }
@@ -0,0 +1,3 @@
1
+ import { RouteCacheConfig, RouteConfig } from '@appweaver/common';
2
+ import { Router } from '../types';
3
+ export declare function registerRoute(handler: (router: Router) => void, config?: RouteConfig & RouteCacheConfig): void;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.registerRoute = registerRoute;
7
+ const fastify_1 = __importDefault(require("fastify"));
8
+ const typebox_1 = require("@sinclair/typebox");
9
+ const common_1 = require("@appweaver/common");
10
+ const context_1 = require("../context");
11
+ const security_1 = require("../security");
12
+ const errors_1 = require("../errors");
13
+ function registerRoute(handler, config) {
14
+ const routes = [];
15
+ const tempServer = (0, fastify_1.default)({
16
+ logger: false,
17
+ ajv: {
18
+ plugins: [(ajv) => ajv.addKeyword('example')]
19
+ }
20
+ });
21
+ tempServer.addHook('onRoute', (routeOptions) => {
22
+ routes.push(routeOptions);
23
+ });
24
+ tempServer.register(handler);
25
+ const routeBuilder = async (server) => {
26
+ const { authenticate, recaptcha } = server;
27
+ // Add all currently configured schemas to the temporary server
28
+ for (const [id, schema] of Object.entries(server.getSchemas())) {
29
+ if (!tempServer.getSchema(id)) {
30
+ tempServer.addSchema({ ...schema, $id: id });
31
+ }
32
+ }
33
+ // Route array will be filled via the 'onRoute' hook after this step
34
+ await tempServer.ready();
35
+ for (const route of routes) {
36
+ const recaptchaHeader = (0, security_1.recaptchaHeaderSchema)({
37
+ recaptcha: config?.recaptcha,
38
+ recaptchaAction: config?.recaptchaAction
39
+ });
40
+ // Merge received route schema with default values based on configuration
41
+ const mergedRoute = {
42
+ ...route,
43
+ schema: {
44
+ ...route.schema,
45
+ security: config?.public
46
+ ? []
47
+ : (0, security_1.authSchema)(config?.auth),
48
+ headers: route.schema?.headers
49
+ ? typebox_1.Type.Composite([
50
+ recaptchaHeader,
51
+ typebox_1.Type.Composite([route.schema.headers])
52
+ ])
53
+ : recaptchaHeader,
54
+ response: {
55
+ ...(route.schema?.response ?? {}),
56
+ ...errors_1.AllErrorResponses
57
+ }
58
+ },
59
+ onRequest: [
60
+ config?.public ? undefined : authenticate(config?.auth),
61
+ config?.recaptcha || config?.recaptchaAction ? recaptcha : undefined,
62
+ ...((0, common_1.isArray)(route.onRequest) ? route.onRequest : [route.onRequest])
63
+ ].filter((h) => h !== undefined),
64
+ config: {
65
+ ...config,
66
+ ...route.config
67
+ }
68
+ };
69
+ common_1.logger.debug({ method: mergedRoute.method, url: mergedRoute.url }, 'Registered route');
70
+ server.route(mergedRoute);
71
+ }
72
+ };
73
+ (0, context_1.define)(routeBuilder, common_1.ROUTE, 'append');
74
+ }
@@ -0,0 +1,3 @@
1
+ import { Server } from '../types';
2
+ declare const _default: (server: Server) => void;
3
+ export default _default;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const fastify_plugin_1 = __importDefault(require("fastify-plugin"));
7
+ const common_1 = require("@appweaver/common");
8
+ const context_1 = require("../context");
9
+ exports.default = (0, fastify_plugin_1.default)((server) => {
10
+ const usedSchemas = new Set();
11
+ // Add all resource models schemas
12
+ for (const model of context_1.context.resource.models.values()) {
13
+ for (const [suffix, property] of Object.entries(common_1.resourceModelProps)) {
14
+ const modelName = `${model.name}${suffix}`;
15
+ const modelSchema = model[property].$defs[modelName];
16
+ usedSchemas.add(modelSchema);
17
+ }
18
+ }
19
+ // Add additional schemas for registered models
20
+ const models = (0, context_1.injectAll)(common_1.MODEL);
21
+ for (const model of models) {
22
+ usedSchemas.add({ ...model.schema, $id: model.name });
23
+ }
24
+ // Add used schemas to the server instance
25
+ for (const schema of usedSchemas.values()) {
26
+ if (schema.$id && !server.getSchema(schema.$id)) {
27
+ server.addSchema({ ...schema });
28
+ }
29
+ }
30
+ });
@@ -0,0 +1,3 @@
1
+ import { Server } from '../types';
2
+ declare const _default: (server: Server) => void;
3
+ export default _default;
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const fastify_plugin_1 = __importDefault(require("fastify-plugin"));
7
+ const swagger_1 = __importDefault(require("@fastify/swagger"));
8
+ const swagger_ui_1 = __importDefault(require("@fastify/swagger-ui"));
9
+ const common_1 = require("@appweaver/common");
10
+ const context_1 = require("../context");
11
+ exports.default = (0, fastify_plugin_1.default)((server) => {
12
+ server.register(swagger_1.default, {
13
+ hideUntagged: common_1.config.SWAGGER_HIDE_UNTAGGED,
14
+ transformObject: (document) => addConfig(pruneUnusedSchemas(document)),
15
+ openapi: {
16
+ info: {
17
+ title: common_1.config.APP_NAME,
18
+ description: common_1.config.APP_DESCRIPTION,
19
+ version: common_1.config.APP_VERSION
20
+ },
21
+ externalDocs: {
22
+ url: 'https://swagger.io',
23
+ description: 'Find more info here'
24
+ },
25
+ servers: [
26
+ {
27
+ url: common_1.config.APP_HOSTNAME
28
+ }
29
+ ],
30
+ tags: [],
31
+ components: {
32
+ securitySchemes: {
33
+ bearer: {
34
+ scheme: 'bearer',
35
+ bearerFormat: 'token',
36
+ type: 'http'
37
+ },
38
+ ...(common_1.config.SECURITY_API_KEY_ENABLED
39
+ ? {
40
+ apiKeyAuth: {
41
+ type: 'apiKey',
42
+ in: 'header',
43
+ name: common_1.config.SECURITY_API_KEY_HEADER_NAME
44
+ }
45
+ }
46
+ : {}),
47
+ ...(common_1.config.SECURITY_BASIC_ENABLED
48
+ ? {
49
+ basicAuth: {
50
+ type: 'http',
51
+ scheme: 'basic'
52
+ }
53
+ }
54
+ : {})
55
+ }
56
+ }
57
+ }
58
+ });
59
+ if (common_1.config.SWAGGER_ENABLED) {
60
+ server.register(swagger_ui_1.default, {
61
+ routePrefix: common_1.config.SWAGGER_PATH,
62
+ indexPrefix: new URL(common_1.config.APP_HOSTNAME).pathname,
63
+ staticCSP: false
64
+ });
65
+ }
66
+ });
67
+ function pruneUnusedSchemas(document) {
68
+ const schemas = document.openapiObject.components?.schemas ?? {};
69
+ const used = new Set();
70
+ const visit = (node) => {
71
+ if (!node || typeof node !== 'object')
72
+ return;
73
+ if (typeof node.$ref === 'string') {
74
+ const match = node.$ref.match(/^#\/components\/schemas\/(.+)$/);
75
+ if (match) {
76
+ const schemaName = match[1];
77
+ if (!used.has(schemaName)) {
78
+ used.add(schemaName);
79
+ visit(schemas[schemaName]);
80
+ }
81
+ }
82
+ }
83
+ if (Array.isArray(node)) {
84
+ for (const item of node)
85
+ visit(item);
86
+ return;
87
+ }
88
+ for (const value of Object.values(node)) {
89
+ visit(value);
90
+ }
91
+ };
92
+ visit(document.openapiObject.paths);
93
+ if (document.openapiObject.components?.schemas) {
94
+ document.openapiObject.components.schemas = Object.fromEntries(Object.entries(document.openapiObject.components.schemas)
95
+ .sort(([nameA, objA], [nameB, objB]) => String(objA.title ?? nameA).localeCompare(String(objB.title ?? nameB)))
96
+ .filter(([name]) => used.has(name)));
97
+ }
98
+ return document.openapiObject;
99
+ }
100
+ function addConfig(document) {
101
+ const normalizePath = (path) => {
102
+ const withLeadingSlash = path.startsWith('/') ? path : `/${path}`;
103
+ return withLeadingSlash.endsWith('/') && withLeadingSlash.length > 1
104
+ ? withLeadingSlash.slice(0, -1)
105
+ : withLeadingSlash;
106
+ };
107
+ document[`x-${common_1.CONFIG_NAME}-config`] = {
108
+ resourcePaths: [...context_1.context.resource.routes.values()].map((r) => ({
109
+ name: r.config.modelName,
110
+ basePath: normalizePath(r.basePath)
111
+ })),
112
+ routePrefixes: {
113
+ api: normalizePath(common_1.config.SERVER_API_PREFIX),
114
+ static: normalizePath(common_1.config.SERVER_STATIC_ROUTE_PREFIX),
115
+ health: normalizePath(common_1.config.HEALTH_CHECK_ROUTE_PREFIX),
116
+ auth: normalizePath(common_1.config.SECURITY_ROUTE_PREFIX),
117
+ account: normalizePath(common_1.config.SECURITY_ACCOUNT_ROUTE_PREFIX),
118
+ files: normalizePath(common_1.config.STORAGE_FILES_ROUTE_PREFIX)
119
+ }
120
+ };
121
+ return document;
122
+ }
@@ -0,0 +1,2 @@
1
+ import { Server } from '../types';
2
+ export declare function files(server: Server): void;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.files = files;
4
+ const common_1 = require("@appweaver/common");
5
+ const file_service_1 = require("./file-service");
6
+ const file_schema_1 = require("./file-schema");
7
+ const context_1 = require("../context");
8
+ function files(server) {
9
+ const { authenticate } = server;
10
+ const fileService = (0, context_1.inject)(file_service_1.FileService);
11
+ const addHeaders = (reply, data, hasRange) => {
12
+ reply.header('Accept-Ranges', 'bytes');
13
+ if (hasRange) {
14
+ reply.header('Content-Range', `bytes ${data.start}-${data.end}/${data.content.size}`);
15
+ }
16
+ reply.header('Content-Length', hasRange ? data.end - data.start + 1 : data.content.size);
17
+ reply.header('Content-Type', data.mimeType ?? 'application/octet-stream');
18
+ reply.header('Content-Disposition', 'inline; filename="' + data.fileName + '"');
19
+ reply.header('Pragma', 'public');
20
+ reply.header('Cache-Control', `public, max-age=${Math.floor(common_1.config.STORAGE_CACHE_TTL / 1000)}`);
21
+ reply.header('Expires', new Date(Date.now() + common_1.config.STORAGE_CACHE_TTL).toUTCString());
22
+ return hasRange ? 206 : 200;
23
+ };
24
+ server.get('/public/*', {
25
+ schema: (0, file_schema_1.createFileAccessSchema)(true)
26
+ }, async (request, reply) => {
27
+ const data = await fileService.stream(request.params['*'], request.headers.range);
28
+ const code = addHeaders(reply, data, !!request.headers.range);
29
+ return reply.status(code).send(data.content.stream);
30
+ });
31
+ server.get('/protected/*', {
32
+ schema: (0, file_schema_1.createFileAccessSchema)(false),
33
+ onRequest: authenticate()
34
+ }, async (request, reply) => {
35
+ const data = await fileService.stream(request.params['*'], request.headers.range);
36
+ const code = addHeaders(reply, data, !!request.headers.range);
37
+ return reply.status(code).send(data.content.stream);
38
+ });
39
+ }
@@ -0,0 +1,9 @@
1
+ import { RouteSchema } from '@appweaver/common';
2
+ export declare const FileName: import("@sinclair/typebox").TObject<{
3
+ '*': import("@sinclair/typebox").TString;
4
+ }>;
5
+ export declare const FileRangeHeader: import("@sinclair/typebox").TObject<{
6
+ Range: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
7
+ }>;
8
+ export declare const FileResponse: import("@sinclair/typebox").TString;
9
+ export declare function createFileAccessSchema(isPublic: boolean): RouteSchema;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FileResponse = exports.FileRangeHeader = exports.FileName = void 0;
4
+ exports.createFileAccessSchema = createFileAccessSchema;
5
+ const typebox_1 = require("@sinclair/typebox");
6
+ const errors_1 = require("../errors");
7
+ exports.FileName = typebox_1.Type.Object({
8
+ '*': typebox_1.Type.String()
9
+ });
10
+ exports.FileRangeHeader = typebox_1.Type.Object({
11
+ Range: typebox_1.Type.Optional(typebox_1.Type.String({ example: 'bytes=0-1023' }))
12
+ });
13
+ exports.FileResponse = typebox_1.Type.String({ format: 'binary' });
14
+ function createFileAccessSchema(isPublic) {
15
+ return {
16
+ tags: ['Files'],
17
+ security: isPublic ? [] : [{ bearer: [] }],
18
+ summary: `Fetch ${isPublic ? 'public' : 'protected'} files`,
19
+ description: `Fetch ${isPublic ? 'public' : 'protected'} files`,
20
+ response: {
21
+ 200: {
22
+ description: 'Binary file content',
23
+ content: {
24
+ 'application/octet-stream': {
25
+ schema: exports.FileResponse
26
+ }
27
+ }
28
+ },
29
+ 206: {
30
+ description: 'Binary partial file content',
31
+ content: {
32
+ 'application/octet-stream': {
33
+ schema: exports.FileResponse
34
+ }
35
+ }
36
+ },
37
+ ...errors_1.AllErrorResponses
38
+ },
39
+ params: exports.FileName,
40
+ headers: exports.FileRangeHeader
41
+ };
42
+ }
@@ -0,0 +1,81 @@
1
+ import { Multipart, MultipartFile } from '@fastify/multipart';
2
+ import { ContentStream, Resource, ResourceClient } from '@appweaver/common';
3
+ import { File } from '../types';
4
+ export type FileStream = {
5
+ content: ContentStream;
6
+ fileName: string;
7
+ mimeType: string;
8
+ start: number;
9
+ end: number;
10
+ };
11
+ export declare class FileService {
12
+ /**
13
+ * Searches for a file by its name from a database.
14
+ *
15
+ * @param {string} fileName - The name of the file to search for.
16
+ * @return {Promise<File>} A promise that resolves to the file object if found.
17
+ * @throws {HttpError} Throws an error if a database error occurs or if the file is not found.
18
+ */
19
+ findByName(fileName: string): Promise<File>;
20
+ /**
21
+ * Streams a file from storage, handling authorization and range-based requests.
22
+ *
23
+ * @param {string} fileName - The name of the file to stream.
24
+ * @param {string} [range] - An optional range header specifying the byte range to stream.
25
+ * @return {Promise<FileStream>} A promise that resolves to a file stream object containing the content, metadata, and
26
+ * range details.
27
+ * @throws {HttpError} Throws a 404 error if the file does not exist.
28
+ * @throws {HttpError} Throws a 403 error if user access to the file is forbidden.
29
+ * @throws {HttpError} Throws a 500 error if an error occurs while reading the file from storage.
30
+ */
31
+ stream(fileName: string, range?: string): Promise<FileStream>;
32
+ /**
33
+ * Saves a file to storage, validates its properties, and associates it with a specific resource and client.
34
+ *
35
+ * @param {MultipartFile} data The multipart file object containing the file data, field name, filename, and metadata.
36
+ * @param {Resource} resource The resource object with which the file is being associated.
37
+ * @param {ResourceClient} client The database client responsible for handling the resource.
38
+ * @return {Promise<File>} A promise that resolves to the saved file object or rejects with an error if the operation
39
+ * fails.
40
+ * @throws {HttpError} Throws an error if file validation, storage, or resource association fails.
41
+ */
42
+ saveFile(data: MultipartFile, resource: Resource, client: ResourceClient): Promise<File>;
43
+ /**
44
+ * Saves files received as an asynchronous iterable of multipart data.
45
+ *
46
+ * @param {AsyncIterableIterator<Multipart>} parts - The asynchronous iterable providing multipart data where each
47
+ * part is expected to represent a file or other data.
48
+ * @param {Resource} resource - The resource associated with the files being saved, providing additional contextual
49
+ * information.
50
+ * @param {ResourceClient} client - The database client responsible for handling resource-related operations, such as
51
+ * database interaction.
52
+ * @return {Promise<File[]>} A promise that resolves to an array of successfully saved files. Rejects with an error
53
+ * if one or more files fail to save.
54
+ */
55
+ saveFiles(parts: AsyncIterableIterator<Multipart>, resource: Resource, client: ResourceClient): Promise<File[]>;
56
+ /**
57
+ * Deletes a file from the storage and database if it meets the specified conditions.
58
+ *
59
+ * @param {string} fileName - The name of the file to be deleted.
60
+ * @param {string} fieldName - The field associated with the resource to which the file belongs.
61
+ * @param {Resource} resource - The resource that the file is associated with.
62
+ * @param {ResourceClient} client - The client instance representing the resource's type.
63
+ * @return {Promise<File>} A promise that resolves with the deleted file information upon successful deletion.
64
+ * @throws {HttpError} If the file is not associated with the provided resource or client,
65
+ * if the current user does not have permission to delete the file,
66
+ * if there is an error removing the file from storage,
67
+ * or if there is an error deleting the file from the database.
68
+ */
69
+ deleteFile(fileName: string, fieldName: string, resource: Resource, client: ResourceClient): Promise<File>;
70
+ /**
71
+ * Deletes a list of files associated with a given resource using the provided resource client.
72
+ *
73
+ * @param {Record<string, string | string[]>} fileNames - An object where the keys correspond to file fields and the
74
+ * values are either a string (single file name) or an array of file names to be deleted.
75
+ * @param {Resource} resource - The resource instance associated with the files to be deleted.
76
+ * @param {ResourceClient} client - The resource a client used to handle deletion operations.
77
+ * @return {Promise<File[]>} A promise that resolves to an array of files that were successfully deleted. Rejects with
78
+ * an error if no files could be deleted.
79
+ */
80
+ deleteFiles(fileNames: Record<string, string | string[]>, resource: Resource, client: ResourceClient): Promise<File[]>;
81
+ }