@praxisui/files-upload 9.0.0-beta.11 → 9.0.0-beta.13

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.
@@ -0,0 +1,1776 @@
1
+ {
2
+ "schemaVersion": "1.0.0",
3
+ "generatedAt": "2026-06-22T22:56:44.148Z",
4
+ "packageName": "@praxisui/files-upload",
5
+ "packageVersion": "9.0.0-beta.13",
6
+ "sourceRegistry": "praxis-component-registry-ingestion",
7
+ "sourceRegistryVersion": "1.0.0",
8
+ "componentCount": 1,
9
+ "components": {
10
+ "praxis-files-upload": {
11
+ "id": "praxis-files-upload",
12
+ "description": "Componente para upload de arquivos com suporte a configuracao dinamica, eventos e integracao com backend.",
13
+ "inputs": [
14
+ {
15
+ "name": "config",
16
+ "type": "FilesUploadConfig",
17
+ "required": false
18
+ },
19
+ {
20
+ "name": "filesUploadId",
21
+ "type": "string",
22
+ "required": false
23
+ },
24
+ {
25
+ "name": "componentInstanceId",
26
+ "type": "string",
27
+ "required": false
28
+ },
29
+ {
30
+ "name": "baseUrl",
31
+ "type": "string",
32
+ "required": false
33
+ },
34
+ {
35
+ "name": "displayMode",
36
+ "type": "'full' | 'compact'",
37
+ "required": false
38
+ },
39
+ {
40
+ "name": "context",
41
+ "type": "Record<string, unknown>",
42
+ "required": false
43
+ },
44
+ {
45
+ "name": "enableCustomization",
46
+ "type": "boolean",
47
+ "required": false
48
+ }
49
+ ],
50
+ "outputs": [
51
+ {
52
+ "name": "uploadSuccess",
53
+ "type": "FileMetadata",
54
+ "required": false
55
+ },
56
+ {
57
+ "name": "bulkComplete",
58
+ "type": "BulkUploadResponseData",
59
+ "required": false
60
+ },
61
+ {
62
+ "name": "error",
63
+ "type": "ErrorResponse",
64
+ "required": false
65
+ },
66
+ {
67
+ "name": "rateLimited",
68
+ "type": "RateLimitInfo",
69
+ "required": false
70
+ },
71
+ {
72
+ "name": "uploadStart",
73
+ "type": "UploadStartEvent",
74
+ "required": false
75
+ },
76
+ {
77
+ "name": "uploadProgress",
78
+ "type": "UploadProgressEvent",
79
+ "required": false
80
+ },
81
+ {
82
+ "name": "retry",
83
+ "type": "BulkUploadFileResult",
84
+ "required": false
85
+ },
86
+ {
87
+ "name": "download",
88
+ "type": "BulkUploadFileResult",
89
+ "required": false
90
+ },
91
+ {
92
+ "name": "copyLink",
93
+ "type": "BulkUploadFileResult",
94
+ "required": false
95
+ },
96
+ {
97
+ "name": "detailsOpened",
98
+ "type": "BulkUploadFileResult",
99
+ "required": false
100
+ },
101
+ {
102
+ "name": "detailsClosed",
103
+ "type": "BulkUploadFileResult",
104
+ "required": false
105
+ },
106
+ {
107
+ "name": "pendingStateChange",
108
+ "type": "PendingFilesState",
109
+ "required": false
110
+ },
111
+ {
112
+ "name": "readinessChange",
113
+ "type": "FilesUploadReadinessEvent",
114
+ "required": false
115
+ },
116
+ {
117
+ "name": "proximityChange",
118
+ "type": "boolean",
119
+ "required": false
120
+ }
121
+ ],
122
+ "configSchemaId": null,
123
+ "selector": "praxis-files-upload",
124
+ "friendlyName": "Praxis Files Upload",
125
+ "icon": "upload_file",
126
+ "tags": [
127
+ "files",
128
+ "upload",
129
+ "widget",
130
+ "configurable"
131
+ ],
132
+ "lib": "@praxisui/files-upload",
133
+ "source": "projects/praxis-files-upload/src/lib/praxis-files-upload.metadata.ts",
134
+ "exportName": "PRAXIS_FILES_UPLOAD_COMPONENT_METADATA",
135
+ "componentCapabilities": [
136
+ {
137
+ "path": "strategy",
138
+ "category": "strategy",
139
+ "valueKind": "enum",
140
+ "allowedValues": [
141
+ "direct",
142
+ "presign",
143
+ "auto"
144
+ ],
145
+ "description": "Upload strategy."
146
+ },
147
+ {
148
+ "path": "ui",
149
+ "category": "ui",
150
+ "valueKind": "object",
151
+ "description": "UI configuration."
152
+ },
153
+ {
154
+ "path": "ui.showDropzone",
155
+ "category": "ui",
156
+ "valueKind": "boolean",
157
+ "description": "Show drag-and-drop dropzone."
158
+ },
159
+ {
160
+ "path": "ui.accept",
161
+ "category": "ui",
162
+ "valueKind": "array",
163
+ "description": "Accept attribute hints (extensions or mime types)."
164
+ },
165
+ {
166
+ "path": "ui.accept[]",
167
+ "category": "ui",
168
+ "valueKind": "string",
169
+ "description": "Single accept entry."
170
+ },
171
+ {
172
+ "path": "ui.dense",
173
+ "category": "ui",
174
+ "valueKind": "boolean",
175
+ "description": "Dense layout."
176
+ },
177
+ {
178
+ "path": "ui.showConflictPolicySelector",
179
+ "category": "ui",
180
+ "valueKind": "boolean",
181
+ "description": "Show conflict policy selector."
182
+ },
183
+ {
184
+ "path": "ui.showMetadataForm",
185
+ "category": "ui",
186
+ "valueKind": "boolean",
187
+ "description": "Show metadata form for each file."
188
+ },
189
+ {
190
+ "path": "ui.showProgress",
191
+ "category": "ui",
192
+ "valueKind": "boolean",
193
+ "description": "Show progress UI."
194
+ },
195
+ {
196
+ "path": "ui.manualUpload",
197
+ "category": "ui",
198
+ "valueKind": "boolean",
199
+ "description": "Require manual start for uploads."
200
+ },
201
+ {
202
+ "path": "ui.dropzone",
203
+ "category": "ui",
204
+ "valueKind": "object",
205
+ "description": "Dropzone interaction options."
206
+ },
207
+ {
208
+ "path": "ui.dropzone.expandOnDragProximity",
209
+ "category": "ui",
210
+ "valueKind": "boolean",
211
+ "description": "Expand dropzone on drag proximity."
212
+ },
213
+ {
214
+ "path": "ui.dropzone.proximityPx",
215
+ "category": "ui",
216
+ "valueKind": "number",
217
+ "description": "Proximity radius in pixels."
218
+ },
219
+ {
220
+ "path": "ui.dropzone.expandMode",
221
+ "category": "ui",
222
+ "valueKind": "enum",
223
+ "allowedValues": [
224
+ "overlay",
225
+ "inline"
226
+ ],
227
+ "description": "Dropzone expansion mode."
228
+ },
229
+ {
230
+ "path": "ui.dropzone.expandHeight",
231
+ "category": "ui",
232
+ "valueKind": "number",
233
+ "description": "Expanded height (px)."
234
+ },
235
+ {
236
+ "path": "ui.dropzone.expandDebounceMs",
237
+ "category": "ui",
238
+ "valueKind": "number",
239
+ "description": "Drag debounce (ms)."
240
+ },
241
+ {
242
+ "path": "ui.list",
243
+ "category": "ui",
244
+ "valueKind": "object",
245
+ "description": "Uploaded files list options."
246
+ },
247
+ {
248
+ "path": "ui.list.collapseAfter",
249
+ "category": "ui",
250
+ "valueKind": "number",
251
+ "description": "Collapse list after N items."
252
+ },
253
+ {
254
+ "path": "ui.list.detailsMode",
255
+ "category": "ui",
256
+ "valueKind": "enum",
257
+ "allowedValues": [
258
+ "card",
259
+ "sidesheet",
260
+ "auto"
261
+ ],
262
+ "description": "Details panel mode."
263
+ },
264
+ {
265
+ "path": "ui.list.detailsMaxWidth",
266
+ "category": "ui",
267
+ "valueKind": "number",
268
+ "description": "Details panel max width (px)."
269
+ },
270
+ {
271
+ "path": "ui.list.detailsShowTechnical",
272
+ "category": "ui",
273
+ "valueKind": "boolean",
274
+ "description": "Show technical details by default."
275
+ },
276
+ {
277
+ "path": "ui.list.detailsFields",
278
+ "category": "ui",
279
+ "valueKind": "array",
280
+ "description": "Allowed metadata fields to display."
281
+ },
282
+ {
283
+ "path": "ui.list.detailsFields[]",
284
+ "category": "ui",
285
+ "valueKind": "string",
286
+ "description": "Single metadata field name."
287
+ },
288
+ {
289
+ "path": "ui.list.detailsAnchor",
290
+ "category": "ui",
291
+ "valueKind": "enum",
292
+ "allowedValues": [
293
+ "item",
294
+ "field"
295
+ ],
296
+ "description": "Details overlay anchor."
297
+ },
298
+ {
299
+ "path": "limits",
300
+ "category": "limits",
301
+ "valueKind": "object",
302
+ "description": "Upload limits."
303
+ },
304
+ {
305
+ "path": "limits.maxFileSizeBytes",
306
+ "category": "limits",
307
+ "valueKind": "number",
308
+ "description": "Max file size (bytes)."
309
+ },
310
+ {
311
+ "path": "limits.maxFilesPerBulk",
312
+ "category": "limits",
313
+ "valueKind": "number",
314
+ "description": "Max files per bulk upload."
315
+ },
316
+ {
317
+ "path": "limits.maxBulkSizeBytes",
318
+ "category": "limits",
319
+ "valueKind": "number",
320
+ "description": "Max bulk size (bytes)."
321
+ },
322
+ {
323
+ "path": "options",
324
+ "category": "options",
325
+ "valueKind": "object",
326
+ "description": "Backend options sent as JSON."
327
+ },
328
+ {
329
+ "path": "options.defaultConflictPolicy",
330
+ "category": "options",
331
+ "valueKind": "enum",
332
+ "allowedValues": [
333
+ "ERROR",
334
+ "SKIP",
335
+ "OVERWRITE",
336
+ "MAKE_UNIQUE",
337
+ "RENAME"
338
+ ],
339
+ "description": "Default conflict policy."
340
+ },
341
+ {
342
+ "path": "options.strictValidation",
343
+ "category": "options",
344
+ "valueKind": "boolean",
345
+ "description": "Strict backend validation."
346
+ },
347
+ {
348
+ "path": "options.maxUploadSizeMb",
349
+ "category": "options",
350
+ "valueKind": "number",
351
+ "description": "Max upload size in MB."
352
+ },
353
+ {
354
+ "path": "options.allowedExtensions",
355
+ "category": "options",
356
+ "valueKind": "array",
357
+ "description": "Allowed file extensions."
358
+ },
359
+ {
360
+ "path": "options.allowedExtensions[]",
361
+ "category": "options",
362
+ "valueKind": "string",
363
+ "description": "Single extension (e.g., pdf)."
364
+ },
365
+ {
366
+ "path": "options.acceptMimeTypes",
367
+ "category": "options",
368
+ "valueKind": "array",
369
+ "description": "Allowed mime types."
370
+ },
371
+ {
372
+ "path": "options.acceptMimeTypes[]",
373
+ "category": "options",
374
+ "valueKind": "string",
375
+ "description": "Single mime type."
376
+ },
377
+ {
378
+ "path": "options.targetDirectory",
379
+ "category": "options",
380
+ "valueKind": "string",
381
+ "description": "Target directory on backend."
382
+ },
383
+ {
384
+ "path": "options.enableVirusScanning",
385
+ "category": "options",
386
+ "valueKind": "boolean",
387
+ "description": "Enable virus scanning."
388
+ },
389
+ {
390
+ "path": "bulk",
391
+ "category": "bulk",
392
+ "valueKind": "object",
393
+ "description": "Bulk upload tuning."
394
+ },
395
+ {
396
+ "path": "bulk.failFast",
397
+ "category": "bulk",
398
+ "valueKind": "boolean",
399
+ "description": "Abort on first error."
400
+ },
401
+ {
402
+ "path": "bulk.parallelUploads",
403
+ "category": "bulk",
404
+ "valueKind": "number",
405
+ "description": "Parallel uploads count."
406
+ },
407
+ {
408
+ "path": "bulk.retryCount",
409
+ "category": "bulk",
410
+ "valueKind": "number",
411
+ "description": "Retry count."
412
+ },
413
+ {
414
+ "path": "bulk.retryBackoffMs",
415
+ "category": "bulk",
416
+ "valueKind": "number",
417
+ "description": "Retry backoff (ms)."
418
+ },
419
+ {
420
+ "path": "quotas",
421
+ "category": "quotas",
422
+ "valueKind": "object",
423
+ "description": "Quota UX behavior."
424
+ },
425
+ {
426
+ "path": "quotas.showQuotaWarnings",
427
+ "category": "quotas",
428
+ "valueKind": "boolean",
429
+ "description": "Show quota warnings."
430
+ },
431
+ {
432
+ "path": "quotas.blockOnExceed",
433
+ "category": "quotas",
434
+ "valueKind": "boolean",
435
+ "description": "Block uploads when exceeded."
436
+ },
437
+ {
438
+ "path": "rateLimit",
439
+ "category": "rateLimit",
440
+ "valueKind": "object",
441
+ "description": "429 handling."
442
+ },
443
+ {
444
+ "path": "rateLimit.autoRetryOn429",
445
+ "category": "rateLimit",
446
+ "valueKind": "boolean",
447
+ "description": "Auto retry on 429."
448
+ },
449
+ {
450
+ "path": "rateLimit.showBannerOn429",
451
+ "category": "rateLimit",
452
+ "valueKind": "boolean",
453
+ "description": "Show rate limit banner."
454
+ },
455
+ {
456
+ "path": "rateLimit.maxAutoRetry",
457
+ "category": "rateLimit",
458
+ "valueKind": "number",
459
+ "description": "Max auto retry attempts."
460
+ },
461
+ {
462
+ "path": "rateLimit.baseBackoffMs",
463
+ "category": "rateLimit",
464
+ "valueKind": "number",
465
+ "description": "Base backoff (ms)."
466
+ },
467
+ {
468
+ "path": "headers",
469
+ "category": "headers",
470
+ "valueKind": "object",
471
+ "description": "Header mapping for backend."
472
+ },
473
+ {
474
+ "path": "headers.tenantHeader",
475
+ "category": "headers",
476
+ "valueKind": "string",
477
+ "description": "Tenant header name."
478
+ },
479
+ {
480
+ "path": "headers.userHeader",
481
+ "category": "headers",
482
+ "valueKind": "string",
483
+ "description": "User header name."
484
+ },
485
+ {
486
+ "path": "messages",
487
+ "category": "messages",
488
+ "valueKind": "object",
489
+ "description": "User-facing text overrides."
490
+ },
491
+ {
492
+ "path": "messages.successSingle",
493
+ "category": "messages",
494
+ "valueKind": "string",
495
+ "description": "Single upload success message."
496
+ },
497
+ {
498
+ "path": "messages.successBulk",
499
+ "category": "messages",
500
+ "valueKind": "string",
501
+ "description": "Bulk upload success message."
502
+ },
503
+ {
504
+ "path": "messages.errors",
505
+ "category": "messages",
506
+ "valueKind": "object",
507
+ "description": "Error message map."
508
+ },
509
+ {
510
+ "path": "messages.errors.[code]",
511
+ "category": "messages",
512
+ "valueKind": "string",
513
+ "description": "Message for a specific error code."
514
+ }
515
+ ],
516
+ "componentCapabilityNotes": [
517
+ "limits.maxFileSizeBytes and limits.maxBulkSizeBytes are bytes (e.g., 10485760 for 10MB).",
518
+ "options.allowedExtensions is enforced by backend validation; ui.accept is only a client hint.",
519
+ "Use options.defaultConflictPolicy to control name collisions on upload."
520
+ ],
521
+ "componentContext": {
522
+ "version": "v1",
523
+ "optionsByPath": {
524
+ "strategy": {
525
+ "mode": "enum",
526
+ "options": [
527
+ {
528
+ "value": "direct",
529
+ "label": "Direct"
530
+ },
531
+ {
532
+ "value": "presign",
533
+ "label": "Presign"
534
+ },
535
+ {
536
+ "value": "auto",
537
+ "label": "Auto"
538
+ }
539
+ ]
540
+ },
541
+ "ui.dropzone.expandMode": {
542
+ "mode": "enum",
543
+ "options": [
544
+ {
545
+ "value": "overlay",
546
+ "label": "Overlay"
547
+ },
548
+ {
549
+ "value": "inline",
550
+ "label": "Inline"
551
+ }
552
+ ]
553
+ },
554
+ "ui.list.detailsMode": {
555
+ "mode": "enum",
556
+ "options": [
557
+ {
558
+ "value": "card",
559
+ "label": "Card"
560
+ },
561
+ {
562
+ "value": "sidesheet",
563
+ "label": "Side sheet"
564
+ },
565
+ {
566
+ "value": "auto",
567
+ "label": "Auto"
568
+ }
569
+ ]
570
+ },
571
+ "ui.list.detailsAnchor": {
572
+ "mode": "enum",
573
+ "options": [
574
+ {
575
+ "value": "item",
576
+ "label": "Item"
577
+ },
578
+ {
579
+ "value": "field",
580
+ "label": "Field"
581
+ }
582
+ ]
583
+ },
584
+ "options.defaultConflictPolicy": {
585
+ "mode": "enum",
586
+ "options": [
587
+ {
588
+ "value": "ERROR",
589
+ "label": "Error"
590
+ },
591
+ {
592
+ "value": "SKIP",
593
+ "label": "Skip"
594
+ },
595
+ {
596
+ "value": "OVERWRITE",
597
+ "label": "Overwrite"
598
+ },
599
+ {
600
+ "value": "MAKE_UNIQUE",
601
+ "label": "Make unique"
602
+ },
603
+ {
604
+ "value": "RENAME",
605
+ "label": "Rename"
606
+ }
607
+ ]
608
+ }
609
+ },
610
+ "actionCatalog": [
611
+ {
612
+ "id": "strategy.set",
613
+ "intentExamples": [
614
+ "strategy",
615
+ "upload strategy"
616
+ ],
617
+ "patchTemplate": {
618
+ "strategy": "{{value}}"
619
+ }
620
+ },
621
+ {
622
+ "id": "ui.showDropzone.enable",
623
+ "intentExamples": [
624
+ "show dropzone",
625
+ "enable dropzone"
626
+ ],
627
+ "patchTemplate": {
628
+ "ui": {
629
+ "showDropzone": true
630
+ }
631
+ }
632
+ },
633
+ {
634
+ "id": "ui.showDropzone.disable",
635
+ "intentExamples": [
636
+ "hide dropzone",
637
+ "disable dropzone"
638
+ ],
639
+ "patchTemplate": {
640
+ "ui": {
641
+ "showDropzone": false
642
+ }
643
+ }
644
+ },
645
+ {
646
+ "id": "ui.manualUpload.enable",
647
+ "intentExamples": [
648
+ "manual upload",
649
+ "upload button"
650
+ ],
651
+ "patchTemplate": {
652
+ "ui": {
653
+ "manualUpload": true
654
+ }
655
+ }
656
+ },
657
+ {
658
+ "id": "ui.manualUpload.disable",
659
+ "intentExamples": [
660
+ "auto upload",
661
+ "instant upload"
662
+ ],
663
+ "patchTemplate": {
664
+ "ui": {
665
+ "manualUpload": false
666
+ }
667
+ }
668
+ },
669
+ {
670
+ "id": "ui.showProgress.enable",
671
+ "intentExamples": [
672
+ "show progress",
673
+ "progress bar"
674
+ ],
675
+ "patchTemplate": {
676
+ "ui": {
677
+ "showProgress": true
678
+ }
679
+ }
680
+ },
681
+ {
682
+ "id": "ui.showProgress.disable",
683
+ "intentExamples": [
684
+ "hide progress",
685
+ "no progress"
686
+ ],
687
+ "patchTemplate": {
688
+ "ui": {
689
+ "showProgress": false
690
+ }
691
+ }
692
+ },
693
+ {
694
+ "id": "limits.maxFileSizeBytes.set",
695
+ "intentExamples": [
696
+ "max file size",
697
+ "size limit"
698
+ ],
699
+ "patchTemplate": {
700
+ "limits": {
701
+ "maxFileSizeBytes": "{{value}}"
702
+ }
703
+ }
704
+ },
705
+ {
706
+ "id": "limits.maxFilesPerBulk.set",
707
+ "intentExamples": [
708
+ "max files",
709
+ "files per upload"
710
+ ],
711
+ "patchTemplate": {
712
+ "limits": {
713
+ "maxFilesPerBulk": "{{value}}"
714
+ }
715
+ }
716
+ },
717
+ {
718
+ "id": "options.defaultConflictPolicy.set",
719
+ "intentExamples": [
720
+ "conflict policy",
721
+ "overwrite",
722
+ "rename"
723
+ ],
724
+ "patchTemplate": {
725
+ "options": {
726
+ "defaultConflictPolicy": "{{value}}"
727
+ }
728
+ }
729
+ },
730
+ {
731
+ "id": "options.allowedExtensions.add",
732
+ "intentExamples": [
733
+ "allowed extensions",
734
+ "extensions",
735
+ "file types"
736
+ ],
737
+ "patchTemplate": {
738
+ "options": {
739
+ "allowedExtensions": [
740
+ "{{value}}"
741
+ ]
742
+ }
743
+ }
744
+ }
745
+ ],
746
+ "fieldResolvers": {},
747
+ "hints": [
748
+ "limits.maxFileSizeBytes expects bytes (e.g., 10485760 for 10MB).",
749
+ "Use options.allowedExtensions for backend validation and ui.accept for input hints."
750
+ ]
751
+ },
752
+ "authoringManifest": {
753
+ "schemaVersion": "1.0.0",
754
+ "componentId": "praxis-files-upload",
755
+ "ownerPackage": "@praxisui/files-upload",
756
+ "configSchemaId": "FilesUploadConfig",
757
+ "manifestVersion": "1.0.0",
758
+ "runtimeInputs": [
759
+ {
760
+ "name": "config",
761
+ "type": "FilesUploadConfig",
762
+ "description": "Upload strategy, UI, limits, backend options, bulk execution, quota/rate feedback, headers and messages."
763
+ },
764
+ {
765
+ "name": "filesUploadId",
766
+ "type": "string",
767
+ "description": "Stable upload id used for config persistence and telemetry correlation."
768
+ },
769
+ {
770
+ "name": "componentInstanceId",
771
+ "type": "string",
772
+ "description": "Optional instance discriminator when the same upload id appears more than once."
773
+ },
774
+ {
775
+ "name": "baseUrl",
776
+ "type": "string",
777
+ "description": "Canonical files API base URL. Direct upload uses baseUrl/upload, bulk uses baseUrl/bulk and presign uses baseUrl/upload/presign."
778
+ },
779
+ {
780
+ "name": "displayMode",
781
+ "type": "'full' | 'compact'",
782
+ "allowedValues": [
783
+ "full",
784
+ "compact"
785
+ ],
786
+ "description": "Runtime display mode input."
787
+ },
788
+ {
789
+ "name": "context",
790
+ "type": "Record<string, unknown>",
791
+ "description": "Host context available to metadata and event consumers."
792
+ },
793
+ {
794
+ "name": "enableCustomization",
795
+ "type": "boolean",
796
+ "description": "Enables the Settings Panel configuration editor."
797
+ }
798
+ ],
799
+ "editableTargets": [
800
+ {
801
+ "kind": "acceptedTypes",
802
+ "resolver": "files-accept-list",
803
+ "description": "Allowed file extensions and MIME types projected to ui.accept, options.allowedExtensions and options.acceptMimeTypes."
804
+ },
805
+ {
806
+ "kind": "sizeLimit",
807
+ "resolver": "max-file-size-policy",
808
+ "description": "Maximum single-file size in limits.maxFileSizeBytes and backend-facing options.maxUploadSizeMb."
809
+ },
810
+ {
811
+ "kind": "fileCountLimit",
812
+ "resolver": "max-files-per-bulk-policy",
813
+ "description": "Maximum number of files accepted in a bulk selection."
814
+ },
815
+ {
816
+ "kind": "presignEndpoint",
817
+ "resolver": "files-api-base-url-presign-contract",
818
+ "description": "Presign operation endpoint derived from baseUrl + /upload/presign; arbitrary per-operation URLs are not accepted."
819
+ },
820
+ {
821
+ "kind": "uploadEndpoint",
822
+ "resolver": "files-api-base-url-upload-contract",
823
+ "description": "Direct and bulk upload endpoints derived from baseUrl + /upload and /bulk."
824
+ },
825
+ {
826
+ "kind": "securityPolicy",
827
+ "resolver": "upload-security-policy",
828
+ "description": "Strict validation, virus scanning, conflict policy, target directory, quotas, rate limit and contextual headers."
829
+ },
830
+ {
831
+ "kind": "errorMessages",
832
+ "resolver": "upload-error-code-message",
833
+ "description": "Host-provided message overrides under messages.errors keyed by backend error code."
834
+ },
835
+ {
836
+ "kind": "display",
837
+ "resolver": "files-upload-display-mode-and-ui",
838
+ "description": "Runtime displayMode plus non-backend visual UI flags."
839
+ }
840
+ ],
841
+ "operations": [
842
+ {
843
+ "operationId": "accept.types.set",
844
+ "title": "Set accepted file types",
845
+ "scope": "global",
846
+ "targetKind": "acceptedTypes",
847
+ "target": {
848
+ "kind": "acceptedTypes",
849
+ "resolver": "files-accept-list",
850
+ "ambiguityPolicy": "fail",
851
+ "required": false
852
+ },
853
+ "inputSchema": {
854
+ "type": "object",
855
+ "required": [
856
+ "accept"
857
+ ],
858
+ "properties": {
859
+ "accept": {
860
+ "type": "array",
861
+ "items": {
862
+ "type": "string"
863
+ }
864
+ },
865
+ "allowedExtensions": {
866
+ "type": "array",
867
+ "items": {
868
+ "type": "string"
869
+ }
870
+ },
871
+ "acceptMimeTypes": {
872
+ "type": "array",
873
+ "items": {
874
+ "type": "string"
875
+ }
876
+ }
877
+ }
878
+ },
879
+ "effects": [
880
+ {
881
+ "kind": "set-value",
882
+ "path": "ui.accept"
883
+ },
884
+ {
885
+ "kind": "set-value",
886
+ "path": "options.allowedExtensions"
887
+ },
888
+ {
889
+ "kind": "set-value",
890
+ "path": "options.acceptMimeTypes"
891
+ }
892
+ ],
893
+ "destructive": false,
894
+ "requiresConfirmation": false,
895
+ "validators": [
896
+ "file-type-list-explicit",
897
+ "file-type-entry-valid",
898
+ "backend-accept-options-consistent",
899
+ "editor-runtime-round-trip"
900
+ ],
901
+ "affectedPaths": [
902
+ "ui.accept",
903
+ "options.allowedExtensions",
904
+ "options.acceptMimeTypes"
905
+ ],
906
+ "submissionImpact": "affects-submission",
907
+ "preconditions": [
908
+ "config-initialized"
909
+ ]
910
+ },
911
+ {
912
+ "operationId": "limit.fileSize.set",
913
+ "title": "Set max file size",
914
+ "scope": "global",
915
+ "targetKind": "sizeLimit",
916
+ "target": {
917
+ "kind": "sizeLimit",
918
+ "resolver": "max-file-size-policy",
919
+ "ambiguityPolicy": "fail",
920
+ "required": false
921
+ },
922
+ "inputSchema": {
923
+ "type": "object",
924
+ "required": [
925
+ "maxFileSizeBytes"
926
+ ],
927
+ "properties": {
928
+ "maxFileSizeBytes": {
929
+ "type": "number"
930
+ },
931
+ "maxUploadSizeMb": {
932
+ "type": "number"
933
+ }
934
+ }
935
+ },
936
+ "effects": [
937
+ {
938
+ "kind": "set-value",
939
+ "path": "limits.maxFileSizeBytes"
940
+ },
941
+ {
942
+ "kind": "set-value",
943
+ "path": "options.maxUploadSizeMb"
944
+ }
945
+ ],
946
+ "destructive": false,
947
+ "requiresConfirmation": false,
948
+ "validators": [
949
+ "size-limit-numeric",
950
+ "size-limit-within-platform-policy",
951
+ "size-limit-client-backend-consistent",
952
+ "editor-runtime-round-trip"
953
+ ],
954
+ "affectedPaths": [
955
+ "limits.maxFileSizeBytes",
956
+ "options.maxUploadSizeMb"
957
+ ],
958
+ "submissionImpact": "affects-submission",
959
+ "preconditions": [
960
+ "config-initialized"
961
+ ]
962
+ },
963
+ {
964
+ "operationId": "limit.fileCount.set",
965
+ "title": "Set max file count",
966
+ "scope": "global",
967
+ "targetKind": "fileCountLimit",
968
+ "target": {
969
+ "kind": "fileCountLimit",
970
+ "resolver": "max-files-per-bulk-policy",
971
+ "ambiguityPolicy": "fail",
972
+ "required": false
973
+ },
974
+ "inputSchema": {
975
+ "type": "object",
976
+ "required": [
977
+ "maxFilesPerBulk"
978
+ ],
979
+ "properties": {
980
+ "maxFilesPerBulk": {
981
+ "type": "number"
982
+ },
983
+ "maxBulkSizeBytes": {
984
+ "type": "number"
985
+ }
986
+ }
987
+ },
988
+ "effects": [
989
+ {
990
+ "kind": "set-value",
991
+ "path": "limits.maxFilesPerBulk"
992
+ },
993
+ {
994
+ "kind": "set-value",
995
+ "path": "limits.maxBulkSizeBytes"
996
+ }
997
+ ],
998
+ "destructive": false,
999
+ "requiresConfirmation": false,
1000
+ "validators": [
1001
+ "file-count-limit-numeric",
1002
+ "bulk-size-limit-numeric",
1003
+ "bulk-limit-within-platform-policy",
1004
+ "editor-runtime-round-trip"
1005
+ ],
1006
+ "affectedPaths": [
1007
+ "limits.maxFilesPerBulk",
1008
+ "limits.maxBulkSizeBytes"
1009
+ ],
1010
+ "submissionImpact": "affects-submission",
1011
+ "preconditions": [
1012
+ "config-initialized"
1013
+ ]
1014
+ },
1015
+ {
1016
+ "operationId": "endpoint.presign.set",
1017
+ "title": "Set presign endpoint",
1018
+ "scope": "global",
1019
+ "targetKind": "presignEndpoint",
1020
+ "target": {
1021
+ "kind": "presignEndpoint",
1022
+ "resolver": "files-api-base-url-presign-contract",
1023
+ "ambiguityPolicy": "fail",
1024
+ "required": false
1025
+ },
1026
+ "inputSchema": {
1027
+ "type": "object",
1028
+ "required": [
1029
+ "baseUrl"
1030
+ ],
1031
+ "properties": {
1032
+ "baseUrl": {
1033
+ "type": "string"
1034
+ },
1035
+ "strategy": {
1036
+ "enum": [
1037
+ "direct",
1038
+ "presign",
1039
+ "auto"
1040
+ ]
1041
+ },
1042
+ "allowCrossOriginPresignedTarget": {
1043
+ "type": "boolean"
1044
+ }
1045
+ }
1046
+ },
1047
+ "effects": [
1048
+ {
1049
+ "kind": "compile-domain-patch",
1050
+ "handler": "files-upload-presign-base-url",
1051
+ "handlerContract": {
1052
+ "reads": [
1053
+ "baseUrl",
1054
+ "strategy"
1055
+ ],
1056
+ "writes": [
1057
+ "baseUrl",
1058
+ "strategy"
1059
+ ],
1060
+ "identityKeys": [
1061
+ "baseUrl"
1062
+ ],
1063
+ "inputSchema": {
1064
+ "type": "object",
1065
+ "required": [
1066
+ "baseUrl"
1067
+ ],
1068
+ "properties": {
1069
+ "baseUrl": {
1070
+ "type": "string"
1071
+ },
1072
+ "strategy": {
1073
+ "enum": [
1074
+ "direct",
1075
+ "presign",
1076
+ "auto"
1077
+ ]
1078
+ },
1079
+ "allowCrossOriginPresignedTarget": {
1080
+ "type": "boolean"
1081
+ }
1082
+ }
1083
+ },
1084
+ "failureModes": [
1085
+ "unsafe-url",
1086
+ "non-praxis-backend-surface",
1087
+ "presign-path-override",
1088
+ "cross-origin-presigned-fields-leak"
1089
+ ],
1090
+ "description": "Validates the files API base URL and preserves the canonical POST baseUrl/upload/presign?filename=... contract; arbitrary presign URLs are rejected."
1091
+ }
1092
+ }
1093
+ ],
1094
+ "destructive": true,
1095
+ "requiresConfirmation": true,
1096
+ "validators": [
1097
+ "endpoint-url-safe",
1098
+ "endpoint-uses-praxis-backend-surface",
1099
+ "presign-endpoint-fixed-contract",
1100
+ "presign-cross-origin-fields-safe",
1101
+ "security-change-confirmed"
1102
+ ],
1103
+ "affectedPaths": [
1104
+ "baseUrl",
1105
+ "strategy"
1106
+ ],
1107
+ "submissionImpact": "affects-remote-binding",
1108
+ "preconditions": [
1109
+ "config-initialized",
1110
+ "confirmation-collected"
1111
+ ]
1112
+ },
1113
+ {
1114
+ "operationId": "endpoint.upload.set",
1115
+ "title": "Set upload endpoint",
1116
+ "scope": "global",
1117
+ "targetKind": "uploadEndpoint",
1118
+ "target": {
1119
+ "kind": "uploadEndpoint",
1120
+ "resolver": "files-api-base-url-upload-contract",
1121
+ "ambiguityPolicy": "fail",
1122
+ "required": false
1123
+ },
1124
+ "inputSchema": {
1125
+ "type": "object",
1126
+ "required": [
1127
+ "baseUrl"
1128
+ ],
1129
+ "properties": {
1130
+ "baseUrl": {
1131
+ "type": "string"
1132
+ },
1133
+ "strategy": {
1134
+ "enum": [
1135
+ "direct",
1136
+ "presign",
1137
+ "auto"
1138
+ ]
1139
+ },
1140
+ "allowCrossOriginPresignedTarget": {
1141
+ "type": "boolean"
1142
+ }
1143
+ }
1144
+ },
1145
+ "effects": [
1146
+ {
1147
+ "kind": "compile-domain-patch",
1148
+ "handler": "files-upload-direct-base-url",
1149
+ "handlerContract": {
1150
+ "reads": [
1151
+ "baseUrl",
1152
+ "strategy"
1153
+ ],
1154
+ "writes": [
1155
+ "baseUrl",
1156
+ "strategy"
1157
+ ],
1158
+ "identityKeys": [
1159
+ "baseUrl"
1160
+ ],
1161
+ "inputSchema": {
1162
+ "type": "object",
1163
+ "required": [
1164
+ "baseUrl"
1165
+ ],
1166
+ "properties": {
1167
+ "baseUrl": {
1168
+ "type": "string"
1169
+ },
1170
+ "strategy": {
1171
+ "enum": [
1172
+ "direct",
1173
+ "presign",
1174
+ "auto"
1175
+ ]
1176
+ },
1177
+ "allowCrossOriginPresignedTarget": {
1178
+ "type": "boolean"
1179
+ }
1180
+ }
1181
+ },
1182
+ "failureModes": [
1183
+ "unsafe-url",
1184
+ "non-praxis-backend-surface",
1185
+ "upload-path-override",
1186
+ "bulk-path-override"
1187
+ ],
1188
+ "description": "Validates the files API base URL and preserves the canonical POST baseUrl/upload and POST baseUrl/bulk contracts."
1189
+ }
1190
+ }
1191
+ ],
1192
+ "destructive": true,
1193
+ "requiresConfirmation": true,
1194
+ "validators": [
1195
+ "endpoint-url-safe",
1196
+ "endpoint-uses-praxis-backend-surface",
1197
+ "upload-endpoint-fixed-contract",
1198
+ "bulk-endpoint-fixed-contract",
1199
+ "security-change-confirmed"
1200
+ ],
1201
+ "affectedPaths": [
1202
+ "baseUrl",
1203
+ "strategy"
1204
+ ],
1205
+ "submissionImpact": "affects-remote-binding",
1206
+ "preconditions": [
1207
+ "config-initialized",
1208
+ "confirmation-collected"
1209
+ ]
1210
+ },
1211
+ {
1212
+ "operationId": "security.policy.set",
1213
+ "title": "Set upload security policy",
1214
+ "scope": "global",
1215
+ "targetKind": "securityPolicy",
1216
+ "target": {
1217
+ "kind": "securityPolicy",
1218
+ "resolver": "upload-security-policy",
1219
+ "ambiguityPolicy": "fail",
1220
+ "required": false
1221
+ },
1222
+ "inputSchema": {
1223
+ "type": "object",
1224
+ "properties": {
1225
+ "strictValidation": {
1226
+ "type": "boolean"
1227
+ },
1228
+ "enableVirusScanning": {
1229
+ "type": "boolean"
1230
+ },
1231
+ "defaultConflictPolicy": {
1232
+ "enum": [
1233
+ "ERROR",
1234
+ "SKIP",
1235
+ "OVERWRITE",
1236
+ "MAKE_UNIQUE",
1237
+ "RENAME"
1238
+ ]
1239
+ },
1240
+ "targetDirectory": {
1241
+ "type": "string"
1242
+ },
1243
+ "showQuotaWarnings": {
1244
+ "type": "boolean"
1245
+ },
1246
+ "blockOnExceed": {
1247
+ "type": "boolean"
1248
+ },
1249
+ "autoRetryOn429": {
1250
+ "type": "boolean"
1251
+ },
1252
+ "showBannerOn429": {
1253
+ "type": "boolean"
1254
+ },
1255
+ "maxAutoRetry": {
1256
+ "type": "number"
1257
+ },
1258
+ "baseBackoffMs": {
1259
+ "type": "number"
1260
+ },
1261
+ "tenantHeader": {
1262
+ "type": "string"
1263
+ },
1264
+ "userHeader": {
1265
+ "type": "string"
1266
+ }
1267
+ }
1268
+ },
1269
+ "effects": [
1270
+ {
1271
+ "kind": "merge-object",
1272
+ "path": "options"
1273
+ },
1274
+ {
1275
+ "kind": "merge-object",
1276
+ "path": "quotas"
1277
+ },
1278
+ {
1279
+ "kind": "merge-object",
1280
+ "path": "rateLimit"
1281
+ },
1282
+ {
1283
+ "kind": "merge-object",
1284
+ "path": "headers"
1285
+ }
1286
+ ],
1287
+ "destructive": true,
1288
+ "requiresConfirmation": true,
1289
+ "validators": [
1290
+ "security-change-confirmed",
1291
+ "security-policy-compatible",
1292
+ "target-directory-safe",
1293
+ "conflict-policy-valid",
1294
+ "quota-rate-policy-valid",
1295
+ "header-names-safe",
1296
+ "editor-runtime-round-trip"
1297
+ ],
1298
+ "affectedPaths": [
1299
+ "options.strictValidation",
1300
+ "options.enableVirusScanning",
1301
+ "options.defaultConflictPolicy",
1302
+ "options.targetDirectory",
1303
+ "quotas",
1304
+ "rateLimit",
1305
+ "headers"
1306
+ ],
1307
+ "submissionImpact": "config-only",
1308
+ "preconditions": [
1309
+ "config-initialized",
1310
+ "confirmation-collected"
1311
+ ]
1312
+ },
1313
+ {
1314
+ "operationId": "message.error.set",
1315
+ "title": "Set error message override",
1316
+ "scope": "global",
1317
+ "targetKind": "errorMessages",
1318
+ "target": {
1319
+ "kind": "errorMessages",
1320
+ "resolver": "upload-error-code-message",
1321
+ "ambiguityPolicy": "fail",
1322
+ "required": false
1323
+ },
1324
+ "inputSchema": {
1325
+ "type": "object",
1326
+ "required": [
1327
+ "code",
1328
+ "message"
1329
+ ],
1330
+ "properties": {
1331
+ "code": {
1332
+ "type": "string"
1333
+ },
1334
+ "message": {
1335
+ "type": "string"
1336
+ }
1337
+ }
1338
+ },
1339
+ "effects": [
1340
+ {
1341
+ "kind": "merge-object",
1342
+ "path": "messages.errors"
1343
+ }
1344
+ ],
1345
+ "destructive": false,
1346
+ "requiresConfirmation": false,
1347
+ "validators": [
1348
+ "error-code-known",
1349
+ "error-message-i18n-compatible",
1350
+ "message-not-empty",
1351
+ "editor-runtime-round-trip"
1352
+ ],
1353
+ "affectedPaths": [
1354
+ "messages.errors"
1355
+ ],
1356
+ "submissionImpact": "config-only",
1357
+ "preconditions": [
1358
+ "config-initialized"
1359
+ ]
1360
+ },
1361
+ {
1362
+ "operationId": "display.mode.set",
1363
+ "title": "Set display mode",
1364
+ "scope": "global",
1365
+ "targetKind": "display",
1366
+ "target": {
1367
+ "kind": "display",
1368
+ "resolver": "files-upload-display-mode-and-ui",
1369
+ "ambiguityPolicy": "fail",
1370
+ "required": false
1371
+ },
1372
+ "inputSchema": {
1373
+ "type": "object",
1374
+ "properties": {
1375
+ "displayMode": {
1376
+ "enum": [
1377
+ "full",
1378
+ "compact"
1379
+ ]
1380
+ },
1381
+ "dense": {
1382
+ "type": "boolean"
1383
+ },
1384
+ "showDropzone": {
1385
+ "type": "boolean"
1386
+ },
1387
+ "showProgress": {
1388
+ "type": "boolean"
1389
+ },
1390
+ "manualUpload": {
1391
+ "type": "boolean"
1392
+ },
1393
+ "showMetadataForm": {
1394
+ "type": "boolean"
1395
+ },
1396
+ "showConflictPolicySelector": {
1397
+ "type": "boolean"
1398
+ }
1399
+ }
1400
+ },
1401
+ "effects": [
1402
+ {
1403
+ "kind": "set-value",
1404
+ "path": "displayMode"
1405
+ },
1406
+ {
1407
+ "kind": "merge-object",
1408
+ "path": "ui"
1409
+ }
1410
+ ],
1411
+ "destructive": false,
1412
+ "requiresConfirmation": false,
1413
+ "validators": [
1414
+ "display-mode-valid",
1415
+ "display-ui-compatible",
1416
+ "editor-runtime-round-trip"
1417
+ ],
1418
+ "affectedPaths": [
1419
+ "displayMode",
1420
+ "ui.dense",
1421
+ "ui.showDropzone",
1422
+ "ui.showProgress",
1423
+ "ui.manualUpload",
1424
+ "ui.showMetadataForm",
1425
+ "ui.showConflictPolicySelector"
1426
+ ],
1427
+ "submissionImpact": "visual-only",
1428
+ "preconditions": [
1429
+ "config-initialized"
1430
+ ]
1431
+ }
1432
+ ],
1433
+ "validators": [
1434
+ {
1435
+ "validatorId": "file-type-list-explicit",
1436
+ "level": "error",
1437
+ "code": "PFU001",
1438
+ "description": "Accepted type edits must provide a non-empty explicit list and may not rely on wildcard-only policy."
1439
+ },
1440
+ {
1441
+ "validatorId": "file-type-entry-valid",
1442
+ "level": "error",
1443
+ "code": "PFU002",
1444
+ "description": "Each accepted type must be a valid extension, exact MIME type or controlled subtype wildcard."
1445
+ },
1446
+ {
1447
+ "validatorId": "backend-accept-options-consistent",
1448
+ "level": "error",
1449
+ "code": "PFU003",
1450
+ "description": "ui.accept hints must remain consistent with options.allowedExtensions and options.acceptMimeTypes when backend validation is configured."
1451
+ },
1452
+ {
1453
+ "validatorId": "size-limit-numeric",
1454
+ "level": "error",
1455
+ "code": "PFU004",
1456
+ "description": "Single file size limits must be positive numeric byte and MB values."
1457
+ },
1458
+ {
1459
+ "validatorId": "size-limit-within-platform-policy",
1460
+ "level": "error",
1461
+ "code": "PFU005",
1462
+ "description": "Single file size limits must not exceed the platform upload policy for the selected backend surface."
1463
+ },
1464
+ {
1465
+ "validatorId": "size-limit-client-backend-consistent",
1466
+ "level": "error",
1467
+ "code": "PFU006",
1468
+ "description": "limits.maxFileSizeBytes and options.maxUploadSizeMb must describe the same effective maximum when both are present."
1469
+ },
1470
+ {
1471
+ "validatorId": "file-count-limit-numeric",
1472
+ "level": "error",
1473
+ "code": "PFU007",
1474
+ "description": "Bulk file count limits must be positive integers."
1475
+ },
1476
+ {
1477
+ "validatorId": "bulk-size-limit-numeric",
1478
+ "level": "error",
1479
+ "code": "PFU008",
1480
+ "description": "Bulk size limits must be positive numeric byte values when provided."
1481
+ },
1482
+ {
1483
+ "validatorId": "bulk-limit-within-platform-policy",
1484
+ "level": "error",
1485
+ "code": "PFU009",
1486
+ "description": "Bulk count and aggregate size limits must not exceed backend batch policy."
1487
+ },
1488
+ {
1489
+ "validatorId": "endpoint-url-safe",
1490
+ "level": "error",
1491
+ "code": "PFU010",
1492
+ "description": "Endpoint edits must use a safe absolute or approved relative baseUrl and reject javascript:, data:, credentials-in-URL and path traversal."
1493
+ },
1494
+ {
1495
+ "validatorId": "endpoint-uses-praxis-backend-surface",
1496
+ "level": "error",
1497
+ "code": "PFU011",
1498
+ "description": "Endpoint edits must resolve to the approved Praxis files backend surface for the host environment."
1499
+ },
1500
+ {
1501
+ "validatorId": "presign-endpoint-fixed-contract",
1502
+ "level": "error",
1503
+ "code": "PFU012",
1504
+ "description": "Presign authoring may change baseUrl but must preserve POST baseUrl/upload/presign?filename=... as the runtime contract."
1505
+ },
1506
+ {
1507
+ "validatorId": "upload-endpoint-fixed-contract",
1508
+ "level": "error",
1509
+ "code": "PFU013",
1510
+ "description": "Direct upload authoring may change baseUrl but must preserve POST baseUrl/upload as the runtime contract."
1511
+ },
1512
+ {
1513
+ "validatorId": "bulk-endpoint-fixed-contract",
1514
+ "level": "error",
1515
+ "code": "PFU014",
1516
+ "description": "Bulk upload authoring may change baseUrl but must preserve POST baseUrl/bulk as the runtime contract."
1517
+ },
1518
+ {
1519
+ "validatorId": "presign-cross-origin-fields-safe",
1520
+ "level": "error",
1521
+ "code": "PFU015",
1522
+ "description": "Cross-origin presigned upload targets must not receive Praxis metadata/options fields unless explicitly approved by the presign response contract."
1523
+ },
1524
+ {
1525
+ "validatorId": "security-change-confirmed",
1526
+ "level": "error",
1527
+ "code": "PFU016",
1528
+ "description": "Endpoint and security policy edits require explicit confirmation before patch compilation."
1529
+ },
1530
+ {
1531
+ "validatorId": "security-policy-compatible",
1532
+ "level": "error",
1533
+ "code": "PFU017",
1534
+ "description": "Strict validation, virus scanning, conflict policy, target directory, quota and rate-limit settings must be compatible with backend effective config."
1535
+ },
1536
+ {
1537
+ "validatorId": "target-directory-safe",
1538
+ "level": "error",
1539
+ "code": "PFU018",
1540
+ "description": "Target directory values must be normalized backend paths and must reject traversal or absolute filesystem paths."
1541
+ },
1542
+ {
1543
+ "validatorId": "conflict-policy-valid",
1544
+ "level": "error",
1545
+ "code": "PFU019",
1546
+ "description": "Default conflict policy must be one of ERROR, SKIP, OVERWRITE, MAKE_UNIQUE or RENAME."
1547
+ },
1548
+ {
1549
+ "validatorId": "quota-rate-policy-valid",
1550
+ "level": "error",
1551
+ "code": "PFU020",
1552
+ "description": "Quota and rate-limit UX settings must use non-negative retry counts/backoffs and cannot silently bypass backend enforcement."
1553
+ },
1554
+ {
1555
+ "validatorId": "header-names-safe",
1556
+ "level": "warning",
1557
+ "code": "PFU021",
1558
+ "description": "Contextual header names must be explicit HTTP token names and must not override authorization, cookie or content-type headers."
1559
+ },
1560
+ {
1561
+ "validatorId": "error-code-known",
1562
+ "level": "warning",
1563
+ "code": "PFU022",
1564
+ "description": "Error message overrides should target known backend error catalog codes or documented host-specific extensions."
1565
+ },
1566
+ {
1567
+ "validatorId": "error-message-i18n-compatible",
1568
+ "level": "warning",
1569
+ "code": "PFU023",
1570
+ "description": "User-facing error messages must remain compatible with the host i18n/editor flow and not expose raw technical exception text."
1571
+ },
1572
+ {
1573
+ "validatorId": "message-not-empty",
1574
+ "level": "error",
1575
+ "code": "PFU024",
1576
+ "description": "Error message overrides must be non-empty user-facing text."
1577
+ },
1578
+ {
1579
+ "validatorId": "display-mode-valid",
1580
+ "level": "error",
1581
+ "code": "PFU025",
1582
+ "description": "Display mode must be full or compact."
1583
+ },
1584
+ {
1585
+ "validatorId": "display-ui-compatible",
1586
+ "level": "warning",
1587
+ "code": "PFU026",
1588
+ "description": "Display changes must keep progress, manual upload and metadata form affordances reachable for the selected mode."
1589
+ },
1590
+ {
1591
+ "validatorId": "editor-runtime-round-trip",
1592
+ "level": "error",
1593
+ "code": "PFU027",
1594
+ "description": "Settings Panel editor, AI adapter snapshot and runtime inputs must round-trip config, baseUrl and displayMode without changing upload behavior."
1595
+ }
1596
+ ],
1597
+ "roundTripRequirements": [
1598
+ "Accepted type authoring must keep UI hints and backend-facing validation options aligned; ui.accept alone is not the canonical server policy.",
1599
+ "Endpoint authoring changes only the canonical files API baseUrl and strategy; direct, bulk and presign paths remain fixed by FilesApiClient.",
1600
+ "Security-affecting edits require confirmation and must round-trip through Settings Panel persistence without weakening strict validation, virus scanning, quota or rate-limit policy by omission.",
1601
+ "Error message overrides remain keyed by backend error catalog code and must stay user-facing/i18n-compatible.",
1602
+ "Display authoring may change displayMode and UI flags, but must not mutate backend options or upload submission payload."
1603
+ ],
1604
+ "examples": [
1605
+ {
1606
+ "id": "accept-pdf-images",
1607
+ "request": "Accept only PDF and image uploads.",
1608
+ "operationId": "accept.types.set",
1609
+ "params": {
1610
+ "accept": [
1611
+ "application/pdf",
1612
+ "image/*"
1613
+ ],
1614
+ "allowedExtensions": [
1615
+ "pdf",
1616
+ "png",
1617
+ "jpg",
1618
+ "jpeg"
1619
+ ],
1620
+ "acceptMimeTypes": [
1621
+ "application/pdf",
1622
+ "image/png",
1623
+ "image/jpeg"
1624
+ ]
1625
+ },
1626
+ "isPositive": true
1627
+ },
1628
+ {
1629
+ "id": "max-five-mb",
1630
+ "request": "Limit each file to 5 MB.",
1631
+ "operationId": "limit.fileSize.set",
1632
+ "params": {
1633
+ "maxFileSizeBytes": 5242880,
1634
+ "maxUploadSizeMb": 5
1635
+ },
1636
+ "isPositive": true
1637
+ },
1638
+ {
1639
+ "id": "max-three-files",
1640
+ "request": "Allow at most three files per upload batch.",
1641
+ "operationId": "limit.fileCount.set",
1642
+ "params": {
1643
+ "maxFilesPerBulk": 3
1644
+ },
1645
+ "isPositive": true
1646
+ },
1647
+ {
1648
+ "id": "set-presign-base-url",
1649
+ "request": "Use the official files API for presigned uploads.",
1650
+ "operationId": "endpoint.presign.set",
1651
+ "params": {
1652
+ "baseUrl": "https://api.praxis.example/files",
1653
+ "strategy": "presign"
1654
+ },
1655
+ "isPositive": true
1656
+ },
1657
+ {
1658
+ "id": "set-direct-base-url",
1659
+ "request": "Use the official files API for direct uploads.",
1660
+ "operationId": "endpoint.upload.set",
1661
+ "params": {
1662
+ "baseUrl": "https://api.praxis.example/files",
1663
+ "strategy": "direct"
1664
+ },
1665
+ "isPositive": true
1666
+ },
1667
+ {
1668
+ "id": "reject-unsafe-endpoint",
1669
+ "request": "Set upload endpoint to javascript:alert(1).",
1670
+ "operationId": "endpoint.upload.set",
1671
+ "params": {
1672
+ "baseUrl": "javascript:alert(1)",
1673
+ "strategy": "direct"
1674
+ },
1675
+ "isPositive": false
1676
+ },
1677
+ {
1678
+ "id": "tighten-security-policy",
1679
+ "request": "Enable strict validation and virus scanning for uploads.",
1680
+ "operationId": "security.policy.set",
1681
+ "params": {
1682
+ "strictValidation": true,
1683
+ "enableVirusScanning": true,
1684
+ "defaultConflictPolicy": "ERROR"
1685
+ },
1686
+ "isPositive": true
1687
+ },
1688
+ {
1689
+ "id": "reject-unconfirmed-security-policy",
1690
+ "request": "Disable strict validation without confirmation.",
1691
+ "operationId": "security.policy.set",
1692
+ "params": {
1693
+ "strictValidation": false,
1694
+ "enableVirusScanning": false
1695
+ },
1696
+ "isPositive": false
1697
+ },
1698
+ {
1699
+ "id": "quota-message",
1700
+ "request": "Show a friendly message when quota is exceeded.",
1701
+ "operationId": "message.error.set",
1702
+ "params": {
1703
+ "code": "QUOTA_EXCEEDED",
1704
+ "message": "Upload quota reached for this period."
1705
+ },
1706
+ "isPositive": true
1707
+ },
1708
+ {
1709
+ "id": "compact-display",
1710
+ "request": "Use compact upload display and keep progress visible.",
1711
+ "operationId": "display.mode.set",
1712
+ "params": {
1713
+ "displayMode": "compact",
1714
+ "dense": true,
1715
+ "showProgress": true
1716
+ },
1717
+ "isPositive": true
1718
+ }
1719
+ ]
1720
+ },
1721
+ "chunks": [
1722
+ {
1723
+ "chunkIndex": 0,
1724
+ "chunkKind": "summary",
1725
+ "content": "Component ID: praxis-files-upload\nSelector: praxis-files-upload\nFriendly Name: Praxis Files Upload\nDescription: Componente para upload de arquivos com suporte a configuracao dinamica, eventos e integracao com backend.\nLib/Package: @praxisui/files-upload\nTags: files, upload, widget, configurable\nInputs:\n - config (FilesUploadConfig)\n - filesUploadId (string)\n - componentInstanceId (string)\n - baseUrl (string)\n - displayMode ('full' | 'compact')\n - context (Record<string, unknown>)\n - enableCustomization (boolean)\nOutputs:\n - uploadSuccess (FileMetadata)\n - bulkComplete (BulkUploadResponseData)\n - error (ErrorResponse)\n - rateLimited (RateLimitInfo)\n - uploadStart (UploadStartEvent)\n - uploadProgress (UploadProgressEvent)\n - retry (BulkUploadFileResult)\n - download (BulkUploadFileResult)\n - copyLink (BulkUploadFileResult)\n - detailsOpened (BulkUploadFileResult)\n - detailsClosed (BulkUploadFileResult)\n - pendingStateChange (PendingFilesState)\n - readinessChange (FilesUploadReadinessEvent)\n - proximityChange (boolean)\n",
1726
+ "sourcePointer": "praxis-ui-angular/projects/praxis-files-upload/src/lib/praxis-files-upload.metadata.ts",
1727
+ "contentHash": "ac9de9f88b3b6c41731da2106436647af09e3f2e469e8df223afeb1d30de9c8e",
1728
+ "sourceKind": "component_definition",
1729
+ "sourceId": "praxis-files-upload",
1730
+ "corpusVersion": "1.0.0"
1731
+ },
1732
+ {
1733
+ "chunkIndex": 1,
1734
+ "chunkKind": "capabilities",
1735
+ "content": "Component Capabilities:\n - Path: strategy\n Category: strategy\n Kind: enum\n Description: Upload strategy.\n - Path: ui\n Category: ui\n Kind: object\n Description: UI configuration.\n - Path: ui.showDropzone\n Category: ui\n Kind: boolean\n Description: Show drag-and-drop dropzone.\n - Path: ui.accept\n Category: ui\n Kind: array\n Description: Accept attribute hints (extensions or mime types).\n - Path: ui.accept[]\n Category: ui\n Kind: string\n Description: Single accept entry.\n - Path: ui.dense\n Category: ui\n Kind: boolean\n Description: Dense layout.\n - Path: ui.showConflictPolicySelector\n Category: ui\n Kind: boolean\n Description: Show conflict policy selector.\n - Path: ui.showMetadataForm\n Category: ui\n Kind: boolean\n Description: Show metadata form for each file.\n - Path: ui.showProgress\n Category: ui\n Kind: boolean\n Description: Show progress UI.\n - Path: ui.manualUpload\n Category: ui\n Kind: boolean\n Description: Require manual start for uploads.\n - Path: ui.dropzone\n Category: ui\n Kind: object\n Description: Dropzone interaction options.\n - Path: ui.dropzone.expandOnDragProximity\n Category: ui\n Kind: boolean\n Description: Expand dropzone on drag proximity.\n - Path: ui.dropzone.proximityPx\n Category: ui\n Kind: number\n Description: Proximity radius in pixels.\n - Path: ui.dropzone.expandMode\n Category: ui\n Kind: enum\n Description: Dropzone expansion mode.\n - Path: ui.dropzone.expandHeight\n Category: ui\n Kind: number\n Description: Expanded height (px).\n - Path: ui.dropzone.expandDebounceMs\n Category: ui\n Kind: number\n Description: Drag debounce (ms).\n - Path: ui.list\n Category: ui\n Kind: object\n Description: Uploaded files list options.\n - Path: ui.list.collapseAfter\n Category: ui\n Kind: number\n Description: Collapse list after N items.\n - Path: ui.list.detailsMode\n Category: ui\n Kind: enum\n Description: Details panel mode.\n - Path: ui.list.detailsMaxWidth\n Category: ui\n Kind: number\n Description: Details panel max width (px).\n - Path: ui.list.detailsShowTechnical\n Category: ui\n Kind: boolean\n Description: Show technical details by default.\n - Path: ui.list.detailsFields\n Category: ui\n Kind: array\n Description: Allowed metadata fields to display.\n - Path: ui.list.detailsFields[]\n Category: ui\n Kind: string\n Description: Single metadata field name.\n - Path: ui.list.detailsAnchor\n Category: ui\n Kind: enum\n Description: Details overlay anchor.\n - Path: limits\n Category: limits\n Kind: object\n Description: Upload limits.\n - Path: limits.maxFileSizeBytes\n Category: limits\n Kind: number\n Description: Max file size (bytes).\n - Path: limits.maxFilesPerBulk\n Category: limits\n Kind: number\n Description: Max files per bulk upload.\n - Path: limits.maxBulkSizeBytes\n Category: limits\n Kind: number\n Description: Max bulk size (bytes).\n - Path: options\n Category: options\n Kind: object\n Description: Backend options sent as JSON.\n - Path: options.defaultConflictPolicy\n Category: options\n Kind: enum\n Description: Default conflict policy.\n - Path: options.strictValidation\n Category: options\n Kind: boolean\n Description: Strict backend validation.\n - Path: options.maxUploadSizeMb\n Category: options\n Kind: number\n Description: Max upload size in MB.\n - Path: options.allowedExtensions\n Category: options\n Kind: array\n Description: Allowed file extensions.\n - Path: options.allowedExtensions[]\n Category: options\n Kind: string\n Description: Single extension (e.g., pdf).\n - Path: options.acceptMimeTypes\n Category: options\n Kind: array\n Description: Allowed mime types.\n - Path: options.acceptMimeTypes[]\n Category: options\n Kind: string\n Description: Single mime type.\n - Path: options.targetDirectory\n Category: options\n Kind: string\n Description: Target directory on backend.\n - Path: options.enableVirusScanning\n Category: options\n Kind: boolean\n Description: Enable virus scanning.\n - Path: bulk\n Category: bulk\n Kind: object\n Description: Bulk upload tuning.\n - Path: bulk.failFast\n Category: bulk\n Kind: boolean\n Description: Abort on first error.\n - Path: bulk.parallelUploads\n Category: bulk\n Kind: number\n Description: Parallel uploads count.\n - Path: bulk.retryCount\n Category: bulk\n Kind: number\n Description: Retry count.\n - Path: bulk.retryBackoffMs\n Category: bulk\n Kind: number\n Description: Retry backoff (ms).\n - Path: quotas\n Category: quotas\n Kind: object\n Description: Quota UX behavior.\n - Path: quotas.showQuotaWarnings\n Category: quotas\n Kind: boolean\n Description: Show quota warnings.\n - Path: quotas.blockOnExceed\n Category: quotas\n Kind: boolean\n Description: Block uploads when exceeded.\n - Path: rateLimit\n Category: rateLimit\n Kind: object\n Description: 429 handling.\n - Path: rateLimit.autoRetryOn429\n Category: rateLimit\n Kind: boolean\n Description: Auto retry on 429.\n - Path: rateLimit.showBannerOn429\n Category: rateLimit\n Kind: boolean\n Description: Show rate limit banner.\n - Path: rateLimit.maxAutoRetry\n Category: rateLimit\n Kind: number\n Description: Max auto retry attempts.\n - Path: rateLimit.baseBackoffMs\n Category: rateLimit\n Kind: number\n Description: Base backoff (ms).\n - Path: headers\n Category: headers\n Kind: object\n Description: Header mapping for backend.\n - Path: headers.tenantHeader\n Category: headers\n Kind: string\n Description: Tenant header name.\n - Path: headers.userHeader\n Category: headers\n Kind: string\n Description: User header name.\n - Path: messages\n Category: messages\n Kind: object\n Description: User-facing text overrides.\n - Path: messages.successSingle\n Category: messages\n Kind: string\n Description: Single upload success message.\n - Path: messages.successBulk\n Category: messages\n Kind: string\n Description: Bulk upload success message.\n - Path: messages.errors\n Category: messages\n Kind: object\n Description: Error message map.\n - Path: messages.errors.[code]\n Category: messages\n Kind: string\n Description: Message for a specific error code.\nCapability Notes:\n - limits.maxFileSizeBytes and limits.maxBulkSizeBytes are bytes (e.g., 10485760 for 10MB).\n - options.allowedExtensions is enforced by backend validation; ui.accept is only a client hint.\n - Use options.defaultConflictPolicy to control name collisions on upload.\n",
1736
+ "sourcePointer": "praxis-ui-angular/projects/praxis-files-upload/src/lib/ai/files-upload-ai-capabilities.ts",
1737
+ "contentHash": "c66760435308ecfd846ae8a2d1ef17f6d264d4e6615e00a6595fd527c536bfb5",
1738
+ "sourceKind": "component_definition",
1739
+ "sourceId": "praxis-files-upload",
1740
+ "corpusVersion": "1.0.0"
1741
+ },
1742
+ {
1743
+ "chunkIndex": 2,
1744
+ "chunkKind": "authoring_manifest",
1745
+ "content": "{\n \"schemaVersion\": \"1.0.0\",\n \"componentId\": \"praxis-files-upload\",\n \"ownerPackage\": \"@praxisui/files-upload\",\n \"configSchemaId\": \"FilesUploadConfig\",\n \"manifestVersion\": \"1.0.0\",\n \"runtimeInputs\": [\n {\n \"name\": \"config\",\n \"type\": \"FilesUploadConfig\",\n \"description\": \"Upload strategy, UI, limits, backend options, bulk execution, quota/rate feedback, headers and messages.\"\n },\n {\n \"name\": \"filesUploadId\",\n \"type\": \"string\",\n \"description\": \"Stable upload id used for config persistence and telemetry correlation.\"\n },\n {\n \"name\": \"componentInstanceId\",\n \"type\": \"string\",\n \"description\": \"Optional instance discriminator when the same upload id appears more than once.\"\n },\n {\n \"name\": \"baseUrl\",\n \"type\": \"string\",\n \"description\": \"Canonical files API base URL. Direct upload uses baseUrl/upload, bulk uses baseUrl/bulk and presign uses baseUrl/upload/presign.\"\n },\n {\n \"name\": \"displayMode\",\n \"type\": \"'full' | 'compact'\",\n \"allowedValues\": [\n \"full\",\n \"compact\"\n ],\n \"description\": \"Runtime display mode input.\"\n },\n {\n \"name\": \"context\",\n \"type\": \"Record<string, unknown>\",\n \"description\": \"Host context available to metadata and event consumers.\"\n },\n {\n \"name\": \"enableCustomization\",\n \"type\": \"boolean\",\n \"description\": \"Enables the Settings Panel configuration editor.\"\n }\n ],\n \"editableTargets\": [\n {\n \"kind\": \"acceptedTypes\",\n \"resolver\": \"files-accept-list\",\n \"description\": \"Allowed file extensions and MIME types projected to ui.accept, options.allowedExtensions and options.acceptMimeTypes.\"\n },\n {\n \"kind\": \"sizeLimit\",\n \"resolver\": \"max-file-size-policy\",\n \"description\": \"Maximum single-file size in limits.maxFileSizeBytes and backend-facing options.maxUploadSizeMb.\"\n },\n {\n \"kind\": \"fileCountLimit\",\n \"resolver\": \"max-files-per-bulk-policy\",\n \"description\": \"Maximum number of files accepted in a bulk selection.\"\n },\n {\n \"kind\": \"presignEndpoint\",\n \"resolver\": \"files-api-base-url-presign-contract\",\n \"description\": \"Presign operation endpoint derived from baseUrl + /upload/presign; arbitrary per-operation URLs are not accepted.\"\n },\n {\n \"kind\": \"uploadEndpoint\",\n \"resolver\": \"files-api-base-url-upload-contract\",\n \"description\": \"Direct and bulk upload endpoints derived from baseUrl + /upload and /bulk.\"\n },\n {\n \"kind\": \"securityPolicy\",\n \"resolver\": \"upload-security-policy\",\n \"description\": \"Strict validation, virus scanning, conflict policy, target directory, quotas, rate limit and contextual headers.\"\n },\n {\n \"kind\": \"errorMessages\",\n \"resolver\": \"upload-error-code-message\",\n \"description\": \"Host-provided message overrides under messages.errors keyed by backend error code.\"\n },\n {\n \"kind\": \"display\",\n \"resolver\": \"files-upload-display-mode-and-ui\",\n \"description\": \"Runtime displayMode plus non-backend visual UI flags.\"\n }\n ],\n \"operations\": [\n {\n \"operationId\": \"accept.types.set\",\n \"title\": \"Set accepted file types\",\n \"scope\": \"global\",\n \"targetKind\": \"acceptedTypes\",\n \"target\": {\n \"kind\": \"acceptedTypes\",\n \"resolver\": \"files-accept-list\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": false\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"accept\"\n ],\n \"properties\": {\n \"accept\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"allowedExtensions\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"acceptMimeTypes\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"set-value\",\n \"path\": \"ui.accept\"\n },\n {\n \"kind\": \"set-value\",\n \"path\": \"options.allowedExtensions\"\n },\n {\n \"kind\": \"set-value\",\n \"path\": \"options.acceptMimeTypes\"\n }\n ],\n \"destructive\": false,\n \"requiresConfirmation\": false,\n \"validators\": [\n \"file-type-list-explicit\",\n \"file-type-entry-valid\",\n \"backend-accept-options-consistent\",\n \"editor-runtime-round-trip\"\n ],\n \"affectedPaths\": [\n \"ui.accept\",\n \"options.allowedExtensions\",\n \"options.acceptMimeTypes\"\n ],\n \"submissionImpact\": \"affects-submission\",\n \"preconditions\": [\n \"config-initialized\"\n ]\n },\n {\n \"operationId\": \"limit.fileSize.set\",\n \"title\": \"Set max file size\",\n \"scope\": \"global\",\n \"targetKind\": \"sizeLimit\",\n \"target\": {\n \"kind\": \"sizeLimit\",\n \"resolver\": \"max-file-size-policy\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": false\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"maxFileSizeBytes\"\n ],\n \"properties\": {\n \"maxFileSizeBytes\": {\n \"type\": \"number\"\n },\n \"maxUploadSizeMb\": {\n \"type\": \"number\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"set-value\",\n \"path\": \"limits.maxFileSizeBytes\"\n },\n {\n \"kind\": \"set-value\",\n \"path\": \"options.maxUploadSizeMb\"\n }\n ],\n \"destructive\": false,\n \"requiresConfirmation\": false,\n \"validators\": [\n \"size-limit-numeric\",\n \"size-limit-within-platform-policy\",\n \"size-limit-client-backend-consistent\",\n \"editor-runtime-round-trip\"\n ],\n \"affectedPaths\": [\n \"limits.maxFileSizeBytes\",\n \"options.maxUploadSizeMb\"\n ],\n \"submissionImpact\": \"affects-submission\",\n \"preconditions\": [\n \"config-initialized\"\n ]\n },\n {\n \"operationId\": \"limit.fileCount.set\",\n \"title\": \"Set max file count\",\n \"scope\": \"global\",\n \"targetKind\": \"fileCountLimit\",\n \"target\": {\n \"kind\": \"fileCountLimit\",\n \"resolver\": \"max-files-per-bulk-policy\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": false\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"maxFilesPerBulk\"\n ],\n \"properties\": {\n \"maxFilesPerBulk\": {\n \"type\": \"number\"\n },\n \"maxBulkSizeBytes\": {\n \"type\": \"number\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"set-value\",\n \"path\": \"limits.maxFilesPerBulk\"\n },\n {\n \"kind\": \"set-value\",\n \"path\": \"limits.maxBulkSizeBytes\"\n }\n ],\n \"destructive\": false,\n \"requiresConfirmation\": false,\n \"validators\": [\n \"file-count-limit-numeric\",\n \"bulk-size-limit-numeric\",\n \"bulk-limit-within-platform-policy\",\n \"editor-runtime-round-trip\"\n ],\n \"affectedPaths\": [\n \"limits.maxFilesPerBulk\",\n \"limits.maxBulkSizeBytes\"\n ],\n \"submissionImpact\": \"affects-submission\",\n \"preconditions\": [\n \"config-initialized\"\n ]\n },\n {\n \"operationId\": \"endpoint.presign.set\",\n \"title\": \"Set presign endpoint\",\n \"scope\": \"global\",\n \"targetKind\": \"presignEndpoint\",\n \"target\": {\n \"kind\": \"presignEndpoint\",\n \"resolver\": \"files-api-base-url-presign-contract\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": false\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"baseUrl\"\n ],\n \"properties\": {\n \"baseUrl\": {\n \"type\": \"string\"\n },\n \"strategy\": {\n \"enum\": [\n \"direct\",\n \"presign\",\n \"auto\"\n ]\n },\n \"allowCrossOriginPresignedTarget\": {\n \"type\": \"boolean\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"files-upload-presign-base-url\",\n \"handlerContract\": {\n \"reads\": [\n \"baseUrl\",\n \"strategy\"\n ],\n \"writes\": [\n \"baseUrl\",\n \"strategy\"\n ],\n \"identityKeys\": [\n \"baseUrl\"\n ],\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"baseUrl\"\n ],\n \"properties\": {\n \"baseUrl\": {\n \"type\": \"string\"\n },\n \"strategy\": {\n \"enum\": [\n \"direct\",\n \"presign\",\n \"auto\"\n ]\n },\n \"allowCrossOriginPresignedTarget\": {\n \"type\": \"boolean\"\n }\n }\n },\n \"failureModes\": [\n \"unsafe-url\",\n \"non-praxis-backend-surface\",\n \"presign-path-override\",\n \"cross-origin-presigned-fields-leak\"\n ],\n \"description\": \"Validates the files API base URL and preserves the canonical POST baseUrl/upload/presign?filename=... contract; arbitrary presign URLs are rejected.\"\n }\n }\n ],\n \"destructive\": true,\n \"requiresConfirmation\": true,\n \"validators\": [\n \"endpoint-url-safe\",\n \"endpoint-uses-praxis-backend-surface\",\n \"presign-endpoint-fixed-contract\",\n \"presign-cross-origin-fields-safe\",\n \"security-change-confirmed\"\n ],\n \"affectedPaths\": [\n \"baseUrl\",\n \"strategy\"\n ],\n \"submissionImpact\": \"affects-remote-binding\",\n \"preconditions\": [\n \"config-initialized\",\n \"confirmation-collected\"\n ]\n },\n {\n \"operationId\": \"endpoint.upload.set\",\n \"title\": \"Set upload endpoint\",\n \"scope\": \"global\",\n \"targetKind\": \"uploadEndpoint\",\n \"target\": {\n \"kind\": \"uploadEndpoint\",\n \"resolver\": \"files-api-base-url-upload-contract\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": false\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"baseUrl\"\n ],\n \"properties\": {\n \"baseUrl\": {\n \"type\": \"string\"\n },\n \"strategy\": {\n \"enum\": [\n \"direct\",\n \"presign\",\n \"auto\"\n ]\n },\n \"allowCrossOriginPresignedTarget\": {\n \"type\": \"boolean\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"files-upload-direct-base-url\",\n \"handlerContract\": {\n \"reads\": [\n \"baseUrl\",\n \"strategy\"\n ],\n \"writes\": [\n \"baseUrl\",\n \"strategy\"\n ],\n \"identityKeys\": [\n \"baseUrl\"\n ],\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"baseUrl\"\n ],\n \"properties\": {\n \"baseUrl\": {\n \"type\": \"string\"\n },\n \"strategy\": {\n \"enum\": [\n \"direct\",\n \"presign\",\n \"auto\"\n ]\n },\n \"allowCrossOriginPresignedTarget\": {\n \"type\": \"boolean\"\n }\n }\n },\n \"failureModes\": [\n \"unsafe-url\",\n \"non-praxis-backend-surface\",\n \"upload-path-override\",\n \"bulk-path-override\"\n ],\n \"description\": \"Validates the files API base URL and preserves the canonical POST baseUrl/upload and POST baseUrl/bulk contracts.\"\n }\n }\n ],\n \"destructive\": true,\n \"requiresConfirmation\": true,\n \"validators\": [\n \"endpoint-url-safe\",\n \"endpoint-uses-praxis-backend-surface\",\n \"upload-endpoint-fixed-contract\",\n \"bulk-endpoint-fixed-contract\",\n \"security-change-confirmed\"\n ],\n \"affectedPaths\": [\n \"baseUrl\",\n \"strategy\"\n ],\n \"submissionImpact\": \"affects-remote-binding\",\n \"preconditions\": [\n \"config-initialized\",\n \"confirmation-collected\"\n ]\n },\n {\n \"operationId\": \"security.policy.set\",\n \"title\": \"Set upload security policy\",\n \"scope\": \"global\",\n \"targetKind\": \"securityPolicy\",\n \"target\": {\n \"kind\": \"securityPolicy\",\n \"resolver\": \"upload-security-policy\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": false\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"properties\": {\n \"strictValidation\": {\n \"type\": \"boolean\"\n },\n \"enableVirusScanning\": {\n \"type\": \"boolean\"\n },\n \"defaultConflictPolicy\": {\n \"enum\": [\n \"ERROR\",\n \"SKIP\",\n \"OVERWRITE\",\n \"MAKE_UNIQUE\",\n \"RENAME\"\n ]\n },\n \"targetDirectory\": {\n \"type\": \"string\"\n },\n \"showQuotaWarnings\": {\n \"type\": \"boolean\"\n },\n \"blockOnExceed\": {\n \"type\": \"boolean\"\n },\n \"autoRetryOn429\": {\n \"type\": \"boolean\"\n },\n \"showBannerOn429\": {\n \"type\": \"boolean\"\n },\n \"maxAutoRetry\": {\n \"type\": \"number\"\n },\n \"baseBackoffMs\": {\n \"type\": \"number\"\n },\n \"tenantHeader\": {\n \"type\": \"string\"\n },\n \"userHeader\": {\n \"type\": \"string\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"merge-object\",\n \"path\": \"options\"\n },\n {\n \"kind\": \"merge-object\",\n \"path\": \"quotas\"\n },\n {\n \"kind\": \"merge-object\",\n \"path\": \"rateLimit\"\n },\n {\n \"kind\": \"merge-object\",\n \"path\": \"headers\"\n }\n ],\n \"destructive\": true,\n \"requiresConfirmation\": true,\n \"validators\": [\n \"security-change-confirmed\",\n \"security-policy-compatible\",\n \"target-directory-safe\",\n \"conflict-policy-valid\",\n \"quota-rate-policy-valid\",\n \"header-names-safe\",\n \"editor-runtime-round-trip\"\n ],\n \"affectedPaths\": [\n \"options.strictValidation\",\n \"options.enableVirusScanning\",\n \"options.defaultConflictPolicy\",\n \"options.targetDirectory\",\n \"quotas\",\n \"rateLimit\",\n \"headers\"\n ],\n \"submissionImpact\": \"config-only\",\n \"preconditions\": [\n \"config-initialized\",\n \"confirmation-collected\"\n ]\n },\n {\n \"operationId\": \"message.error.set\",\n \"title\": \"Set error message override\",\n \"scope\": \"global\",\n \"targetKind\": \"errorMessages\",\n \"target\": {\n \"kind\": \"errorMessages\",\n \"resolver\": \"upload-error-code-message\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": false\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"code\",\n \"message\"\n ],\n \"properties\": {\n \"code\": {\n \"type\": \"string\"\n },\n \"message\": {\n \"type\": \"string\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"merge-object\",\n \"path\": \"messages.errors\"\n }\n ],\n \"destructive\": false,\n \"requiresConfirmation\": false,\n \"validators\": [\n \"error-code-known\",\n \"error-message-i18n-compatible\",\n \"message-not-empty\",\n \"editor-runtime-round-trip\"\n ],\n \"affectedPaths\": [\n \"messages.errors\"\n ],\n \"submissionImpact\": \"config-only\",\n \"preconditions\": [\n \"config-initialized\"\n ]\n },\n {\n \"operationId\": \"display.mode.set\",\n \"title\": \"Set display mode\",\n \"scope\": \"global\",\n \"targetKind\": \"display\",\n \"target\": {\n \"kind\": \"display\",\n \"resolver\": \"files-upload-display-mode-and-ui\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": false\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"properties\": {\n \"displayMode\": {\n \"enum\": [\n \"full\",\n \"compact\"\n ]\n },\n \"dense\": {\n \"type\": \"boolean\"\n },\n \"showDropzone\": {\n \"type\": \"boolean\"\n },\n \"showProgress\": {\n \"type\": \"boolean\"\n },\n \"manualUpload\": {\n \"type\": \"boolean\"\n },\n \"showMetadataForm\": {\n \"type\": \"boolean\"\n },\n \"showConflictPolicySelector\": {\n \"type\": \"boolean\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"set-value\",\n \"path\": \"displayMode\"\n },\n {\n \"kind\": \"merge-object\",\n \"path\": \"ui\"\n }\n ],\n \"destructive\": false,\n \"requiresConfirmation\": false,\n \"validators\": [\n \"display-mode-valid\",\n \"display-ui-compatible\",\n \"editor-runtime-round-trip\"\n ],\n \"affectedPaths\": [\n \"displayMode\",\n \"ui.dense\",\n \"ui.showDropzone\",\n \"ui.showProgress\",\n \"ui.manualUpload\",\n \"ui.showMetadataForm\",\n \"ui.showConflictPolicySelector\"\n ],\n \"submissionImpact\": \"visual-only\",\n \"preconditions\": [\n \"config-initialized\"\n ]\n }\n ],\n \"validators\": [\n {\n \"validatorId\": \"file-type-list-explicit\",\n \"level\": \"error\",\n \"code\": \"PFU001\",\n \"description\": \"Accepted type edits must provide a non-empty explicit list and may not rely on wildcard-only policy.\"\n },\n {\n \"validatorId\": \"file-type-entry-valid\",\n \"level\": \"error\",\n \"code\": \"PFU002\",\n \"description\": \"Each accepted type must be a valid extension, exact MIME type or controlled subtype wildcard.\"\n },\n {\n \"validatorId\": \"backend-accept-options-consistent\",\n \"level\": \"error\",\n \"code\": \"PFU003\",\n \"description\": \"ui.accept hints must remain consistent with options.allowedExtensions and options.acceptMimeTypes when backend validation is configured.\"\n },\n {\n \"validatorId\": \"size-limit-numeric\",\n \"level\": \"error\",\n \"code\": \"PFU004\",\n \"description\": \"Single file size limits must be positive numeric byte and MB values.\"\n },\n {\n \"validatorId\": \"size-limit-within-platform-policy\",\n \"level\": \"error\",\n \"code\": \"PFU005\",\n \"description\": \"Single file size limits must not exceed the platform upload policy for the selected backend surface.\"\n },\n {\n \"validatorId\": \"size-limit-client-backend-consistent\",\n \"level\": \"error\",\n \"code\": \"PFU006\",\n \"description\": \"limits.maxFileSizeBytes and options.maxUploadSizeMb must describe the same effective maximum when both are present.\"\n },\n {\n \"validatorId\": \"file-count-limit-numeric\",\n \"level\": \"error\",\n \"code\": \"PFU007\",\n \"description\": \"Bulk file count limits must be positive integers.\"\n },\n {\n \"validatorId\": \"bulk-size-limit-numeric\",\n \"level\": \"error\",\n \"code\": \"PFU008\",\n \"description\": \"Bulk size limits must be positive numeric byte values when provided.\"\n },\n {\n \"validatorId\": \"bulk-limit-within-platform-policy\",\n \"level\": \"error\",\n \"code\": \"PFU009\",\n \"description\": \"Bulk count and aggregate size limits must not exceed backend batch policy.\"\n },\n {\n \"validatorId\": \"endpoint-url-safe\",\n \"level\": \"error\",\n \"code\": \"PFU010\",\n \"description\": \"Endpoint edits must use a safe absolute or approved relative baseUrl and reject javascript:, data:, credentials-in-URL and path traversal.\"\n },\n {\n \"validatorId\": \"endpoint-uses-praxis-backend-surface\",\n \"level\": \"error\",\n \"code\": \"PFU011\",\n \"description\": \"Endpoint edits must resolve to the approved Praxis files backend surface for the host environment.\"\n },\n {\n \"validatorId\": \"presign-endpoint-fixed-contract\",\n \"level\": \"error\",\n \"code\": \"PFU012\",\n \"description\": \"Presign authoring may change baseUrl but must preserve POST baseUrl/upload/presign?filename=... as the runtime contract.\"\n },\n {\n \"validatorId\": \"upload-endpoint-fixed-contract\",\n \"level\": \"error\",\n \"code\": \"PFU013\",\n \"description\": \"Direct upload authoring may change baseUrl but must preserve POST baseUrl/upload as the runtime contract.\"\n },\n {\n \"validatorId\": \"bulk-endpoint-fixed-contract\",\n \"level\": \"error\",\n \"code\": \"PFU014\",\n \"description\": \"Bulk upload authoring may change baseUrl but must preserve POST baseUrl/bulk as the runtime contract.\"\n },\n {\n \"validatorId\": \"presign-cross-origin-fields-safe\",\n \"level\": \"error\",\n \"code\": \"PFU015\",\n \"description\": \"Cross-origin presigned upload targets must not receive Praxis metadata/options fields unless explicitly approved by the presign response contract.\"\n },\n {\n \"validatorId\": \"security-change-confirmed\",\n \"level\": \"error\",\n \"code\": \"PFU016\",\n \"description\": \"Endpoint and security policy edits require explicit confirmation before patch compilation.\"\n },\n {\n \"validatorId\": \"security-policy-compatible\",\n \"level\": \"error\",\n \"code\": \"PFU017\",\n \"description\": \"Strict validation, virus scanning, conflict policy, target directory, quota and rate-limit settings must be compatible with backend effective config.\"\n },\n {\n \"validatorId\": \"target-directory-safe\",\n \"level\": \"error\",\n \"code\": \"PFU018\",\n \"description\": \"Target directory values must be normalized backend paths and must reject traversal or absolute filesystem paths.\"\n },\n {\n \"validatorId\": \"conflict-policy-valid\",\n \"level\": \"error\",\n \"code\": \"PFU019\",\n \"description\": \"Default conflict policy must be one of ERROR, SKIP, OVERWRITE, MAKE_UNIQUE or RENAME.\"\n },\n {\n \"validatorId\": \"quota-rate-policy-valid\",\n \"level\": \"error\",\n \"code\": \"PFU020\",\n \"description\": \"Quota and rate-limit UX settings must use non-negative retry counts/backoffs and cannot silently bypass backend enforcement.\"\n },\n {\n \"validatorId\": \"header-names-safe\",\n \"level\": \"warning\",\n \"code\": \"PFU021\",\n \"description\": \"Contextual header names must be explicit HTTP token names and must not override authorization, cookie or content-type headers.\"\n },\n {\n \"validatorId\": \"error-code-known\",\n \"level\": \"warning\",\n \"code\": \"PFU022\",\n \"description\": \"Error message overrides should target known backend error catalog codes or documented host-specific extensions.\"\n },\n {\n \"validatorId\": \"error-message-i18n-compatible\",\n \"level\": \"warning\",\n \"code\": \"PFU023\",\n \"description\": \"User-facing error messages must remain compatible with the host i18n/editor flow and not expose raw technical exception text.\"\n },\n {\n \"validatorId\": \"message-not-empty\",\n \"level\": \"error\",\n \"code\": \"PFU024\",\n \"description\": \"Error message overrides must be non-empty user-facing text.\"\n },\n {\n \"validatorId\": \"display-mode-valid\",\n \"level\": \"error\",\n \"code\": \"PFU025\",\n \"description\": \"Display mode must be full or compact.\"\n },\n {\n \"validatorId\": \"display-ui-compatible\",\n \"level\": \"warning\",\n \"code\": \"PFU026\",\n \"description\": \"Display changes must keep progress, manual upload and metadata form affordances reachable for the selected mode.\"\n },\n {\n \"validatorId\": \"editor-runtime-round-trip\",\n \"level\": \"error\",\n \"code\": \"PFU027\",\n \"description\": \"Settings Panel editor, AI adapter snapshot and runtime inputs must round-trip config, baseUrl and displayMode without changing upload behavior.\"\n }\n ],\n \"roundTripRequirements\": [\n \"Accepted type authoring must keep UI hints and backend-facing validation options aligned; ui.accept alone is not the canonical server policy.\",\n \"Endpoint authoring changes only the canonical files API baseUrl and strategy; direct, bulk and presign paths remain fixed by FilesApiClient.\",\n \"Security-affecting edits require confirmation and must round-trip through Settings Panel persistence without weakening strict validation, virus scanning, quota or rate-limit policy by omission.\",\n \"Error message overrides remain keyed by backend error catalog code and must stay user-facing/i18n-compatible.\",\n \"Display authoring may change displayMode and UI flags, but must not mutate backend options or upload submission payload.\"\n ],\n \"examples\": [\n {\n \"id\": \"accept-pdf-images\",\n \"request\": \"Accept only PDF and image uploads.\",\n \"operationId\": \"accept.types.set\",\n \"params\": {\n \"accept\": [\n \"application/pdf\",\n \"image/*\"\n ],\n \"allowedExtensions\": [\n \"pdf\",\n \"png\",\n \"jpg\",\n \"jpeg\"\n ],\n \"acceptMimeTypes\": [\n \"application/pdf\",\n \"image/png\",\n \"image/jpeg\"\n ]\n },\n \"isPositive\": true\n },\n {\n \"id\": \"max-five-mb\",\n \"request\": \"Limit each file to 5 MB.\",\n \"operationId\": \"limit.fileSize.set\",\n \"params\": {\n \"maxFileSizeBytes\": 5242880,\n \"maxUploadSizeMb\": 5\n },\n \"isPositive\": true\n },\n {\n \"id\": \"max-three-files\",\n \"request\": \"Allow at most three files per upload batch.\",\n \"operationId\": \"limit.fileCount.set\",\n \"params\": {\n \"maxFilesPerBulk\": 3\n },\n \"isPositive\": true\n },\n {\n \"id\": \"set-presign-base-url\",\n \"request\": \"Use the official files API for presigned uploads.\",\n \"operationId\": \"endpoint.presign.set\",\n \"params\": {\n \"baseUrl\": \"https://api.praxis.example/files\",\n \"strategy\": \"presign\"\n },\n \"isPositive\": true\n },\n {\n \"id\": \"set-direct-base-url\",\n \"request\": \"Use the official files API for direct uploads.\",\n \"operationId\": \"endpoint.upload.set\",\n \"params\": {\n \"baseUrl\": \"https://api.praxis.example/files\",\n \"strategy\": \"direct\"\n },\n \"isPositive\": true\n },\n {\n \"id\": \"reject-unsafe-endpoint\",\n \"request\": \"Set upload endpoint to javascript:alert(1).\",\n \"operationId\": \"endpoint.upload.set\",\n \"params\": {\n \"baseUrl\": \"javascript:alert(1)\",\n \"strategy\": \"direct\"\n },\n \"isPositive\": false\n },\n {\n \"id\": \"tighten-security-policy\",\n \"request\": \"Enable strict validation and virus scanning for uploads.\",\n \"operationId\": \"security.policy.set\",\n \"params\": {\n \"strictValidation\": true,\n \"enableVirusScanning\": true,\n \"defaultConflictPolicy\": \"ERROR\"\n },\n \"isPositive\": true\n },\n {\n \"id\": \"reject-unconfirmed-security-policy\",\n \"request\": \"Disable strict validation without confirmation.\",\n \"operationId\": \"security.policy.set\",\n \"params\": {\n \"strictValidation\": false,\n \"enableVirusScanning\": false\n },\n \"isPositive\": false\n },\n {\n \"id\": \"quota-message\",\n \"request\": \"Show a friendly message when quota is exceeded.\",\n \"operationId\": \"message.error.set\",\n \"params\": {\n \"code\": \"QUOTA_EXCEEDED\",\n \"message\": \"Upload quota reached for this period.\"\n },\n \"isPositive\": true\n },\n {\n \"id\": \"compact-display\",\n \"request\": \"Use compact upload display and keep progress visible.\",\n \"operationId\": \"display.mode.set\",\n \"params\": {\n \"displayMode\": \"compact\",\n \"dense\": true,\n \"showProgress\": true\n },\n \"isPositive\": true\n }\n ]\n}",
1746
+ "sourcePointer": "praxis-ui-angular/projects/praxis-files-upload/src/lib/ai/praxis-files-upload-authoring-manifest.ts",
1747
+ "contentHash": "b9d1c1169ded284421d4a18e3b6227cc963b1aaa8a19d1ebd02cf61280ffbc68",
1748
+ "sourceKind": "component_definition",
1749
+ "sourceId": "praxis-files-upload",
1750
+ "corpusVersion": "1.0.0"
1751
+ },
1752
+ {
1753
+ "chunkIndex": 3,
1754
+ "chunkKind": "context_pack",
1755
+ "content": "{\n \"componentContext\": {\n \"version\": \"v1\",\n \"optionsByPath\": {\n \"strategy\": {\n \"mode\": \"enum\",\n \"options\": [\n {\n \"value\": \"direct\",\n \"label\": \"Direct\"\n },\n {\n \"value\": \"presign\",\n \"label\": \"Presign\"\n },\n {\n \"value\": \"auto\",\n \"label\": \"Auto\"\n }\n ]\n },\n \"ui.dropzone.expandMode\": {\n \"mode\": \"enum\",\n \"options\": [\n {\n \"value\": \"overlay\",\n \"label\": \"Overlay\"\n },\n {\n \"value\": \"inline\",\n \"label\": \"Inline\"\n }\n ]\n },\n \"ui.list.detailsMode\": {\n \"mode\": \"enum\",\n \"options\": [\n {\n \"value\": \"card\",\n \"label\": \"Card\"\n },\n {\n \"value\": \"sidesheet\",\n \"label\": \"Side sheet\"\n },\n {\n \"value\": \"auto\",\n \"label\": \"Auto\"\n }\n ]\n },\n \"ui.list.detailsAnchor\": {\n \"mode\": \"enum\",\n \"options\": [\n {\n \"value\": \"item\",\n \"label\": \"Item\"\n },\n {\n \"value\": \"field\",\n \"label\": \"Field\"\n }\n ]\n },\n \"options.defaultConflictPolicy\": {\n \"mode\": \"enum\",\n \"options\": [\n {\n \"value\": \"ERROR\",\n \"label\": \"Error\"\n },\n {\n \"value\": \"SKIP\",\n \"label\": \"Skip\"\n },\n {\n \"value\": \"OVERWRITE\",\n \"label\": \"Overwrite\"\n },\n {\n \"value\": \"MAKE_UNIQUE\",\n \"label\": \"Make unique\"\n },\n {\n \"value\": \"RENAME\",\n \"label\": \"Rename\"\n }\n ]\n }\n },\n \"actionCatalog\": [\n {\n \"id\": \"strategy.set\",\n \"intentExamples\": [\n \"strategy\",\n \"upload strategy\"\n ],\n \"patchTemplate\": {\n \"strategy\": \"{{value}}\"\n }\n },\n {\n \"id\": \"ui.showDropzone.enable\",\n \"intentExamples\": [\n \"show dropzone\",\n \"enable dropzone\"\n ],\n \"patchTemplate\": {\n \"ui\": {\n \"showDropzone\": true\n }\n }\n },\n {\n \"id\": \"ui.showDropzone.disable\",\n \"intentExamples\": [\n \"hide dropzone\",\n \"disable dropzone\"\n ],\n \"patchTemplate\": {\n \"ui\": {\n \"showDropzone\": false\n }\n }\n },\n {\n \"id\": \"ui.manualUpload.enable\",\n \"intentExamples\": [\n \"manual upload\",\n \"upload button\"\n ],\n \"patchTemplate\": {\n \"ui\": {\n \"manualUpload\": true\n }\n }\n },\n {\n \"id\": \"ui.manualUpload.disable\",\n \"intentExamples\": [\n \"auto upload\",\n \"instant upload\"\n ],\n \"patchTemplate\": {\n \"ui\": {\n \"manualUpload\": false\n }\n }\n },\n {\n \"id\": \"ui.showProgress.enable\",\n \"intentExamples\": [\n \"show progress\",\n \"progress bar\"\n ],\n \"patchTemplate\": {\n \"ui\": {\n \"showProgress\": true\n }\n }\n },\n {\n \"id\": \"ui.showProgress.disable\",\n \"intentExamples\": [\n \"hide progress\",\n \"no progress\"\n ],\n \"patchTemplate\": {\n \"ui\": {\n \"showProgress\": false\n }\n }\n },\n {\n \"id\": \"limits.maxFileSizeBytes.set\",\n \"intentExamples\": [\n \"max file size\",\n \"size limit\"\n ],\n \"patchTemplate\": {\n \"limits\": {\n \"maxFileSizeBytes\": \"{{value}}\"\n }\n }\n },\n {\n \"id\": \"limits.maxFilesPerBulk.set\",\n \"intentExamples\": [\n \"max files\",\n \"files per upload\"\n ],\n \"patchTemplate\": {\n \"limits\": {\n \"maxFilesPerBulk\": \"{{value}}\"\n }\n }\n },\n {\n \"id\": \"options.defaultConflictPolicy.set\",\n \"intentExamples\": [\n \"conflict policy\",\n \"overwrite\",\n \"rename\"\n ],\n \"patchTemplate\": {\n \"options\": {\n \"defaultConflictPolicy\": \"{{value}}\"\n }\n }\n },\n {\n \"id\": \"options.allowedExtensions.add\",\n \"intentExamples\": [\n \"allowed extensions\",\n \"extensions\",\n \"file types\"\n ],\n \"patchTemplate\": {\n \"options\": {\n \"allowedExtensions\": [\n \"{{value}}\"\n ]\n }\n }\n }\n ],\n \"fieldResolvers\": {},\n \"hints\": [\n \"limits.maxFileSizeBytes expects bytes (e.g., 10485760 for 10MB).\",\n \"Use options.allowedExtensions for backend validation and ui.accept for input hints.\"\n ]\n }\n}",
1756
+ "sourcePointer": "praxis-ui-angular/projects/praxis-files-upload/src/lib/ai/files-upload-context-pack.ts",
1757
+ "contentHash": "5ffa84516ca618908b0795e584de1b6adc21e3072cd1ad5dafa241ff07b184e5",
1758
+ "sourceKind": "component_definition",
1759
+ "sourceId": "praxis-files-upload",
1760
+ "corpusVersion": "1.0.0"
1761
+ },
1762
+ {
1763
+ "chunkIndex": 4,
1764
+ "chunkKind": "recipe",
1765
+ "content": "{\n \"_comment\": \"Recipe for advanced file upload configuration with Praxis Files Upload.\",\n \"templateMeta\": {\n \"registryKey\": \"praxis-files-upload\",\n \"variantId\": \"base\",\n \"useWhen\": \"Base files upload configuration aligned with the current @praxisui/files-upload contract.\",\n \"examplePrompts\": [\n \"configure file upload limits\",\n \"set allowed file types for upload\",\n \"create an evidence upload flow with metadata and validation\"\n ]\n },\n \"config\": {\n \"strategy\": \"direct\",\n \"ui\": {\n \"showDropzone\": true,\n \"accept\": [\"application/pdf\", \"image/png\", \"image/jpeg\", \".pdf\", \".png\", \".jpg\"],\n \"dense\": false,\n \"showConflictPolicySelector\": true,\n \"showMetadataForm\": true,\n \"showProgress\": true,\n \"manualUpload\": true,\n \"dropzone\": {\n \"expandOnDragProximity\": true,\n \"proximityPx\": 96,\n \"expandMode\": \"inline\",\n \"expandHeight\": 180,\n \"expandDebounceMs\": 120\n },\n \"list\": {\n \"collapseAfter\": 4,\n \"detailsMode\": \"card\",\n \"detailsShowTechnical\": true,\n \"detailsFields\": [\"id\", \"fileName\", \"contentType\", \"fileSize\", \"uploadedAt\", \"scanStatus\"]\n }\n },\n \"limits\": {\n \"maxFileSizeBytes\": 10485760,\n \"maxFilesPerBulk\": 6,\n \"maxBulkSizeBytes\": 52428800\n },\n \"options\": {\n \"defaultConflictPolicy\": \"MAKE_UNIQUE\",\n \"strictValidation\": true,\n \"maxUploadSizeMb\": 10,\n \"allowedExtensions\": [\"pdf\", \"png\", \"jpg\", \"jpeg\"],\n \"acceptMimeTypes\": [\"application/pdf\", \"image/png\", \"image/jpeg\"],\n \"targetDirectory\": \"mission-evidence\",\n \"enableVirusScanning\": true\n },\n \"bulk\": {\n \"failFast\": false,\n \"parallelUploads\": 2,\n \"retryCount\": 2,\n \"retryBackoffMs\": 600\n },\n \"quotas\": {\n \"showQuotaWarnings\": true,\n \"blockOnExceed\": true\n },\n \"rateLimit\": {\n \"autoRetryOn429\": true,\n \"showBannerOn429\": true,\n \"maxAutoRetry\": 2,\n \"baseBackoffMs\": 1000\n },\n \"headers\": {\n \"tenantHeader\": \"X-Tenant-Id\",\n \"userHeader\": \"X-User-Id\"\n },\n \"messages\": {\n \"successSingle\": \"Evidence uploaded and ready for review.\",\n \"successBulk\": \"Evidence batch processed.\",\n \"errors\": {\n \"QUOTA_EXCEEDED\": \"Evidence quota reached.\",\n \"TIPO_ARQUIVO_INVALIDO\": \"Only PDF, PNG and JPEG files are accepted.\",\n \"FILE_TOO_LARGE\": \"File exceeds the configured size limit.\"\n }\n }\n }\n}\n",
1766
+ "sourcePointer": "praxis-ui-angular/examples/ai-recipes/praxis-files-upload.json",
1767
+ "contentHash": "0571f31320873a9c01859005967efcd5e15c08ddb12dfb020e8003a90d52f7c4",
1768
+ "sourceKind": "component_definition",
1769
+ "sourceId": "praxis-files-upload",
1770
+ "corpusVersion": "1.0.0"
1771
+ }
1772
+ ]
1773
+ }
1774
+ },
1775
+ "note": "Package-scoped Praxis component registry for source-free agent discovery. Use the canonical ingestion registry for cross-package aggregate analysis."
1776
+ }