@antelopejs/dms 0.5.2 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/dist/attachments/access.d.ts +1 -0
- package/dist/attachments/access.js +7 -3
- package/dist/attachments/access.js.map +1 -1
- package/dist/attachments/constraints.d.ts +4 -0
- package/dist/attachments/constraints.js +28 -0
- package/dist/attachments/constraints.js.map +1 -0
- package/dist/attachments/save.js +23 -12
- package/dist/attachments/save.js.map +1 -1
- package/dist/attachments/uploads.js +2 -0
- package/dist/attachments/uploads.js.map +1 -1
- package/dist/implementations/dms-base/search-route.js +3 -4
- package/dist/implementations/dms-base/search-route.js.map +1 -1
- package/dist/test/attachment-host/native.d.ts +25 -0
- package/dist/test/attachment-host/native.js +54 -1
- package/dist/test/attachment-host/native.js.map +1 -1
- package/dist/test/helpers/attachments.d.ts +1 -1
- package/dist/test/helpers/attachments.js +2 -2
- package/dist/test/helpers/attachments.js.map +1 -1
- package/dist/test/integration/files/field-constraints.test.d.ts +1 -0
- package/dist/test/integration/files/field-constraints.test.js +100 -0
- package/dist/test/integration/files/field-constraints.test.js.map +1 -0
- package/dist/test/integration/files/page-mode-form-files.test.d.ts +1 -0
- package/dist/test/integration/files/page-mode-form-files.test.js +114 -0
- package/dist/test/integration/files/page-mode-form-files.test.js.map +1 -0
- package/dist/test/integration/files/resource-form-files.test.d.ts +1 -0
- package/dist/test/integration/files/resource-form-files.test.js +121 -0
- package/dist/test/integration/files/resource-form-files.test.js.map +1 -0
- package/dist/test/integration/files/shared-controller-files.test.d.ts +1 -0
- package/dist/test/integration/files/shared-controller-files.test.js +136 -0
- package/dist/test/integration/files/shared-controller-files.test.js.map +1 -0
- package/dist/test/unit/implementations/dms-base/table-view-shared-controller.test.d.ts +1 -0
- package/dist/test/unit/implementations/dms-base/table-view-shared-controller.test.js +113 -0
- package/dist/test/unit/implementations/dms-base/table-view-shared-controller.test.js.map +1 -0
- package/dist/test/unit/interfaces/dms-base/resource-form.test.js +19 -0
- package/dist/test/unit/interfaces/dms-base/resource-form.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms-base/table-view-tenant-gate.test.js +2 -2
- package/dist/test/unit/interfaces/dms-base/table-view-tenant-gate.test.js.map +1 -1
- package/frontend-vue/layers/dms-ui/app/components/form/components/File.vue +50 -21
- package/frontend-vue/layers/dms-ui/app/components/form/components/Image.vue +54 -21
- package/frontend-vue/layers/dms-ui/app/components/form/components/Relation.vue +4 -3
- package/frontend-vue/layers/dms-ui/app/composables/form/useUploadWithProgress.ts +44 -3
- package/frontend-vue/layers/dms-ui/app/utils/metadataRetry.ts +47 -0
- package/frontend-vue/layers/dms-ui/i18n/locales/ui-en-GB.json +3 -1
- package/frontend-vue/layers/dms-ui/i18n/locales/ui-fr-FR.json +3 -1
- package/frontend-vue/tests/file-unavailable.test.ts +107 -0
- package/frontend-vue/tests/image-hydration-ids.test.ts +87 -0
- package/frontend-vue/tests/image-reference-preservation.test.ts +12 -2
- package/frontend-vue/tests/metadata-retry.test.ts +187 -0
- package/frontend-vue/tests/upload-forbidden-headers.test.ts +52 -0
- package/package.json +2 -2
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import {
|
|
3
|
+
computed,
|
|
4
|
+
createSSRApp,
|
|
5
|
+
defineComponent,
|
|
6
|
+
h,
|
|
7
|
+
inject,
|
|
8
|
+
onBeforeUnmount,
|
|
9
|
+
ref,
|
|
10
|
+
useId,
|
|
11
|
+
watch,
|
|
12
|
+
type App,
|
|
13
|
+
} from "vue";
|
|
14
|
+
import { renderToString } from "vue/server-renderer";
|
|
15
|
+
import { afterEach, beforeEach, expect, it, vi } from "vitest";
|
|
16
|
+
import Image from "../layers/dms-ui/app/components/form/components/Image.vue";
|
|
17
|
+
|
|
18
|
+
const STORED_IMAGE = { key: "files/profile/cover.png", alt: "Cover" };
|
|
19
|
+
|
|
20
|
+
const passthrough = defineComponent({
|
|
21
|
+
inheritAttrs: false,
|
|
22
|
+
setup:
|
|
23
|
+
(_, { slots }) =>
|
|
24
|
+
() =>
|
|
25
|
+
slots.default?.(),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
function createImageApp(): App {
|
|
29
|
+
const app = createSSRApp({
|
|
30
|
+
render: () => h(Image, { modelValue: STORED_IMAGE }),
|
|
31
|
+
});
|
|
32
|
+
app.component("UButton", defineComponent({ setup: () => () => h("button") }));
|
|
33
|
+
app.component("UIcon", defineComponent({ setup: () => () => h("span") }));
|
|
34
|
+
app.component("UInput", defineComponent({ setup: () => () => h("input") }));
|
|
35
|
+
app.component("UTooltip", passthrough);
|
|
36
|
+
app.component("UModal", defineComponent({ setup: () => () => null }));
|
|
37
|
+
return app;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
vi.stubGlobal("ref", ref);
|
|
42
|
+
vi.stubGlobal("computed", computed);
|
|
43
|
+
vi.stubGlobal("watch", watch);
|
|
44
|
+
vi.stubGlobal("inject", inject);
|
|
45
|
+
vi.stubGlobal("useId", useId);
|
|
46
|
+
vi.stubGlobal("onBeforeUnmount", onBeforeUnmount);
|
|
47
|
+
vi.stubGlobal("FORM_FIELD_LOADING_KEY", Symbol());
|
|
48
|
+
vi.stubGlobal("FORM_CONTENT_LANGUAGE_KEY", Symbol());
|
|
49
|
+
vi.stubGlobal("CONTENT_LANGUAGE_HEADER", "x-content-language");
|
|
50
|
+
vi.stubGlobal("useAuthFetch", () => ({
|
|
51
|
+
$authFetch: () => new Promise(() => undefined),
|
|
52
|
+
}));
|
|
53
|
+
vi.stubGlobal("useUploadWithProgress", () => ({
|
|
54
|
+
uploadWithProgress: vi.fn(),
|
|
55
|
+
}));
|
|
56
|
+
vi.stubGlobal("useFormField", () => ({ emitFormChange: vi.fn() }));
|
|
57
|
+
vi.stubGlobal("useI18n", () => ({ t: (key: string) => key }));
|
|
58
|
+
vi.stubGlobal("useToast", () => ({ add: vi.fn() }));
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
afterEach(() => {
|
|
62
|
+
vi.unstubAllGlobals();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("hydrates a stored single image without an attribute mismatch", async () => {
|
|
66
|
+
const html = await renderToString(createImageApp());
|
|
67
|
+
const container = document.createElement("div");
|
|
68
|
+
container.innerHTML = html;
|
|
69
|
+
const warnings: string[] = [];
|
|
70
|
+
const app = createImageApp();
|
|
71
|
+
app.config.warnHandler = (message) => warnings.push(message);
|
|
72
|
+
const consoleError = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
73
|
+
|
|
74
|
+
app.mount(container);
|
|
75
|
+
|
|
76
|
+
expect(warnings.filter((message) => message.includes("Hydration"))).toEqual(
|
|
77
|
+
[],
|
|
78
|
+
);
|
|
79
|
+
expect(consoleError).not.toHaveBeenCalledWith(
|
|
80
|
+
expect.stringContaining("Hydration"),
|
|
81
|
+
);
|
|
82
|
+
const label = container.querySelector("label")!;
|
|
83
|
+
expect(label.htmlFor).not.toBe("");
|
|
84
|
+
expect(container.querySelector("input:not([type])")!.id).toBe(label.htmlFor);
|
|
85
|
+
app.unmount();
|
|
86
|
+
consoleError.mockRestore();
|
|
87
|
+
});
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
createSSRApp,
|
|
6
6
|
defineComponent,
|
|
7
7
|
effectScope,
|
|
8
|
+
getCurrentInstance,
|
|
8
9
|
h,
|
|
9
10
|
nextTick,
|
|
10
11
|
onScopeDispose,
|
|
@@ -12,12 +13,17 @@ import {
|
|
|
12
13
|
reactive,
|
|
13
14
|
ref,
|
|
14
15
|
watch,
|
|
16
|
+
useId,
|
|
15
17
|
type EffectScope,
|
|
16
18
|
type Ref,
|
|
17
19
|
} from "vue";
|
|
18
20
|
import { renderToString } from "vue/server-renderer";
|
|
19
21
|
import { afterEach, beforeEach, expect, it, vi } from "vitest";
|
|
20
22
|
import Image from "../layers/dms-ui/app/components/form/components/Image.vue";
|
|
23
|
+
import {
|
|
24
|
+
isDefinitiveMetadataFailure,
|
|
25
|
+
resolveMetadataRetryDelay,
|
|
26
|
+
} from "../layers/dms-ui/app/utils/metadataRetry";
|
|
21
27
|
|
|
22
28
|
interface ImageValue {
|
|
23
29
|
key: string;
|
|
@@ -90,11 +96,14 @@ beforeEach(() => {
|
|
|
90
96
|
}),
|
|
91
97
|
);
|
|
92
98
|
vi.stubGlobal("defineProps", () => props);
|
|
99
|
+
vi.stubGlobal("isDefinitiveMetadataFailure", isDefinitiveMetadataFailure);
|
|
100
|
+
vi.stubGlobal("resolveMetadataRetryDelay", resolveMetadataRetryDelay);
|
|
93
101
|
vi.stubGlobal("defineEmits", () => emit);
|
|
94
102
|
vi.stubGlobal("ref", ref);
|
|
95
103
|
vi.stubGlobal("computed", computed);
|
|
96
104
|
vi.stubGlobal("watch", watch);
|
|
97
105
|
vi.stubGlobal("inject", () => null);
|
|
106
|
+
vi.stubGlobal("useId", () => (getCurrentInstance() ? useId() : "image"));
|
|
98
107
|
vi.stubGlobal("FORM_FIELD_LOADING_KEY", Symbol());
|
|
99
108
|
vi.stubGlobal("FORM_CONTENT_LANGUAGE_KEY", Symbol());
|
|
100
109
|
vi.stubGlobal("CONTENT_LANGUAGE_HEADER", "x-content-language");
|
|
@@ -117,7 +126,7 @@ afterEach(() => {
|
|
|
117
126
|
it("preserves a denied image when another image is removed", async () => {
|
|
118
127
|
const image = loadImage();
|
|
119
128
|
await nextTick();
|
|
120
|
-
expect(image.items.value[0]!.status).toBe("
|
|
129
|
+
expect(image.items.value[0]!.status).toBe("unavailable");
|
|
121
130
|
image.removeItem(image.items.value[1]!.id);
|
|
122
131
|
expect(emit).toHaveBeenLastCalledWith("update:modelValue", [original]);
|
|
123
132
|
});
|
|
@@ -191,7 +200,8 @@ it("keeps the denied image and its explicit deletion control in rendered markup"
|
|
|
191
200
|
);
|
|
192
201
|
app.component("UModal", defineComponent({ setup: () => () => null }));
|
|
193
202
|
const html = await renderToString(app);
|
|
194
|
-
expect(html).toContain("dms.form.image.
|
|
203
|
+
expect(html).toContain("dms.form.image.file_unavailable");
|
|
204
|
+
expect(html).not.toContain("dms.form.image.upload_failed");
|
|
195
205
|
expect(html).toContain("dms.form.image.delete</button>");
|
|
196
206
|
expect(emit).not.toHaveBeenCalled();
|
|
197
207
|
});
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import {
|
|
3
|
+
type App,
|
|
4
|
+
type Component,
|
|
5
|
+
computed,
|
|
6
|
+
createApp,
|
|
7
|
+
type FunctionalComponent,
|
|
8
|
+
h,
|
|
9
|
+
inject,
|
|
10
|
+
onBeforeUnmount,
|
|
11
|
+
onScopeDispose,
|
|
12
|
+
ref,
|
|
13
|
+
useId,
|
|
14
|
+
watch,
|
|
15
|
+
} from "vue";
|
|
16
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
17
|
+
import File from "../layers/dms-ui/app/components/form/components/File.vue";
|
|
18
|
+
import Image from "../layers/dms-ui/app/components/form/components/Image.vue";
|
|
19
|
+
import {
|
|
20
|
+
isDefinitiveMetadataFailure,
|
|
21
|
+
resolveMetadataRetryDelay,
|
|
22
|
+
} from "../layers/dms-ui/app/utils/metadataRetry";
|
|
23
|
+
|
|
24
|
+
const authFetch = vi.fn();
|
|
25
|
+
const LONG_WAIT_MS = 120000;
|
|
26
|
+
|
|
27
|
+
interface FieldCase {
|
|
28
|
+
name: string;
|
|
29
|
+
component: Component;
|
|
30
|
+
modelValue: unknown;
|
|
31
|
+
unavailableLabel: string;
|
|
32
|
+
metadata: Record<string, unknown>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const FIELD_CASES: FieldCase[] = [
|
|
36
|
+
{
|
|
37
|
+
name: "File",
|
|
38
|
+
component: File,
|
|
39
|
+
modelValue: "files/profile/avatar.pdf",
|
|
40
|
+
unavailableLabel: "dms.form.file.file_unavailable",
|
|
41
|
+
metadata: {
|
|
42
|
+
resourceKey: "files/profile/avatar.pdf",
|
|
43
|
+
filename: "avatar.pdf",
|
|
44
|
+
size: 2048,
|
|
45
|
+
mimetype: "application/pdf",
|
|
46
|
+
url: "https://example.test/avatar.pdf",
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: "Image",
|
|
51
|
+
component: Image,
|
|
52
|
+
modelValue: { key: "files/profile/cover.png", alt: "Cover" },
|
|
53
|
+
unavailableLabel: "dms.form.image.file_unavailable",
|
|
54
|
+
metadata: {
|
|
55
|
+
resourceKey: "files/profile/cover.png",
|
|
56
|
+
filename: "cover.png",
|
|
57
|
+
size: 2048,
|
|
58
|
+
mimetype: "image/png",
|
|
59
|
+
url: "https://example.test/cover.png",
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
const passthrough: FunctionalComponent = (_, { slots }) =>
|
|
65
|
+
h("span", slots.default?.());
|
|
66
|
+
|
|
67
|
+
const renderTag =
|
|
68
|
+
(tag: string): FunctionalComponent =>
|
|
69
|
+
() =>
|
|
70
|
+
h(tag);
|
|
71
|
+
|
|
72
|
+
function httpError(status: number): Error {
|
|
73
|
+
return Object.assign(new Error(`HTTP ${status}`), {
|
|
74
|
+
status,
|
|
75
|
+
statusCode: status,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function mountField(field: FieldCase): { app: App; container: HTMLElement } {
|
|
80
|
+
const app = createApp({
|
|
81
|
+
render: () => h(field.component, { modelValue: field.modelValue }),
|
|
82
|
+
});
|
|
83
|
+
app.config.globalProperties.$t = (key: string) => key;
|
|
84
|
+
for (const name of ["UFileUpload", "ULink", "UTooltip"])
|
|
85
|
+
app.component(name, passthrough);
|
|
86
|
+
app.component("UButton", renderTag("button"));
|
|
87
|
+
app.component("UIcon", renderTag("i"));
|
|
88
|
+
app.component("UInput", renderTag("input"));
|
|
89
|
+
app.component("UModal", () => null);
|
|
90
|
+
const container = document.createElement("div");
|
|
91
|
+
app.mount(container);
|
|
92
|
+
return { app, container };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
beforeEach(() => {
|
|
96
|
+
vi.useFakeTimers();
|
|
97
|
+
vi.stubGlobal("ref", ref);
|
|
98
|
+
vi.stubGlobal("computed", computed);
|
|
99
|
+
vi.stubGlobal("watch", watch);
|
|
100
|
+
vi.stubGlobal("inject", inject);
|
|
101
|
+
vi.stubGlobal("useId", useId);
|
|
102
|
+
vi.stubGlobal("onBeforeUnmount", onBeforeUnmount);
|
|
103
|
+
vi.stubGlobal("onScopeDispose", onScopeDispose);
|
|
104
|
+
vi.stubGlobal("FORM_FIELD_LOADING_KEY", Symbol());
|
|
105
|
+
vi.stubGlobal("FORM_CONTENT_LANGUAGE_KEY", Symbol());
|
|
106
|
+
vi.stubGlobal("CONTENT_LANGUAGE_HEADER", "x-content-language");
|
|
107
|
+
vi.stubGlobal("useAuthFetch", () => ({ $authFetch: authFetch }));
|
|
108
|
+
vi.stubGlobal("useUploadWithProgress", () => ({
|
|
109
|
+
uploadWithProgress: vi.fn(),
|
|
110
|
+
}));
|
|
111
|
+
vi.stubGlobal("useFormField", () => ({ emitFormChange: vi.fn() }));
|
|
112
|
+
vi.stubGlobal("useI18n", () => ({ t: (key: string) => key }));
|
|
113
|
+
vi.stubGlobal("useToast", () => ({ add: vi.fn() }));
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
afterEach(() => {
|
|
117
|
+
vi.useRealTimers();
|
|
118
|
+
vi.unstubAllGlobals();
|
|
119
|
+
vi.resetAllMocks();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe.each(FIELD_CASES)("$name stored-value metadata", (field) => {
|
|
123
|
+
it.each([403, 404, 410])(
|
|
124
|
+
"reads a file answered with %i exactly once and shows it unavailable",
|
|
125
|
+
async (status) => {
|
|
126
|
+
authFetch.mockRejectedValue(httpError(status));
|
|
127
|
+
const { app, container } = mountField(field);
|
|
128
|
+
|
|
129
|
+
await vi.advanceTimersByTimeAsync(LONG_WAIT_MS);
|
|
130
|
+
|
|
131
|
+
expect(authFetch).toHaveBeenCalledTimes(1);
|
|
132
|
+
expect(container.textContent).toContain(field.unavailableLabel);
|
|
133
|
+
app.unmount();
|
|
134
|
+
},
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
it("retries transient failures with a growing delay until the read succeeds", async () => {
|
|
138
|
+
authFetch
|
|
139
|
+
.mockRejectedValueOnce(httpError(503))
|
|
140
|
+
.mockRejectedValueOnce(new Error("network down"))
|
|
141
|
+
.mockRejectedValueOnce(httpError(429))
|
|
142
|
+
.mockResolvedValueOnce(field.metadata);
|
|
143
|
+
const { app, container } = mountField(field);
|
|
144
|
+
await vi.advanceTimersByTimeAsync(0);
|
|
145
|
+
expect(authFetch).toHaveBeenCalledTimes(1);
|
|
146
|
+
expect(container.textContent).toContain(field.unavailableLabel);
|
|
147
|
+
|
|
148
|
+
await vi.advanceTimersByTimeAsync(1000);
|
|
149
|
+
expect(authFetch).toHaveBeenCalledTimes(2);
|
|
150
|
+
await vi.advanceTimersByTimeAsync(1999);
|
|
151
|
+
expect(authFetch).toHaveBeenCalledTimes(2);
|
|
152
|
+
await vi.advanceTimersByTimeAsync(1);
|
|
153
|
+
expect(authFetch).toHaveBeenCalledTimes(3);
|
|
154
|
+
await vi.advanceTimersByTimeAsync(4000);
|
|
155
|
+
expect(authFetch).toHaveBeenCalledTimes(4);
|
|
156
|
+
|
|
157
|
+
expect(container.textContent).not.toContain(field.unavailableLabel);
|
|
158
|
+
await vi.advanceTimersByTimeAsync(LONG_WAIT_MS);
|
|
159
|
+
expect(authFetch).toHaveBeenCalledTimes(4);
|
|
160
|
+
app.unmount();
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
describe("metadata retry policy", () => {
|
|
165
|
+
it("treats refusals and missing files as definitive", () => {
|
|
166
|
+
for (const status of [400, 401, 403, 404, 410])
|
|
167
|
+
expect(isDefinitiveMetadataFailure(httpError(status))).toBe(true);
|
|
168
|
+
for (const error of [
|
|
169
|
+
httpError(408),
|
|
170
|
+
httpError(429),
|
|
171
|
+
httpError(500),
|
|
172
|
+
httpError(503),
|
|
173
|
+
new Error("network down"),
|
|
174
|
+
undefined,
|
|
175
|
+
])
|
|
176
|
+
expect(isDefinitiveMetadataFailure(error)).toBe(false);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("backs off exponentially up to a cap and never retries a definitive failure", () => {
|
|
180
|
+
const transient = httpError(503);
|
|
181
|
+
expect(resolveMetadataRetryDelay(transient, 1)).toBe(1000);
|
|
182
|
+
expect(resolveMetadataRetryDelay(transient, 2)).toBe(2000);
|
|
183
|
+
expect(resolveMetadataRetryDelay(transient, 3)).toBe(4000);
|
|
184
|
+
expect(resolveMetadataRetryDelay(transient, 50)).toBe(30000);
|
|
185
|
+
expect(resolveMetadataRetryDelay(httpError(404), 1)).toBeNull();
|
|
186
|
+
});
|
|
187
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { afterEach, beforeEach, expect, it, vi } from "vitest";
|
|
2
|
+
import { useUploadWithProgress } from "../layers/dms-ui/app/composables/form/useUploadWithProgress";
|
|
3
|
+
|
|
4
|
+
const UPLOAD_URL = "https://storage.example.test/upload/token";
|
|
5
|
+
const setRequestHeader = vi.fn();
|
|
6
|
+
|
|
7
|
+
class FakeXMLHttpRequest {
|
|
8
|
+
status = 200;
|
|
9
|
+
upload = {};
|
|
10
|
+
onload: (() => void) | null = null;
|
|
11
|
+
open = vi.fn();
|
|
12
|
+
setRequestHeader = setRequestHeader;
|
|
13
|
+
send() {
|
|
14
|
+
this.onload?.();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
vi.stubGlobal("XMLHttpRequest", FakeXMLHttpRequest);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
vi.unstubAllGlobals();
|
|
24
|
+
vi.resetAllMocks();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("forwards presign headers except the ones a browser refuses to set", async () => {
|
|
28
|
+
const { uploadWithProgress } = useUploadWithProgress();
|
|
29
|
+
|
|
30
|
+
await uploadWithProgress(
|
|
31
|
+
{
|
|
32
|
+
uploadUrl: UPLOAD_URL,
|
|
33
|
+
resourceKey: "__staging__/cover.png",
|
|
34
|
+
headers: {
|
|
35
|
+
"Content-Type": "image/png",
|
|
36
|
+
"Content-Length": "42",
|
|
37
|
+
host: "storage.example.test",
|
|
38
|
+
Connection: "keep-alive",
|
|
39
|
+
"Sec-Fetch-Mode": "cors",
|
|
40
|
+
"Proxy-Authorization": "Basic secret",
|
|
41
|
+
"x-amz-meta-owner": "tenant",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
new File(["bytes"], "cover.png", { type: "image/png" }),
|
|
45
|
+
() => undefined,
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
expect(setRequestHeader.mock.calls).toEqual([
|
|
49
|
+
["Content-Type", "image/png"],
|
|
50
|
+
["x-amz-meta-owner", "tenant"],
|
|
51
|
+
]);
|
|
52
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antelopejs/dms",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/AntelopeJS/dms.git"
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"@antelopejs/interface-data-api": ">=0.1.9 <1.0.0",
|
|
37
37
|
"@antelopejs/interface-database": ">=0.1.8 <1.0.0",
|
|
38
38
|
"@antelopejs/interface-database-decorators": ">=0.1.7 <1.0.0",
|
|
39
|
-
"@antelopejs/interface-dms": ">=0.3.
|
|
39
|
+
"@antelopejs/interface-dms": ">=0.3.4 <0.4.0",
|
|
40
40
|
"@antelopejs/interface-email": ">=0.0.5 <1.0.0",
|
|
41
41
|
"@antelopejs/interface-file-storage": ">=0.1.3 <1.0.0",
|
|
42
42
|
"archiver": "^7.0.1",
|