@mandujs/core 0.9.41 → 0.9.42

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 (67) hide show
  1. package/package.json +1 -1
  2. package/src/bundler/build.ts +91 -73
  3. package/src/bundler/dev.ts +21 -14
  4. package/src/client/globals.ts +44 -0
  5. package/src/client/index.ts +5 -4
  6. package/src/client/island.ts +8 -13
  7. package/src/client/router.ts +33 -41
  8. package/src/client/runtime.ts +23 -51
  9. package/src/client/window-state.ts +101 -0
  10. package/src/config/index.ts +1 -0
  11. package/src/config/mandu.ts +45 -9
  12. package/src/config/validate.ts +158 -0
  13. package/src/constants.ts +25 -0
  14. package/src/contract/client.ts +4 -3
  15. package/src/contract/define.ts +459 -0
  16. package/src/devtools/ai/context-builder.ts +375 -0
  17. package/src/devtools/ai/index.ts +25 -0
  18. package/src/devtools/ai/mcp-connector.ts +465 -0
  19. package/src/devtools/client/catchers/error-catcher.ts +327 -0
  20. package/src/devtools/client/catchers/index.ts +18 -0
  21. package/src/devtools/client/catchers/network-proxy.ts +363 -0
  22. package/src/devtools/client/components/index.ts +39 -0
  23. package/src/devtools/client/components/kitchen-root.tsx +362 -0
  24. package/src/devtools/client/components/mandu-character.tsx +241 -0
  25. package/src/devtools/client/components/overlay.tsx +368 -0
  26. package/src/devtools/client/components/panel/errors-panel.tsx +259 -0
  27. package/src/devtools/client/components/panel/guard-panel.tsx +244 -0
  28. package/src/devtools/client/components/panel/index.ts +32 -0
  29. package/src/devtools/client/components/panel/islands-panel.tsx +304 -0
  30. package/src/devtools/client/components/panel/network-panel.tsx +292 -0
  31. package/src/devtools/client/components/panel/panel-container.tsx +259 -0
  32. package/src/devtools/client/filters/context-filters.ts +282 -0
  33. package/src/devtools/client/filters/index.ts +16 -0
  34. package/src/devtools/client/index.ts +63 -0
  35. package/src/devtools/client/persistence.ts +335 -0
  36. package/src/devtools/client/state-manager.ts +478 -0
  37. package/src/devtools/design-tokens.ts +263 -0
  38. package/src/devtools/hook/create-hook.ts +207 -0
  39. package/src/devtools/hook/index.ts +13 -0
  40. package/src/devtools/index.ts +439 -0
  41. package/src/devtools/init.ts +266 -0
  42. package/src/devtools/protocol.ts +237 -0
  43. package/src/devtools/server/index.ts +17 -0
  44. package/src/devtools/server/source-context.ts +444 -0
  45. package/src/devtools/types.ts +319 -0
  46. package/src/devtools/worker/index.ts +25 -0
  47. package/src/devtools/worker/redaction-worker.ts +222 -0
  48. package/src/devtools/worker/worker-manager.ts +409 -0
  49. package/src/error/formatter.ts +28 -24
  50. package/src/error/index.ts +13 -9
  51. package/src/error/result.ts +46 -0
  52. package/src/error/types.ts +6 -4
  53. package/src/filling/filling.ts +6 -5
  54. package/src/guard/check.ts +60 -56
  55. package/src/guard/types.ts +3 -1
  56. package/src/guard/watcher.ts +10 -1
  57. package/src/index.ts +81 -0
  58. package/src/intent/index.ts +310 -0
  59. package/src/island/index.ts +304 -0
  60. package/src/router/fs-patterns.ts +7 -0
  61. package/src/router/fs-routes.ts +20 -8
  62. package/src/router/fs-scanner.ts +117 -133
  63. package/src/runtime/server.ts +261 -201
  64. package/src/runtime/ssr.ts +5 -4
  65. package/src/runtime/streaming-ssr.ts +5 -4
  66. package/src/utils/bun.ts +8 -0
  67. package/src/utils/lru-cache.ts +75 -0
@@ -368,63 +368,67 @@ export async function runGuardCheck(
368
368
  manifest: RoutesManifest,
369
369
  rootDir: string
370
370
  ): Promise<GuardCheckResult> {
371
- const violations: GuardViolation[] = [];
372
371
  const config = await loadManduConfig(rootDir);
373
-
374
- const lockPath = path.join(rootDir, "spec/spec.lock.json");
375
- const mapPath = path.join(rootDir, "packages/core/map/generated.map.json");
376
-
377
- // Rule 1
378
- const hashViolation = await checkSpecHashMismatch(manifest, lockPath);
379
- if (hashViolation) {
380
- violations.push(hashViolation);
381
- }
382
-
383
- // Load generated map for other checks
384
- let generatedMap: GeneratedMap | null = null;
385
- if (await fileExists(mapPath)) {
386
- try {
387
- const mapContent = await Bun.file(mapPath).text();
388
- generatedMap = JSON.parse(mapContent);
389
- } catch {
390
- // Map file corrupted or missing
391
- }
392
- }
393
-
394
- if (generatedMap) {
395
- // Rule 2
396
- const editViolations = await checkGeneratedManualEdit(rootDir, generatedMap);
397
- violations.push(...editViolations);
398
-
399
- // Rule 4
400
- const forbiddenViolations = await checkForbiddenImportsInGenerated(rootDir, generatedMap);
401
- violations.push(...forbiddenViolations);
402
- }
403
-
404
- // Rule 3
405
- const importViolations = await checkInvalidGeneratedImport(rootDir);
406
- violations.push(...importViolations);
407
-
408
- // Rule 5: Slot file existence
409
- const slotViolations = await checkSlotFileExists(manifest, rootDir);
410
- violations.push(...slotViolations);
411
-
412
- // Rule 6: Slot content validation (신규 - 강화된 검증)
413
- const slotContentViolations = await checkSlotContentValidation(manifest, rootDir);
414
- violations.push(...slotContentViolations);
415
-
416
- // Rule 7-10: Contract-related checks
417
- const contractViolations = await runContractGuardCheck(manifest, rootDir);
418
- violations.push(...contractViolations);
419
-
420
- // Rule: Island-First Integrity
421
- const islandViolations = await checkIslandFirstIntegrity(manifest, rootDir);
422
- violations.push(...islandViolations);
423
-
424
- // Rule: spec/ directory naming convention
425
- const specDirViolations = await checkSpecDirNaming(rootDir);
426
- violations.push(...specDirViolations);
427
-
372
+
373
+ const lockPath = path.join(rootDir, "spec/spec.lock.json");
374
+ const mapPath = path.join(rootDir, "packages/core/map/generated.map.json");
375
+
376
+ // ============================================
377
+ // Phase 1: 독립적인 검사 병렬 실행
378
+ // ============================================
379
+ const [
380
+ hashViolation,
381
+ importViolations,
382
+ slotViolations,
383
+ specDirViolations,
384
+ islandViolations,
385
+ ] = await Promise.all([
386
+ checkSpecHashMismatch(manifest, lockPath),
387
+ checkInvalidGeneratedImport(rootDir),
388
+ checkSlotFileExists(manifest, rootDir),
389
+ checkSpecDirNaming(rootDir),
390
+ checkIslandFirstIntegrity(manifest, rootDir),
391
+ ]);
392
+
393
+ const violations: GuardViolation[] = [];
394
+ if (hashViolation) violations.push(hashViolation);
395
+ violations.push(...importViolations);
396
+ violations.push(...slotViolations);
397
+ violations.push(...specDirViolations);
398
+ violations.push(...islandViolations);
399
+
400
+ // ============================================
401
+ // Phase 2: generatedMap 의존 검사
402
+ // ============================================
403
+ let generatedMap: GeneratedMap | null = null;
404
+ if (await fileExists(mapPath)) {
405
+ try {
406
+ const mapContent = await Bun.file(mapPath).text();
407
+ generatedMap = JSON.parse(mapContent);
408
+ } catch {
409
+ // Map file corrupted or missing
410
+ }
411
+ }
412
+
413
+ if (generatedMap) {
414
+ const [editViolations, forbiddenViolations] = await Promise.all([
415
+ checkGeneratedManualEdit(rootDir, generatedMap),
416
+ checkForbiddenImportsInGenerated(rootDir, generatedMap),
417
+ ]);
418
+ violations.push(...editViolations);
419
+ violations.push(...forbiddenViolations);
420
+ }
421
+
422
+ // ============================================
423
+ // Phase 3: Slot + Contract 검사 병렬
424
+ // ============================================
425
+ const [slotContentViolations, contractViolations] = await Promise.all([
426
+ checkSlotContentValidation(manifest, rootDir),
427
+ runContractGuardCheck(manifest, rootDir),
428
+ ]);
429
+ violations.push(...slotContentViolations);
430
+ violations.push(...contractViolations);
431
+
428
432
  const resolvedViolations = applyRuleSeverity(violations, config.guard ?? {});
429
433
  const passed = resolvedViolations.every((v) => v.severity !== "error");
430
434
 
@@ -6,6 +6,8 @@
6
6
  * @module guard/types
7
7
  */
8
8
 
9
+ import { TIMEOUTS } from "../constants";
10
+
9
11
  // ═══════════════════════════════════════════════════════════════════════════
10
12
  // Configuration Types
11
13
  // ═══════════════════════════════════════════════════════════════════════════
@@ -336,7 +338,7 @@ export const DEFAULT_GUARD_CONFIG: Required<Omit<GuardConfig, "preset" | "layers
336
338
  realtimeOutput: "console",
337
339
  cache: true,
338
340
  incremental: true,
339
- debounceMs: 100,
341
+ debounceMs: TIMEOUTS.WATCHER_DEBOUNCE,
340
342
  };
341
343
 
342
344
  /**
@@ -45,6 +45,15 @@ interface WatcherOptions {
45
45
 
46
46
  const analysisCache = new Map<string, FileAnalysis>();
47
47
 
48
+ let globModulePromise: Promise<typeof import("glob")> | null = null;
49
+
50
+ async function getGlobModule(): Promise<typeof import("glob")> {
51
+ if (!globModulePromise) {
52
+ globModulePromise = import("glob");
53
+ }
54
+ return globModulePromise;
55
+ }
56
+
48
57
  /**
49
58
  * 캐시 초기화
50
59
  */
@@ -167,7 +176,7 @@ export function createGuardWatcher(options: WatcherOptions): GuardWatcher {
167
176
  const analyses: FileAnalysis[] = [];
168
177
 
169
178
  // 글로브로 모든 파일 찾기
170
- const { glob } = await import("glob");
179
+ const { glob } = await getGlobModule();
171
180
  const extensions = WATCH_EXTENSIONS.map((ext) => ext.slice(1)).join(",");
172
181
  const scanRoots = new Set<string>([srcDir]);
173
182
  if (config.fsRoutes) {
package/src/index.ts CHANGED
@@ -15,10 +15,17 @@ export * from "./watcher";
15
15
  export * from "./router";
16
16
  export * from "./config";
17
17
  export * from "./seo";
18
+ export * from "./island";
19
+ export * from "./intent";
20
+ export * from "./devtools";
18
21
 
19
22
  // Consolidated Mandu namespace
20
23
  import { ManduFilling, ManduContext, ManduFillingFactory } from "./filling";
21
24
  import { createContract, defineHandler, defineRoute, createClient, contractFetch, createClientContract } from "./contract";
25
+ import { defineContract, generateAllFromContract, generateOpenAPISpec } from "./contract/define";
26
+ import { island, isIsland, type IslandComponent, type HydrationStrategy } from "./island";
27
+ import { intent, isIntent, getIntentDocs, generateOpenAPIFromIntent } from "./intent";
28
+ import { initializeHook, reportError, ManduDevTools, getStateManager } from "./devtools";
22
29
  import type { ContractDefinition, ContractInstance, ContractSchema } from "./contract";
23
30
  import type { ContractHandlers, ClientOptions } from "./contract";
24
31
 
@@ -94,4 +101,78 @@ export const Mandu = {
94
101
  * Make a type-safe fetch call
95
102
  */
96
103
  fetch: contractFetch,
104
+
105
+ // === AI-Native APIs ===
106
+ /**
107
+ * Define a Contract for code generation
108
+ * @example
109
+ * const api = Mandu.define({
110
+ * getUser: { method: 'GET', path: '/users/:id', output: userSchema },
111
+ * });
112
+ */
113
+ define: defineContract,
114
+
115
+ /**
116
+ * Create an Island component (declarative hydration)
117
+ * @example
118
+ * export default Mandu.island('visible', ({ name }) => <div>{name}</div>);
119
+ */
120
+ island,
121
+
122
+ /**
123
+ * Check if a component is an Island
124
+ */
125
+ isIsland,
126
+
127
+ /**
128
+ * Create an Intent-based API handler
129
+ * @example
130
+ * export default Mandu.intent({
131
+ * '사용자 조회': { method: 'GET', handler: (ctx) => ctx.ok(user) },
132
+ * });
133
+ */
134
+ intent,
135
+
136
+ /**
137
+ * Check if a handler is an Intent
138
+ */
139
+ isIntent,
140
+
141
+ /**
142
+ * Generate code from Contract
143
+ */
144
+ generate: generateAllFromContract,
145
+
146
+ /**
147
+ * Generate OpenAPI spec from Contract
148
+ */
149
+ openapi: generateOpenAPISpec,
150
+
151
+ // === DevTools API ===
152
+ /**
153
+ * Initialize DevTools hook (call at app startup)
154
+ * @example
155
+ * Mandu.devtools.init();
156
+ */
157
+ devtools: {
158
+ /**
159
+ * Initialize DevTools
160
+ */
161
+ init: initializeHook,
162
+
163
+ /**
164
+ * Report an error to DevTools
165
+ */
166
+ reportError,
167
+
168
+ /**
169
+ * Get the state manager instance
170
+ */
171
+ getStateManager,
172
+
173
+ /**
174
+ * DevTools public API (also available as window.ManduDevTools)
175
+ */
176
+ api: ManduDevTools,
177
+ },
97
178
  } as const;
@@ -0,0 +1,310 @@
1
+ /**
2
+ * Mandu Intent - 의도 기반 API 라우팅
3
+ *
4
+ * @example
5
+ * ```ts
6
+ * import { intent } from '@mandujs/core';
7
+ *
8
+ * export default intent({
9
+ * '사용자 목록 조회': {
10
+ * method: 'GET',
11
+ * handler: (ctx) => ctx.ok(users),
12
+ * },
13
+ * '사용자 생성': {
14
+ * method: 'POST',
15
+ * input: z.object({ name: z.string() }),
16
+ * handler: async (ctx) => {
17
+ * const data = await ctx.body();
18
+ * return ctx.created(createUser(data));
19
+ * },
20
+ * },
21
+ * });
22
+ * ```
23
+ */
24
+
25
+ import { z, type ZodType } from 'zod';
26
+ import { ManduFillingFactory, type ManduFilling } from '../filling/filling';
27
+ import type { ManduContext } from '../filling/context';
28
+
29
+ // ============================================================================
30
+ // Types
31
+ // ============================================================================
32
+
33
+ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
34
+
35
+ export interface IntentDefinition<TInput = unknown, TOutput = unknown> {
36
+ /** HTTP 메서드 */
37
+ method: HttpMethod;
38
+ /** 추가 경로 (예: '/:id') */
39
+ path?: string;
40
+ /** 입력 스키마 (Zod) */
41
+ input?: ZodType<TInput>;
42
+ /** 출력 스키마 (Zod) - 문서화/검증용 */
43
+ output?: ZodType<TOutput>;
44
+ /** 가능한 에러 코드 목록 */
45
+ errors?: readonly string[];
46
+ /** 설명 (OpenAPI 문서용) */
47
+ description?: string;
48
+ /** 핸들러 함수 */
49
+ handler: (ctx: ManduContext) => Response | Promise<Response>;
50
+ /** Guard/Middleware */
51
+ guard?: (ctx: ManduContext) => Response | void | Promise<Response | void>;
52
+ }
53
+
54
+ export type IntentMap = Record<string, IntentDefinition<any, any>>;
55
+
56
+ export interface IntentMeta {
57
+ __intent: true;
58
+ __intents: IntentMap;
59
+ __docs: IntentDocumentation[];
60
+ }
61
+
62
+ export interface IntentDocumentation {
63
+ name: string;
64
+ method: HttpMethod;
65
+ path: string;
66
+ description?: string;
67
+ input?: ZodType<unknown>;
68
+ output?: ZodType<unknown>;
69
+ errors?: readonly string[];
70
+ }
71
+
72
+ // ============================================================================
73
+ // intent() - 의도 기반 API 생성
74
+ // ============================================================================
75
+
76
+ /**
77
+ * 의도 기반 API 라우트 생성
78
+ *
79
+ * 하나의 파일에서 여러 관련 API를 의도(intent)로 그룹화
80
+ * - 의도 이름이 자동으로 OpenAPI description이 됨
81
+ * - AI가 "사용자 삭제 API"를 쉽게 찾을 수 있음
82
+ * - 타입 안전한 입출력
83
+ */
84
+ export function intent(intents: IntentMap): ManduFilling & IntentMeta {
85
+ const filling = ManduFillingFactory.filling();
86
+ const docs: IntentDocumentation[] = [];
87
+
88
+ // 메서드별로 핸들러 그룹화
89
+ const methodHandlers: Record<HttpMethod, IntentDefinition<any, any>[]> = {
90
+ GET: [],
91
+ POST: [],
92
+ PUT: [],
93
+ PATCH: [],
94
+ DELETE: [],
95
+ HEAD: [],
96
+ OPTIONS: [],
97
+ };
98
+
99
+ // Intent 분류 및 문서화
100
+ for (const [intentName, definition] of Object.entries(intents)) {
101
+ methodHandlers[definition.method].push({
102
+ ...definition,
103
+ description: definition.description || intentName,
104
+ });
105
+
106
+ docs.push({
107
+ name: intentName,
108
+ method: definition.method,
109
+ path: definition.path || '/',
110
+ description: definition.description || intentName,
111
+ input: definition.input,
112
+ output: definition.output,
113
+ errors: definition.errors,
114
+ });
115
+ }
116
+
117
+ // 각 메서드에 대해 핸들러 등록
118
+ const registerMethod = (method: HttpMethod, handlers: IntentDefinition<any, any>[]) => {
119
+ if (handlers.length === 0) return;
120
+
121
+ const methodLower = method.toLowerCase() as Lowercase<HttpMethod>;
122
+
123
+ (filling as any)[methodLower](async (ctx: ManduContext) => {
124
+ // 경로 매칭 (path가 있는 경우)
125
+ for (const def of handlers) {
126
+ if (def.path && !matchPath(ctx.url, def.path)) {
127
+ continue;
128
+ }
129
+
130
+ // Guard 실행
131
+ if (def.guard) {
132
+ const guardResult = await def.guard(ctx);
133
+ if (guardResult instanceof Response) {
134
+ return guardResult;
135
+ }
136
+ }
137
+
138
+ // Input 검증
139
+ if (def.input && ['POST', 'PUT', 'PATCH'].includes(method)) {
140
+ const bodyResult = await ctx.body(def.input);
141
+ if (!bodyResult.success) {
142
+ return ctx.error('Validation failed', bodyResult.error);
143
+ }
144
+ }
145
+
146
+ // 핸들러 실행
147
+ return def.handler(ctx);
148
+ }
149
+
150
+ // 매칭되는 핸들러 없음
151
+ return ctx.notFound(`No handler for ${method} ${ctx.url}`);
152
+ });
153
+ };
154
+
155
+ // 모든 메서드 등록
156
+ for (const [method, handlers] of Object.entries(methodHandlers)) {
157
+ registerMethod(method as HttpMethod, handlers);
158
+ }
159
+
160
+ // 메타데이터 부착
161
+ const result = filling as ManduFilling & IntentMeta;
162
+ result.__intent = true;
163
+ result.__intents = intents;
164
+ result.__docs = docs;
165
+
166
+ return result;
167
+ }
168
+
169
+ // ============================================================================
170
+ // Helper Functions
171
+ // ============================================================================
172
+
173
+ /**
174
+ * 간단한 경로 매칭 (/:id 같은 패턴)
175
+ */
176
+ function matchPath(url: string, pattern: string): boolean {
177
+ if (pattern === '/') return true;
178
+
179
+ const urlPath = new URL(url, 'http://localhost').pathname;
180
+ const patternParts = pattern.split('/').filter(Boolean);
181
+ const urlParts = urlPath.split('/').filter(Boolean);
182
+
183
+ if (patternParts.length !== urlParts.length) return false;
184
+
185
+ return patternParts.every((part, i) => {
186
+ if (part.startsWith(':')) return true; // 동적 파라미터
187
+ return part === urlParts[i];
188
+ });
189
+ }
190
+
191
+ /**
192
+ * Intent에서 OpenAPI 스펙 생성
193
+ */
194
+ export function generateOpenAPIFromIntent(
195
+ basePath: string,
196
+ intentFilling: IntentMeta
197
+ ): Record<string, unknown> {
198
+ const paths: Record<string, Record<string, unknown>> = {};
199
+
200
+ for (const doc of intentFilling.__docs) {
201
+ const fullPath = basePath + (doc.path === '/' ? '' : doc.path);
202
+ const method = doc.method.toLowerCase();
203
+
204
+ if (!paths[fullPath]) {
205
+ paths[fullPath] = {};
206
+ }
207
+
208
+ paths[fullPath][method] = {
209
+ summary: doc.name,
210
+ description: doc.description,
211
+ requestBody: doc.input
212
+ ? {
213
+ content: {
214
+ 'application/json': {
215
+ schema: zodToJsonSchema(doc.input),
216
+ },
217
+ },
218
+ }
219
+ : undefined,
220
+ responses: {
221
+ '200': {
222
+ description: 'Success',
223
+ content: doc.output
224
+ ? {
225
+ 'application/json': {
226
+ schema: zodToJsonSchema(doc.output),
227
+ },
228
+ }
229
+ : undefined,
230
+ },
231
+ ...(doc.errors?.reduce(
232
+ (acc, error) => ({
233
+ ...acc,
234
+ [getErrorStatusCode(error)]: { description: error },
235
+ }),
236
+ {}
237
+ ) || {}),
238
+ },
239
+ };
240
+ }
241
+
242
+ return { paths };
243
+ }
244
+
245
+ /**
246
+ * 간단한 Zod → JSON Schema 변환
247
+ */
248
+ function zodToJsonSchema(schema: ZodType<unknown>): Record<string, unknown> {
249
+ // 실제 구현은 zod-to-json-schema 라이브러리 사용 권장
250
+ const def = (schema as any)._def;
251
+
252
+ if (def.typeName === 'ZodString') {
253
+ return { type: 'string' };
254
+ }
255
+ if (def.typeName === 'ZodNumber') {
256
+ return { type: 'number' };
257
+ }
258
+ if (def.typeName === 'ZodBoolean') {
259
+ return { type: 'boolean' };
260
+ }
261
+ if (def.typeName === 'ZodObject') {
262
+ const properties: Record<string, unknown> = {};
263
+ for (const [key, value] of Object.entries(def.shape())) {
264
+ properties[key] = zodToJsonSchema(value as ZodType<unknown>);
265
+ }
266
+ return { type: 'object', properties };
267
+ }
268
+ if (def.typeName === 'ZodArray') {
269
+ return { type: 'array', items: zodToJsonSchema(def.type) };
270
+ }
271
+
272
+ return { type: 'unknown' };
273
+ }
274
+
275
+ /**
276
+ * 에러 코드 → HTTP 상태 코드
277
+ */
278
+ function getErrorStatusCode(error: string): number {
279
+ const errorMap: Record<string, number> = {
280
+ NOT_FOUND: 404,
281
+ UNAUTHORIZED: 401,
282
+ FORBIDDEN: 403,
283
+ RATE_LIMITED: 429,
284
+ INVALID_INPUT: 400,
285
+ VALIDATION_ERROR: 400,
286
+ INTERNAL_ERROR: 500,
287
+ };
288
+
289
+ return errorMap[error] || 400;
290
+ }
291
+
292
+ // ============================================================================
293
+ // isIntent() - Intent 체크
294
+ // ============================================================================
295
+
296
+ export function isIntent(value: unknown): value is ManduFilling & IntentMeta {
297
+ return (
298
+ typeof value === 'object' &&
299
+ value !== null &&
300
+ (value as IntentMeta).__intent === true
301
+ );
302
+ }
303
+
304
+ // ============================================================================
305
+ // getIntentDocs() - Intent 문서 추출
306
+ // ============================================================================
307
+
308
+ export function getIntentDocs(intentFilling: IntentMeta): IntentDocumentation[] {
309
+ return intentFilling.__docs;
310
+ }