@fluojs/openapi 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.ko.md CHANGED
@@ -97,7 +97,7 @@ HTTP 핸들러가 `@fluojs/http`의 `@Produces(...)`를 선언하면, 생성된
97
97
  `ui: true`를 활성화하면 생성되는 `/docs` 페이지는 정확한 `swagger-ui-dist` 버전의 자산을 참조하여 패키지 릴리스마다 동일한 동작을 유지합니다. 오프라인 또는 CSP 제어 환경에서 자체 호스팅 자산이 필요하면 `swaggerUiAssets.cssUrl`과 `swaggerUiAssets.jsBundleUrl`을 설정하세요. 생성된 HTML은 해당 URL을 이스케이프하며 Swagger UI 인스턴스를 `window.ui`에 노출하지 않습니다.
98
98
 
99
99
  ### 모듈 옵션 결정성
100
- `OpenApiModule.forRoot(...)`는 등록 시점에 옵션을 스냅샷하고 freeze합니다. 등록 후 원본 options 객체, `sources`, `descriptors`, `securitySchemes`, `extraModels`, `swaggerUiAssets`를 변경해도 제공되는 OpenAPI 문서나 `/docs` HTML은 바뀌지 않습니다. `OpenApiModule.forRootAsync(...)`도 async factory가 resolve된 뒤 같은 스냅샷을 적용하며, factory 실패는 bootstrap 중 전파됩니다.
100
+ `OpenApiModule.forRoot(...)`는 등록 시점에 옵션을 스냅샷하고 freeze합니다. 등록 후 원본 options 객체, `sources`, `descriptors`, `securitySchemes`, `extraModels`, `swaggerUiAssets`를 변경해도 제공되는 OpenAPI 문서나 `/docs` HTML은 바뀌지 않습니다. 생성된 singleton 문서도 defensive copy로 제공되므로 downstream response serialization이나 테스트가 이후 요청에 쓰이는 저장 문서를 변경할 수 없습니다. `OpenApiModule.forRootAsync(...)`도 async factory가 resolve된 뒤 같은 스냅샷을 적용하며, factory 실패는 bootstrap 중 전파됩니다.
101
101
 
102
102
  ### Async 등록과 옵션
103
103
  title/version/source 설정이 DI나 async setup에서 나오는 경우 `OpenApiModule.forRootAsync(...)`를 사용합니다. Module option에는 `sources`, `descriptors`, `securitySchemes`, `extraModels`, `defaultErrorResponsesPolicy`, `documentTransform`, `ui`, `swaggerUiAssets`가 포함됩니다. `defaultErrorResponsesPolicy`는 기본적으로 표준 error response와 `ErrorResponse` schema를 주입하며, `documentTransform`은 문서 생성 뒤 제공되기 전에 실행됩니다.
package/README.md CHANGED
@@ -97,7 +97,7 @@ Stacking multiple `@ApiSecurity()` decorators for the same scheme merges scopes
97
97
  When `ui: true` is enabled, the generated `/docs` page references an exact `swagger-ui-dist` asset version so release behavior stays deterministic across package updates. If your deployment requires self-hosted assets for offline or CSP-controlled environments, set `swaggerUiAssets.cssUrl` and `swaggerUiAssets.jsBundleUrl`; the generated HTML escapes those URLs and does not expose the Swagger UI instance on `window.ui`.
98
98
 
99
99
  ### Module Option Determinism
100
- `OpenApiModule.forRoot(...)` snapshots and freezes its options at registration time. Mutating the original options object, `sources`, `descriptors`, `securitySchemes`, `extraModels`, or `swaggerUiAssets` after registration does not alter the served OpenAPI document or `/docs` HTML. `OpenApiModule.forRootAsync(...)` applies the same snapshot once the async factory resolves, and factory failures propagate during bootstrap.
100
+ `OpenApiModule.forRoot(...)` snapshots and freezes its options at registration time. Mutating the original options object, `sources`, `descriptors`, `securitySchemes`, `extraModels`, or `swaggerUiAssets` after registration does not alter the served OpenAPI document or `/docs` HTML. The generated singleton document is also served through defensive copies, so downstream response serialization or tests cannot mutate the stored document for later requests. `OpenApiModule.forRootAsync(...)` applies the same snapshot once the async factory resolves, and factory failures propagate during bootstrap.
101
101
 
102
102
  ### Async Registration and Options
103
103
  Use `OpenApiModule.forRootAsync(...)` when title/version/source configuration comes from DI or async setup. Module options include `sources`, `descriptors`, `securitySchemes`, `extraModels`, `defaultErrorResponsesPolicy`, `documentTransform`, `ui`, and `swaggerUiAssets`. `defaultErrorResponsesPolicy` defaults to injecting standard error responses and an `ErrorResponse` schema, while `documentTransform` runs after document generation and before serving.
@@ -1 +1 @@
1
- {"version":3,"file":"handler-registry.d.ts","sourceRoot":"","sources":["../src/handler-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD;;GAEG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,WAAW,CAA2B;IAE9C;;;;OAIG;IACH,cAAc,CAAC,WAAW,EAAE,SAAS,iBAAiB,EAAE,GAAG,IAAI;IAI/D;;;;OAIG;IACH,cAAc,IAAI,iBAAiB,EAAE;CAGtC"}
1
+ {"version":3,"file":"handler-registry.d.ts","sourceRoot":"","sources":["../src/handler-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAItD;;GAEG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,WAAW,CAA2B;IAE9C;;;;OAIG;IACH,cAAc,CAAC,WAAW,EAAE,SAAS,iBAAiB,EAAE,GAAG,IAAI;IAI/D;;;;OAIG;IACH,cAAc,IAAI,iBAAiB,EAAE;CAGtC"}
@@ -1,3 +1,5 @@
1
+ import { cloneSnapshotValue } from './snapshot.js';
2
+
1
3
  /**
2
4
  * Mutable registry used to snapshot handler descriptors before document generation.
3
5
  */
@@ -10,7 +12,7 @@ export class OpenApiHandlerRegistry {
10
12
  * @param descriptors Handler descriptors to retain for later document generation.
11
13
  */
12
14
  setDescriptors(descriptors) {
13
- this.descriptors = [...descriptors];
15
+ this.descriptors = cloneSnapshotValue(descriptors);
14
16
  }
15
17
 
16
18
  /**
@@ -19,6 +21,6 @@ export class OpenApiHandlerRegistry {
19
21
  * @returns A defensive copy of the current handler descriptors.
20
22
  */
21
23
  getDescriptors() {
22
- return [...this.descriptors];
24
+ return cloneSnapshotValue(this.descriptors);
23
25
  }
24
26
  }
@@ -1 +1 @@
1
- {"version":3,"file":"openapi-module.d.ts","sourceRoot":"","sources":["../src/openapi-module.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAEnB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAU,KAAK,kBAAkB,EAAE,KAAK,WAAW,EAAsD,MAAM,cAAc,CAAC;AACrI,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGhE,OAAO,EAEL,KAAK,2BAA2B,EAChC,KAAK,eAAe,EACpB,KAAK,2BAA2B,EACjC,MAAM,qBAAqB,CAAC;AAO7B;;GAEG;AACH,MAAM,WAAW,6BAA6B;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,2BAA2B,CAAC,EAAE,2BAA2B,CAAC;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,WAAW,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC3C,OAAO,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IACnC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,2BAA2B,CAAC,CAAC;IAC9D,eAAe,CAAC,EAAE,6BAA6B,CAAC;IAChD,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC;IAC5B,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE,eAAe,KAAK,eAAe,CAAC;CACpE;AA6ID;;GAEG;AACH,qBAAa,aAAa;IACxB;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,UAAU;IAOzD;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,kBAAkB,CAAC,oBAAoB,CAAC,GAAG,UAAU;IAQlF,OAAO,CAAC,MAAM,CAAC,YAAY;CAqE5B"}
1
+ {"version":3,"file":"openapi-module.d.ts","sourceRoot":"","sources":["../src/openapi-module.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAEnB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAU,KAAK,kBAAkB,EAAE,KAAK,WAAW,EAA0C,MAAM,cAAc,CAAC;AACzH,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGhE,OAAO,EAEL,KAAK,2BAA2B,EAChC,KAAK,eAAe,EACpB,KAAK,2BAA2B,EACjC,MAAM,qBAAqB,CAAC;AAQ7B;;GAEG;AACH,MAAM,WAAW,6BAA6B;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,2BAA2B,CAAC,EAAE,2BAA2B,CAAC;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,WAAW,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC3C,OAAO,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IACnC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,2BAA2B,CAAC,CAAC;IAC9D,eAAe,CAAC,EAAE,6BAA6B,CAAC;IAChD,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC;IAC5B,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE,eAAe,KAAK,eAAe,CAAC;CACpE;AA2GD;;GAEG;AACH,qBAAa,aAAa;IACxB;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,UAAU;IAOzD;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,kBAAkB,CAAC,oBAAoB,CAAC,GAAG,UAAU;IAQlF,OAAO,CAAC,MAAM,CAAC,YAAY;CAqE5B"}
@@ -8,6 +8,7 @@ import { Inject } from '@fluojs/core';
8
8
  import { defineModule } from '@fluojs/runtime';
9
9
  import { OpenApiHandlerRegistry } from './handler-registry.js';
10
10
  import { buildOpenApiDocument } from './schema-builder.js';
11
+ import { cloneSnapshotValue, createFrozenSnapshot } from './snapshot.js';
11
12
  const SWAGGER_UI_DIST_VERSION = '5.32.2';
12
13
  const SWAGGER_UI_DIST_BASE_URL = `https://unpkg.com/swagger-ui-dist@${SWAGGER_UI_DIST_VERSION}`;
13
14
  const SWAGGER_UI_CSS_URL = `${SWAGGER_UI_DIST_BASE_URL}/swagger-ui.css`;
@@ -38,33 +39,8 @@ function cloneRecord(record) {
38
39
  }
39
40
  return clone;
40
41
  }
41
- function cloneSnapshotValue(value) {
42
- if (value === null || value === undefined) {
43
- return value;
44
- }
45
- if (Array.isArray(value)) {
46
- return value.map(entry => cloneSnapshotValue(entry));
47
- }
48
- if (typeof value !== 'object') {
49
- return value;
50
- }
51
- const clone = {};
52
- for (const key of Reflect.ownKeys(value)) {
53
- clone[key] = cloneSnapshotValue(value[key]);
54
- }
55
- return clone;
56
- }
57
- function deepFreeze(value) {
58
- if (value === null || typeof value !== 'object') {
59
- return value;
60
- }
61
- for (const key of Reflect.ownKeys(value)) {
62
- deepFreeze(value[key]);
63
- }
64
- return Object.freeze(value);
65
- }
66
42
  function snapshotOpenApiModuleOptions(options) {
67
- return deepFreeze({
43
+ return createFrozenSnapshot({
68
44
  defaultErrorResponsesPolicy: options.defaultErrorResponsesPolicy,
69
45
  descriptors: options.descriptors ? cloneSnapshotValue(options.descriptors) : undefined,
70
46
  documentTransform: options.documentTransform,
@@ -195,7 +171,7 @@ export class OpenApiModule {
195
171
  _initProto(this);
196
172
  }
197
173
  getDocument() {
198
- return this.document;
174
+ return cloneSnapshotValue(this.document);
199
175
  }
200
176
  getSwaggerUi(_input, context) {
201
177
  if (!(this.options.ui ?? false)) {
@@ -225,7 +201,7 @@ export class OpenApiModule {
225
201
  }
226
202
  const registry = new OpenApiHandlerRegistry();
227
203
  registry.setDescriptors(resolveOpenApiDescriptors(options));
228
- return buildOpenApiDocument({
204
+ return createFrozenSnapshot(buildOpenApiDocument({
229
205
  documentTransform: options.documentTransform,
230
206
  defaultErrorResponsesPolicy: options.defaultErrorResponsesPolicy,
231
207
  descriptors: registry.getDescriptors(),
@@ -233,7 +209,7 @@ export class OpenApiModule {
233
209
  securitySchemes: options.securitySchemes,
234
210
  title: options.title,
235
211
  version: options.version
236
- });
212
+ }));
237
213
  }
238
214
  }]
239
215
  });
@@ -1,4 +1,4 @@
1
- import { type Constructor } from '@fluojs/core';
1
+ import type { Constructor } from '@fluojs/core';
2
2
  import type { HandlerDescriptor } from '@fluojs/http';
3
3
  /**
4
4
  * JSON Schema primitive type names accepted by OpenAPI 3.1 schema objects.
@@ -1 +1 @@
1
- {"version":3,"file":"schema-builder.d.ts","sourceRoot":"","sources":["../src/schema-builder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema-builder.d.ts","sourceRoot":"","sources":["../src/schema-builder.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { getDtoBindingSchema, getDtoValidationSchema } from '@fluojs/core/internal';
2
2
  import { getControllerTags, getMethodApiMetadata } from './decorators.js';
3
+ import { cloneSnapshotValue } from './snapshot.js';
3
4
 
4
5
  /**
5
6
  * JSON Schema primitive type names accepted by OpenAPI 3.1 schema objects.
@@ -829,7 +830,7 @@ function buildOperationEntry(descriptor, componentSchemas, defaultErrorResponses
829
830
  }
830
831
  function createOpenApiComponents(componentSchemas, hasBearerAuth, configuredSecuritySchemes) {
831
832
  const securitySchemes = {
832
- ...(configuredSecuritySchemes ?? {}),
833
+ ...(configuredSecuritySchemes ? cloneSnapshotValue(configuredSecuritySchemes) : {}),
833
834
  ...(hasBearerAuth && !(configuredSecuritySchemes && 'bearerAuth' in configuredSecuritySchemes) ? {
834
835
  bearerAuth: {
835
836
  bearerFormat: 'JWT',
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Clone JSON-like OpenAPI snapshot values while preserving function and class references.
3
+ *
4
+ * @param value Snapshot value to clone.
5
+ * @returns A detached clone of arrays and plain objects in the value graph.
6
+ */
7
+ export declare function cloneSnapshotValue<T>(value: T): T;
8
+ /**
9
+ * Recursively freeze arrays and objects in an OpenAPI snapshot.
10
+ *
11
+ * @param value Snapshot value to freeze.
12
+ * @returns The same value after freezing nested object references.
13
+ */
14
+ export declare function deepFreeze<T>(value: T): T;
15
+ /**
16
+ * Create a detached immutable OpenAPI snapshot.
17
+ *
18
+ * @param value Snapshot value to clone and freeze.
19
+ * @returns An immutable clone that cannot be mutated through caller-owned references.
20
+ */
21
+ export declare function createFrozenSnapshot<T>(value: T): T;
22
+ //# sourceMappingURL=snapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../src/snapshot.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAoBjD;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAUzC;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAEnD"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Clone JSON-like OpenAPI snapshot values while preserving function and class references.
3
+ *
4
+ * @param value Snapshot value to clone.
5
+ * @returns A detached clone of arrays and plain objects in the value graph.
6
+ */
7
+ export function cloneSnapshotValue(value) {
8
+ if (value === null || value === undefined) {
9
+ return value;
10
+ }
11
+ if (Array.isArray(value)) {
12
+ return value.map(entry => cloneSnapshotValue(entry));
13
+ }
14
+ if (typeof value !== 'object') {
15
+ return value;
16
+ }
17
+ const clone = {};
18
+ for (const key of Reflect.ownKeys(value)) {
19
+ clone[key] = cloneSnapshotValue(value[key]);
20
+ }
21
+ return clone;
22
+ }
23
+
24
+ /**
25
+ * Recursively freeze arrays and objects in an OpenAPI snapshot.
26
+ *
27
+ * @param value Snapshot value to freeze.
28
+ * @returns The same value after freezing nested object references.
29
+ */
30
+ export function deepFreeze(value) {
31
+ if (value === null || typeof value !== 'object' || Object.isFrozen(value)) {
32
+ return value;
33
+ }
34
+ for (const key of Reflect.ownKeys(value)) {
35
+ deepFreeze(value[key]);
36
+ }
37
+ return Object.freeze(value);
38
+ }
39
+
40
+ /**
41
+ * Create a detached immutable OpenAPI snapshot.
42
+ *
43
+ * @param value Snapshot value to clone and freeze.
44
+ * @returns An immutable clone that cannot be mutated through caller-owned references.
45
+ */
46
+ export function createFrozenSnapshot(value) {
47
+ return deepFreeze(cloneSnapshotValue(value));
48
+ }
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "documentation",
10
10
  "rest"
11
11
  ],
12
- "version": "1.0.1",
12
+ "version": "1.0.3",
13
13
  "private": false,
14
14
  "license": "MIT",
15
15
  "repository": {
@@ -36,10 +36,10 @@
36
36
  "dist"
37
37
  ],
38
38
  "dependencies": {
39
- "@fluojs/core": "^1.0.1",
40
- "@fluojs/validation": "^1.0.1",
41
- "@fluojs/http": "^1.0.0",
42
- "@fluojs/runtime": "^1.0.1"
39
+ "@fluojs/http": "^1.1.0",
40
+ "@fluojs/validation": "^1.0.4",
41
+ "@fluojs/core": "^1.0.3",
42
+ "@fluojs/runtime": "^1.1.1"
43
43
  },
44
44
  "devDependencies": {
45
45
  "vitest": "^3.2.4"