simple-strapi 1.0.0-alpha.23 → 1.0.0-alpha.24
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/dist/client.d.ts +28 -1
- package/dist/client.js +164 -0
- package/dist/fields/media.d.ts +1 -2
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import z from "zod";
|
|
|
6
6
|
import { DynamicField, DynamicOptions, InferDynamic } from "./fields/dynamic";
|
|
7
7
|
import { defaultStrapiFieldsSchema } from "./utils/schema";
|
|
8
8
|
import { ComponentRepeatableField, ComponentRepeatableOptions, ComponentSingleField, ComponentSingleOptions, InferComponentRepeatable, InferComponentSingle } from "./fields/component";
|
|
9
|
-
import { InferMediaSingle, MediaSingleField, MediaSingleOptions } from "./fields/media";
|
|
9
|
+
import { InferMediaSingle, MediaSingleField, MediaSingleOptions, ZodMediaType } from "./fields/media";
|
|
10
10
|
import { EnumerationField, EnumerationOptions, InferEnumeration } from "./fields/enumeration";
|
|
11
11
|
import { InferRichTextBlocks, RichTextBlocksField, RichTextBlocksOptions } from "./fields/richText";
|
|
12
12
|
import { InferJSON, JSONField, JSONOptions } from "./fields/json";
|
|
@@ -75,6 +75,7 @@ declare class Client {
|
|
|
75
75
|
}>);
|
|
76
76
|
private getAuthorizedHeaders;
|
|
77
77
|
private populateFromSchema;
|
|
78
|
+
private resolveRef;
|
|
78
79
|
getSingle<S extends Schema>(pluralID: string, options: EntityRequest<{
|
|
79
80
|
schema: S;
|
|
80
81
|
populate?: any;
|
|
@@ -138,5 +139,31 @@ declare class Client {
|
|
|
138
139
|
data: any;
|
|
139
140
|
meta: any;
|
|
140
141
|
}>;
|
|
142
|
+
private getOrCreateFolder;
|
|
143
|
+
/**
|
|
144
|
+
* Carica un file sulla Media Library di Strapi.
|
|
145
|
+
*
|
|
146
|
+
* @param file - Sorgente del file: `Blob`, `File` (browser) oppure stringa base64
|
|
147
|
+
* (data URI `data:mime;base64,...` o raw base64).
|
|
148
|
+
* @param options.filename - Nome del file nel FormData. Obbligatorio per base64 e
|
|
149
|
+
* Blob senza nome; per `File` viene estratto automaticamente.
|
|
150
|
+
* @param options.ref - Nome del Content Type (es. `"product"` → `api::product.product`)
|
|
151
|
+
* oppure UID completo (es. `"plugin::users-permissions.user"`).
|
|
152
|
+
* @param options.refId - `documentId` dell'entità a cui agganciare il file.
|
|
153
|
+
* @param options.field - Nome del campo top-level dell'entità.
|
|
154
|
+
* ⚠️ I campi annidati (dot-notation) non sono supportati
|
|
155
|
+
* nativamente dall'endpoint `/upload` di Strapi: caricare
|
|
156
|
+
* il file separatamente e aggiornare l'entità con `update`.
|
|
157
|
+
* @param options.path - Percorso della cartella nella Media Library (es. `"products/2024"`).
|
|
158
|
+
* La cartella viene creata automaticamente se non esiste (mkdir -p).
|
|
159
|
+
*/
|
|
160
|
+
upload(file: Blob | string, options?: {
|
|
161
|
+
filename?: string;
|
|
162
|
+
ref?: string;
|
|
163
|
+
refId?: string | number;
|
|
164
|
+
field?: string;
|
|
165
|
+
path?: string;
|
|
166
|
+
headers?: Record<string, string>;
|
|
167
|
+
}): Promise<ZodMediaType[]>;
|
|
141
168
|
}
|
|
142
169
|
export default Client;
|
package/dist/client.js
CHANGED
|
@@ -4,6 +4,7 @@ import fetch from "node-fetch";
|
|
|
4
4
|
import qs from "qs";
|
|
5
5
|
import z from "zod";
|
|
6
6
|
import { defaultStrapiFields, schemaToParser } from "./utils/schema";
|
|
7
|
+
import { zodMediaSchema } from "./fields/media";
|
|
7
8
|
class Client {
|
|
8
9
|
static async create(endpoint, { auth, ...options } = {}) {
|
|
9
10
|
const endpointURL = new URL(endpoint);
|
|
@@ -119,6 +120,11 @@ class Client {
|
|
|
119
120
|
}
|
|
120
121
|
return populate;
|
|
121
122
|
};
|
|
123
|
+
this.resolveRef = (ref) => {
|
|
124
|
+
if (ref.includes("::"))
|
|
125
|
+
return ref;
|
|
126
|
+
return `api::${ref}.${ref}`;
|
|
127
|
+
};
|
|
122
128
|
const headers = (() => {
|
|
123
129
|
return { ...Client.headers, ...(this.options.headers || {}) };
|
|
124
130
|
})();
|
|
@@ -378,6 +384,164 @@ class Client {
|
|
|
378
384
|
throw ensureSimpleException(exception);
|
|
379
385
|
}
|
|
380
386
|
}
|
|
387
|
+
/*
|
|
388
|
+
* ==========================================
|
|
389
|
+
* AUTO GENERATED - upload method
|
|
390
|
+
* ==========================================
|
|
391
|
+
*/
|
|
392
|
+
async getOrCreateFolder(folderPath) {
|
|
393
|
+
const segments = folderPath.split("/").filter(Boolean);
|
|
394
|
+
let currentParentId = null;
|
|
395
|
+
for (const segment of segments) {
|
|
396
|
+
const params = currentParentId === null
|
|
397
|
+
? { filters: { name: { $eq: segment }, parent: { $null: true } } }
|
|
398
|
+
: { filters: { name: { $eq: segment }, parent: { id: { $eq: currentParentId } } } };
|
|
399
|
+
const listURL = Client.getRequestURL({
|
|
400
|
+
origin: this.origin,
|
|
401
|
+
pathname: join(this.pathname, "upload/folders"),
|
|
402
|
+
params,
|
|
403
|
+
});
|
|
404
|
+
const listResponse = await fetch(listURL, {
|
|
405
|
+
method: "GET",
|
|
406
|
+
headers: this.getAuthorizedHeaders(),
|
|
407
|
+
});
|
|
408
|
+
if (!listResponse.ok) {
|
|
409
|
+
const errorBody = await listResponse.json().catch(() => ({}));
|
|
410
|
+
throw createSimpleException({
|
|
411
|
+
code: listResponse.status,
|
|
412
|
+
message: errorBody.error?.message || listResponse.statusText,
|
|
413
|
+
type: "error",
|
|
414
|
+
source: "strapi-utils/client.ts",
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
const { data: folders } = z
|
|
418
|
+
.object({ data: z.array(z.object({ id: z.number() }).loose()) })
|
|
419
|
+
.parse(await listResponse.json());
|
|
420
|
+
if (folders.length > 0) {
|
|
421
|
+
currentParentId = folders[0].id;
|
|
422
|
+
}
|
|
423
|
+
else {
|
|
424
|
+
const createURL = Client.getRequestURL({
|
|
425
|
+
origin: this.origin,
|
|
426
|
+
pathname: join(this.pathname, "upload/folders"),
|
|
427
|
+
params: {},
|
|
428
|
+
});
|
|
429
|
+
const createBody = currentParentId === null
|
|
430
|
+
? { name: segment }
|
|
431
|
+
: { name: segment, parent: currentParentId };
|
|
432
|
+
const createResponse = await fetch(createURL, {
|
|
433
|
+
method: "POST",
|
|
434
|
+
headers: this.getAuthorizedHeaders(),
|
|
435
|
+
body: JSON.stringify(createBody),
|
|
436
|
+
});
|
|
437
|
+
if (!createResponse.ok) {
|
|
438
|
+
const errorBody = await createResponse.json().catch(() => ({}));
|
|
439
|
+
throw createSimpleException({
|
|
440
|
+
code: createResponse.status,
|
|
441
|
+
message: errorBody.error?.message || createResponse.statusText,
|
|
442
|
+
type: "error",
|
|
443
|
+
source: "strapi-utils/client.ts",
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
const { data: created } = z
|
|
447
|
+
.object({ data: z.object({ id: z.number() }).loose() })
|
|
448
|
+
.parse(await createResponse.json());
|
|
449
|
+
currentParentId = created.id;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return currentParentId;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Carica un file sulla Media Library di Strapi.
|
|
456
|
+
*
|
|
457
|
+
* @param file - Sorgente del file: `Blob`, `File` (browser) oppure stringa base64
|
|
458
|
+
* (data URI `data:mime;base64,...` o raw base64).
|
|
459
|
+
* @param options.filename - Nome del file nel FormData. Obbligatorio per base64 e
|
|
460
|
+
* Blob senza nome; per `File` viene estratto automaticamente.
|
|
461
|
+
* @param options.ref - Nome del Content Type (es. `"product"` → `api::product.product`)
|
|
462
|
+
* oppure UID completo (es. `"plugin::users-permissions.user"`).
|
|
463
|
+
* @param options.refId - `documentId` dell'entità a cui agganciare il file.
|
|
464
|
+
* @param options.field - Nome del campo top-level dell'entità.
|
|
465
|
+
* ⚠️ I campi annidati (dot-notation) non sono supportati
|
|
466
|
+
* nativamente dall'endpoint `/upload` di Strapi: caricare
|
|
467
|
+
* il file separatamente e aggiornare l'entità con `update`.
|
|
468
|
+
* @param options.path - Percorso della cartella nella Media Library (es. `"products/2024"`).
|
|
469
|
+
* La cartella viene creata automaticamente se non esiste (mkdir -p).
|
|
470
|
+
*/
|
|
471
|
+
async upload(file, options = {}) {
|
|
472
|
+
try {
|
|
473
|
+
const { ref, refId, field, headers = {} } = options;
|
|
474
|
+
let blob;
|
|
475
|
+
let fileName;
|
|
476
|
+
if (typeof file === "string") {
|
|
477
|
+
let mimeType = "application/octet-stream";
|
|
478
|
+
let rawBase64 = file;
|
|
479
|
+
if (file.startsWith("data:")) {
|
|
480
|
+
const commaIndex = file.indexOf(",");
|
|
481
|
+
mimeType = file.slice(5, file.indexOf(";"));
|
|
482
|
+
rawBase64 = file.slice(commaIndex + 1);
|
|
483
|
+
}
|
|
484
|
+
const bytes = typeof Buffer !== "undefined"
|
|
485
|
+
? new Uint8Array(Buffer.from(rawBase64, "base64"))
|
|
486
|
+
: (() => {
|
|
487
|
+
const bin = atob(rawBase64);
|
|
488
|
+
const arr = new Uint8Array(bin.length);
|
|
489
|
+
for (let i = 0; i < bin.length; i++)
|
|
490
|
+
arr[i] = bin.charCodeAt(i);
|
|
491
|
+
return arr;
|
|
492
|
+
})();
|
|
493
|
+
blob = new Blob([bytes], { type: mimeType });
|
|
494
|
+
fileName = options.filename ?? "upload";
|
|
495
|
+
}
|
|
496
|
+
else {
|
|
497
|
+
blob = file;
|
|
498
|
+
fileName = options.filename ?? ("name" in file ? file.name : "upload");
|
|
499
|
+
}
|
|
500
|
+
let folderId;
|
|
501
|
+
if (options.path) {
|
|
502
|
+
folderId = await this.getOrCreateFolder(options.path);
|
|
503
|
+
}
|
|
504
|
+
const formData = new FormData();
|
|
505
|
+
formData.append("files", blob, fileName);
|
|
506
|
+
if (ref !== undefined)
|
|
507
|
+
formData.append("ref", this.resolveRef(ref));
|
|
508
|
+
if (refId !== undefined)
|
|
509
|
+
formData.append("refId", String(refId));
|
|
510
|
+
if (field !== undefined)
|
|
511
|
+
formData.append("field", field);
|
|
512
|
+
if (folderId !== undefined) {
|
|
513
|
+
formData.append("fileInfo", JSON.stringify({ folder: folderId }));
|
|
514
|
+
}
|
|
515
|
+
const requestURL = Client.getRequestURL({
|
|
516
|
+
origin: this.origin,
|
|
517
|
+
pathname: join(this.pathname, "upload"),
|
|
518
|
+
params: {},
|
|
519
|
+
});
|
|
520
|
+
const { "Content-Type": _ct, ...headersWithoutContentType } = this.getAuthorizedHeaders();
|
|
521
|
+
const response = await fetch(requestURL, {
|
|
522
|
+
method: "POST",
|
|
523
|
+
headers: {
|
|
524
|
+
...headersWithoutContentType,
|
|
525
|
+
...headers,
|
|
526
|
+
},
|
|
527
|
+
body: formData,
|
|
528
|
+
});
|
|
529
|
+
if (!response.ok) {
|
|
530
|
+
const errorBody = await response.json().catch(() => ({}));
|
|
531
|
+
throw createSimpleException({
|
|
532
|
+
code: response.status,
|
|
533
|
+
message: errorBody.error?.message || response.statusText,
|
|
534
|
+
type: "error",
|
|
535
|
+
source: "strapi-utils/client.ts",
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
const data = await response.json();
|
|
539
|
+
return z.array(zodMediaSchema).parse(data);
|
|
540
|
+
}
|
|
541
|
+
catch (exception) {
|
|
542
|
+
throw ensureSimpleException(exception);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
381
545
|
}
|
|
382
546
|
// #region STATIC
|
|
383
547
|
Client.headers = {
|
package/dist/fields/media.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ export declare const zodMediaSchema: z.ZodObject<{
|
|
|
28
28
|
createdAt: z.ZodISODateTime;
|
|
29
29
|
updatedAt: z.ZodISODateTime;
|
|
30
30
|
}, z.core.$strip>;
|
|
31
|
-
type ZodMediaType = z.output<typeof zodMediaSchema>;
|
|
31
|
+
export type ZodMediaType = z.output<typeof zodMediaSchema>;
|
|
32
32
|
export type MediaSingleOptions = {
|
|
33
33
|
required?: boolean;
|
|
34
34
|
};
|
|
@@ -38,4 +38,3 @@ export type MediaSingleField = readonly ["media.single", MediaSingleOptions];
|
|
|
38
38
|
export declare const media: {
|
|
39
39
|
single: <O extends MediaSingleOptions = {}>(options?: O) => ["media.single", O];
|
|
40
40
|
};
|
|
41
|
-
export {};
|