@jrmc/adonis-attachment 2.4.2 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/build/bin/test.d.ts +1 -0
  2. package/build/bin/test.js +34 -0
  3. package/build/index.d.ts +1 -0
  4. package/build/providers/attachment_provider.d.ts +2 -2
  5. package/build/services/main.d.ts +2 -2
  6. package/build/src/adapters/exif.d.ts +7 -1
  7. package/build/src/adapters/exif.js +8 -5
  8. package/build/src/attachment_manager.d.ts +7 -4
  9. package/build/src/attachment_manager.js +21 -8
  10. package/build/src/define_config.d.ts +16 -2
  11. package/build/src/define_config.js +8 -9
  12. package/build/src/errors.d.ts +18 -14
  13. package/build/src/errors.js +4 -0
  14. package/build/src/mixins/attachmentable.d.ts +127 -112
  15. package/build/src/mixins/attachmentable.js +2 -2
  16. package/build/src/types/attachment.d.ts +2 -1
  17. package/build/src/types/config.d.ts +22 -19
  18. package/build/src/types/index.d.ts +5 -0
  19. package/build/src/types/index.js +5 -0
  20. package/build/src/utils/helpers.d.ts +2 -0
  21. package/build/src/utils/helpers.js +35 -1
  22. package/build/stubs/config.stub +11 -5
  23. package/build/tests/attachment-manager.spec.d.ts +7 -0
  24. package/build/tests/attachment-manager.spec.js +234 -0
  25. package/build/tests/attachment.spec.d.ts +7 -0
  26. package/build/tests/attachment.spec.js +16 -0
  27. package/build/tests/commands.spec.d.ts +7 -0
  28. package/build/tests/commands.spec.js +58 -0
  29. package/build/tests/fixtures/converters/image_converter.d.ts +12 -0
  30. package/build/tests/fixtures/converters/image_converter.js +12 -0
  31. package/build/tests/fixtures/factories/user.d.ts +8 -0
  32. package/build/tests/fixtures/factories/user.js +19 -0
  33. package/build/tests/fixtures/factories/user_with_variants.d.ts +8 -0
  34. package/build/tests/fixtures/factories/user_with_variants.js +19 -0
  35. package/build/tests/fixtures/migrations/create_users_table.d.ts +12 -0
  36. package/build/tests/fixtures/migrations/create_users_table.js +23 -0
  37. package/build/tests/fixtures/models/user.d.ts +466 -0
  38. package/build/tests/fixtures/models/user.js +36 -0
  39. package/build/tests/fixtures/models/user_with_variants.d.ts +465 -0
  40. package/build/tests/fixtures/models/user_with_variants.js +33 -0
  41. package/build/tests/helpers/app.d.ts +29 -0
  42. package/build/tests/helpers/app.js +104 -0
  43. package/build/tests/helpers/index.d.ts +7 -0
  44. package/build/tests/helpers/index.js +7 -0
  45. package/build/tests/options.spec.d.ts +7 -0
  46. package/build/tests/options.spec.js +126 -0
  47. package/build/tests/variants.spec.d.ts +7 -0
  48. package/build/tests/variants.spec.js +21 -0
  49. package/package.json +39 -14
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,34 @@
1
+ import { assert } from '@japa/assert';
2
+ import { expectTypeOf } from '@japa/expect-type';
3
+ import { processCLIArgs, configure, run } from '@japa/runner';
4
+ import { createApp, initializeDatabase } from '../tests/helpers/app.js';
5
+ import { fileSystem } from '@japa/file-system';
6
+ import app from '@adonisjs/core/services/app';
7
+ import { BASE_URL } from '../tests/helpers/index.js';
8
+ let testApp;
9
+ processCLIArgs(process.argv.slice(2));
10
+ configure({
11
+ files: ['tests/**/*.spec.ts'],
12
+ plugins: [assert(), fileSystem({ basePath: BASE_URL }), expectTypeOf()],
13
+ setup: [
14
+ async () => {
15
+ testApp = await createApp();
16
+ await initializeDatabase(testApp);
17
+ },
18
+ ],
19
+ teardown: [
20
+ async () => {
21
+ await app.terminate();
22
+ await testApp.terminate();
23
+ },
24
+ ],
25
+ });
26
+ /*
27
+ |--------------------------------------------------------------------------
28
+ | Run tests
29
+ |--------------------------------------------------------------------------
30
+ |
31
+ | The following "run" method is required to execute all the tests.
32
+ |
33
+ */
34
+ run();
package/build/index.d.ts CHANGED
@@ -6,3 +6,4 @@ export { defineConfig } from './src/define_config.js';
6
6
  export { Attachmentable } from './src/mixins/attachmentable.js';
7
7
  export * as errors from './src/errors.js';
8
8
  export { attachmentManager };
9
+ export { type AttachmentVariants } from './src/types/config.js';
@@ -5,10 +5,10 @@
5
5
  * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
6
  */
7
7
  import type { ApplicationService } from '@adonisjs/core/types';
8
- import type { AttachmentManager } from '../src/attachment_manager.js';
8
+ import type { AttachmentService } from '../src/types/config.js';
9
9
  declare module '@adonisjs/core/types' {
10
10
  interface ContainerBindings {
11
- 'jrmc.attachment': AttachmentManager;
11
+ 'jrmc.attachment': AttachmentService;
12
12
  }
13
13
  }
14
14
  export default class AttachmentProvider {
@@ -4,6 +4,6 @@
4
4
  * @license MIT
5
5
  * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
6
  */
7
- import { AttachmentManager } from '../src/attachment_manager.js';
8
- declare let manager: AttachmentManager;
7
+ import { AttachmentService } from '../src/types/config.js';
8
+ declare let manager: AttachmentService;
9
9
  export { manager as default };
@@ -5,4 +5,10 @@
5
5
  * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
6
  */
7
7
  import type { Exif, Input } from '../types/input.js';
8
- export declare const exif: (input: Input) => Promise<Exif | undefined>;
8
+ import { ResolvedAttachmentConfig } from '../define_config.js';
9
+ import { Converter } from '../types/converter.js';
10
+ type KnownConverters = Record<string, Converter>;
11
+ declare const _default: {
12
+ exif(input: Input, config: ResolvedAttachmentConfig<KnownConverters>): Promise<Exif | undefined>;
13
+ };
14
+ export default _default;
@@ -9,8 +9,12 @@ import ExifReader from 'exifreader';
9
9
  import logger from '@adonisjs/core/services/logger';
10
10
  import { fileTypeFromBuffer, fileTypeFromFile } from 'file-type';
11
11
  import { bufferToTempFile, cleanObject, use } from '../utils/helpers.js';
12
- import { attachmentManager } from '../../index.js';
13
- export const exif = async (input) => {
12
+ export default {
13
+ async exif(input, config) {
14
+ return exif(input, config);
15
+ },
16
+ };
17
+ const exif = async (input, config) => {
14
18
  let fileType;
15
19
  let buffer;
16
20
  if (Buffer.isBuffer(input)) {
@@ -26,7 +30,7 @@ export const exif = async (input) => {
26
30
  }
27
31
  }
28
32
  if (fileType?.mime.includes('video')) {
29
- return videoExif(input);
33
+ return videoExif(input, config);
30
34
  }
31
35
  if (buffer && fileType?.mime.includes('image')) {
32
36
  return imageExif(buffer);
@@ -103,7 +107,7 @@ async function imageExif(buffer) {
103
107
  }
104
108
  return cleanObject(data);
105
109
  }
106
- async function videoExif(input) {
110
+ async function videoExif(input, config) {
107
111
  return new Promise(async (resolve) => {
108
112
  const ffmpeg = await use('fluent-ffmpeg');
109
113
  let file = input;
@@ -111,7 +115,6 @@ async function videoExif(input) {
111
115
  file = await bufferToTempFile(input);
112
116
  }
113
117
  const ff = ffmpeg(file);
114
- const config = attachmentManager.getConfig();
115
118
  if (config.bin) {
116
119
  if (config.bin.ffprobePath) {
117
120
  ff.setFfprobePath(config.bin.ffprobePath);
@@ -7,18 +7,21 @@
7
7
  import type { DriveService, SignedURLOptions } from '@adonisjs/drive/types';
8
8
  import type { MultipartFile } from '@adonisjs/core/bodyparser';
9
9
  import type { AttachmentBase, Attachment as AttachmentType } from './types/attachment.js';
10
- import type { ResolvedAttachmentConfig } from './types/config.js';
11
10
  import { DeferQueue } from '@poppinss/defer';
12
11
  import Converter from './converters/converter.js';
13
- export declare class AttachmentManager {
12
+ import { ResolvedAttachmentConfig } from './define_config.js';
13
+ export declare class AttachmentManager<KnownConverters extends Record<string, Converter>> {
14
14
  #private;
15
15
  queue: DeferQueue;
16
- constructor(config: ResolvedAttachmentConfig, drive: DriveService);
17
- getConfig(): ResolvedAttachmentConfig;
16
+ constructor(config: ResolvedAttachmentConfig<KnownConverters>, drive: DriveService);
17
+ getConfig(): ResolvedAttachmentConfig<KnownConverters>;
18
18
  createFromDbResponse(response: any): AttachmentType | null;
19
19
  createFromFile(file: MultipartFile): Promise<AttachmentType>;
20
+ createFromPath(path: string, name?: string): Promise<AttachmentType>;
20
21
  createFromBuffer(buffer: Buffer, name?: string): Promise<AttachmentType>;
21
22
  createFromBase64(data: string, name?: string): Promise<AttachmentType>;
23
+ createFromUrl(url: URL, name?: string): Promise<AttachmentType>;
24
+ createFromStream(stream: NodeJS.ReadableStream, name?: string): Promise<AttachmentType>;
22
25
  getConverter(key: string): Promise<void | Converter>;
23
26
  computeUrl(attachment: AttachmentType | AttachmentBase, signedUrlOptions?: SignedURLOptions): Promise<void>;
24
27
  preComputeUrl(attachment: AttachmentType): Promise<void>;
@@ -7,8 +7,8 @@
7
7
  import { DeferQueue } from '@poppinss/defer';
8
8
  import * as errors from './errors.js';
9
9
  import { Attachment } from './attachments/attachment.js';
10
- import { createAttachmentAttributes, isBase64 } from './utils/helpers.js';
11
- import { exif } from './adapters/exif.js';
10
+ import { createAttachmentAttributes, downloadToTempFile, isBase64, streamToTempFile } from './utils/helpers.js';
11
+ import ExifAdapter from './adapters/exif.js';
12
12
  const REQUIRED_ATTRIBUTES = ['name', 'size', 'extname', 'mimeType'];
13
13
  export class AttachmentManager {
14
14
  queue;
@@ -49,6 +49,11 @@ export class AttachmentManager {
49
49
  const attachment = new Attachment(this.#drive, attributes, file.tmpPath);
50
50
  return this.#configureAttachment(attachment);
51
51
  }
52
+ async createFromPath(path, name) {
53
+ const attributes = await createAttachmentAttributes(path, name);
54
+ const attachment = new Attachment(this.#drive, attributes, path);
55
+ return this.#configureAttachment(attachment);
56
+ }
52
57
  async createFromBuffer(buffer, name) {
53
58
  if (!Buffer.isBuffer(buffer)) {
54
59
  throw new errors.E_ISNOT_BUFFER();
@@ -65,13 +70,21 @@ export class AttachmentManager {
65
70
  const buffer = Buffer.from(base64Data, 'base64');
66
71
  return await this.createFromBuffer(buffer, name);
67
72
  }
73
+ async createFromUrl(url, name) {
74
+ const path = await downloadToTempFile(url);
75
+ const attributes = await createAttachmentAttributes(path, name);
76
+ const attachment = new Attachment(this.#drive, attributes, path);
77
+ return this.#configureAttachment(attachment);
78
+ }
79
+ async createFromStream(stream, name) {
80
+ const path = await streamToTempFile(stream);
81
+ const attributes = await createAttachmentAttributes(path, name);
82
+ const attachment = new Attachment(this.#drive, attributes, path);
83
+ return this.#configureAttachment(attachment);
84
+ }
68
85
  async getConverter(key) {
69
86
  if (this.#config.converters) {
70
- for (const c of this.#config.converters) {
71
- if (c.key === key) {
72
- return c.converter;
73
- }
74
- }
87
+ return this.#config.converters[key];
75
88
  }
76
89
  }
77
90
  async computeUrl(attachment, signedUrlOptions) {
@@ -100,7 +113,7 @@ export class AttachmentManager {
100
113
  async save(attachment) {
101
114
  const destinationPath = attachment.path;
102
115
  if (attachment.options?.meta) {
103
- attachment.meta = await exif(attachment.input);
116
+ attachment.meta = await ExifAdapter.exif(attachment.input, this.#config);
104
117
  }
105
118
  else {
106
119
  attachment.meta = undefined;
@@ -4,6 +4,20 @@
4
4
  * @license MIT
5
5
  * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
6
  */
7
- import type { AttachmentConfig, ResolvedAttachmentConfig } from './types/config.js';
7
+ import type { AttachmentConfig, BinPaths, ConverterConfig, Queue } from './types/config.js';
8
8
  import { ConfigProvider } from '@adonisjs/core/types';
9
- export declare function defineConfig(config: AttachmentConfig): ConfigProvider<ResolvedAttachmentConfig>;
9
+ import { Converter } from './types/converter.js';
10
+ /**
11
+ * Config resolved by the "defineConfig" method
12
+ */
13
+ export type ResolvedAttachmentConfig<KnownConverters extends Record<string, Converter>> = {
14
+ bin?: BinPaths;
15
+ meta?: boolean;
16
+ rename?: boolean;
17
+ preComputeUrl?: boolean;
18
+ converters?: {
19
+ [K in keyof KnownConverters]: KnownConverters[K];
20
+ };
21
+ queue?: Queue;
22
+ };
23
+ export declare function defineConfig<KnownConverter extends Record<string, ConverterConfig>>(config: AttachmentConfig<KnownConverter>): ConfigProvider<ResolvedAttachmentConfig<KnownConverter>>;
@@ -8,21 +8,20 @@ import { configProvider } from '@adonisjs/core';
8
8
  // export function defineConfig<T extends AttachmentConfig>(config: T): T {
9
9
  export function defineConfig(config) {
10
10
  return configProvider.create(async (_app) => {
11
- let convertersMap = [];
11
+ const convertersList = Object.keys(config.converters || {});
12
+ const converters = {};
12
13
  if (config.converters) {
13
- convertersMap = await Promise.all(config.converters.map(async (c) => {
14
+ for (let converterName of convertersList) {
15
+ const converter = config.converters[converterName];
14
16
  const binConfig = config.bin;
15
- const { default: value } = await c.converter();
17
+ const { default: value } = await converter.converter();
16
18
  const Converter = value;
17
- return {
18
- key: c.key,
19
- converter: new Converter(c.options, binConfig),
20
- };
21
- }));
19
+ converters[converterName] = new Converter(converter.options, binConfig);
20
+ }
22
21
  }
23
22
  return {
24
23
  ...config,
25
- converters: convertersMap,
24
+ converters,
26
25
  };
27
26
  });
28
27
  }
@@ -7,7 +7,7 @@
7
7
  /**
8
8
  * Unable to write file to the destination
9
9
  */
10
- export declare const E_CANNOT_WRITE_FILE: new (args: [key: string], options?: ErrorOptions) => import("@adonisjs/core/exceptions").Exception;
10
+ export declare const E_CANNOT_WRITE_FILE: new (args: [key: string], options?: ErrorOptions) => import("@poppinss/utils/exception").Exception;
11
11
  /**
12
12
  * Unable to read file
13
13
  */
@@ -15,52 +15,56 @@ export declare const E_CANNOT_READ_FILE: new (args: [key: string], options?: Err
15
15
  /**
16
16
  * Unable to read file
17
17
  */
18
- "@adonisjs/core/exceptions").Exception;
18
+ "@poppinss/utils/exception").Exception;
19
19
  /**
20
20
  * Unable to delete file
21
21
  */
22
- export declare const E_CANNOT_DELETE_FILE: new (args: [key: string], options?: ErrorOptions) => import("@adonisjs/core/exceptions").Exception;
22
+ export declare const E_CANNOT_DELETE_FILE: new (args: [key: string], options?: ErrorOptions) => import("@poppinss/utils/exception").Exception;
23
23
  /**
24
24
  * Unable to set file visibility
25
25
  */
26
- export declare const E_CANNOT_SET_VISIBILITY: new (args: [key: string], options?: ErrorOptions) => import("@adonisjs/core/exceptions").Exception;
26
+ export declare const E_CANNOT_SET_VISIBILITY: new (args: [key: string], options?: ErrorOptions) => import("@poppinss/utils/exception").Exception;
27
27
  /**
28
28
  * Unable to generate URL for a file
29
29
  */
30
- export declare const E_CANNOT_GENERATE_URL: new (args: [key: string], options?: ErrorOptions) => import("@adonisjs/core/exceptions").Exception;
30
+ export declare const E_CANNOT_GENERATE_URL: new (args: [key: string], options?: ErrorOptions) => import("@poppinss/utils/exception").Exception;
31
+ /**
32
+ * Unable to generate temp file
33
+ */
34
+ export declare const E_CANNOT_GENERATE_TEMP_FILE: new (args: [key: string], options?: ErrorOptions) => import("@poppinss/utils/exception").Exception;
31
35
  /**
32
36
  * The file key has unallowed set of characters
33
37
  */
34
- export declare const E_UNALLOWED_CHARACTERS: new (args: [key: string], options?: ErrorOptions) => import("@adonisjs/core/exceptions").Exception;
38
+ export declare const E_UNALLOWED_CHARACTERS: new (args: [key: string], options?: ErrorOptions) => import("@poppinss/utils/exception").Exception;
35
39
  /**
36
40
  * Key post normalization leads to an empty string
37
41
  */
38
- export declare const E_INVALID_KEY: new (args: [key: string], options?: ErrorOptions) => import("@adonisjs/core/exceptions").Exception;
42
+ export declare const E_INVALID_KEY: new (args: [key: string], options?: ErrorOptions) => import("@poppinss/utils/exception").Exception;
39
43
  /**
40
44
  * Missing package
41
45
  */
42
- export declare const E_MISSING_PACKAGE: new (args: [key: string], options?: ErrorOptions) => import("@adonisjs/core/exceptions").Exception;
46
+ export declare const E_MISSING_PACKAGE: new (args: [key: string], options?: ErrorOptions) => import("@poppinss/utils/exception").Exception;
43
47
  /**
44
48
  * Unable to create Attachment Object
45
49
  */
46
- export declare const E_CANNOT_CREATE_ATTACHMENT: new (args: [key: string], options?: ErrorOptions) => import("@adonisjs/core/exceptions").Exception;
50
+ export declare const E_CANNOT_CREATE_ATTACHMENT: new (args: [key: string], options?: ErrorOptions) => import("@poppinss/utils/exception").Exception;
47
51
  /**
48
52
  * Unable to create variant
49
53
  */
50
- export declare const E_CANNOT_CREATE_VARIANT: new (args: [key: string], options?: ErrorOptions) => import("@adonisjs/core/exceptions").Exception;
54
+ export declare const E_CANNOT_CREATE_VARIANT: new (args: [key: string], options?: ErrorOptions) => import("@poppinss/utils/exception").Exception;
51
55
  /**
52
56
  * Missing path
53
57
  */
54
- export declare const E_CANNOT_PATH_BY_CONVERTER: new (args?: any, options?: ErrorOptions) => import("@adonisjs/core/exceptions").Exception;
58
+ export declare const E_CANNOT_PATH_BY_CONVERTER: new (args?: any, options?: ErrorOptions) => import("@poppinss/utils/exception").Exception;
55
59
  /**
56
60
  * Is not a Buffer
57
61
  */
58
- export declare const E_ISNOT_BUFFER: new (args?: any, options?: ErrorOptions) => import("@adonisjs/core/exceptions").Exception;
62
+ export declare const E_ISNOT_BUFFER: new (args?: any, options?: ErrorOptions) => import("@poppinss/utils/exception").Exception;
59
63
  /**
60
64
  * Is not a Base64
61
65
  */
62
- export declare const E_ISNOT_BASE64: new (args?: any, options?: ErrorOptions) => import("@adonisjs/core/exceptions").Exception;
66
+ export declare const E_ISNOT_BASE64: new (args?: any, options?: ErrorOptions) => import("@poppinss/utils/exception").Exception;
63
67
  /**
64
68
  * Unable to read file
65
69
  */
66
- export declare const ENOENT: new (args?: any, options?: ErrorOptions) => import("@adonisjs/core/exceptions").Exception;
70
+ export declare const ENOENT: new (args?: any, options?: ErrorOptions) => import("@poppinss/utils/exception").Exception;
@@ -26,6 +26,10 @@ export const E_CANNOT_SET_VISIBILITY = errors.E_CANNOT_SET_VISIBILITY;
26
26
  * Unable to generate URL for a file
27
27
  */
28
28
  export const E_CANNOT_GENERATE_URL = errors.E_CANNOT_GENERATE_URL;
29
+ /**
30
+ * Unable to generate temp file
31
+ */
32
+ export const E_CANNOT_GENERATE_TEMP_FILE = createError('Cannot generate temp file "%s"', 'E_CANNOT_GENERATE_TEMP_FILE');
29
33
  /**
30
34
  * The file key has unallowed set of characters
31
35
  */