@navios/adapter-xml 0.1.0 → 0.7.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 (99) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +2 -1
  3. package/bun-plugin.mts +5 -3
  4. package/bunPlugin.cache +1 -1
  5. package/dist/bun-plugin.d.mts.map +1 -1
  6. package/dist/src/adapters/xml-stream-adapter.service.d.mts +63 -8
  7. package/dist/src/adapters/xml-stream-adapter.service.d.mts.map +1 -1
  8. package/dist/src/decorators/component.decorator.d.mts +68 -2
  9. package/dist/src/decorators/component.decorator.d.mts.map +1 -1
  10. package/dist/src/decorators/xml-stream.decorator.d.mts +58 -3
  11. package/dist/src/decorators/xml-stream.decorator.d.mts.map +1 -1
  12. package/dist/src/define-environment.d.mts +2 -2
  13. package/dist/src/define-environment.d.mts.map +1 -1
  14. package/dist/src/handlers/xml-stream.d.mts +25 -3
  15. package/dist/src/handlers/xml-stream.d.mts.map +1 -1
  16. package/dist/src/runtime/render-to-xml.d.mts +70 -2
  17. package/dist/src/runtime/render-to-xml.d.mts.map +1 -1
  18. package/dist/src/tags/define-tag.d.mts +8 -0
  19. package/dist/src/tags/define-tag.d.mts.map +1 -1
  20. package/dist/src/types/component.d.mts +46 -2
  21. package/dist/src/types/component.d.mts.map +1 -1
  22. package/dist/src/types/config.d.mts +22 -0
  23. package/dist/src/types/config.d.mts.map +1 -1
  24. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  25. package/dist/tsconfig.spec.tsbuildinfo +1 -1
  26. package/dist/tsconfig.tsbuildinfo +1 -1
  27. package/dist/tsdown.config.d.mts +3 -0
  28. package/dist/tsdown.config.d.mts.map +1 -0
  29. package/dist/vitest.e2e.fastify.config.d.mts.map +1 -1
  30. package/lib/create-element--Gd2L8UR.d.cts +26 -0
  31. package/lib/create-element--Gd2L8UR.d.cts.map +1 -0
  32. package/lib/create-element-61MP7_99.d.mts +26 -0
  33. package/lib/create-element-61MP7_99.d.mts.map +1 -0
  34. package/lib/create-element-CTOxv6Df.cjs +183 -0
  35. package/lib/create-element-CTOxv6Df.cjs.map +1 -0
  36. package/lib/create-element-NZEYaRw5.mjs +124 -0
  37. package/lib/create-element-NZEYaRw5.mjs.map +1 -0
  38. package/lib/index.cjs +746 -0
  39. package/lib/index.cjs.map +1 -0
  40. package/lib/index.d.cts +520 -0
  41. package/lib/index.d.cts.map +1 -0
  42. package/lib/index.d.mts +520 -29
  43. package/lib/index.d.mts.map +1 -0
  44. package/lib/index.mjs +692 -223
  45. package/lib/index.mjs.map +1 -1
  46. package/lib/jsx-dev-runtime.cjs +11 -0
  47. package/lib/jsx-dev-runtime.cjs.map +1 -0
  48. package/lib/jsx-dev-runtime.d.cts +8 -0
  49. package/lib/jsx-dev-runtime.d.cts.map +1 -0
  50. package/lib/jsx-dev-runtime.d.mts +8 -4
  51. package/lib/jsx-dev-runtime.d.mts.map +1 -0
  52. package/lib/jsx-dev-runtime.mjs +5 -6
  53. package/lib/jsx-dev-runtime.mjs.map +1 -1
  54. package/lib/jsx-runtime.cjs +5 -0
  55. package/lib/jsx-runtime.d.cts +3 -0
  56. package/lib/jsx-runtime.d.mts +3 -3
  57. package/lib/jsx-runtime.mjs +3 -3
  58. package/lib/jsx.cjs +0 -0
  59. package/lib/jsx.d.cts +19 -0
  60. package/lib/jsx.d.cts.map +1 -0
  61. package/lib/jsx.d.mts +19 -1
  62. package/lib/jsx.d.mts.map +1 -0
  63. package/lib/jsx.mjs +1 -3
  64. package/lib/xml-node-BQA44ydQ.d.mts +96 -0
  65. package/lib/xml-node-BQA44ydQ.d.mts.map +1 -0
  66. package/lib/xml-node-CddziLym.d.cts +96 -0
  67. package/lib/xml-node-CddziLym.d.cts.map +1 -0
  68. package/package.json +9 -9
  69. package/project.json +2 -2
  70. package/src/adapters/xml-stream-adapter.service.mts +77 -16
  71. package/src/decorators/component.decorator.mts +72 -10
  72. package/src/decorators/component.decorator.spec.mts +40 -22
  73. package/src/decorators/xml-stream.decorator.mts +58 -3
  74. package/src/define-environment.mts +5 -6
  75. package/src/handlers/xml-stream.mts +25 -3
  76. package/src/runtime/render-to-xml.mts +72 -4
  77. package/src/tags/define-tag.mts +8 -0
  78. package/src/types/component.mts +46 -2
  79. package/src/types/config.mts +22 -0
  80. package/tsdown.config.mts +39 -0
  81. package/lib/_tsup-dts-rollup.d.mts +0 -414
  82. package/lib/_tsup-dts-rollup.d.ts +0 -414
  83. package/lib/chunk-6OR6LGJA.mjs +0 -153
  84. package/lib/chunk-6OR6LGJA.mjs.map +0 -1
  85. package/lib/index.d.ts +0 -29
  86. package/lib/index.js +0 -376
  87. package/lib/index.js.map +0 -1
  88. package/lib/jsx-dev-runtime.d.ts +0 -4
  89. package/lib/jsx-dev-runtime.js +0 -61
  90. package/lib/jsx-dev-runtime.js.map +0 -1
  91. package/lib/jsx-runtime.d.ts +0 -3
  92. package/lib/jsx-runtime.js +0 -57
  93. package/lib/jsx-runtime.js.map +0 -1
  94. package/lib/jsx-runtime.mjs.map +0 -1
  95. package/lib/jsx.d.ts +0 -1
  96. package/lib/jsx.js +0 -4
  97. package/lib/jsx.js.map +0 -1
  98. package/lib/jsx.mjs.map +0 -1
  99. package/tsup.config.mts +0 -18
@@ -1,33 +1,74 @@
1
1
  import type {
2
2
  AbstractHttpHandlerAdapterInterface,
3
+ ClassType,
3
4
  HandlerMetadata,
5
+ ScopedContainer,
4
6
  } from '@navios/core'
5
- import type { ClassType, RequestContextHolder } from '@navios/di'
6
7
 
7
- import { StreamAdapterToken, XmlStreamAdapterToken } from '@navios/core'
8
- import { Container, inject, Injectable } from '@navios/di'
8
+ import {
9
+ inject,
10
+ Injectable,
11
+ StreamAdapterToken,
12
+ XmlStreamAdapterToken,
13
+ } from '@navios/core'
9
14
 
10
15
  import type { BaseXmlStreamConfig } from '../types/config.mjs'
11
16
  import type { AnyXmlNode } from '../types/xml-node.mjs'
12
17
 
13
18
  import { renderToXml } from '../runtime/render-to-xml.mjs'
14
19
 
20
+ /**
21
+ * Adapter service for handling XML Stream endpoints in Navios.
22
+ *
23
+ * This service integrates with the base stream adapter (Fastify or Bun) to handle
24
+ * XML endpoints that return JSX-based XML responses. It automatically renders JSX
25
+ * nodes to XML strings and sends them with the appropriate Content-Type headers.
26
+ *
27
+ * The service supports:
28
+ * - Async components (resolved in parallel)
29
+ * - Class components (resolved via DI container)
30
+ * - Regular JSX elements
31
+ * - CDATA sections
32
+ * - Raw XML content
33
+ *
34
+ * @implements {AbstractHttpHandlerAdapterInterface}
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * // This service is automatically registered when using defineXmlEnvironment()
39
+ * // and is used by endpoints decorated with @XmlStream()
40
+ * ```
41
+ */
15
42
  @Injectable({
16
43
  token: XmlStreamAdapterToken,
17
44
  })
18
45
  export class XmlStreamAdapterService implements AbstractHttpHandlerAdapterInterface {
19
- protected container = inject(Container)
20
46
  /** Base stream adapter - we proxy hasSchema, prepareArguments, provideSchema to it */
21
47
  protected streamAdapter = inject(StreamAdapterToken)
22
48
 
23
49
  /**
24
- * Proxy to base StreamAdapter - reuses existing argument preparation logic
25
- * (handles querySchema, requestSchema, URL params for both Fastify and Bun)
50
+ * Prepares argument getters for parsing request data.
51
+ *
52
+ * Proxies to the base stream adapter to reuse existing argument preparation logic
53
+ * that handles query parameters, request body, and URL parameters for both
54
+ * Fastify and Bun adapters.
55
+ *
56
+ * @param handlerMetadata - The handler metadata with schemas and configuration.
57
+ * @returns An array of getter functions that populate request arguments.
26
58
  */
27
59
  prepareArguments(handlerMetadata: HandlerMetadata<BaseXmlStreamConfig>) {
28
60
  return this.streamAdapter.prepareArguments?.(handlerMetadata) ?? []
29
61
  }
30
62
 
63
+ /**
64
+ * Provides schema information for the handler.
65
+ *
66
+ * Proxies to the base stream adapter to reuse existing schema generation logic.
67
+ * For Fastify, this enables built-in validation. For Bun, this returns an empty object.
68
+ *
69
+ * @param handlerMetadata - The handler metadata containing configuration and schemas.
70
+ * @returns Schema information (Fastify route schema or empty object for Bun).
71
+ */
31
72
  provideSchema(
32
73
  handlerMetadata: HandlerMetadata<BaseXmlStreamConfig>,
33
74
  ): Record<string, any> {
@@ -40,6 +81,14 @@ export class XmlStreamAdapterService implements AbstractHttpHandlerAdapterInterf
40
81
  return {}
41
82
  }
42
83
 
84
+ /**
85
+ * Checks if the handler has any validation schemas defined.
86
+ *
87
+ * Proxies to the base stream adapter to check for query or request schemas.
88
+ *
89
+ * @param handlerMetadata - The handler metadata containing configuration.
90
+ * @returns `true` if the handler has any schemas (query or request).
91
+ */
43
92
  hasSchema(handlerMetadata: HandlerMetadata<any>): boolean {
44
93
  if (
45
94
  'hasSchema' in this.streamAdapter &&
@@ -51,12 +100,25 @@ export class XmlStreamAdapterService implements AbstractHttpHandlerAdapterInterf
51
100
  }
52
101
 
53
102
  /**
54
- * Custom handler - renders JSX to XML and handles response for both Fastify and Bun
103
+ * Creates a request handler function for XML Stream endpoints.
104
+ *
105
+ * This method generates a handler that:
106
+ * 1. Parses and validates request data (body, query, URL params) using the base adapter
107
+ * 2. Invokes the controller method with validated arguments (returns JSX)
108
+ * 3. Renders the JSX tree to XML string (resolves async and class components)
109
+ * 4. Sends the XML response with appropriate Content-Type header
110
+ *
111
+ * The handler automatically detects the environment (Fastify vs Bun) and uses the
112
+ * appropriate response mechanism (reply object vs Response object).
113
+ *
114
+ * @param controller - The controller class containing the handler method.
115
+ * @param handlerMetadata - The handler metadata with configuration and schemas.
116
+ * @returns A function that handles incoming requests and sends XML responses.
55
117
  */
56
118
  provideHandler(
57
119
  controller: ClassType,
58
120
  handlerMetadata: HandlerMetadata<BaseXmlStreamConfig>,
59
- ): (context: RequestContextHolder, request: any, reply: any) => Promise<any> {
121
+ ): (context: ScopedContainer, request: any, reply: any) => Promise<any> {
60
122
  const getters = this.prepareArguments(handlerMetadata)
61
123
  const config = handlerMetadata.config
62
124
 
@@ -74,14 +136,9 @@ export class XmlStreamAdapterService implements AbstractHttpHandlerAdapterInterf
74
136
  }
75
137
 
76
138
  const contentType = config.contentType ?? 'application/xml'
77
- const renderOptions = {
78
- declaration: config.xmlDeclaration ?? true,
79
- encoding: config.encoding ?? 'UTF-8',
80
- container: this.container,
81
- }
82
139
 
83
- return async (context: RequestContextHolder, request: any, reply: any) => {
84
- const controllerInstance = await this.container.get(controller)
140
+ return async (context: ScopedContainer, request: any, reply: any) => {
141
+ const controllerInstance = await context.get(controller)
85
142
  const argument = await formatArguments(request)
86
143
 
87
144
  // Call controller method - returns XmlNode (JSX), may contain async/class components
@@ -89,7 +146,11 @@ export class XmlStreamAdapterService implements AbstractHttpHandlerAdapterInterf
89
146
  await controllerInstance[handlerMetadata.classMethod](argument)
90
147
 
91
148
  // Render JSX to XML string (async - resolves all async and class components)
92
- const xml = await renderToXml(xmlNode, renderOptions)
149
+ const xml = await renderToXml(xmlNode, {
150
+ declaration: config.xmlDeclaration ?? true,
151
+ encoding: config.encoding ?? 'UTF-8',
152
+ container: context,
153
+ })
93
154
 
94
155
  // Environment detection: Bun doesn't have reply
95
156
  const isHttpStandardEnvironment = reply === undefined
@@ -1,19 +1,70 @@
1
+ import type { Registry } from '@navios/core'
1
2
  import type { z, ZodObject, ZodRawShape } from 'zod/v4'
2
3
 
3
- import type { Registry } from '@navios/di'
4
-
5
4
  import {
5
+ globalRegistry,
6
6
  InjectableScope,
7
- InjectableType,
8
7
  InjectableTokenMeta,
8
+ InjectableType,
9
9
  InjectionToken,
10
- globalRegistry,
11
- } from '@navios/di'
10
+ } from '@navios/core'
12
11
 
13
12
  import type { ComponentClass, XmlComponent } from '../types/component.mjs'
14
13
 
15
14
  export const ComponentMeta = Symbol.for('xml.component.meta')
16
15
 
16
+ /**
17
+ * Decorator for class-based XML components with dependency injection support.
18
+ *
19
+ * Class components must implement the `XmlComponent` interface with a `render()` method.
20
+ * They can optionally accept props via constructor, validated with a Zod schema.
21
+ *
22
+ * @overload
23
+ * Component without props (no schema).
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * @Component()
28
+ * class LatestPostsComponent implements XmlComponent {
29
+ * private readonly postService = inject(PostService)
30
+ *
31
+ * async render() {
32
+ * const posts = await this.postService.getLatestPosts()
33
+ * return <>{posts.map(post => <item>...</item>)}</>
34
+ * }
35
+ * }
36
+ * ```
37
+ *
38
+ * @overload
39
+ * Component with props schema for type-safe props.
40
+ *
41
+ * @param options - Configuration object with schema and optional registry.
42
+ * @param options.schema - Zod schema for validating and typing component props.
43
+ * @param options.registry - Optional custom DI registry (defaults to global registry).
44
+ *
45
+ * @example
46
+ * ```tsx
47
+ * const DescriptionSchema = z.object({
48
+ * content: z.string(),
49
+ * wrapInCData: z.boolean().optional(),
50
+ * })
51
+ *
52
+ * @Component({ schema: DescriptionSchema })
53
+ * class DescriptionComponent implements XmlComponent {
54
+ * constructor(private props: z.output<typeof DescriptionSchema>) {}
55
+ *
56
+ * async render() {
57
+ * return <description>{this.props.wrapInCData ? <CData>{this.props.content}</CData> : this.props.content}</description>
58
+ * }
59
+ * }
60
+ * ```
61
+ *
62
+ * @overload
63
+ * Component with custom registry only (no props).
64
+ *
65
+ * @param options - Configuration object with registry.
66
+ * @param options.registry - Custom DI registry to use for this component.
67
+ */
17
68
  // #1 Component without props (no schema)
18
69
  export function Component(): <T extends ComponentClass>(
19
70
  target: T,
@@ -32,10 +83,7 @@ export function Component<Schema extends ZodObject<ZodRawShape>>(options: {
32
83
  // #3 Component with custom registry only
33
84
  export function Component(options: {
34
85
  registry: Registry
35
- }): <T extends ComponentClass>(
36
- target: T,
37
- context?: ClassDecoratorContext,
38
- ) => T
86
+ }): <T extends ComponentClass>(target: T, context?: ClassDecoratorContext) => T
39
87
 
40
88
  export function Component(
41
89
  options: {
@@ -91,7 +139,21 @@ export function Component(
91
139
  }
92
140
 
93
141
  /**
94
- * Type guard to check if a class is a component
142
+ * Type guard to check if a value is a component class.
143
+ *
144
+ * Component classes are classes decorated with `@Component` that implement
145
+ * the `XmlComponent` interface.
146
+ *
147
+ * @param value - The value to check.
148
+ * @returns `true` if the value is a component class, `false` otherwise.
149
+ *
150
+ * @example
151
+ * ```ts
152
+ * if (isComponentClass(MyClass)) {
153
+ * // MyClass is a component class
154
+ * const instance = await container.get(MyClass)
155
+ * }
156
+ * ```
95
157
  */
96
158
  export function isComponentClass(value: unknown): value is ComponentClass {
97
159
  return (
@@ -1,4 +1,4 @@
1
- import { Container, Registry } from '@navios/di'
1
+ import { Container, Registry } from '@navios/core'
2
2
 
3
3
  import { describe, expect, it } from 'vitest'
4
4
  import { z } from 'zod/v4'
@@ -152,13 +152,16 @@ describe('class component rendering', () => {
152
152
  }
153
153
 
154
154
  const container = new Container()
155
- container.beginRequest('test-request')
155
+ const requestContainer = container.beginRequest('test-request')
156
156
  try {
157
157
  const node = createElement(SimpleComponent, null)
158
- const xml = await renderToXml(node, { declaration: false, container })
158
+ const xml = await renderToXml(node, {
159
+ declaration: false,
160
+ container: requestContainer,
161
+ })
159
162
  expect(xml).toBe('<simple>content</simple>')
160
163
  } finally {
161
- await container.endRequest('test-request')
164
+ await requestContainer.endRequest()
162
165
  }
163
166
  })
164
167
 
@@ -177,13 +180,16 @@ describe('class component rendering', () => {
177
180
  }
178
181
 
179
182
  const container = new Container()
180
- container.beginRequest('test-request')
183
+ const requestContainer = container.beginRequest('test-request')
181
184
  try {
182
185
  const node = createElement(Greeting, { name: 'World' })
183
- const xml = await renderToXml(node, { declaration: false, container })
186
+ const xml = await renderToXml(node, {
187
+ declaration: false,
188
+ container: requestContainer,
189
+ })
184
190
  expect(xml).toBe('<greeting>Hello, World!</greeting>')
185
191
  } finally {
186
- await container.endRequest('test-request')
192
+ await requestContainer.endRequest()
187
193
  }
188
194
  })
189
195
 
@@ -203,13 +209,16 @@ describe('class component rendering', () => {
203
209
  }
204
210
 
205
211
  const container = new Container()
206
- container.beginRequest('test-request')
212
+ const requestContainer = container.beginRequest('test-request')
207
213
  try {
208
214
  const node = createElement(Outer, null)
209
- const xml = await renderToXml(node, { declaration: false, container })
215
+ const xml = await renderToXml(node, {
216
+ declaration: false,
217
+ container: requestContainer,
218
+ })
210
219
  expect(xml).toBe('<outer><inner>nested</inner></outer>')
211
220
  } finally {
212
- await container.endRequest('test-request')
221
+ await requestContainer.endRequest()
213
222
  }
214
223
  })
215
224
 
@@ -223,13 +232,16 @@ describe('class component rendering', () => {
223
232
  }
224
233
 
225
234
  const container = new Container()
226
- container.beginRequest('test-request')
235
+ const requestContainer = container.beginRequest('test-request')
227
236
  try {
228
237
  const node = createElement(AsyncComponent, null)
229
- const xml = await renderToXml(node, { declaration: false, container })
238
+ const xml = await renderToXml(node, {
239
+ declaration: false,
240
+ container: requestContainer,
241
+ })
230
242
  expect(xml).toBe('<async>loaded</async>')
231
243
  } finally {
232
- await container.endRequest('test-request')
244
+ await requestContainer.endRequest()
233
245
  }
234
246
  })
235
247
 
@@ -263,13 +275,13 @@ describe('class component rendering', () => {
263
275
  }
264
276
 
265
277
  const container = new Container()
266
- container.beginRequest('test-request')
278
+ const requestContainer = container.beginRequest('test-request')
267
279
  try {
268
280
  // Valid props
269
281
  const validNode = createElement(StrictComponent, { count: 5 })
270
282
  const xml = await renderToXml(validNode, {
271
283
  declaration: false,
272
- container,
284
+ container: requestContainer,
273
285
  })
274
286
  expect(xml).toBe('<count>5</count>')
275
287
 
@@ -279,7 +291,7 @@ describe('class component rendering', () => {
279
291
  renderToXml(invalidNode, { declaration: false, container }),
280
292
  ).rejects.toThrow()
281
293
  } finally {
282
- await container.endRequest('test-request')
294
+ await requestContainer.endRequest()
283
295
  }
284
296
  })
285
297
 
@@ -296,7 +308,7 @@ describe('class component rendering', () => {
296
308
  }
297
309
 
298
310
  const container = new Container()
299
- container.beginRequest('test-request')
311
+ const requestContainer = container.beginRequest('test-request')
300
312
  try {
301
313
  const node = createElement(
302
314
  'page',
@@ -304,12 +316,15 @@ describe('class component rendering', () => {
304
316
  createElement(Header, { title: 'Welcome' }),
305
317
  createElement(Footer, null),
306
318
  )
307
- const xml = await renderToXml(node, { declaration: false, container })
319
+ const xml = await renderToXml(node, {
320
+ declaration: false,
321
+ container: requestContainer,
322
+ })
308
323
  expect(xml).toBe(
309
324
  '<page><header>Welcome</header><footer>Copyright 2025</footer></page>',
310
325
  )
311
326
  } finally {
312
- await container.endRequest('test-request')
327
+ await requestContainer.endRequest()
313
328
  }
314
329
  })
315
330
 
@@ -328,7 +343,7 @@ describe('class component rendering', () => {
328
343
  }
329
344
 
330
345
  const container = new Container()
331
- container.beginRequest('test-request')
346
+ const requestContainer = container.beginRequest('test-request')
332
347
  try {
333
348
  const node = createElement(
334
349
  Wrapper,
@@ -336,10 +351,13 @@ describe('class component rendering', () => {
336
351
  createElement('child1', null),
337
352
  createElement('child2', null),
338
353
  )
339
- const xml = await renderToXml(node, { declaration: false, container })
354
+ const xml = await renderToXml(node, {
355
+ declaration: false,
356
+ container: requestContainer,
357
+ })
340
358
  expect(xml).toBe('<wrapper><child1/><child2/></wrapper>')
341
359
  } finally {
342
- await container.endRequest('test-request')
360
+ await requestContainer.endRequest()
343
361
  }
344
362
  })
345
363
  })
@@ -5,6 +5,28 @@ import { getEndpointMetadata, XmlStreamAdapterToken } from '@navios/core'
5
5
 
6
6
  import type { BaseXmlStreamConfig } from '../types/config.mjs'
7
7
 
8
+ /**
9
+ * Type helper that extracts the parameter types for an XML Stream endpoint handler.
10
+ *
11
+ * This type automatically infers the correct parameter types based on the endpoint
12
+ * configuration, including URL parameters, query parameters, and request body.
13
+ *
14
+ * @template EndpointDeclaration - The endpoint declaration type from `declareXmlStream`.
15
+ * @template Url - The URL path pattern.
16
+ * @template QuerySchema - The query parameter schema type.
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * const getFeed = declareXmlStream({
21
+ * method: 'GET',
22
+ * url: '/feed/:category',
23
+ * querySchema: z.object({ page: z.string() }),
24
+ * })
25
+ *
26
+ * // XmlStreamParams<typeof getFeed> resolves to:
27
+ * // { urlParams: { category: string }, query: { page: string } }
28
+ * ```
29
+ */
8
30
  export type XmlStreamParams<
9
31
  EndpointDeclaration extends {
10
32
  config: BaseXmlStreamConfig<any, any, any, any>
@@ -22,16 +44,30 @@ export type XmlStreamParams<
22
44
  /**
23
45
  * Decorator for XML Stream endpoints that return JSX-based XML responses.
24
46
  *
47
+ * This decorator marks controller methods that return JSX elements, which will be
48
+ * automatically rendered to XML and sent with the appropriate Content-Type header.
49
+ * The method can be async and can contain async components, class components, and
50
+ * regular JSX elements.
51
+ *
52
+ * @template Method - The HTTP method (GET, POST, etc.).
53
+ * @template Url - The URL path pattern (supports parameters like `/posts/:id`).
54
+ * @template QuerySchema - Optional Zod schema for query parameter validation.
55
+ * @template RequestSchema - Optional Zod schema for request body validation.
56
+ *
57
+ * @param endpoint - The endpoint declaration created with `declareXmlStream`.
58
+ * @returns A method decorator function.
59
+ *
60
+ * @throws {Error} If used on a non-function or non-method.
61
+ * @throws {Error} If the endpoint URL already exists.
62
+ *
25
63
  * @example
26
64
  * ```typescript
27
- * import { XmlStream } from '@navios/adapter-xml'
65
+ * import { XmlStream, declareXmlStream } from '@navios/adapter-xml'
28
66
  * import { Controller } from '@navios/core'
29
67
  *
30
68
  * const getRssFeed = declareXmlStream({
31
69
  * method: 'GET',
32
70
  * url: '/feed.xml',
33
- * querySchema: undefined,
34
- * requestSchema: undefined,
35
71
  * contentType: 'application/rss+xml',
36
72
  * })
37
73
  *
@@ -49,6 +85,25 @@ export type XmlStreamParams<
49
85
  * }
50
86
  * }
51
87
  * ```
88
+ *
89
+ * @example
90
+ * ```typescript
91
+ * // With query parameters
92
+ * const getSitemap = declareXmlStream({
93
+ * method: 'GET',
94
+ * url: '/sitemap.xml',
95
+ * querySchema: z.object({ page: z.string().optional() }),
96
+ * })
97
+ *
98
+ * @Controller()
99
+ * class SitemapController {
100
+ * @XmlStream(getSitemap)
101
+ * async getSitemap(params: { query?: { page?: string } }) {
102
+ * const page = params.query?.page
103
+ * return <urlset>...</urlset>
104
+ * }
105
+ * }
106
+ * ```
52
107
  */
53
108
  export function XmlStream<
54
109
  Method extends HttpMethod = HttpMethod,
@@ -1,7 +1,6 @@
1
- import type { AnyInjectableType } from '@navios/di'
1
+ import type { AnyInjectableType } from '@navios/core'
2
2
 
3
- import { XmlStreamAdapterToken } from '@navios/core'
4
- import { InjectionToken } from '@navios/di'
3
+ import { InjectionToken, XmlStreamAdapterToken } from '@navios/core'
5
4
 
6
5
  import { XmlStreamAdapterService } from './adapters/index.mjs'
7
6
 
@@ -31,9 +30,9 @@ import { XmlStreamAdapterService } from './adapters/index.mjs'
31
30
  * ```
32
31
  */
33
32
  export function defineXmlEnvironment() {
34
- const httpTokens = new Map<InjectionToken<any, undefined>, AnyInjectableType>([
35
- [XmlStreamAdapterToken, XmlStreamAdapterService],
36
- ])
33
+ const httpTokens = new Map<InjectionToken<any, undefined>, AnyInjectableType>(
34
+ [[XmlStreamAdapterToken, XmlStreamAdapterService]],
35
+ )
37
36
  return {
38
37
  httpTokens,
39
38
  }
@@ -3,19 +3,41 @@ import type { HttpMethod } from '@navios/builder'
3
3
  import type { BaseXmlStreamConfig } from '../types/config.mjs'
4
4
 
5
5
  /**
6
- * Declares an XML Stream endpoint configuration for use with @XmlStream decorator.
6
+ * Declares an XML Stream endpoint configuration for use with `@XmlStream` decorator.
7
+ *
8
+ * This function creates an endpoint declaration that can be used with the `@XmlStream`
9
+ * decorator to mark controller methods that return JSX-based XML responses.
10
+ *
11
+ * @template Method - The HTTP method (GET, POST, etc.).
12
+ * @template Url - The URL path pattern (supports parameters like `/posts/:id`).
13
+ * @template QuerySchema - Optional Zod schema for query parameter validation.
14
+ * @template RequestSchema - Optional Zod schema for request body validation.
15
+ *
16
+ * @param config - The endpoint configuration including method, URL, schemas, and XML options.
17
+ * @returns An endpoint declaration object to be used with `@XmlStream` decorator.
7
18
  *
8
19
  * @example
9
20
  * ```typescript
10
21
  * import { declareXmlStream } from '@navios/adapter-xml'
22
+ * import { z } from 'zod/v4'
11
23
  *
24
+ * // Simple endpoint
12
25
  * export const getRssFeed = declareXmlStream({
13
26
  * method: 'GET',
14
27
  * url: '/feed.xml',
15
- * querySchema: undefined,
16
- * requestSchema: undefined,
17
28
  * contentType: 'application/rss+xml',
29
+ * })
30
+ *
31
+ * // With query parameters
32
+ * export const getSitemap = declareXmlStream({
33
+ * method: 'GET',
34
+ * url: '/sitemap.xml',
35
+ * querySchema: z.object({
36
+ * page: z.string().optional(),
37
+ * }),
38
+ * contentType: 'application/xml',
18
39
  * xmlDeclaration: true,
40
+ * encoding: 'UTF-8',
19
41
  * })
20
42
  * ```
21
43
  */