@facetlayer/prism-framework 0.4.0 → 0.4.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 (130) hide show
  1. package/README.md +176 -8
  2. package/dist/Errors.d.ts +38 -0
  3. package/dist/Errors.d.ts.map +1 -0
  4. package/dist/Metrics.d.ts +5 -0
  5. package/dist/Metrics.d.ts.map +1 -0
  6. package/dist/RequestContext.d.ts +17 -0
  7. package/dist/RequestContext.d.ts.map +1 -0
  8. package/dist/ServiceDefinition.d.ts +16 -0
  9. package/dist/ServiceDefinition.d.ts.map +1 -0
  10. package/dist/app/PrismApp.d.ts +31 -0
  11. package/dist/app/PrismApp.d.ts.map +1 -0
  12. package/dist/app/callEndpoint.d.ts +13 -0
  13. package/dist/app/callEndpoint.d.ts.map +1 -0
  14. package/dist/app/validateApp.d.ts +20 -0
  15. package/dist/app/validateApp.d.ts.map +1 -0
  16. package/dist/authorization/AuthSource.d.ts +8 -0
  17. package/dist/authorization/AuthSource.d.ts.map +1 -0
  18. package/dist/authorization/Authorization.d.ts +24 -0
  19. package/dist/authorization/Authorization.d.ts.map +1 -0
  20. package/dist/authorization/Resource.d.ts +5 -0
  21. package/dist/authorization/Resource.d.ts.map +1 -0
  22. package/dist/authorization/index.d.ts +5 -0
  23. package/dist/authorization/index.d.ts.map +1 -0
  24. package/dist/cli.js +1 -1
  25. package/dist/databases/DatabaseInitializationOptions.d.ts +9 -0
  26. package/dist/databases/DatabaseInitializationOptions.d.ts.map +1 -0
  27. package/dist/databases/DatabaseSetup.d.ts +3 -0
  28. package/dist/databases/DatabaseSetup.d.ts.map +1 -0
  29. package/dist/endpoints/createEndpoint.d.ts +4 -0
  30. package/dist/endpoints/createEndpoint.d.ts.map +1 -0
  31. package/dist/endpoints/getEffectiveOperationId.d.ts +19 -0
  32. package/dist/endpoints/getEffectiveOperationId.d.ts.map +1 -0
  33. package/dist/env/Env.d.ts +2 -0
  34. package/dist/env/Env.d.ts.map +1 -0
  35. package/dist/index.d.ts +34 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +1364 -0
  38. package/dist/launch/launchConfig.d.ts +18 -0
  39. package/dist/launch/launchConfig.d.ts.map +1 -0
  40. package/dist/logging/index.d.ts +9 -0
  41. package/dist/logging/index.d.ts.map +1 -0
  42. package/dist/sse/ConnectionManager.d.ts +23 -0
  43. package/dist/sse/ConnectionManager.d.ts.map +1 -0
  44. package/dist/stdin/StdinServer.d.ts +38 -0
  45. package/dist/stdin/StdinServer.d.ts.map +1 -0
  46. package/dist/web/EndpointListing.d.ts +3 -0
  47. package/dist/web/EndpointListing.d.ts.map +1 -0
  48. package/dist/web/ExpressAppSetup.d.ts +18 -0
  49. package/dist/web/ExpressAppSetup.d.ts.map +1 -0
  50. package/dist/web/ExpressEndpointSetup.d.ts +31 -0
  51. package/dist/web/ExpressEndpointSetup.d.ts.map +1 -0
  52. package/dist/web/SseResponse.d.ts +15 -0
  53. package/dist/web/SseResponse.d.ts.map +1 -0
  54. package/dist/web/ViteIntegration.d.ts +19 -0
  55. package/dist/web/ViteIntegration.d.ts.map +1 -0
  56. package/dist/web/corsMiddleware.d.ts +14 -0
  57. package/dist/web/corsMiddleware.d.ts.map +1 -0
  58. package/dist/web/localhostOnlyMiddleware.d.ts +3 -0
  59. package/dist/web/localhostOnlyMiddleware.d.ts.map +1 -0
  60. package/dist/web/openapi/OpenAPI.d.ts +37 -0
  61. package/dist/web/openapi/OpenAPI.d.ts.map +1 -0
  62. package/dist/web/openapi/validateServicesForOpenapi.d.ts +32 -0
  63. package/dist/web/openapi/validateServicesForOpenapi.d.ts.map +1 -0
  64. package/dist/web/requestContextMiddleware.d.ts +3 -0
  65. package/dist/web/requestContextMiddleware.d.ts.map +1 -0
  66. package/docs/authorization.md +281 -0
  67. package/docs/cors-setup.md +172 -0
  68. package/docs/creating-services.md +220 -0
  69. package/docs/database-setup.md +134 -0
  70. package/docs/endpoint-tools.md +1 -11
  71. package/docs/env-files.md +12 -1
  72. package/docs/error-handling.md +70 -0
  73. package/docs/getting-started.md +22 -12
  74. package/docs/launch-configuration.md +223 -0
  75. package/docs/overview.md +62 -0
  76. package/docs/server-setup.md +144 -0
  77. package/docs/source-directory-organization.md +115 -0
  78. package/docs/stdin-protocol.md +176 -0
  79. package/package.json +42 -9
  80. package/src/Errors.ts +120 -0
  81. package/src/Metrics.ts +53 -0
  82. package/src/RequestContext.ts +36 -0
  83. package/src/ServiceDefinition.ts +35 -0
  84. package/src/__tests__/Authorization.test.ts +350 -0
  85. package/src/__tests__/Errors.test.ts +378 -0
  86. package/src/__tests__/ListEndpoints.test.ts +98 -0
  87. package/src/__tests__/PrismApp.test.ts +274 -0
  88. package/src/__tests__/RequestContext.test.ts +295 -0
  89. package/src/__tests__/SseResponse.test.ts +189 -0
  90. package/src/__tests__/StdinServer.test.ts +304 -0
  91. package/src/__tests__/corsMiddleware.test.ts +293 -0
  92. package/src/__tests__/createEndpoint.test.ts +412 -0
  93. package/src/__tests__/validateApp.test.ts +206 -0
  94. package/src/app/PrismApp.ts +117 -0
  95. package/src/app/callEndpoint.ts +55 -0
  96. package/src/app/validateApp.ts +78 -0
  97. package/src/authorization/AuthSource.ts +14 -0
  98. package/src/authorization/Authorization.ts +78 -0
  99. package/src/authorization/Resource.ts +8 -0
  100. package/src/authorization/index.ts +4 -0
  101. package/src/databases/DatabaseInitializationOptions.ts +9 -0
  102. package/src/databases/DatabaseSetup.ts +19 -0
  103. package/src/endpoints/createEndpoint.ts +39 -0
  104. package/src/endpoints/getEffectiveOperationId.ts +90 -0
  105. package/src/env/Env.ts +23 -0
  106. package/src/index.ts +78 -0
  107. package/src/launch/launchConfig.ts +59 -0
  108. package/src/list-endpoints-command.ts +1 -1
  109. package/src/logging/index.ts +25 -0
  110. package/src/sse/ConnectionManager.ts +79 -0
  111. package/src/stdin/StdinServer.ts +129 -0
  112. package/src/web/EndpointListing.ts +166 -0
  113. package/src/web/ExpressAppSetup.ts +125 -0
  114. package/src/web/ExpressEndpointSetup.ts +178 -0
  115. package/src/web/SseResponse.ts +78 -0
  116. package/src/web/ViteIntegration.ts +72 -0
  117. package/src/web/__tests__/OpenAPI.invalidZodSchemas.test.ts +250 -0
  118. package/src/web/corsMiddleware.ts +63 -0
  119. package/src/web/localhostOnlyMiddleware.ts +19 -0
  120. package/src/web/openapi/OpenAPI.ts +248 -0
  121. package/src/web/openapi/validateServicesForOpenapi.ts +76 -0
  122. package/src/web/requestContextMiddleware.ts +25 -0
  123. package/.claude/settings.local.json +0 -20
  124. package/CHANGELOG +0 -28
  125. package/CLAUDE.md +0 -44
  126. package/build.mts +0 -8
  127. package/test/call-command.test.ts +0 -96
  128. package/test/generate-api-clients.test.ts +0 -33
  129. package/test/generate-api-clients.test.ts.disabled +0 -75
  130. package/tsconfig.json +0 -21
@@ -0,0 +1,18 @@
1
+ import type { DatabaseInitializationOptions } from '../databases/DatabaseInitializationOptions.ts';
2
+ import type { LoadDatabaseFn } from '@facetlayer/sqlite-wrapper';
3
+ export interface LoggingSettings {
4
+ databaseFilename: string;
5
+ enableConsoleLogging: boolean;
6
+ loadDatabase: LoadDatabaseFn;
7
+ }
8
+ export interface LaunchConfig {
9
+ logging?: LoggingSettings;
10
+ database?: {
11
+ [databaseName: string]: DatabaseInitializationOptions;
12
+ };
13
+ }
14
+ export declare function getLaunchConfig(): LaunchConfig;
15
+ export declare function setLaunchConfig(config: LaunchConfig): void;
16
+ export declare function getDatabaseConfig(databaseName: string): DatabaseInitializationOptions;
17
+ export declare function getLoggingConfig(): LoggingSettings;
18
+ //# sourceMappingURL=launchConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launchConfig.d.ts","sourceRoot":"","sources":["../../src/launch/launchConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,+CAA+C,CAAC;AACnG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AASjE,MAAM,WAAW,eAAe;IAC9B,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,YAAY,EAAE,cAAc,CAAC;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,QAAQ,CAAC,EAAE;QACT,CAAC,YAAY,EAAE,MAAM,GAAG,6BAA6B,CAAC;KACvD,CAAC;CACH;AAID,wBAAgB,eAAe,IAAI,YAAY,CAK9C;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAK1D;AAED,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,6BAA6B,CAYrF;AAED,wBAAgB,gBAAgB,IAAI,eAAe,CAKlD"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * When enabled, logInfo writes to stderr instead of stdout.
3
+ * This is used in stdin protocol mode to avoid corrupting the JSON protocol on stdout.
4
+ */
5
+ export declare function setLogStderr(enabled: boolean): void;
6
+ export declare function logInfo(...args: any[]): void;
7
+ export declare function logWarn(...args: any[]): void;
8
+ export declare function logError(...args: any[]): void;
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/logging/index.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAEnD;AAED,wBAAgB,OAAO,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,QAMrC;AAED,wBAAgB,OAAO,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,QAErC;AAED,wBAAgB,QAAQ,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,QAEtC"}
@@ -0,0 +1,23 @@
1
+ import type { SseResponse } from '../web/SseResponse.ts';
2
+ interface SetupOptions {
3
+ managerName: string;
4
+ logDebug?: (message: string) => void;
5
+ logError?: (message: string, error?: any) => void;
6
+ }
7
+ interface Connection {
8
+ key: string;
9
+ sseResponse: SseResponse;
10
+ connectedAt: Date;
11
+ }
12
+ export declare class ConnectionManager<EventType extends object> {
13
+ private connections;
14
+ private managerName;
15
+ private logDebug;
16
+ private logError;
17
+ constructor(options: SetupOptions);
18
+ addConnection(key: string, sseResponse: SseResponse): void;
19
+ getConnections(key: string): Connection[];
20
+ postEvent(key: string, event: EventType): Promise<void>;
21
+ }
22
+ export {};
23
+ //# sourceMappingURL=ConnectionManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConnectionManager.d.ts","sourceRoot":"","sources":["../../src/sse/ConnectionManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,UAAU,YAAY;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;CACnD;AAED,UAAU,UAAU;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,IAAI,CAAC;CACnB;AAWD,qBAAa,iBAAiB,CAAC,SAAS,SAAS,MAAM;IACrD,OAAO,CAAC,WAAW,CAAwC;IAC3D,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,QAAQ,CAAyC;gBAE7C,OAAO,EAAE,YAAY;IAMjC,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,GAAG,IAAI;IA0B1D,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,EAAE;IAInC,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;CAa9D"}
@@ -0,0 +1,38 @@
1
+ import { PrismApp } from '../app/PrismApp.ts';
2
+ /**
3
+ * JSON message sent from the parent process to the stdin server.
4
+ */
5
+ export interface StdinRequest {
6
+ /** Unique request ID for correlating responses. */
7
+ id: string;
8
+ /** HTTP method (GET, POST, PUT, DELETE, PATCH). */
9
+ method: string;
10
+ /** Endpoint path, e.g. "/users" or "/users/123". */
11
+ path: string;
12
+ /** Request body / input data. */
13
+ body?: any;
14
+ }
15
+ /**
16
+ * JSON message sent back from the stdin server to the parent process.
17
+ */
18
+ export interface StdinResponse {
19
+ /** Matches the request ID. */
20
+ id: string;
21
+ /** HTTP-style status code. */
22
+ status: number;
23
+ /** Response body. */
24
+ body: any;
25
+ }
26
+ export interface StdinServerConfig {
27
+ app: PrismApp;
28
+ }
29
+ /**
30
+ * Start processing requests from stdin and writing responses to stdout.
31
+ *
32
+ * Each line on stdin must be a JSON-encoded StdinRequest.
33
+ * Each response is a JSON-encoded StdinResponse written as a single line to stdout.
34
+ *
35
+ * When stdin closes, the process exits.
36
+ */
37
+ export declare function startStdinServer(config: StdinServerConfig): void;
38
+ //# sourceMappingURL=StdinServer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StdinServer.d.ts","sourceRoot":"","sources":["../../src/stdin/StdinServer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAK9C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAC;IACX,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,8BAA8B;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,IAAI,EAAE,GAAG,CAAC;CACX;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,QAAQ,CAAC;CACf;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAoFhE"}
@@ -0,0 +1,3 @@
1
+ import { type EndpointDefinition } from './ExpressEndpointSetup.ts';
2
+ export declare function createListingEndpoints(endpoints: EndpointDefinition[]): EndpointDefinition[];
3
+ //# sourceMappingURL=EndpointListing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EndpointListing.d.ts","sourceRoot":"","sources":["../../src/web/EndpointListing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAKpF,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,kBAAkB,EAAE,wBA+DrE"}
@@ -0,0 +1,18 @@
1
+ import express from 'express';
2
+ import type { Server } from 'http';
3
+ import { PrismApp } from '../app/PrismApp.ts';
4
+ import { type CorsConfig } from './corsMiddleware.ts';
5
+ import { type OpenAPIConfig } from './openapi/OpenAPI.ts';
6
+ import { type WebConfig } from './ViteIntegration.ts';
7
+ export type { WebConfig } from './ViteIntegration.ts';
8
+ export interface ServerSetupConfig {
9
+ port: number;
10
+ app: PrismApp;
11
+ openapiConfig?: OpenAPIConfig;
12
+ corsConfig?: CorsConfig;
13
+ /** Serve web files alongside the API. When provided, API endpoints are mounted at /api/. */
14
+ web?: WebConfig;
15
+ }
16
+ export declare function createExpressApp(config: ServerSetupConfig): express.Application;
17
+ export declare function startServer(config: ServerSetupConfig): Promise<Server>;
18
+ //# sourceMappingURL=ExpressAppSetup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpressAppSetup.d.ts","sourceRoot":"","sources":["../../src/web/ExpressAppSetup.ts"],"names":[],"mappings":"AACA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAItE,OAAO,EAAyB,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAKjF,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAE1E,YAAY,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,QAAQ,CAAC;IACd,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,4FAA4F;IAC5F,GAAG,CAAC,EAAE,SAAS,CAAC;CACjB;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAoE/E;AAED,wBAAsB,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2B5E"}
@@ -0,0 +1,31 @@
1
+ import express, { type NextFunction, type Request, type Response } from 'express';
2
+ import { z } from 'zod';
3
+ import { PrismApp } from '../app/PrismApp.ts';
4
+ export { createEndpoint } from '../endpoints/createEndpoint.ts';
5
+ type EndpointRequireOption = 'authenticated-user';
6
+ export interface EndpointDefinition {
7
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
8
+ path: string;
9
+ handler: (input: any) => Promise<any> | any;
10
+ requestSchema?: z.ZodSchema;
11
+ responseSchema?: z.ZodSchema;
12
+ description?: string;
13
+ requires?: EndpointRequireOption[];
14
+ /**
15
+ * Unique identifier for this endpoint in the OpenAPI schema.
16
+ * If not provided, one will be generated from the method and path.
17
+ * Must be unique across all endpoints in the app.
18
+ */
19
+ operationId?: string;
20
+ }
21
+ export declare function getRequestDataFromReq(req: Request): any;
22
+ export declare function mountPrismApp(app: express.Application | express.Router, prismApp: PrismApp): void;
23
+ export declare function mountMiddleware(app: express.Application, middleware: {
24
+ path: string;
25
+ handler: (req: Request, res: Response, next: NextFunction) => void;
26
+ }): void;
27
+ export declare function mountMiddlewares(app: express.Application, middlewares: {
28
+ path: string;
29
+ handler: (req: Request, res: Response, next: NextFunction) => void;
30
+ }[]): void;
31
+ //# sourceMappingURL=ExpressEndpointSetup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpressEndpointSetup.d.ts","sourceRoot":"","sources":["../../src/web/ExpressEndpointSetup.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,EAAE,EAAE,KAAK,YAAY,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AAClF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,EAAE,QAAQ,EAAe,MAAM,oBAAoB,CAAC;AAG3D,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAEhE,KAAK,qBAAqB,GAAG,oBAAoB,CAAC;AAElD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IAC5C,aAAa,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IAC5B,cAAc,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,qBAAqB,EAAE,CAAC;IACnC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,CAgBvD;AAiFD,wBAAgB,aAAa,CAC3B,GAAG,EAAE,OAAO,CAAC,WAAW,GAAG,OAAO,CAAC,MAAM,EACzC,QAAQ,EAAE,QAAQ,GACjB,IAAI,CA2BN;AAED,wBAAgB,eAAe,CAC7B,GAAG,EAAE,OAAO,CAAC,WAAW,EACxB,UAAU,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAA;CAAE,GAC/F,IAAI,CAEN;AAED,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,OAAO,CAAC,WAAW,EACxB,WAAW,EAAE;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;CACpE,EAAE,GACF,IAAI,CAEN"}
@@ -0,0 +1,15 @@
1
+ import type { Response } from 'express';
2
+ export declare class SseResponse {
3
+ response: Response;
4
+ private isResponseOpen;
5
+ private _onClose;
6
+ constructor(response: Response);
7
+ private setupSseHeaders;
8
+ private setupCloseHandlers;
9
+ send(data: object): void;
10
+ isOpen(): boolean;
11
+ close(): void;
12
+ _triggerOnClose(): void;
13
+ onClose(callback: () => void): void;
14
+ }
15
+ //# sourceMappingURL=SseResponse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SseResponse.d.ts","sourceRoot":"","sources":["../../src/web/SseResponse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAQxC,qBAAa,WAAW;IACf,QAAQ,EAAE,QAAQ,CAAC;IAC1B,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,QAAQ,CAAa;gBAEjB,QAAQ,EAAE,QAAQ;IAM9B,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,kBAAkB;IAU1B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IASxB,MAAM,IAAI,OAAO;IAKjB,KAAK,IAAI,IAAI;IAWb,eAAe,IAAI,IAAI;IASvB,OAAO,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;CAMpC"}
@@ -0,0 +1,19 @@
1
+ import express from 'express';
2
+ export interface WebConfig {
3
+ /** Directory containing web files (index.html, etc.). In production, serves from dir/dist if it exists. */
4
+ dir: string;
5
+ }
6
+ /**
7
+ * Sets up web file serving on the Express app. This should be called AFTER
8
+ * API routes are mounted so that /api/* takes priority.
9
+ *
10
+ * In development (NODE_ENV !== 'production'):
11
+ * - Tries to use Vite dev server in middleware mode
12
+ * - Falls back to express.static if Vite is not installed
13
+ *
14
+ * In production:
15
+ * - Serves static files from dir/dist (or dir if dist doesn't exist)
16
+ * - SPA fallback: unmatched GET requests serve index.html
17
+ */
18
+ export declare function setupWebMiddleware(expressApp: express.Application, webConfig: WebConfig): Promise<void>;
19
+ //# sourceMappingURL=ViteIntegration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ViteIntegration.d.ts","sourceRoot":"","sources":["../../src/web/ViteIntegration.ts"],"names":[],"mappings":"AAQA,OAAO,OAAO,MAAM,SAAS,CAAC;AAK9B,MAAM,WAAW,SAAS;IACxB,2GAA2G;IAC3G,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,OAAO,CAAC,WAAW,EAC/B,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,IAAI,CAAC,CAsCf"}
@@ -0,0 +1,14 @@
1
+ import express from 'express';
2
+ export interface CorsConfig {
3
+ /** Base URL for web application (e.g., 'example.com' or 'https://example.com') */
4
+ webBaseUrl?: string;
5
+ /** Allow any localhost origin (http://localhost:*) for local development */
6
+ allowLocalhost?: boolean;
7
+ /**
8
+ * @deprecated Use `allowLocalhost` instead. This field controls both test endpoints and localhost CORS.
9
+ * When `allowLocalhost` is set, it takes precedence for CORS behavior.
10
+ */
11
+ enableTestEndpoints?: boolean;
12
+ }
13
+ export declare function corsMiddleware(config?: CorsConfig): (req: express.Request, res: express.Response, next: express.NextFunction) => void;
14
+ //# sourceMappingURL=corsMiddleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"corsMiddleware.d.ts","sourceRoot":"","sources":["../../src/web/corsMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,MAAM,WAAW,UAAU;IACzB,kFAAkF;IAClF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AA+BD,wBAAgB,cAAc,CAAC,MAAM,GAAE,UAAe,SACvC,OAAO,CAAC,OAAO,OAAO,OAAO,CAAC,QAAQ,QAAQ,OAAO,CAAC,YAAY,UAkBhF"}
@@ -0,0 +1,3 @@
1
+ import type { NextFunction, Request, Response } from 'express';
2
+ export declare function localhostOnlyMiddleware(req: Request, res: Response, next: NextFunction): Response<any, Record<string, any>>;
3
+ //# sourceMappingURL=localhostOnlyMiddleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"localhostOnlyMiddleware.d.ts","sourceRoot":"","sources":["../../src/web/localhostOnlyMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAQ/D,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,sCAUtF"}
@@ -0,0 +1,37 @@
1
+ import type { OpenAPIObject } from 'openapi3-ts/oas31';
2
+ import type { ServiceDefinition } from '../../ServiceDefinition.ts';
3
+ import { PrismApp } from '../../app/PrismApp.ts';
4
+ import express from 'express';
5
+ export { validateServicesForOpenapi as validateEndpointForOpenapi } from './validateServicesForOpenapi.ts';
6
+ export interface OpenAPIConfig {
7
+ enable: boolean;
8
+ enableSwagger?: boolean;
9
+ }
10
+ export type ParseExpressPathForOpenAPIResult = {
11
+ openApiPath: string;
12
+ pathParams: string[];
13
+ };
14
+ export interface OpenAPIDocumentInfo {
15
+ version: string;
16
+ title: string;
17
+ description: string;
18
+ }
19
+ /**
20
+ * Transforms path parameters in an Express-style URL path (e.g. :pathParameter) into their OpenAPI equivalents (e.g. {pathParameter})
21
+ * Returns the transformed OpenAPI-style URL path along with any path parameters found.
22
+ *
23
+ * @param {string} expressApiPath - An Express-style URL path
24
+ * @returns {ParseExpressPathForOpenAPIResult} - the transformed OpenAPI-style URL path with any path parameters found
25
+ */
26
+ export declare function parseExpressPathForOpenAPI(expressApiPath: string): ParseExpressPathForOpenAPIResult;
27
+ /**
28
+ * Generates the Open API Schema for all services.
29
+ *
30
+ * @param {ServiceDefinition[]} services - Array of service definitions to generate OpenAPI schema for
31
+ * @param {OpenAPIDocumentInfo} documentInfo - Metadata for the OpenAPI document
32
+ * @returns {OpenAPIObject} - the Open API schema for all service definitions.
33
+ */
34
+ export declare function generateOpenAPISchema(services: ServiceDefinition[], documentInfo: OpenAPIDocumentInfo): OpenAPIObject;
35
+ export declare function setupSwaggerUI(app: express.Application | express.Router, openApiJsonPath?: string): void;
36
+ export declare function mountOpenAPIEndpoints(config: OpenAPIConfig, target: express.Application | express.Router, prismApp: PrismApp): void;
37
+ //# sourceMappingURL=OpenAPI.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OpenAPI.d.ts","sourceRoot":"","sources":["../../../src/web/openapi/OpenAPI.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,OAAwC,MAAM,SAAS,CAAC;AAK/D,OAAO,EAAE,0BAA0B,IAAI,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAI3G,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,OAAO,CAAA;IACf,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED,MAAM,MAAM,gCAAgC,GAAG;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB,CAAC;AAEF,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAKD;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,cAAc,EAAE,MAAM,GAAG,gCAAgC,CAkBnG;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,YAAY,EAAE,mBAAmB,GAChC,aAAa,CA0Hf;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,WAAW,GAAG,OAAO,CAAC,MAAM,EAAE,eAAe,GAAE,MAAwB,GAAG,IAAI,CAYzH;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,WAAW,GAAG,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CA0BnI"}
@@ -0,0 +1,32 @@
1
+ import type { ServiceDefinition } from "../../ServiceDefinition.ts";
2
+ import type { EndpointDefinition } from "../ExpressEndpointSetup.ts";
3
+ import { type ErrorDetails } from "@facetlayer/streams";
4
+ export interface EndpointValidationResult {
5
+ error: ErrorDetails;
6
+ }
7
+ export interface FailedEndpoint {
8
+ serviceName: string;
9
+ path: string;
10
+ method: string;
11
+ error: ErrorDetails;
12
+ }
13
+ export interface ServicesValidationResult {
14
+ problemEndpoints: FailedEndpoint[];
15
+ }
16
+ /**
17
+ * Validates a single endpoint for OpenAPI schema generation compatibility.
18
+ *
19
+ * @param serviceName - Name of the service containing the endpoint
20
+ * @param endpoint - The endpoint definition to validate
21
+ * @returns ProblematicEndpoint if validation fails, null if endpoint is valid
22
+ */
23
+ export declare function validateEndpointForOpenapi(endpoint: EndpointDefinition): EndpointValidationResult;
24
+ /**
25
+ * Finds endpoints that will fail OpenAPI schema generation.
26
+ * Tests each endpoint individually to identify which ones have unsupported Zod types.
27
+ *
28
+ * @param services - Array of service definitions to check
29
+ * @returns ValidationResult containing any problematic endpoints
30
+ */
31
+ export declare function validateServicesForOpenapi(services: ServiceDefinition[]): ServicesValidationResult;
32
+ //# sourceMappingURL=validateServicesForOpenapi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validateServicesForOpenapi.d.ts","sourceRoot":"","sources":["../../../src/web/openapi/validateServicesForOpenapi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAErE,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEtE,MAAM,WAAW,wBAAwB;IACrC,KAAK,EAAE,YAAY,CAAA;CACtB;AAED,MAAM,WAAW,cAAc;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,YAAY,CAAC;CACvB;AAED,MAAM,WAAW,wBAAwB;IACrC,gBAAgB,EAAE,cAAc,EAAE,CAAC;CACtC;AAGD;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,kBAAkB,GAC3B,wBAAwB,CAgB1B;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,wBAAwB,CAoBhG"}
@@ -0,0 +1,3 @@
1
+ import type { NextFunction, Request, Response } from 'express';
2
+ export declare function requestContextMiddleware(req: Request, res: Response, next: NextFunction): void;
3
+ //# sourceMappingURL=requestContextMiddleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requestContextMiddleware.d.ts","sourceRoot":"","sources":["../../src/web/requestContextMiddleware.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAM/D,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAiB9F"}
@@ -0,0 +1,281 @@
1
+ ---
2
+ name: authorization
3
+ description: Authorization system with resources, auth sources, and permissions
4
+ ---
5
+
6
+ # Authorization System
7
+
8
+ Prism Framework includes a flexible authorization system based on resources, auth sources, and permissions.
9
+
10
+ ## Core Concepts
11
+
12
+ ### Resources
13
+
14
+ Resources represent entities that can be accessed:
15
+
16
+ ```typescript
17
+ interface Resource {
18
+ type: 'user' | 'project' | 'session' | 'custom';
19
+ id: string;
20
+ }
21
+ ```
22
+
23
+ ### Auth Sources
24
+
25
+ Auth sources represent how a user authenticated:
26
+
27
+ ```typescript
28
+ interface AuthSource {
29
+ type: string;
30
+ }
31
+
32
+ interface CookieAuthSource extends AuthSource {
33
+ type: 'cookie';
34
+ sessionId: string;
35
+ }
36
+ ```
37
+
38
+ ### Permissions
39
+
40
+ Permissions are string-based capabilities:
41
+
42
+ ```typescript
43
+ type Permission = string;
44
+
45
+ interface UserPermissions {
46
+ userId: string;
47
+ permissions: Permission[];
48
+ }
49
+ ```
50
+
51
+ ## Authorization Class
52
+
53
+ The `Authorization` class manages resources, auth sources, and permissions:
54
+
55
+ ```typescript
56
+ import { Authorization } from '@facetlayer/prism-framework';
57
+
58
+ const auth = new Authorization();
59
+
60
+ // Add resources
61
+ auth.addResource({ type: 'user', id: '123' });
62
+ auth.addResource({ type: 'project', id: 'abc' });
63
+
64
+ // Check resources
65
+ if (auth.hasResource('user')) {
66
+ const user = auth.getResource('user');
67
+ console.log(user.id); // '123'
68
+ }
69
+
70
+ // Add auth sources
71
+ auth.addAuthSource({
72
+ type: 'cookie',
73
+ sessionId: 'session-xyz',
74
+ });
75
+
76
+ // Set permissions
77
+ auth.setUserPermissions({
78
+ userId: '123',
79
+ permissions: ['read:projects', 'write:projects'],
80
+ });
81
+
82
+ // Check permissions
83
+ if (auth.hasPermission('write:projects')) {
84
+ // User can write projects
85
+ }
86
+ ```
87
+
88
+ ## Request Context Integration
89
+
90
+ Every request has an `Authorization` instance in its context:
91
+
92
+ ```typescript
93
+ import { getCurrentRequestContext } from '@facetlayer/prism-framework';
94
+
95
+ // In endpoint handler
96
+ const context = getCurrentRequestContext();
97
+ const auth = context.auth;
98
+
99
+ // Check if user is authenticated
100
+ const user = auth.getResource('user');
101
+ if (!user) {
102
+ throw new UnauthorizedError('Authentication required');
103
+ }
104
+ ```
105
+
106
+ ## Middleware Example
107
+
108
+ Create middleware to populate authorization:
109
+
110
+ ```typescript
111
+ import { MiddlewareDefinition } from '@facetlayer/prism-framework';
112
+
113
+ export const authMiddleware: MiddlewareDefinition = {
114
+ path: '/api/*',
115
+ handler: async (req, res, next) => {
116
+ const context = getCurrentRequestContext();
117
+
118
+ // Check for session cookie
119
+ const sessionId = req.cookies.sessionId;
120
+ if (sessionId) {
121
+ // Look up session
122
+ const session = await getSession(sessionId);
123
+ if (session) {
124
+ // Add auth source
125
+ context.auth.addAuthSource({
126
+ type: 'cookie',
127
+ sessionId,
128
+ });
129
+
130
+ // Add user resource
131
+ context.auth.addResource({
132
+ type: 'user',
133
+ id: session.userId,
134
+ });
135
+
136
+ // Load and set permissions
137
+ const permissions = await getUserPermissions(session.userId);
138
+ context.auth.setUserPermissions({
139
+ userId: session.userId,
140
+ permissions,
141
+ });
142
+ }
143
+ }
144
+
145
+ next();
146
+ },
147
+ };
148
+ ```
149
+
150
+ ## Endpoint Requirements
151
+
152
+ Use the `requires` array to enforce authentication:
153
+
154
+ ```typescript
155
+ createEndpoint({
156
+ method: 'GET',
157
+ path: '/api/protected',
158
+ requires: ['authenticated-user'],
159
+ handler: async () => {
160
+ // This handler only runs if user is authenticated
161
+ const context = getCurrentRequestContext();
162
+ const user = context.auth.getResource('user');
163
+ return { userId: user.id };
164
+ },
165
+ });
166
+ ```
167
+
168
+ The `'authenticated-user'` requirement checks that a user resource exists in the authorization context.
169
+
170
+ ## Custom Authorization Checks
171
+
172
+ Implement custom authorization logic in your handlers:
173
+
174
+ ```typescript
175
+ import { ForbiddenError } from '@facetlayer/prism-framework';
176
+
177
+ createEndpoint({
178
+ method: 'DELETE',
179
+ path: '/api/projects/:projectId',
180
+ requires: ['authenticated-user'],
181
+ handler: async (input) => {
182
+ const context = getCurrentRequestContext();
183
+
184
+ // Check permission
185
+ if (!context.auth.hasPermission('delete:projects')) {
186
+ throw new ForbiddenError('Insufficient permissions');
187
+ }
188
+
189
+ // Check project ownership
190
+ const project = await getProject(input.projectId);
191
+ const user = context.auth.getResource('user');
192
+
193
+ if (project.ownerId !== user.id) {
194
+ throw new ForbiddenError('Not the project owner');
195
+ }
196
+
197
+ await deleteProject(input.projectId);
198
+ return { success: true };
199
+ },
200
+ });
201
+ ```
202
+
203
+ ## Permission Patterns
204
+
205
+ Common permission naming patterns:
206
+
207
+ ```typescript
208
+ // Resource:Action format
209
+ 'read:projects'
210
+ 'write:projects'
211
+ 'delete:projects'
212
+ 'admin:users'
213
+
214
+ // Hierarchical permissions
215
+ 'projects:read'
216
+ 'projects:write'
217
+ 'projects:delete'
218
+
219
+ // Role-based
220
+ 'role:admin'
221
+ 'role:editor'
222
+ 'role:viewer'
223
+ ```
224
+
225
+ ## Helper Functions
226
+
227
+ Create helper functions for common authorization checks:
228
+
229
+ ```typescript
230
+ import { getCurrentRequestContext, ForbiddenError } from '@facetlayer/prism-framework';
231
+
232
+ export function requirePermission(permission: string) {
233
+ const context = getCurrentRequestContext();
234
+ if (!context?.auth.hasPermission(permission)) {
235
+ throw new ForbiddenError(`Missing permission: ${permission}`);
236
+ }
237
+ }
238
+
239
+ export function requireProjectAccess(projectId: string) {
240
+ const context = getCurrentRequestContext();
241
+ const user = context?.auth.getResource('user');
242
+ if (!user) {
243
+ throw new UnauthorizedError('Authentication required');
244
+ }
245
+
246
+ const project = getProject(projectId);
247
+ if (project.ownerId !== user.id) {
248
+ throw new ForbiddenError('Project access denied');
249
+ }
250
+ }
251
+
252
+ // Usage in handlers
253
+ handler: async (input) => {
254
+ requirePermission('write:projects');
255
+ requireProjectAccess(input.projectId);
256
+
257
+ // Proceed with the operation
258
+ await updateProject(input.projectId, input.updates);
259
+ return { success: true };
260
+ }
261
+ ```
262
+
263
+ ## Multi-Tenant Support
264
+
265
+ Use resources to track tenant/organization context:
266
+
267
+ ```typescript
268
+ // Add organization resource
269
+ context.auth.addResource({
270
+ type: 'custom',
271
+ id: 'org:acme-corp',
272
+ });
273
+
274
+ // Check organization access
275
+ const org = context.auth.getAllResources()
276
+ .find(r => r.id.startsWith('org:'));
277
+
278
+ if (!org) {
279
+ throw new ForbiddenError('No organization context');
280
+ }
281
+ ```