@openapi-typescript-infra/service 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 (121) hide show
  1. package/.eslintignore +7 -0
  2. package/.eslintrc.js +14 -0
  3. package/.github/workflows/codeql-analysis.yml +74 -0
  4. package/.github/workflows/nodejs.yml +23 -0
  5. package/.github/workflows/npmpublish.yml +35 -0
  6. package/.husky/pre-commit +6 -0
  7. package/.prettierrc.js +14 -0
  8. package/@types/config.d.ts +56 -0
  9. package/CHANGELOG.md +5 -0
  10. package/LICENSE +21 -0
  11. package/README.md +28 -0
  12. package/SECURITY.md +12 -0
  13. package/__tests__/config.test.ts +31 -0
  14. package/__tests__/fake-serv/api/fake-serv.yaml +48 -0
  15. package/__tests__/fake-serv/config/config.json +15 -0
  16. package/__tests__/fake-serv/src/handlers/hello.ts +10 -0
  17. package/__tests__/fake-serv/src/index.ts +29 -0
  18. package/__tests__/fake-serv/src/routes/error.ts +13 -0
  19. package/__tests__/fake-serv/src/routes/index.ts +22 -0
  20. package/__tests__/fake-serv/src/routes/other/world.ts +7 -0
  21. package/__tests__/fake-serv.test.ts +74 -0
  22. package/build/bin/start-service.d.ts +2 -0
  23. package/build/bin/start-service.js +31 -0
  24. package/build/bin/start-service.js.map +1 -0
  25. package/build/bootstrap.d.ts +16 -0
  26. package/build/bootstrap.js +90 -0
  27. package/build/bootstrap.js.map +1 -0
  28. package/build/config/index.d.ts +10 -0
  29. package/build/config/index.js +98 -0
  30. package/build/config/index.js.map +1 -0
  31. package/build/config/schema.d.ts +48 -0
  32. package/build/config/schema.js +3 -0
  33. package/build/config/schema.js.map +1 -0
  34. package/build/config/shortstops.d.ts +31 -0
  35. package/build/config/shortstops.js +109 -0
  36. package/build/config/shortstops.js.map +1 -0
  37. package/build/config/types.d.ts +3 -0
  38. package/build/config/types.js +3 -0
  39. package/build/config/types.js.map +1 -0
  40. package/build/development/port-finder.d.ts +1 -0
  41. package/build/development/port-finder.js +41 -0
  42. package/build/development/port-finder.js.map +1 -0
  43. package/build/development/repl.d.ts +2 -0
  44. package/build/development/repl.js +29 -0
  45. package/build/development/repl.js.map +1 -0
  46. package/build/env.d.ts +2 -0
  47. package/build/env.js +19 -0
  48. package/build/env.js.map +1 -0
  49. package/build/error.d.ts +25 -0
  50. package/build/error.js +28 -0
  51. package/build/error.js.map +1 -0
  52. package/build/express-app/app.d.ts +6 -0
  53. package/build/express-app/app.js +327 -0
  54. package/build/express-app/app.js.map +1 -0
  55. package/build/express-app/index.d.ts +2 -0
  56. package/build/express-app/index.js +19 -0
  57. package/build/express-app/index.js.map +1 -0
  58. package/build/express-app/internal-server.d.ts +3 -0
  59. package/build/express-app/internal-server.js +34 -0
  60. package/build/express-app/internal-server.js.map +1 -0
  61. package/build/express-app/route-loader.d.ts +2 -0
  62. package/build/express-app/route-loader.js +46 -0
  63. package/build/express-app/route-loader.js.map +1 -0
  64. package/build/express-app/types.d.ts +14 -0
  65. package/build/express-app/types.js +3 -0
  66. package/build/express-app/types.js.map +1 -0
  67. package/build/index.d.ts +8 -0
  68. package/build/index.js +25 -0
  69. package/build/index.js.map +1 -0
  70. package/build/openapi.d.ts +5 -0
  71. package/build/openapi.js +78 -0
  72. package/build/openapi.js.map +1 -0
  73. package/build/service-calls/index.d.ts +16 -0
  74. package/build/service-calls/index.js +85 -0
  75. package/build/service-calls/index.js.map +1 -0
  76. package/build/telemetry/fetchInstrumentation.d.ts +50 -0
  77. package/build/telemetry/fetchInstrumentation.js +144 -0
  78. package/build/telemetry/fetchInstrumentation.js.map +1 -0
  79. package/build/telemetry/index.d.ts +6 -0
  80. package/build/telemetry/index.js +80 -0
  81. package/build/telemetry/index.js.map +1 -0
  82. package/build/telemetry/instrumentations.d.ts +29 -0
  83. package/build/telemetry/instrumentations.js +47 -0
  84. package/build/telemetry/instrumentations.js.map +1 -0
  85. package/build/telemetry/requestLogger.d.ts +6 -0
  86. package/build/telemetry/requestLogger.js +144 -0
  87. package/build/telemetry/requestLogger.js.map +1 -0
  88. package/build/tsconfig.build.tsbuildinfo +1 -0
  89. package/build/types.d.ts +77 -0
  90. package/build/types.js +3 -0
  91. package/build/types.js.map +1 -0
  92. package/config/config.json +31 -0
  93. package/config/development.json +11 -0
  94. package/config/test.json +5 -0
  95. package/jest.config.js +14 -0
  96. package/package.json +111 -0
  97. package/src/bin/start-service.ts +28 -0
  98. package/src/bootstrap.ts +112 -0
  99. package/src/config/index.ts +115 -0
  100. package/src/config/schema.ts +66 -0
  101. package/src/config/shortstops.ts +118 -0
  102. package/src/config/types.ts +5 -0
  103. package/src/development/port-finder.ts +40 -0
  104. package/src/development/repl.ts +24 -0
  105. package/src/env.ts +14 -0
  106. package/src/error.ts +44 -0
  107. package/src/express-app/app.ts +399 -0
  108. package/src/express-app/index.ts +2 -0
  109. package/src/express-app/internal-server.ts +31 -0
  110. package/src/express-app/route-loader.ts +48 -0
  111. package/src/express-app/types.ts +31 -0
  112. package/src/index.ts +8 -0
  113. package/src/openapi.ts +67 -0
  114. package/src/service-calls/index.ts +129 -0
  115. package/src/telemetry/fetchInstrumentation.ts +209 -0
  116. package/src/telemetry/index.ts +69 -0
  117. package/src/telemetry/instrumentations.ts +54 -0
  118. package/src/telemetry/requestLogger.ts +193 -0
  119. package/src/types.ts +139 -0
  120. package/tsconfig.build.json +10 -0
  121. package/tsconfig.json +36 -0
package/src/types.ts ADDED
@@ -0,0 +1,139 @@
1
+ import type { Server } from 'http';
2
+
3
+ import type pino from 'pino';
4
+ import type { Request, Response } from 'express';
5
+ import type { Application } from 'express-serve-static-core';
6
+ import type { middleware } from 'express-openapi-validator';
7
+ import type { Meter, MeterProvider } from '@opentelemetry/api-metrics';
8
+
9
+ import type { ConfigStore } from './config/types';
10
+
11
+ export interface InternalLocals extends Record<string, unknown> {
12
+ server?: Server;
13
+ meterProvider: MeterProvider;
14
+ mainApp: ServiceExpress;
15
+ }
16
+
17
+ export type ServiceLogger = pino.BaseLogger & Pick<pino.Logger, 'isLevelEnabled'>;
18
+
19
+ // Vanilla express wants this to extend Record<string, any> but this is a mistake
20
+ // because you lose type checking on it, even though I get that underneath it truly
21
+ // is Record<string, any>
22
+ export interface ServiceLocals {
23
+ service: Service;
24
+ name: string;
25
+ logger: ServiceLogger;
26
+ config: ConfigStore;
27
+ meter: Meter;
28
+ internalApp: Application<InternalLocals>;
29
+ }
30
+
31
+ export interface RequestLocals {
32
+ // Set this to true during the request "attachment" and if there is a body,
33
+ // it will be set to the buffer before API and route handlers run.
34
+ rawBody?: Buffer | true;
35
+ logger: ServiceLogger;
36
+ }
37
+
38
+ export type ServiceExpress<Locals extends ServiceLocals = ServiceLocals> = Application<Locals>;
39
+ export type RequestWithApp<Locals extends ServiceLocals = ServiceLocals> = Omit<Request, 'app'> & {
40
+ app: Application<Locals>;
41
+ };
42
+ export type ResponseFromApp<
43
+ ResBody = unknown,
44
+ RLocals extends RequestLocals = RequestLocals,
45
+ > = Response<ResBody, RLocals>;
46
+
47
+ /**
48
+ * This is the core type you need to implement to provide a service
49
+ */
50
+ export interface Service<
51
+ SLocals extends ServiceLocals = ServiceLocals,
52
+ RLocals extends RequestLocals = RequestLocals,
53
+ > {
54
+ name?: string;
55
+
56
+ // Modify options used for application start
57
+ configure?: (
58
+ startOptions: ServiceStartOptions<SLocals, RLocals>,
59
+ options: ServiceOptions,
60
+ ) => ServiceOptions;
61
+
62
+ start(app: ServiceExpress<SLocals>): void | Promise<void>;
63
+ stop?: (app: ServiceExpress<SLocals>) => void | Promise<void>;
64
+
65
+ healthy?: (app: ServiceExpress<SLocals>) => boolean | Promise<boolean>;
66
+
67
+ // This runs as middleware right BEFORE the body parsers.
68
+ // If you want to run AFTER the body parsers, the current
69
+ // way to do that would be via /routes/index.ts and router.use()
70
+ // in that file.
71
+ onRequest?(req: RequestWithApp<SLocals>, res: Response<unknown, RLocals>): void | Promise<void>;
72
+
73
+ // This runs after body parsing but before routing
74
+ authorize?(req: RequestWithApp<SLocals>, res: Response<unknown, RLocals>): boolean | Promise<boolean>;
75
+
76
+ // Add or redact any fields for logging. Note this will be called twice per request,
77
+ // once at the start and once at the end. Modify the values directly.
78
+ getLogFields?(req: RequestWithApp<SLocals>, values: Record<string, string | string[] | number | undefined>): void;
79
+ }
80
+
81
+ export type ServiceFactory<
82
+ SLocals extends ServiceLocals = ServiceLocals,
83
+ RLocals extends RequestLocals = RequestLocals,
84
+ > = () => Service<SLocals, RLocals>;
85
+
86
+ export interface ServiceStartOptions<
87
+ SLocals extends ServiceLocals = ServiceLocals,
88
+ RLocals extends RequestLocals = RequestLocals,
89
+ > {
90
+ name: string;
91
+ rootDirectory: string;
92
+
93
+ // Defaults to "build", but can be set to "src" to run off non-built source
94
+ codepath?: 'build' | 'src';
95
+
96
+ // NOTE: if you use this, you need to cast it because of a Typescript error:
97
+ // https://github.com/microsoft/TypeScript/issues/22229
98
+ // locals: { stuff } as Partial<MyLocals>
99
+ locals?: Partial<SLocals>;
100
+
101
+ // And finally, the function that creates the service instance
102
+ service: () => Service<SLocals, RLocals>;
103
+ }
104
+
105
+ export interface DelayLoadServiceStartOptions extends Omit<ServiceStartOptions, 'service'> {
106
+ service: string;
107
+ }
108
+
109
+ // Handled by service.configure
110
+ export interface ServiceOptions {
111
+ // If you need multiple configuration directories, pass them here
112
+ // in the desired order (later trumps earlier)
113
+ configurationDirectories: string[];
114
+
115
+ // Add or control OpenAPI options such as security handlers
116
+ openApiOptions?: Parameters<typeof middleware>[0];
117
+ }
118
+
119
+ export interface ServiceLike<SLocals extends ServiceLocals = ServiceLocals> {
120
+ locals: SLocals;
121
+ }
122
+
123
+ /**
124
+ * This type should be used (or extended) to pass "context"
125
+ * into functions not directly wired into the Express request
126
+ * handling flow. It will allow "synthetic" requests to be
127
+ * easily constructed without depending on things they should not,
128
+ * like query strings or body or similar. Most often, you want the
129
+ * logger.
130
+ */
131
+ export interface RequestLike<
132
+ SLocals extends ServiceLocals = ServiceLocals,
133
+ RLocals extends RequestLocals = RequestLocals,
134
+ > {
135
+ app: ServiceLike<SLocals>;
136
+ res: {
137
+ locals: RLocals;
138
+ };
139
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "exclude": [
4
+ "src/**/*.spec.ts",
5
+ "src/**/*.test.ts",
6
+ "__tests__/**/*.ts",
7
+ "__mocks__/**/*.ts",
8
+ "coconfig.ts"
9
+ ]
10
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "include": [
3
+ "@types/**/*",
4
+ "src/**/*",
5
+ "__tests__/**/*",
6
+ "__mocks__/**/*",
7
+ "coconfig.ts"
8
+ ],
9
+ "exclude": [
10
+ "node_modules",
11
+ "build"
12
+ ],
13
+ "ts-node": {
14
+ "transpileOnly": true,
15
+ "files": true
16
+ },
17
+ "compilerOptions": {
18
+ "lib": [
19
+ "ES2022",
20
+ "DOM"
21
+ ],
22
+ "module": "CommonJS",
23
+ "target": "ES2022",
24
+ "declaration": true,
25
+ "sourceMap": true,
26
+ "outDir": "./build",
27
+ "incremental": true,
28
+ "isolatedModules": true,
29
+ "strict": true,
30
+ "moduleResolution": "NodeNext",
31
+ "baseUrl": "./src",
32
+ "allowSyntheticDefaultImports": true,
33
+ "esModuleInterop": true,
34
+ "experimentalDecorators": true
35
+ }
36
+ }