@praxisui/files-upload 8.0.0-beta.0 → 8.0.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/fesm2022/praxisui-files-upload.mjs +327 -11
- package/index.d.ts +7 -3
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -271,6 +271,25 @@ const cfg: FilesUploadConfig = {
|
|
|
271
271
|
- `maxFilesPerBulkValidator`
|
|
272
272
|
- `maxBulkSizeValidator`
|
|
273
273
|
|
|
274
|
+
## Agentic Authoring Contract
|
|
275
|
+
|
|
276
|
+
`@praxisui/files-upload` publishes an executable `ComponentAuthoringManifest` through
|
|
277
|
+
`PRAXIS_FILES_UPLOAD_AUTHORING_MANIFEST`.
|
|
278
|
+
|
|
279
|
+
The contract exposes typed operation families for:
|
|
280
|
+
|
|
281
|
+
- accepted types: `accept.types.set`
|
|
282
|
+
- single-file and batch limits: `limit.fileSize.set`, `limit.fileCount.set`
|
|
283
|
+
- backend upload surfaces: `endpoint.presign.set`, `endpoint.upload.set`
|
|
284
|
+
- upload policy: `security.policy.set`
|
|
285
|
+
- error message overrides: `message.error.set`
|
|
286
|
+
- display mode and UI flags: `display.mode.set`
|
|
287
|
+
|
|
288
|
+
Endpoint authoring intentionally changes only the canonical `baseUrl` runtime input
|
|
289
|
+
and the upload `strategy`. The direct, bulk and presign paths remain fixed as
|
|
290
|
+
`baseUrl/upload`, `baseUrl/bulk` and `baseUrl/upload/presign?filename=...` so hosts
|
|
291
|
+
do not create parallel endpoint semantics outside `FilesApiClient`.
|
|
292
|
+
|
|
274
293
|
## Error handling
|
|
275
294
|
|
|
276
295
|
`ErrorMapperService` translates backend error codes from `errors[0]` into user-facing messages and exposes rate limit information.
|
|
@@ -1063,7 +1063,7 @@ function createPraxisFilesUploadI18nConfig(options = {}) {
|
|
|
1063
1063
|
};
|
|
1064
1064
|
}
|
|
1065
1065
|
return {
|
|
1066
|
-
locale: options.locale,
|
|
1066
|
+
locale: options.locale ?? 'pt-BR',
|
|
1067
1067
|
fallbackLocale: options.fallbackLocale ?? 'pt-BR',
|
|
1068
1068
|
dictionaries,
|
|
1069
1069
|
};
|
|
@@ -3775,7 +3775,7 @@ class PraxisFilesUpload {
|
|
|
3775
3775
|
return this.t('selectFiles', 'Selecionar arquivo(s)');
|
|
3776
3776
|
}
|
|
3777
3777
|
get policySummaryAriaLabel() {
|
|
3778
|
-
return this.t('policySummaryAction', '
|
|
3778
|
+
return this.t('policySummaryAction', 'Informações sobre políticas de upload');
|
|
3779
3779
|
}
|
|
3780
3780
|
pendingFileRemoveAriaLabel(file) {
|
|
3781
3781
|
return `${this.t('removePendingFile', 'Remover arquivo selecionado')}: ${file.name}`;
|
|
@@ -3976,14 +3976,15 @@ class PraxisFilesUpload {
|
|
|
3976
3976
|
}
|
|
3977
3977
|
const optionsJson = this.buildOptionsJson(metadataObj);
|
|
3978
3978
|
const strategy = this.config?.strategy ?? 'direct';
|
|
3979
|
+
const isBulkMode = this.shouldUseBulkMode(files);
|
|
3979
3980
|
this.uploadStart.emit({
|
|
3980
3981
|
files,
|
|
3981
|
-
mode:
|
|
3982
|
+
mode: isBulkMode ? 'bulk' : 'single',
|
|
3982
3983
|
strategy,
|
|
3983
3984
|
filesUploadId: this.filesUploadId || undefined,
|
|
3984
3985
|
baseUrl: this.baseUrl,
|
|
3985
3986
|
});
|
|
3986
|
-
if (
|
|
3987
|
+
if (isBulkMode) {
|
|
3987
3988
|
this.uploadMultipleFiles(files, strategy, metadataObj, optionsJson);
|
|
3988
3989
|
}
|
|
3989
3990
|
else if (strategy === 'presign' || strategy === 'auto') {
|
|
@@ -4060,6 +4061,13 @@ class PraxisFilesUpload {
|
|
|
4060
4061
|
});
|
|
4061
4062
|
}
|
|
4062
4063
|
}
|
|
4064
|
+
shouldUseBulkMode(files) {
|
|
4065
|
+
const maxFilesPerBulk = this.config?.limits?.maxFilesPerBulk;
|
|
4066
|
+
const allowsBulk = maxFilesPerBulk !== undefined
|
|
4067
|
+
? maxFilesPerBulk > 1
|
|
4068
|
+
: this.allowMultiple;
|
|
4069
|
+
return files.length > 1 && allowsBulk;
|
|
4070
|
+
}
|
|
4063
4071
|
directUpload(file, options) {
|
|
4064
4072
|
const api = this.requireApiClient();
|
|
4065
4073
|
const baseUrl = this.requireBaseUrl();
|
|
@@ -5622,8 +5630,8 @@ class PdxFilesUploadFieldComponent extends SimpleBaseInputComponent {
|
|
|
5622
5630
|
this.control().markAsTouched();
|
|
5623
5631
|
this.control().markAsDirty();
|
|
5624
5632
|
}
|
|
5625
|
-
clearUploadState() {
|
|
5626
|
-
this.updateUploadValidationState();
|
|
5633
|
+
clearUploadState(externalErrors) {
|
|
5634
|
+
this.updateUploadValidationState(undefined, externalErrors);
|
|
5627
5635
|
this.uploadError = null;
|
|
5628
5636
|
}
|
|
5629
5637
|
applyUploadErrorState(message, validationKey) {
|
|
@@ -5640,8 +5648,9 @@ class PdxFilesUploadFieldComponent extends SimpleBaseInputComponent {
|
|
|
5640
5648
|
return `${extraFiles} ${this.t('fieldChipAria', 'arquivos adicionais selecionados')}`;
|
|
5641
5649
|
}
|
|
5642
5650
|
onUploadSuccess(file) {
|
|
5651
|
+
const externalErrors = this.getNonUploadErrors();
|
|
5643
5652
|
this.applyResolvedValue(file);
|
|
5644
|
-
this.clearUploadState();
|
|
5653
|
+
this.clearUploadState(externalErrors);
|
|
5645
5654
|
this.batchCount = 1;
|
|
5646
5655
|
this.uploadSuccess.emit(file);
|
|
5647
5656
|
}
|
|
@@ -5784,6 +5793,7 @@ class PdxFilesUploadFieldComponent extends SimpleBaseInputComponent {
|
|
|
5784
5793
|
onOpenInfo() { }
|
|
5785
5794
|
onOpenMenu() { }
|
|
5786
5795
|
onClear() {
|
|
5796
|
+
const externalErrors = this.getNonUploadErrors();
|
|
5787
5797
|
this.lastFileName = null;
|
|
5788
5798
|
this.batchCount = 0;
|
|
5789
5799
|
this.uploadError = null;
|
|
@@ -5794,7 +5804,7 @@ class PdxFilesUploadFieldComponent extends SimpleBaseInputComponent {
|
|
|
5794
5804
|
const c = this.control();
|
|
5795
5805
|
c.markAsPristine();
|
|
5796
5806
|
c.markAsUntouched();
|
|
5797
|
-
this.updateUploadValidationState();
|
|
5807
|
+
this.updateUploadValidationState(undefined, externalErrors);
|
|
5798
5808
|
}
|
|
5799
5809
|
catch { }
|
|
5800
5810
|
}
|
|
@@ -5840,14 +5850,19 @@ class PdxFilesUploadFieldComponent extends SimpleBaseInputComponent {
|
|
|
5840
5850
|
this.pendingPanel?.nativeElement.focus();
|
|
5841
5851
|
});
|
|
5842
5852
|
}
|
|
5843
|
-
|
|
5853
|
+
getNonUploadErrors() {
|
|
5844
5854
|
const currentErrors = { ...(this.control().errors ?? {}) };
|
|
5845
5855
|
delete currentErrors.upload;
|
|
5846
5856
|
delete currentErrors.uploadPartial;
|
|
5857
|
+
return currentErrors;
|
|
5858
|
+
}
|
|
5859
|
+
updateUploadValidationState(validationKey, baseErrors) {
|
|
5860
|
+
const control = this.control();
|
|
5861
|
+
const currentErrors = { ...(baseErrors ?? this.getNonUploadErrors()) };
|
|
5847
5862
|
if (validationKey) {
|
|
5848
5863
|
currentErrors[validationKey] = true;
|
|
5849
5864
|
}
|
|
5850
|
-
|
|
5865
|
+
control.setErrors(Object.keys(currentErrors).length ? currentErrors : null);
|
|
5851
5866
|
}
|
|
5852
5867
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PdxFilesUploadFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
5853
5868
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: PdxFilesUploadFieldComponent, isStandalone: true, selector: "pdx-material-files-upload", inputs: { config: "config", valueMode: "valueMode", baseUrl: "baseUrl" }, outputs: { uploadSuccess: "uploadSuccess", bulkComplete: "bulkComplete", error: "error" }, host: { properties: { "class": "componentCssClasses()", "attr.data-field-type": "\"files-upload\"", "attr.data-field-name": "metadata()?.name", "attr.data-component-id": "componentId()" } }, providers: [providePraxisFilesUploadI18n()], viewQueries: [{ propertyName: "uploader", first: true, predicate: ["uploader"], descendants: true }, { propertyName: "pendingTrigger", first: true, predicate: ["pendingTrigger"], descendants: true }, { propertyName: "pendingPanel", first: true, predicate: ["pendingPanel"], descendants: true }], usesInheritance: true, ngImport: i0, template: `
|
|
@@ -6343,6 +6358,12 @@ const PRAXIS_FILES_UPLOAD_COMPONENT_METADATA = {
|
|
|
6343
6358
|
label: 'Arquivos pendentes',
|
|
6344
6359
|
description: 'Disparado quando o estado de selecao pendente muda.',
|
|
6345
6360
|
},
|
|
6361
|
+
{
|
|
6362
|
+
name: 'readinessChange',
|
|
6363
|
+
type: 'FilesUploadReadinessEvent',
|
|
6364
|
+
label: 'Prontidao',
|
|
6365
|
+
description: 'Disparado quando o componente alterna entre configuracao local, servidor ou fallback.',
|
|
6366
|
+
},
|
|
6346
6367
|
{
|
|
6347
6368
|
name: 'proximityChange',
|
|
6348
6369
|
type: 'boolean',
|
|
@@ -6544,10 +6565,305 @@ const FILES_UPLOAD_AI_CAPABILITIES = {
|
|
|
6544
6565
|
],
|
|
6545
6566
|
};
|
|
6546
6567
|
|
|
6568
|
+
const conflictPolicyEnum = ['ERROR', 'SKIP', 'OVERWRITE', 'MAKE_UNIQUE', 'RENAME'];
|
|
6569
|
+
const displayModeEnum = ['full', 'compact'];
|
|
6570
|
+
const strategyEnum = ['direct', 'presign', 'auto'];
|
|
6571
|
+
const endpointInputSchema = {
|
|
6572
|
+
type: 'object',
|
|
6573
|
+
required: ['baseUrl'],
|
|
6574
|
+
properties: {
|
|
6575
|
+
baseUrl: { type: 'string' },
|
|
6576
|
+
strategy: { enum: strategyEnum },
|
|
6577
|
+
allowCrossOriginPresignedTarget: { type: 'boolean' },
|
|
6578
|
+
},
|
|
6579
|
+
};
|
|
6580
|
+
const PRAXIS_FILES_UPLOAD_AUTHORING_MANIFEST = {
|
|
6581
|
+
schemaVersion: '1.0.0',
|
|
6582
|
+
componentId: 'praxis-files-upload',
|
|
6583
|
+
ownerPackage: '@praxisui/files-upload',
|
|
6584
|
+
configSchemaId: 'FilesUploadConfig',
|
|
6585
|
+
manifestVersion: '1.0.0',
|
|
6586
|
+
runtimeInputs: [
|
|
6587
|
+
{ name: 'config', type: 'FilesUploadConfig', description: 'Upload strategy, UI, limits, backend options, bulk execution, quota/rate feedback, headers and messages.' },
|
|
6588
|
+
{ name: 'filesUploadId', type: 'string', description: 'Stable upload id used for config persistence and telemetry correlation.' },
|
|
6589
|
+
{ name: 'componentInstanceId', type: 'string', description: 'Optional instance discriminator when the same upload id appears more than once.' },
|
|
6590
|
+
{ name: 'baseUrl', type: 'string', description: 'Canonical files API base URL. Direct upload uses baseUrl/upload, bulk uses baseUrl/bulk and presign uses baseUrl/upload/presign.' },
|
|
6591
|
+
{ name: 'displayMode', type: "'full' | 'compact'", allowedValues: displayModeEnum, description: 'Runtime display mode input.' },
|
|
6592
|
+
{ name: 'context', type: 'Record<string, unknown>', description: 'Host context available to metadata and event consumers.' },
|
|
6593
|
+
{ name: 'enableCustomization', type: 'boolean', description: 'Enables the Settings Panel configuration editor.' },
|
|
6594
|
+
],
|
|
6595
|
+
editableTargets: [
|
|
6596
|
+
{ kind: 'acceptedTypes', resolver: 'files-accept-list', description: 'Allowed file extensions and MIME types projected to ui.accept, options.allowedExtensions and options.acceptMimeTypes.' },
|
|
6597
|
+
{ kind: 'sizeLimit', resolver: 'max-file-size-policy', description: 'Maximum single-file size in limits.maxFileSizeBytes and backend-facing options.maxUploadSizeMb.' },
|
|
6598
|
+
{ kind: 'fileCountLimit', resolver: 'max-files-per-bulk-policy', description: 'Maximum number of files accepted in a bulk selection.' },
|
|
6599
|
+
{ kind: 'presignEndpoint', resolver: 'files-api-base-url-presign-contract', description: 'Presign operation endpoint derived from baseUrl + /upload/presign; arbitrary per-operation URLs are not accepted.' },
|
|
6600
|
+
{ kind: 'uploadEndpoint', resolver: 'files-api-base-url-upload-contract', description: 'Direct and bulk upload endpoints derived from baseUrl + /upload and /bulk.' },
|
|
6601
|
+
{ kind: 'securityPolicy', resolver: 'upload-security-policy', description: 'Strict validation, virus scanning, conflict policy, target directory, quotas, rate limit and contextual headers.' },
|
|
6602
|
+
{ kind: 'errorMessages', resolver: 'upload-error-code-message', description: 'Host-provided message overrides under messages.errors keyed by backend error code.' },
|
|
6603
|
+
{ kind: 'display', resolver: 'files-upload-display-mode-and-ui', description: 'Runtime displayMode plus non-backend visual UI flags.' },
|
|
6604
|
+
],
|
|
6605
|
+
operations: [
|
|
6606
|
+
{
|
|
6607
|
+
operationId: 'accept.types.set',
|
|
6608
|
+
title: 'Set accepted file types',
|
|
6609
|
+
scope: 'global',
|
|
6610
|
+
targetKind: 'acceptedTypes',
|
|
6611
|
+
target: { kind: 'acceptedTypes', resolver: 'files-accept-list', ambiguityPolicy: 'fail', required: false },
|
|
6612
|
+
inputSchema: {
|
|
6613
|
+
type: 'object',
|
|
6614
|
+
required: ['accept'],
|
|
6615
|
+
properties: {
|
|
6616
|
+
accept: { type: 'array', items: { type: 'string' } },
|
|
6617
|
+
allowedExtensions: { type: 'array', items: { type: 'string' } },
|
|
6618
|
+
acceptMimeTypes: { type: 'array', items: { type: 'string' } },
|
|
6619
|
+
},
|
|
6620
|
+
},
|
|
6621
|
+
effects: [
|
|
6622
|
+
{ kind: 'set-value', path: 'ui.accept' },
|
|
6623
|
+
{ kind: 'set-value', path: 'options.allowedExtensions' },
|
|
6624
|
+
{ kind: 'set-value', path: 'options.acceptMimeTypes' },
|
|
6625
|
+
],
|
|
6626
|
+
validators: ['file-type-list-explicit', 'file-type-entry-valid', 'backend-accept-options-consistent', 'editor-runtime-round-trip'],
|
|
6627
|
+
affectedPaths: ['ui.accept', 'options.allowedExtensions', 'options.acceptMimeTypes'],
|
|
6628
|
+
submissionImpact: true,
|
|
6629
|
+
preconditions: ['config-initialized'],
|
|
6630
|
+
},
|
|
6631
|
+
{
|
|
6632
|
+
operationId: 'limit.fileSize.set',
|
|
6633
|
+
title: 'Set max file size',
|
|
6634
|
+
scope: 'global',
|
|
6635
|
+
targetKind: 'sizeLimit',
|
|
6636
|
+
target: { kind: 'sizeLimit', resolver: 'max-file-size-policy', ambiguityPolicy: 'fail', required: false },
|
|
6637
|
+
inputSchema: {
|
|
6638
|
+
type: 'object',
|
|
6639
|
+
required: ['maxFileSizeBytes'],
|
|
6640
|
+
properties: {
|
|
6641
|
+
maxFileSizeBytes: { type: 'number' },
|
|
6642
|
+
maxUploadSizeMb: { type: 'number' },
|
|
6643
|
+
},
|
|
6644
|
+
},
|
|
6645
|
+
effects: [
|
|
6646
|
+
{ kind: 'set-value', path: 'limits.maxFileSizeBytes' },
|
|
6647
|
+
{ kind: 'set-value', path: 'options.maxUploadSizeMb' },
|
|
6648
|
+
],
|
|
6649
|
+
validators: ['size-limit-numeric', 'size-limit-within-platform-policy', 'size-limit-client-backend-consistent', 'editor-runtime-round-trip'],
|
|
6650
|
+
affectedPaths: ['limits.maxFileSizeBytes', 'options.maxUploadSizeMb'],
|
|
6651
|
+
submissionImpact: true,
|
|
6652
|
+
preconditions: ['config-initialized'],
|
|
6653
|
+
},
|
|
6654
|
+
{
|
|
6655
|
+
operationId: 'limit.fileCount.set',
|
|
6656
|
+
title: 'Set max file count',
|
|
6657
|
+
scope: 'global',
|
|
6658
|
+
targetKind: 'fileCountLimit',
|
|
6659
|
+
target: { kind: 'fileCountLimit', resolver: 'max-files-per-bulk-policy', ambiguityPolicy: 'fail', required: false },
|
|
6660
|
+
inputSchema: {
|
|
6661
|
+
type: 'object',
|
|
6662
|
+
required: ['maxFilesPerBulk'],
|
|
6663
|
+
properties: {
|
|
6664
|
+
maxFilesPerBulk: { type: 'number' },
|
|
6665
|
+
maxBulkSizeBytes: { type: 'number' },
|
|
6666
|
+
},
|
|
6667
|
+
},
|
|
6668
|
+
effects: [
|
|
6669
|
+
{ kind: 'set-value', path: 'limits.maxFilesPerBulk' },
|
|
6670
|
+
{ kind: 'set-value', path: 'limits.maxBulkSizeBytes' },
|
|
6671
|
+
],
|
|
6672
|
+
validators: ['file-count-limit-numeric', 'bulk-size-limit-numeric', 'bulk-limit-within-platform-policy', 'editor-runtime-round-trip'],
|
|
6673
|
+
affectedPaths: ['limits.maxFilesPerBulk', 'limits.maxBulkSizeBytes'],
|
|
6674
|
+
submissionImpact: true,
|
|
6675
|
+
preconditions: ['config-initialized'],
|
|
6676
|
+
},
|
|
6677
|
+
{
|
|
6678
|
+
operationId: 'endpoint.presign.set',
|
|
6679
|
+
title: 'Set presign endpoint',
|
|
6680
|
+
scope: 'global',
|
|
6681
|
+
targetKind: 'presignEndpoint',
|
|
6682
|
+
target: { kind: 'presignEndpoint', resolver: 'files-api-base-url-presign-contract', ambiguityPolicy: 'fail', required: false },
|
|
6683
|
+
inputSchema: endpointInputSchema,
|
|
6684
|
+
effects: [{
|
|
6685
|
+
kind: 'compile-domain-patch',
|
|
6686
|
+
handler: 'files-upload-presign-base-url',
|
|
6687
|
+
handlerContract: {
|
|
6688
|
+
reads: ['baseUrl', 'strategy', 'config.strategy'],
|
|
6689
|
+
writes: ['baseUrl', 'config.strategy'],
|
|
6690
|
+
identityKeys: ['baseUrl'],
|
|
6691
|
+
inputSchema: endpointInputSchema,
|
|
6692
|
+
failureModes: ['unsafe-url', 'non-praxis-backend-surface', 'presign-path-override', 'cross-origin-presigned-fields-leak'],
|
|
6693
|
+
description: 'Validates the files API base URL and preserves the canonical POST baseUrl/upload/presign?filename=... contract; arbitrary presign URLs are rejected.',
|
|
6694
|
+
},
|
|
6695
|
+
}],
|
|
6696
|
+
destructive: true,
|
|
6697
|
+
requiresConfirmation: true,
|
|
6698
|
+
validators: ['endpoint-url-safe', 'endpoint-uses-praxis-backend-surface', 'presign-endpoint-fixed-contract', 'presign-cross-origin-fields-safe', 'security-change-confirmed'],
|
|
6699
|
+
affectedPaths: ['baseUrl', 'strategy'],
|
|
6700
|
+
submissionImpact: true,
|
|
6701
|
+
preconditions: ['config-initialized', 'confirmation-collected'],
|
|
6702
|
+
},
|
|
6703
|
+
{
|
|
6704
|
+
operationId: 'endpoint.upload.set',
|
|
6705
|
+
title: 'Set upload endpoint',
|
|
6706
|
+
scope: 'global',
|
|
6707
|
+
targetKind: 'uploadEndpoint',
|
|
6708
|
+
target: { kind: 'uploadEndpoint', resolver: 'files-api-base-url-upload-contract', ambiguityPolicy: 'fail', required: false },
|
|
6709
|
+
inputSchema: endpointInputSchema,
|
|
6710
|
+
effects: [{
|
|
6711
|
+
kind: 'compile-domain-patch',
|
|
6712
|
+
handler: 'files-upload-direct-base-url',
|
|
6713
|
+
handlerContract: {
|
|
6714
|
+
reads: ['baseUrl', 'strategy', 'config.strategy'],
|
|
6715
|
+
writes: ['baseUrl', 'config.strategy'],
|
|
6716
|
+
identityKeys: ['baseUrl'],
|
|
6717
|
+
inputSchema: endpointInputSchema,
|
|
6718
|
+
failureModes: ['unsafe-url', 'non-praxis-backend-surface', 'upload-path-override', 'bulk-path-override'],
|
|
6719
|
+
description: 'Validates the files API base URL and preserves the canonical POST baseUrl/upload and POST baseUrl/bulk contracts.',
|
|
6720
|
+
},
|
|
6721
|
+
}],
|
|
6722
|
+
destructive: true,
|
|
6723
|
+
requiresConfirmation: true,
|
|
6724
|
+
validators: ['endpoint-url-safe', 'endpoint-uses-praxis-backend-surface', 'upload-endpoint-fixed-contract', 'bulk-endpoint-fixed-contract', 'security-change-confirmed'],
|
|
6725
|
+
affectedPaths: ['baseUrl', 'strategy'],
|
|
6726
|
+
submissionImpact: true,
|
|
6727
|
+
preconditions: ['config-initialized', 'confirmation-collected'],
|
|
6728
|
+
},
|
|
6729
|
+
{
|
|
6730
|
+
operationId: 'security.policy.set',
|
|
6731
|
+
title: 'Set upload security policy',
|
|
6732
|
+
scope: 'global',
|
|
6733
|
+
targetKind: 'securityPolicy',
|
|
6734
|
+
target: { kind: 'securityPolicy', resolver: 'upload-security-policy', ambiguityPolicy: 'fail', required: false },
|
|
6735
|
+
inputSchema: {
|
|
6736
|
+
type: 'object',
|
|
6737
|
+
properties: {
|
|
6738
|
+
strictValidation: { type: 'boolean' },
|
|
6739
|
+
enableVirusScanning: { type: 'boolean' },
|
|
6740
|
+
defaultConflictPolicy: { enum: conflictPolicyEnum },
|
|
6741
|
+
targetDirectory: { type: 'string' },
|
|
6742
|
+
showQuotaWarnings: { type: 'boolean' },
|
|
6743
|
+
blockOnExceed: { type: 'boolean' },
|
|
6744
|
+
autoRetryOn429: { type: 'boolean' },
|
|
6745
|
+
showBannerOn429: { type: 'boolean' },
|
|
6746
|
+
maxAutoRetry: { type: 'number' },
|
|
6747
|
+
baseBackoffMs: { type: 'number' },
|
|
6748
|
+
tenantHeader: { type: 'string' },
|
|
6749
|
+
userHeader: { type: 'string' },
|
|
6750
|
+
},
|
|
6751
|
+
},
|
|
6752
|
+
effects: [
|
|
6753
|
+
{ kind: 'merge-object', path: 'options' },
|
|
6754
|
+
{ kind: 'merge-object', path: 'quotas' },
|
|
6755
|
+
{ kind: 'merge-object', path: 'rateLimit' },
|
|
6756
|
+
{ kind: 'merge-object', path: 'headers' },
|
|
6757
|
+
],
|
|
6758
|
+
destructive: true,
|
|
6759
|
+
requiresConfirmation: true,
|
|
6760
|
+
validators: ['security-change-confirmed', 'security-policy-compatible', 'target-directory-safe', 'conflict-policy-valid', 'quota-rate-policy-valid', 'header-names-safe', 'editor-runtime-round-trip'],
|
|
6761
|
+
affectedPaths: ['options.strictValidation', 'options.enableVirusScanning', 'options.defaultConflictPolicy', 'options.targetDirectory', 'quotas', 'rateLimit', 'headers'],
|
|
6762
|
+
submissionImpact: true,
|
|
6763
|
+
preconditions: ['config-initialized', 'confirmation-collected'],
|
|
6764
|
+
},
|
|
6765
|
+
{
|
|
6766
|
+
operationId: 'message.error.set',
|
|
6767
|
+
title: 'Set error message override',
|
|
6768
|
+
scope: 'global',
|
|
6769
|
+
targetKind: 'errorMessages',
|
|
6770
|
+
target: { kind: 'errorMessages', resolver: 'upload-error-code-message', ambiguityPolicy: 'fail', required: false },
|
|
6771
|
+
inputSchema: {
|
|
6772
|
+
type: 'object',
|
|
6773
|
+
required: ['code', 'message'],
|
|
6774
|
+
properties: {
|
|
6775
|
+
code: { type: 'string' },
|
|
6776
|
+
message: { type: 'string' },
|
|
6777
|
+
},
|
|
6778
|
+
},
|
|
6779
|
+
effects: [{ kind: 'merge-object', path: 'messages.errors' }],
|
|
6780
|
+
validators: ['error-code-known', 'error-message-i18n-compatible', 'message-not-empty', 'editor-runtime-round-trip'],
|
|
6781
|
+
affectedPaths: ['messages.errors'],
|
|
6782
|
+
submissionImpact: false,
|
|
6783
|
+
preconditions: ['config-initialized'],
|
|
6784
|
+
},
|
|
6785
|
+
{
|
|
6786
|
+
operationId: 'display.mode.set',
|
|
6787
|
+
title: 'Set display mode',
|
|
6788
|
+
scope: 'global',
|
|
6789
|
+
targetKind: 'display',
|
|
6790
|
+
target: { kind: 'display', resolver: 'files-upload-display-mode-and-ui', ambiguityPolicy: 'fail', required: false },
|
|
6791
|
+
inputSchema: {
|
|
6792
|
+
type: 'object',
|
|
6793
|
+
properties: {
|
|
6794
|
+
displayMode: { enum: displayModeEnum },
|
|
6795
|
+
dense: { type: 'boolean' },
|
|
6796
|
+
showDropzone: { type: 'boolean' },
|
|
6797
|
+
showProgress: { type: 'boolean' },
|
|
6798
|
+
manualUpload: { type: 'boolean' },
|
|
6799
|
+
showMetadataForm: { type: 'boolean' },
|
|
6800
|
+
showConflictPolicySelector: { type: 'boolean' },
|
|
6801
|
+
},
|
|
6802
|
+
},
|
|
6803
|
+
effects: [
|
|
6804
|
+
{ kind: 'set-value', path: 'displayMode' },
|
|
6805
|
+
{ kind: 'merge-object', path: 'ui' },
|
|
6806
|
+
],
|
|
6807
|
+
validators: ['display-mode-valid', 'display-ui-compatible', 'editor-runtime-round-trip'],
|
|
6808
|
+
affectedPaths: ['displayMode', 'ui.dense', 'ui.showDropzone', 'ui.showProgress', 'ui.manualUpload', 'ui.showMetadataForm', 'ui.showConflictPolicySelector'],
|
|
6809
|
+
submissionImpact: false,
|
|
6810
|
+
preconditions: ['config-initialized'],
|
|
6811
|
+
},
|
|
6812
|
+
],
|
|
6813
|
+
validators: [
|
|
6814
|
+
{ validatorId: 'file-type-list-explicit', level: 'error', code: 'PFU001', description: 'Accepted type edits must provide a non-empty explicit list and may not rely on wildcard-only policy.' },
|
|
6815
|
+
{ validatorId: 'file-type-entry-valid', level: 'error', code: 'PFU002', description: 'Each accepted type must be a valid extension, exact MIME type or controlled subtype wildcard.' },
|
|
6816
|
+
{ validatorId: 'backend-accept-options-consistent', level: 'error', code: 'PFU003', description: 'ui.accept hints must remain consistent with options.allowedExtensions and options.acceptMimeTypes when backend validation is configured.' },
|
|
6817
|
+
{ validatorId: 'size-limit-numeric', level: 'error', code: 'PFU004', description: 'Single file size limits must be positive numeric byte and MB values.' },
|
|
6818
|
+
{ validatorId: 'size-limit-within-platform-policy', level: 'error', code: 'PFU005', description: 'Single file size limits must not exceed the platform upload policy for the selected backend surface.' },
|
|
6819
|
+
{ validatorId: 'size-limit-client-backend-consistent', level: 'error', code: 'PFU006', description: 'limits.maxFileSizeBytes and options.maxUploadSizeMb must describe the same effective maximum when both are present.' },
|
|
6820
|
+
{ validatorId: 'file-count-limit-numeric', level: 'error', code: 'PFU007', description: 'Bulk file count limits must be positive integers.' },
|
|
6821
|
+
{ validatorId: 'bulk-size-limit-numeric', level: 'error', code: 'PFU008', description: 'Bulk size limits must be positive numeric byte values when provided.' },
|
|
6822
|
+
{ validatorId: 'bulk-limit-within-platform-policy', level: 'error', code: 'PFU009', description: 'Bulk count and aggregate size limits must not exceed backend batch policy.' },
|
|
6823
|
+
{ validatorId: 'endpoint-url-safe', level: 'error', code: 'PFU010', description: 'Endpoint edits must use a safe absolute or approved relative baseUrl and reject javascript:, data:, credentials-in-URL and path traversal.' },
|
|
6824
|
+
{ validatorId: 'endpoint-uses-praxis-backend-surface', level: 'error', code: 'PFU011', description: 'Endpoint edits must resolve to the approved Praxis files backend surface for the host environment.' },
|
|
6825
|
+
{ validatorId: 'presign-endpoint-fixed-contract', level: 'error', code: 'PFU012', description: 'Presign authoring may change baseUrl but must preserve POST baseUrl/upload/presign?filename=... as the runtime contract.' },
|
|
6826
|
+
{ validatorId: 'upload-endpoint-fixed-contract', level: 'error', code: 'PFU013', description: 'Direct upload authoring may change baseUrl but must preserve POST baseUrl/upload as the runtime contract.' },
|
|
6827
|
+
{ validatorId: 'bulk-endpoint-fixed-contract', level: 'error', code: 'PFU014', description: 'Bulk upload authoring may change baseUrl but must preserve POST baseUrl/bulk as the runtime contract.' },
|
|
6828
|
+
{ validatorId: 'presign-cross-origin-fields-safe', level: 'error', code: 'PFU015', description: 'Cross-origin presigned upload targets must not receive Praxis metadata/options fields unless explicitly approved by the presign response contract.' },
|
|
6829
|
+
{ validatorId: 'security-change-confirmed', level: 'error', code: 'PFU016', description: 'Endpoint and security policy edits require explicit confirmation before patch compilation.' },
|
|
6830
|
+
{ validatorId: 'security-policy-compatible', level: 'error', code: 'PFU017', description: 'Strict validation, virus scanning, conflict policy, target directory, quota and rate-limit settings must be compatible with backend effective config.' },
|
|
6831
|
+
{ validatorId: 'target-directory-safe', level: 'error', code: 'PFU018', description: 'Target directory values must be normalized backend paths and must reject traversal or absolute filesystem paths.' },
|
|
6832
|
+
{ validatorId: 'conflict-policy-valid', level: 'error', code: 'PFU019', description: 'Default conflict policy must be one of ERROR, SKIP, OVERWRITE, MAKE_UNIQUE or RENAME.' },
|
|
6833
|
+
{ validatorId: 'quota-rate-policy-valid', level: 'error', code: 'PFU020', description: 'Quota and rate-limit UX settings must use non-negative retry counts/backoffs and cannot silently bypass backend enforcement.' },
|
|
6834
|
+
{ validatorId: 'header-names-safe', level: 'warning', code: 'PFU021', description: 'Contextual header names must be explicit HTTP token names and must not override authorization, cookie or content-type headers.' },
|
|
6835
|
+
{ validatorId: 'error-code-known', level: 'warning', code: 'PFU022', description: 'Error message overrides should target known backend error catalog codes or documented host-specific extensions.' },
|
|
6836
|
+
{ validatorId: 'error-message-i18n-compatible', level: 'warning', code: 'PFU023', description: 'User-facing error messages must remain compatible with the host i18n/editor flow and not expose raw technical exception text.' },
|
|
6837
|
+
{ validatorId: 'message-not-empty', level: 'error', code: 'PFU024', description: 'Error message overrides must be non-empty user-facing text.' },
|
|
6838
|
+
{ validatorId: 'display-mode-valid', level: 'error', code: 'PFU025', description: 'Display mode must be full or compact.' },
|
|
6839
|
+
{ validatorId: 'display-ui-compatible', level: 'warning', code: 'PFU026', description: 'Display changes must keep progress, manual upload and metadata form affordances reachable for the selected mode.' },
|
|
6840
|
+
{ validatorId: 'editor-runtime-round-trip', level: 'error', code: 'PFU027', description: 'Settings Panel editor, AI adapter snapshot and runtime inputs must round-trip config, baseUrl and displayMode without changing upload behavior.' },
|
|
6841
|
+
],
|
|
6842
|
+
roundTripRequirements: [
|
|
6843
|
+
'Accepted type authoring must keep UI hints and backend-facing validation options aligned; ui.accept alone is not the canonical server policy.',
|
|
6844
|
+
'Endpoint authoring changes only the canonical files API baseUrl and strategy; direct, bulk and presign paths remain fixed by FilesApiClient.',
|
|
6845
|
+
'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.',
|
|
6846
|
+
'Error message overrides remain keyed by backend error catalog code and must stay user-facing/i18n-compatible.',
|
|
6847
|
+
'Display authoring may change displayMode and UI flags, but must not mutate backend options or upload submission payload.',
|
|
6848
|
+
],
|
|
6849
|
+
examples: [
|
|
6850
|
+
{ id: 'accept-pdf-images', request: 'Accept only PDF and image uploads.', operationId: 'accept.types.set', params: { accept: ['application/pdf', 'image/*'], allowedExtensions: ['pdf', 'png', 'jpg', 'jpeg'], acceptMimeTypes: ['application/pdf', 'image/png', 'image/jpeg'] }, isPositive: true },
|
|
6851
|
+
{ id: 'max-five-mb', request: 'Limit each file to 5 MB.', operationId: 'limit.fileSize.set', params: { maxFileSizeBytes: 5242880, maxUploadSizeMb: 5 }, isPositive: true },
|
|
6852
|
+
{ id: 'max-three-files', request: 'Allow at most three files per upload batch.', operationId: 'limit.fileCount.set', params: { maxFilesPerBulk: 3 }, isPositive: true },
|
|
6853
|
+
{ id: 'set-presign-base-url', request: 'Use the official files API for presigned uploads.', operationId: 'endpoint.presign.set', params: { baseUrl: 'https://api.praxis.example/files', strategy: 'presign' }, isPositive: true },
|
|
6854
|
+
{ id: 'set-direct-base-url', request: 'Use the official files API for direct uploads.', operationId: 'endpoint.upload.set', params: { baseUrl: 'https://api.praxis.example/files', strategy: 'direct' }, isPositive: true },
|
|
6855
|
+
{ id: 'reject-unsafe-endpoint', request: 'Set upload endpoint to javascript:alert(1).', operationId: 'endpoint.upload.set', params: { baseUrl: 'javascript:alert(1)', strategy: 'direct' }, isPositive: false },
|
|
6856
|
+
{ id: 'tighten-security-policy', request: 'Enable strict validation and virus scanning for uploads.', operationId: 'security.policy.set', params: { strictValidation: true, enableVirusScanning: true, defaultConflictPolicy: 'ERROR' }, isPositive: true },
|
|
6857
|
+
{ id: 'reject-unconfirmed-security-policy', request: 'Disable strict validation without confirmation.', operationId: 'security.policy.set', params: { strictValidation: false, enableVirusScanning: false }, isPositive: false },
|
|
6858
|
+
{ id: 'quota-message', request: 'Show a friendly message when quota is exceeded.', operationId: 'message.error.set', params: { code: 'QUOTA_EXCEEDED', message: 'Upload quota reached for this period.' }, isPositive: true },
|
|
6859
|
+
{ id: 'compact-display', request: 'Use compact upload display and keep progress visible.', operationId: 'display.mode.set', params: { displayMode: 'compact', dense: true, showProgress: true }, isPositive: true },
|
|
6860
|
+
],
|
|
6861
|
+
};
|
|
6862
|
+
|
|
6547
6863
|
// Export all public API from subdirectories
|
|
6548
6864
|
|
|
6549
6865
|
/**
|
|
6550
6866
|
* Generated bundle index. Do not edit.
|
|
6551
6867
|
*/
|
|
6552
6868
|
|
|
6553
|
-
export { BulkUploadResultStatus, ErrorCode, ErrorMapperService, FILES_UPLOAD_AI_CAPABILITIES, FILES_UPLOAD_EN_US, FILES_UPLOAD_ERROR_MESSAGES, FILES_UPLOAD_PT_BR, FILES_UPLOAD_TEXTS, FilesApiClient, PRAXIS_FILES_UPLOAD_COMPONENT_METADATA, PdxFilesUploadFieldComponent, PraxisFilesUpload, PraxisFilesUploadConfigEditor, PresignedUploaderService, ScanStatus, TRANSLATE_LIKE, acceptValidator, createPraxisFilesUploadI18nConfig, getPrimaryErrorItem, isErrorEnvelope, maxBulkSizeValidator, maxFileSizeValidator, maxFilesPerBulkValidator, providePraxisFilesUploadI18n, providePraxisFilesUploadMetadata, resolvePraxisFilesUploadText };
|
|
6869
|
+
export { BulkUploadResultStatus, ErrorCode, ErrorMapperService, FILES_UPLOAD_AI_CAPABILITIES, FILES_UPLOAD_EN_US, FILES_UPLOAD_ERROR_MESSAGES, FILES_UPLOAD_PT_BR, FILES_UPLOAD_TEXTS, FilesApiClient, PRAXIS_FILES_UPLOAD_AUTHORING_MANIFEST, PRAXIS_FILES_UPLOAD_COMPONENT_METADATA, PdxFilesUploadFieldComponent, PraxisFilesUpload, PraxisFilesUploadConfigEditor, PresignedUploaderService, ScanStatus, TRANSLATE_LIKE, acceptValidator, createPraxisFilesUploadI18nConfig, getPrimaryErrorItem, isErrorEnvelope, maxBulkSizeValidator, maxFileSizeValidator, maxFilesPerBulkValidator, providePraxisFilesUploadI18n, providePraxisFilesUploadMetadata, resolvePraxisFilesUploadText };
|
package/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { InjectionToken, OnDestroy, NgZone, OnInit, OnChanges, AfterViewInit, EventEmitter, ViewContainerRef, ChangeDetectorRef, DestroyRef, Provider } from '@angular/core';
|
|
3
3
|
import { FormControl, ValidatorFn, FormGroup, FormBuilder } from '@angular/forms';
|
|
4
|
-
import { PraxisI18nDictionary, PraxisI18nConfig, PraxisI18nService, AsyncConfigStorage, ComponentDocMeta, AiCapabilityCategory, AiValueKind, AiCapability, AiCapabilityCatalog } from '@praxisui/core';
|
|
4
|
+
import { PraxisI18nDictionary, PraxisI18nConfig, PraxisI18nService, AsyncConfigStorage, ComponentDocMeta, AiCapabilityCategory, AiValueKind, AiCapability, AiCapabilityCatalog, ComponentAuthoringManifest } from '@praxisui/core';
|
|
5
5
|
import { SettingsPanelService, SettingsValueProvider } from '@praxisui/settings-panel';
|
|
6
6
|
import { HttpClient, HttpEvent, HttpHeaders } from '@angular/common/http';
|
|
7
7
|
import { Observable, BehaviorSubject } from 'rxjs';
|
|
@@ -384,7 +384,7 @@ declare const FILES_UPLOAD_TEXTS: InjectionToken<FilesUploadTexts>;
|
|
|
384
384
|
/** @deprecated Transitional compatibility token. Prefer PraxisI18nService. */
|
|
385
385
|
declare const TRANSLATE_LIKE: InjectionToken<TranslateLike>;
|
|
386
386
|
declare function createPraxisFilesUploadI18nConfig(options?: PraxisFilesUploadI18nOptions): Partial<PraxisI18nConfig>;
|
|
387
|
-
declare function providePraxisFilesUploadI18n(options?: PraxisFilesUploadI18nOptions): i0.Provider;
|
|
387
|
+
declare function providePraxisFilesUploadI18n(options?: PraxisFilesUploadI18nOptions): i0.Provider[];
|
|
388
388
|
declare function resolvePraxisFilesUploadText(i18n: PraxisI18nService, key: string, fallback: string, legacyTexts?: FilesUploadTexts, legacyTranslate?: TranslateLike): string;
|
|
389
389
|
|
|
390
390
|
interface RateLimitInfo {
|
|
@@ -631,6 +631,7 @@ declare class PraxisFilesUpload implements OnInit, OnChanges, AfterViewInit, OnD
|
|
|
631
631
|
removePendingFile(file: File): void;
|
|
632
632
|
private emitPendingState;
|
|
633
633
|
private startUpload;
|
|
634
|
+
private shouldUseBulkMode;
|
|
634
635
|
private directUpload;
|
|
635
636
|
private uploadMultipleFiles;
|
|
636
637
|
private uploadMultipleFilesDirect;
|
|
@@ -732,6 +733,7 @@ declare class PdxFilesUploadFieldComponent extends SimpleBaseInputComponent {
|
|
|
732
733
|
pendingFileSummary(file: File): string;
|
|
733
734
|
formatBytes(bytes: number): string;
|
|
734
735
|
private focusPendingPanelSoon;
|
|
736
|
+
private getNonUploadErrors;
|
|
735
737
|
private updateUploadValidationState;
|
|
736
738
|
static ɵfac: i0.ɵɵFactoryDeclaration<PdxFilesUploadFieldComponent, never>;
|
|
737
739
|
static ɵcmp: i0.ɵɵComponentDeclaration<PdxFilesUploadFieldComponent, "pdx-material-files-upload", never, { "config": { "alias": "config"; "required": false; }; "valueMode": { "alias": "valueMode"; "required": false; }; "baseUrl": { "alias": "baseUrl"; "required": false; }; }, { "uploadSuccess": "uploadSuccess"; "bulkComplete": "bulkComplete"; "error": "error"; }, never, never, true, never>;
|
|
@@ -1463,5 +1465,7 @@ interface CapabilityCatalog extends AiCapabilityCatalog {
|
|
|
1463
1465
|
}
|
|
1464
1466
|
declare const FILES_UPLOAD_AI_CAPABILITIES: CapabilityCatalog;
|
|
1465
1467
|
|
|
1466
|
-
|
|
1468
|
+
declare const PRAXIS_FILES_UPLOAD_AUTHORING_MANIFEST: ComponentAuthoringManifest;
|
|
1469
|
+
|
|
1470
|
+
export { BulkUploadResultStatus, ErrorCode, ErrorMapperService, FILES_UPLOAD_AI_CAPABILITIES, FILES_UPLOAD_EN_US, FILES_UPLOAD_ERROR_MESSAGES, FILES_UPLOAD_PT_BR, FILES_UPLOAD_TEXTS, FilesApiClient, PRAXIS_FILES_UPLOAD_AUTHORING_MANIFEST, PRAXIS_FILES_UPLOAD_COMPONENT_METADATA, PdxFilesUploadFieldComponent, PraxisFilesUpload, PraxisFilesUploadConfigEditor, PresignedUploaderService, ScanStatus, TRANSLATE_LIKE, acceptValidator, createPraxisFilesUploadI18nConfig, getPrimaryErrorItem, isErrorEnvelope, maxBulkSizeValidator, maxFileSizeValidator, maxFilesPerBulkValidator, providePraxisFilesUploadI18n, providePraxisFilesUploadMetadata, resolvePraxisFilesUploadText };
|
|
1467
1471
|
export type { ApiErrorEnvelope, ApiErrorItem, ApiResponseStatus, ApiSuccessEnvelope, BulkConfig, BulkUploadFile, BulkUploadFileResult, BulkUploadOptions, BulkUploadResponse, BulkUploadResponseData, Capability, CapabilityCatalog, CapabilityCategory, EffectiveUploadConfig, ErrorLike, ErrorResponse, FileMetadata, FileUploadOptions, FilesUploadBackendOptionsConfig, FilesUploadConfig, FilesUploadExecutionConfig, FilesUploadHeadersConfig, FilesUploadMessagesConfig, FilesUploadQuotaFeedbackConfig, FilesUploadRateLimitFeedbackConfig, FilesUploadReadinessEvent, FilesUploadReadySource, FilesUploadReadyState, FilesUploadStrategy, FilesUploadTexts, FilesUploadValidationConfig, FilesUploadVisualConfig, MappedError, Metadata, PendingFilesState, PraxisFilesUploadI18nOptions, PresignResponse, QuotasConfig, RateLimitConfig, RateLimitInfo, ServerMessages, TranslateLike, UploadOptions, UploadProgressEvent, UploadResponse, UploadResponseData, UploadStartEvent, ValueKind };
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@praxisui/files-upload",
|
|
3
|
-
"version": "8.0.0-beta.
|
|
3
|
+
"version": "8.0.0-beta.11",
|
|
4
4
|
"description": "File upload components and services for Praxis UI with presigned and direct strategies, quotas and rate-limit handling.",
|
|
5
5
|
"peerDependencies": {
|
|
6
6
|
"@angular/common": "^20.0.0",
|
|
7
7
|
"@angular/cdk": "^20.0.0",
|
|
8
8
|
"@angular/core": "^20.0.0",
|
|
9
9
|
"@angular/material": "^20.0.0",
|
|
10
|
-
"@praxisui/core": "^8.0.0-beta.
|
|
11
|
-
"@praxisui/dynamic-fields": "^8.0.0-beta.
|
|
12
|
-
"@praxisui/settings-panel": "^8.0.0-beta.
|
|
10
|
+
"@praxisui/core": "^8.0.0-beta.11",
|
|
11
|
+
"@praxisui/dynamic-fields": "^8.0.0-beta.11",
|
|
12
|
+
"@praxisui/settings-panel": "^8.0.0-beta.11"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"tslib": "^2.3.0"
|