@toa.io/extensions.storages 1.0.0-alpha.21 → 1.0.0-alpha.219

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 (91) hide show
  1. package/package.json +14 -14
  2. package/readme.md +96 -51
  3. package/schemas/annotation.cos.yaml +1 -0
  4. package/schemas/cloudinary.cos.yaml +37 -0
  5. package/schemas/fs.cos.yaml +2 -0
  6. package/schemas/s3.cos.yaml +1 -0
  7. package/schemas/tmp.cos.yaml +0 -1
  8. package/source/Entry.ts +13 -11
  9. package/source/Factory.ts +16 -9
  10. package/source/Provider.ts +22 -19
  11. package/source/Scanner.ts +58 -26
  12. package/source/Secrets.ts +6 -0
  13. package/source/Storage.test.ts +118 -274
  14. package/source/Storage.ts +62 -207
  15. package/source/deployment.ts +52 -16
  16. package/source/errors.ts +3 -0
  17. package/source/index.ts +3 -1
  18. package/source/manifest.ts +7 -6
  19. package/source/providers/Cloudinary.ts +320 -0
  20. package/source/providers/Declaration.ts +2 -1
  21. package/source/providers/FileSystem.ts +79 -25
  22. package/source/providers/S3.ts +81 -80
  23. package/source/providers/Temporary.ts +2 -3
  24. package/source/providers/Test.ts +4 -4
  25. package/source/providers/index.test.ts +102 -76
  26. package/source/providers/index.ts +10 -4
  27. package/source/schemas.ts +1 -0
  28. package/source/test/.env.example +4 -0
  29. package/source/test/arny.jpg +0 -0
  30. package/source/test/lenna.48x48.jpeg +0 -0
  31. package/source/test/plank.mp4 +0 -0
  32. package/source/test/sample.avi +0 -0
  33. package/source/test/sample.wav +0 -0
  34. package/source/test/sport.mp4 +0 -0
  35. package/source/test/util.ts +62 -12
  36. package/transpiled/Entry.d.ts +15 -11
  37. package/transpiled/Factory.js +11 -5
  38. package/transpiled/Factory.js.map +1 -1
  39. package/transpiled/Provider.d.ts +17 -16
  40. package/transpiled/Provider.js +6 -4
  41. package/transpiled/Provider.js.map +1 -1
  42. package/transpiled/Scanner.d.ts +6 -2
  43. package/transpiled/Scanner.js +49 -22
  44. package/transpiled/Scanner.js.map +1 -1
  45. package/transpiled/Secrets.d.ts +5 -0
  46. package/transpiled/Secrets.js +3 -0
  47. package/transpiled/Secrets.js.map +1 -0
  48. package/transpiled/Storage.d.ts +13 -21
  49. package/transpiled/Storage.js +52 -155
  50. package/transpiled/Storage.js.map +1 -1
  51. package/transpiled/deployment.d.ts +1 -1
  52. package/transpiled/deployment.js +43 -16
  53. package/transpiled/deployment.js.map +1 -1
  54. package/transpiled/errors.d.ts +2 -0
  55. package/transpiled/errors.js +6 -0
  56. package/transpiled/errors.js.map +1 -0
  57. package/transpiled/index.d.ts +3 -1
  58. package/transpiled/manifest.js +5 -2
  59. package/transpiled/manifest.js.map +1 -1
  60. package/transpiled/providers/Cloudinary.d.ts +51 -0
  61. package/transpiled/providers/Cloudinary.js +223 -0
  62. package/transpiled/providers/Cloudinary.js.map +1 -0
  63. package/transpiled/providers/Declaration.d.ts +3 -2
  64. package/transpiled/providers/FileSystem.d.ts +15 -7
  65. package/transpiled/providers/FileSystem.js +64 -24
  66. package/transpiled/providers/FileSystem.js.map +1 -1
  67. package/transpiled/providers/S3.d.ts +14 -14
  68. package/transpiled/providers/S3.js +62 -60
  69. package/transpiled/providers/S3.js.map +1 -1
  70. package/transpiled/providers/Temporary.d.ts +1 -2
  71. package/transpiled/providers/Temporary.js +2 -2
  72. package/transpiled/providers/Temporary.js.map +1 -1
  73. package/transpiled/providers/Test.d.ts +3 -3
  74. package/transpiled/providers/Test.js +2 -2
  75. package/transpiled/providers/Test.js.map +1 -1
  76. package/transpiled/providers/index.d.ts +7 -2
  77. package/transpiled/providers/index.js +2 -2
  78. package/transpiled/providers/index.js.map +1 -1
  79. package/transpiled/schemas.d.ts +1 -0
  80. package/transpiled/schemas.js +2 -1
  81. package/transpiled/schemas.js.map +1 -1
  82. package/transpiled/test/util.d.ts +89 -5
  83. package/transpiled/test/util.js +51 -4
  84. package/transpiled/test/util.js.map +1 -1
  85. package/transpiled/tsconfig.tsbuildinfo +1 -1
  86. package/source/providers/FileSystem.test.ts +0 -5
  87. package/source/providers/Memory.ts +0 -41
  88. package/source/providers/S3.test.ts +0 -133
  89. package/transpiled/providers/Memory.d.ts +0 -13
  90. package/transpiled/providers/Memory.js +0 -60
  91. package/transpiled/providers/Memory.js.map +0 -1
@@ -1,16 +1,15 @@
1
1
  import { tmpdir } from 'node:os'
2
2
  import { join } from 'node:path'
3
3
  import { FileSystem } from './FileSystem'
4
- import type { ProviderSecrets } from '../Provider'
5
4
 
6
5
  export interface TemporaryOptions {
7
6
  directory: string
8
7
  }
9
8
 
10
9
  export class Temporary extends FileSystem {
11
- public constructor (options: TemporaryOptions, secrets?: ProviderSecrets) {
10
+ public constructor (options: TemporaryOptions) {
12
11
  const path = join(tmpdir(), options.directory)
13
12
 
14
- super({ path }, secrets)
13
+ super({ path })
15
14
  }
16
15
  }
@@ -1,13 +1,13 @@
1
1
  import { Temporary, type TemporaryOptions } from './Temporary'
2
- import type { ProviderSecret, ProviderSecrets } from '../Provider'
2
+ import type { Secret } from '../Secrets'
3
3
 
4
4
  export class Test extends Temporary {
5
- public static override readonly SECRETS: readonly ProviderSecret[] = [
5
+ public static override readonly SECRETS: readonly Secret[] = [
6
6
  { name: 'USERNAME' },
7
7
  { name: 'PASSWORD' }
8
8
  ]
9
9
 
10
- public constructor (options: TemporaryOptions, secrets?: ProviderSecrets) {
11
- super(options, secrets)
10
+ public constructor (options: TemporaryOptions) {
11
+ super(options)
12
12
  }
13
13
  }
@@ -1,126 +1,152 @@
1
- import { type Readable } from 'node:stream'
2
- import { buffer } from 'node:stream/consumers'
3
- import { readFile } from 'node:fs/promises'
1
+ import assert from 'node:assert'
4
2
  import { createReadStream } from 'node:fs'
5
- import path from 'node:path'
6
- import { randomUUID } from 'node:crypto'
3
+ import { resolve } from 'node:path'
7
4
  import { suites } from '../test/util'
8
5
  import { providers } from './index'
9
- import type { ProviderConstructor } from '../Provider'
6
+ import type { Constructor } from '../Provider'
7
+ import type { Metadata, Stream } from '../Entry'
8
+
9
+ const sample = resolve(__dirname, '../test/sample.jpeg')
10
+ const lenna = resolve(__dirname, '../test/lenna.png')
11
+
12
+ const metadata: Metadata = {
13
+ type: 'image/jpeg',
14
+ size: 73444,
15
+ checksum: 'd41d8cd98f00b204e9800998ecf8427e',
16
+ created: new Date().toISOString(),
17
+ attributes: {}
18
+ }
10
19
 
11
20
  describe.each(suites)('$provider', (suite) => {
21
+ const id = Math.random().toString(36).substring(7)
12
22
  const it = suite.run ? global.it : global.it.skip
13
- const Provider: ProviderConstructor = providers[suite.provider]
23
+ const Provider: Constructor = providers[suite.provider]
14
24
  const provider = new Provider(suite.options, suite.secrets)
15
25
 
16
- let dir: string
26
+ describe('put, get, head', () => {
27
+ let entry: Stream
17
28
 
18
- beforeAll(async () => {
19
- process.chdir(path.resolve(__dirname, '../test/'))
20
- })
29
+ beforeAll(async () => {
30
+ await provider.put(id, createReadStream(sample))
31
+ await provider.commit(id, metadata)
21
32
 
22
- beforeEach(() => {
23
- dir = '/' + randomUUID()
24
- })
33
+ entry = await provider.get(id) as Stream
34
+ })
25
35
 
26
- it('should be', async () => {
27
- expect(provider).toBeInstanceOf(Provider)
28
- })
36
+ afterAll(() => entry.stream.destroy())
29
37
 
30
- it('should return null if file not found', async () => {
31
- const result = await provider.get(randomUUID())
38
+ it('should create metadata', async () => {
39
+ expect(entry.size).toEqual(metadata.size)
40
+ })
32
41
 
33
- expect(result).toBeNull()
34
- })
42
+ if (suite.provider !== 'cloudinary')
43
+ it('should store attributes', async () => {
44
+ const path = '/path/to/file'
35
45
 
36
- it('should create entry', async () => {
37
- const stream = createReadStream('lenna.png')
46
+ await provider.put(path, createReadStream(sample))
47
+ await provider.commit(path, { ...metadata, attributes: { foo: 'bar' } })
38
48
 
39
- await provider.put(dir, 'lenna.png', stream)
49
+ const entry = await provider.get(path) as Stream
40
50
 
41
- const readable = await provider.get(dir + '/lenna.png') as Readable
42
- const output = await buffer(readable)
43
- const lenna = await readFile('lenna.png')
51
+ expect(entry.attributes).toEqual({ foo: 'bar' })
44
52
 
45
- expect(output.compare(lenna)).toBe(0)
46
- })
53
+ entry.stream.destroy()
54
+ })
47
55
 
48
- it('should overwrite existing entry', async () => {
49
- const stream0 = createReadStream('lenna.png')
50
- const stream1 = createReadStream('albert.jpg')
56
+ it('should overwrite', async () => {
57
+ const path = Math.random().toString(36).substring(7)
51
58
 
52
- await provider.put(dir, 'lenna.png', stream0)
53
- await provider.put(dir, 'lenna.png', stream1)
59
+ await provider.put(path, createReadStream(sample))
60
+ await provider.commit(path, metadata)
54
61
 
55
- const readable = await provider.get(dir + '/lenna.png') as Readable
56
- const output = await buffer(readable)
57
- const albert = await readFile('albert.jpg')
62
+ if (suite.provider === 'cloudinary')
63
+ await new Promise((resolve) => setTimeout(resolve, 5_000))
58
64
 
59
- expect(output.compare(albert)).toBe(0)
60
- })
65
+ await expect(provider.put(path, createReadStream(lenna)))
66
+ .resolves.not.toThrow()
61
67
 
62
- it('should get by path', async () => {
63
- const stream = createReadStream('lenna.png')
68
+ const meta = { ...metadata, size: 473831 } // lenna size
64
69
 
65
- await provider.put(dir, 'lenna.png', stream)
70
+ await provider.commit(path, meta)
66
71
 
67
- const result = await provider.get('/bar/lenna.png')
72
+ if (suite.provider === 'cloudinary')
73
+ await new Promise((resolve) => setTimeout(resolve, 10_000))
68
74
 
69
- expect(result).toBeNull()
70
- })
75
+ const overwritten = await provider.get(path) as Stream
71
76
 
72
- describe('danger', () => {
73
- /*
77
+ expect(overwritten.size).toEqual(meta.size)
74
78
 
75
- WHEN MAKING CHANGES TO DELETION,
76
- ALWAYS RUN TESTS IN STEP-BY-STEP DEBUGGING MODE
79
+ overwritten.stream.destroy()
80
+ })
77
81
 
78
- YOU MAY EVENTUALLY DELETE YOUR ENTIRE FILE SYSTEM
82
+ it('should return error if not found', async () => {
83
+ const error = await provider.get(Math.random().toString(36).substring(7)) as any
79
84
 
80
- Sincerely yours, Murphy
85
+ expect(error).toBeInstanceOf(Error)
86
+ expect(error.code).toBe('NOT_FOUND')
87
+ })
88
+
89
+ it('should return entry', async () => {
90
+ const entry = await provider.head(id)
91
+
92
+ assert.ok(!(entry instanceof Error))
81
93
 
82
- */
94
+ expect(entry.size).toEqual(metadata.size)
95
+ })
96
+ })
83
97
 
84
- it('should delete entry', async () => {
85
- const stream = createReadStream('lenna.png')
98
+ describe('delete', () => {
99
+ const path = '/path/to/' + Math.random().toString(36).substring(7)
86
100
 
87
- await provider.put(dir, 'lenna.png', stream)
88
- await provider.delete(dir + '/lenna.png')
101
+ it('should remove file', async () => {
102
+ await provider.put(path, createReadStream(sample))
103
+ await provider.commit(path, metadata)
104
+ await provider.delete(path)
89
105
 
90
- const result = await provider.get(dir + '/lenna.png')
106
+ const error = await provider.get(path) as any
91
107
 
92
- expect(result).toBeNull()
108
+ expect(error).toBeInstanceOf(Error)
109
+ expect(error.code).toBe('NOT_FOUND')
93
110
  })
94
111
 
95
- it('should not throw if path does not exists', async () => {
96
- await expect(provider.delete(dir + '/whatever')).resolves.not.toThrow()
112
+ it('should not return error if not found', async () => {
113
+ const empty = await provider.delete(Math.random().toString(36).substring(7))
114
+
115
+ expect(empty).toBeUndefined()
97
116
  })
117
+ })
98
118
 
99
- it('should delete directory', async () => {
100
- const stream = createReadStream('lenna.png')
119
+ describe('move', () => {
120
+ it.each([true, false])('should move (commit: %s)', async (committed) => {
121
+ const from = Math.random().toString(36).substring(7)
122
+ const to = Math.random().toString(36).substring(7)
101
123
 
102
- await provider.put(dir, 'lenna.png', stream)
103
- await provider.delete(dir)
124
+ await provider.put(from, createReadStream(sample))
104
125
 
105
- const result = await provider.get(dir + '/lenna.png')
126
+ if (committed)
127
+ await provider.commit(from, metadata)
106
128
 
107
- expect(result).toBeNull()
108
- })
129
+ await provider.move(from, to)
109
130
 
110
- it('should move an entry', async () => {
111
- const stream = createReadStream('lenna.png')
112
- const dir2 = '/' + randomUUID()
131
+ if (!committed)
132
+ await provider.commit(to, metadata)
113
133
 
114
- await provider.put(dir, 'lenna.png', stream)
115
- await provider.move(dir + '/lenna.png', dir2 + '/lenna2.png')
134
+ const error = await provider.get(from) as any
116
135
 
117
- const result = await provider.get(dir2 + '/lenna2.png') as Readable
136
+ expect(error).toBeInstanceOf(Error)
118
137
 
119
- expect(result).not.toBeNull()
138
+ const entry = await provider.get(to) as Stream
120
139
 
121
- const nope = await provider.get(dir + '/lenna.png')
140
+ expect(entry.stream).toBeDefined()
141
+ })
122
142
 
123
- expect(nope).toBeNull()
143
+ it('should return error if not found', async () => {
144
+ const error = await provider.move(Math.random().toString(36).substring(7), 'whatever') as any
145
+
146
+ expect(error).toBeInstanceOf(Error)
147
+ expect(error.code).toBe('NOT_FOUND')
124
148
  })
125
149
  })
126
150
  })
151
+
152
+ jest.setTimeout(30_000)
@@ -1,16 +1,22 @@
1
1
  import { FileSystem } from './FileSystem'
2
2
  import { S3 } from './S3'
3
+ import { Cloudinary } from './Cloudinary'
3
4
  import { Temporary } from './Temporary'
4
5
  import { Test } from './Test'
5
- import { InMemory } from './Memory'
6
- import type { ProviderConstructor } from '../Provider'
6
+ import type { Constructor } from '../Provider'
7
7
 
8
8
  export const providers = {
9
9
  s3: S3,
10
+ cloudinary: Cloudinary,
10
11
  fs: FileSystem,
11
12
  tmp: Temporary,
12
- mem: InMemory,
13
13
  test: Test
14
- } as const satisfies Record<string, ProviderConstructor>
14
+ } as const satisfies Record<string, Constructor>
15
15
 
16
16
  export type { Declaration } from './Declaration'
17
+
18
+ export type { S3Options } from './S3'
19
+ export type { CloudinaryOptions } from './Cloudinary'
20
+ export type { FileSystemOptions } from './FileSystem'
21
+ export type { TemporaryOptions } from './Temporary'
22
+ export type { FileSystem, S3, Cloudinary, Temporary }
package/source/schemas.ts CHANGED
@@ -9,6 +9,7 @@ const ns = namespace(path)
9
9
 
10
10
  export const annotation: Schema<Annotation> = ns.schema<Annotation>('annotation')
11
11
  export const s3: Schema<Declaration> = ns.schema<Declaration>('s3')
12
+ export const cloudinary: Schema<Declaration> = ns.schema<Declaration>('cloudinary')
12
13
  export const fs: Schema<Declaration> = ns.schema<Declaration>('fs')
13
14
  export const mem: Schema<Declaration> = ns.schema<Declaration>('mem')
14
15
  export const tmp: Schema<Declaration> = ns.schema<Declaration>('tmp')
@@ -1 +1,5 @@
1
1
  RUN_S3=1
2
+ RUN_CLOUDINARY=1
3
+
4
+ CLOUDINARY_API_KEY=cloudinary_api_key
5
+ CLOUDINARY_API_SECRET=cloudinary_api_secret
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -1,10 +1,13 @@
1
1
  import { join } from 'node:path'
2
2
  import dotenv from 'dotenv'
3
- import type { ProviderSecrets } from '../Provider'
4
- import type { providers } from '../providers'
5
- import type { FileSystemOptions } from '../providers/FileSystem'
6
- import type { S3Options } from '../providers/S3'
7
- import type { TemporaryOptions } from '../providers/Temporary'
3
+ import type { Secrets } from '../Secrets'
4
+ import type {
5
+ providers,
6
+ S3Options,
7
+ CloudinaryOptions,
8
+ FileSystemOptions,
9
+ TemporaryOptions
10
+ } from '../providers'
8
11
 
9
12
  dotenv.config({ path: join(__dirname, '.env') })
10
13
 
@@ -16,10 +19,6 @@ export const suites = [
16
19
  directory: 'toa-storages-temp'
17
20
  }
18
21
  },
19
- {
20
- run: true,
21
- provider: 'mem'
22
- },
23
22
  {
24
23
  run: process.env.RUN_S3 === '1',
25
24
  provider: 's3',
@@ -32,14 +31,65 @@ export const suites = [
32
31
  ACCESS_KEY_ID: 'developer',
33
32
  SECRET_ACCESS_KEY: 'secret'
34
33
  }
34
+ },
35
+ {
36
+ run: process.env.RUN_CLOUDINARY === '1',
37
+ provider: 'cloudinary',
38
+ options: {
39
+ environment: 'dl5z4zgth',
40
+ type: 'image',
41
+ prefix: 'toa-dev',
42
+ transformations: [
43
+ {
44
+ extension: '(?<width>\\d*)x(?<height>\\d*)(z(?<zoom>\\d*))?',
45
+ transformation: {
46
+ width: '<width>',
47
+ height: '<height>',
48
+ zoom: '<zoom>',
49
+ crop: 'thumb',
50
+ gravity: 'face'
51
+ },
52
+ optional: true
53
+ },
54
+ {
55
+ extension: '\\[(?<width>\\d*)x(?<height>\\d*)\\](z(?<zoom>\\d+))?',
56
+ transformation: {
57
+ width: '<width>',
58
+ height: '<height>',
59
+ zoom: '<zoom>',
60
+ crop: 'fit'
61
+ },
62
+ optional: true
63
+ },
64
+ {
65
+ extension: 'vertical',
66
+ condition: 'w_gt_h',
67
+ transformation: {
68
+ angle: 90
69
+ },
70
+ optional: true
71
+ },
72
+ {
73
+ extension: '(?<format>jpeg|webp)',
74
+ transformation: {
75
+ fetch_format: '<format>'
76
+ },
77
+ optional: true
78
+ }
79
+ ]
80
+ },
81
+ secrets: {
82
+ API_KEY: process.env.CLOUDINARY_API_KEY ?? '',
83
+ API_SECRET: process.env.CLOUDINARY_API_SECRET ?? ''
84
+ }
35
85
  }
36
86
  // add more providers here, use `run` as a condition to run the test
37
87
  // e.g.: `run: process.env.ACCESS_KEY_ID !== undefined`
38
88
  ] satisfies Suite[]
39
89
 
40
- interface Suite {
90
+ export interface Suite {
41
91
  run: boolean
42
92
  provider: keyof typeof providers
43
- options?: FileSystemOptions | S3Options | TemporaryOptions
44
- secrets?: ProviderSecrets
93
+ options?: S3Options | CloudinaryOptions | FileSystemOptions | TemporaryOptions
94
+ secrets?: Secrets
45
95
  }
@@ -1,14 +1,18 @@
1
- export interface Entry {
1
+ /// <reference types="node" />
2
+ import type { Readable } from 'node:stream';
3
+ export type Entry = {
2
4
  id: string;
3
- size: number;
5
+ } & Metadata;
6
+ export type Stream = {
7
+ stream: Readable;
8
+ } & Metadata;
9
+ export interface Metadata {
4
10
  type: string;
5
- created: number;
6
- variants: Variant[];
7
- meta: Record<string, unknown>;
11
+ size: number | null;
12
+ checksum: string;
13
+ created: string;
14
+ attributes: Attributes;
15
+ range?: string;
16
+ partial?: boolean;
8
17
  }
9
- interface Variant {
10
- name: string;
11
- size: number;
12
- type: string;
13
- }
14
- export {};
18
+ export type Attributes = Record<string, string>;
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.Factory = void 0;
7
7
  const node_assert_1 = __importDefault(require("node:assert"));
8
+ const openspan_1 = require("openspan");
8
9
  const generic_1 = require("@toa.io/generic");
9
10
  const providers_1 = require("./providers");
10
11
  const Storage_1 = require("./Storage");
@@ -14,8 +15,8 @@ const Annotation_1 = require("./Annotation");
14
15
  class Factory {
15
16
  annotation;
16
17
  constructor() {
17
- const env = process.env.TOA_STORAGES;
18
- node_assert_1.default.ok(env !== undefined, 'TOA_STORAGES is not defined');
18
+ const env = process.env[deployment_1.ENV_PREFIX];
19
+ node_assert_1.default.ok(env !== undefined, `${deployment_1.ENV_PREFIX} is not defined`);
19
20
  this.annotation = (0, generic_1.decode)(env);
20
21
  (0, Annotation_1.validateAnnotation)(this.annotation);
21
22
  }
@@ -30,10 +31,15 @@ class Factory {
30
31
  return storages;
31
32
  }
32
33
  createStorage(name, declaration) {
33
- const { provider: providerId, ...options } = declaration;
34
- const Provider = providers_1.providers[providerId];
34
+ const { provider: id, ...options } = declaration;
35
+ const Provider = providers_1.providers[id];
35
36
  const secrets = this.resolveSecrets(name, Provider);
36
37
  const provider = new Provider(options, secrets);
38
+ openspan_1.console.debug('Storage created', {
39
+ name,
40
+ provider: id,
41
+ ...(provider.root === undefined ? undefined : { root: provider.root })
42
+ });
37
43
  return new Storage_1.Storage(provider);
38
44
  }
39
45
  resolveSecrets(storageName, Class) {
@@ -41,7 +47,7 @@ class Factory {
41
47
  return {};
42
48
  const secrets = {};
43
49
  for (const secret of Class.SECRETS) {
44
- const variable = `${deployment_1.SERIALIZATION_PREFIX}_${storageName}_${secret.name}`.toUpperCase();
50
+ const variable = `${deployment_1.ENV_PREFIX}_${storageName}_${secret.name}`.toUpperCase();
45
51
  const value = process.env[variable];
46
52
  node_assert_1.default.ok(secret.optional === true || value !== undefined, `'${variable}' is not defined`);
47
53
  secrets[secret.name] = value;
@@ -1 +1 @@
1
- {"version":3,"file":"Factory.js","sourceRoot":"","sources":["../source/Factory.ts"],"names":[],"mappings":";;;;;;AAAA,8DAAgC;AAChC,6CAAwC;AACxC,2CAAuC;AACvC,uCAAkD;AAClD,qCAAiC;AACjC,6CAAmD;AACnD,6CAAiD;AAKjD,MAAa,OAAO;IACD,UAAU,CAAY;IAEvC;QACE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAA;QAEpC,qBAAM,CAAC,EAAE,CAAC,GAAG,KAAK,SAAS,EAAE,6BAA6B,CAAC,CAAA;QAE3D,IAAI,CAAC,UAAU,GAAG,IAAA,gBAAM,EAAC,GAAG,CAAC,CAAA;QAE7B,IAAA,+BAAkB,EAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IACrC,CAAC;IAEM,MAAM;QACX,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,EAAE,CAAA;QAEtC,OAAO,IAAI,eAAM,CAAC,QAAQ,CAAC,CAAA;IAC7B,CAAC;IAEO,cAAc;QACpB,MAAM,QAAQ,GAAa,EAAE,CAAA;QAE7B,KAAK,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC;YAC/D,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,WAAW,CAAC,CAAA;QAExD,OAAO,QAAQ,CAAA;IACjB,CAAC;IAEO,aAAa,CAAE,IAAY,EAAE,WAAwB;QAC3D,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,OAAO,EAAE,GAAG,WAAW,CAAA;QACxD,MAAM,QAAQ,GAAwB,qBAAS,CAAC,UAAU,CAAC,CAAA;QAC3D,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;QACnD,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QAE/C,OAAO,IAAI,iBAAO,CAAC,QAAQ,CAAC,CAAA;IAC9B,CAAC;IAEO,cAAc,CAAE,WAAmB,EACzC,KAA0B;QAC1B,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;YAC7B,OAAO,EAAE,CAAA;QAEX,MAAM,OAAO,GAAuC,EAAE,CAAA;QAEtD,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YACnC,MAAM,QAAQ,GAAG,GAAG,iCAAoB,IAAI,WAAW,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;YACtF,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;YAEnC,qBAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EACvD,IAAI,QAAQ,kBAAkB,CAAC,CAAA;YAEjC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAA;QAC9B,CAAC;QAED,OAAO,OAAO,CAAA;IAChB,CAAC;CACF;AAxDD,0BAwDC"}
1
+ {"version":3,"file":"Factory.js","sourceRoot":"","sources":["../source/Factory.ts"],"names":[],"mappings":";;;;;;AAAA,8DAAgC;AAChC,uCAAkC;AAClC,6CAAwC;AACxC,2CAAuC;AACvC,uCAAkD;AAClD,qCAAiC;AACjC,6CAAyC;AACzC,6CAAiD;AAMjD,MAAa,OAAO;IACD,UAAU,CAAY;IAEvC;QACE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAU,CAAC,CAAA;QAEnC,qBAAM,CAAC,EAAE,CAAC,GAAG,KAAK,SAAS,EAAE,GAAG,uBAAU,iBAAiB,CAAC,CAAA;QAE5D,IAAI,CAAC,UAAU,GAAG,IAAA,gBAAM,EAAC,GAAG,CAAC,CAAA;QAE7B,IAAA,+BAAkB,EAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IACrC,CAAC;IAEM,MAAM;QACX,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,EAAE,CAAA;QAEtC,OAAO,IAAI,eAAM,CAAC,QAAQ,CAAC,CAAA;IAC7B,CAAC;IAEO,cAAc;QACpB,MAAM,QAAQ,GAAa,EAAE,CAAA;QAE7B,KAAK,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC;YAC/D,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,WAAW,CAAC,CAAA;QAExD,OAAO,QAAQ,CAAA;IACjB,CAAC;IAEO,aAAa,CAAE,IAAY,EAAE,WAAwB;QAC3D,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,GAAG,OAAO,EAAE,GAAG,WAAW,CAAA;QAChD,MAAM,QAAQ,GAAgB,qBAAS,CAAC,EAAE,CAAC,CAAA;QAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;QACnD,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QAE/C,kBAAO,CAAC,KAAK,CAAC,iBAAiB,EAAE;YAC/B,IAAI;YACJ,QAAQ,EAAE,EAAE;YACZ,GAAG,CAAC,QAAQ,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;SACvE,CAAC,CAAA;QAEF,OAAO,IAAI,iBAAO,CAAC,QAAQ,CAAC,CAAA;IAC9B,CAAC;IAEO,cAAc,CAAE,WAAmB,EAAE,KAAkB;QAC7D,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;YAC7B,OAAO,EAAE,CAAA;QAEX,MAAM,OAAO,GAAuC,EAAE,CAAA;QAEtD,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YACnC,MAAM,QAAQ,GAAG,GAAG,uBAAU,IAAI,WAAW,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;YAC5E,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;YAEnC,qBAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EACvD,IAAI,QAAQ,kBAAkB,CAAC,CAAA;YAEjC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAA;QAC9B,CAAC;QAED,OAAO,OAAO,CAAA;IAChB,CAAC;CACF;AA7DD,0BA6DC"}
@@ -1,20 +1,21 @@
1
1
  /// <reference types="node" />
2
- import { type Readable } from 'node:stream';
3
- export type ProviderSecrets<K extends string = string> = Record<K | string, string | undefined>;
4
- export interface ProviderSecret {
5
- readonly name: string;
6
- readonly optional?: boolean;
7
- }
8
- export declare abstract class Provider<Options = void> {
9
- static readonly SECRETS: readonly ProviderSecret[];
10
- constructor(_: Options, secrets?: ProviderSecrets);
11
- abstract get(path: string): Promise<Readable | null>;
12
- abstract put(path: string, filename: string, stream: Readable): Promise<void>;
2
+ import type { Metadata, Stream } from './Entry';
3
+ import type { Readable } from 'node:stream';
4
+ import type { Maybe } from '@toa.io/types';
5
+ import type { Secret, Secrets } from './Secrets';
6
+ export declare abstract class Provider<Options = unknown> {
7
+ static readonly SECRETS?: readonly Secret[];
8
+ readonly root?: string;
9
+ readonly options: Options;
10
+ protected constructor(options: Options, secrets?: Secrets);
11
+ abstract get(path: string, options?: unknown): Promise<Maybe<Stream>>;
12
+ abstract head(path: string): Promise<Maybe<Metadata>>;
13
+ abstract put(path: string, stream: Readable): Promise<void>;
14
+ abstract commit(path: string, metadata: Metadata): Promise<void>;
13
15
  abstract delete(path: string): Promise<void>;
14
- abstract move(from: string, to: string): Promise<void>;
16
+ abstract move(from: string, to: string): Promise<Maybe<void>>;
15
17
  }
16
- export interface ProviderConstructor {
17
- readonly SECRETS: readonly ProviderSecret[];
18
- prototype: Provider;
19
- new (options: any, secrets?: ProviderSecrets): Provider;
18
+ export interface Constructor<Options = any> {
19
+ SECRETS?: readonly Secret[];
20
+ new (options: Options, secrets?: Secrets): Provider<Options>;
20
21
  }
@@ -26,10 +26,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.Provider = void 0;
27
27
  const assert = __importStar(require("node:assert"));
28
28
  class Provider {
29
- static SECRETS = [];
30
- constructor(_, secrets) {
31
- for (const { name, optional = false } of new.target.SECRETS)
32
- assert.ok(optional || secrets?.[name] !== undefined, `Missing secret '${name}'`);
29
+ static SECRETS;
30
+ root;
31
+ options;
32
+ constructor(options, secrets) {
33
+ this.options = options;
34
+ new.target.SECRETS?.forEach(({ name, optional }) => assert.ok(optional === true || secrets?.[name] !== undefined, `Missing secret '${name}'`));
33
35
  }
34
36
  }
35
37
  exports.Provider = Provider;
@@ -1 +1 @@
1
- {"version":3,"file":"Provider.js","sourceRoot":"","sources":["../source/Provider.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AACA,oDAAqC;AASrC,MAAsB,QAAQ;IACrB,MAAM,CAAU,OAAO,GAA8B,EAAE,CAAA;IAE9D,YAAoB,CAAU,EAAE,OAAyB;QACvD,KAAK,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,KAAK,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO;YACzD,MAAM,CAAC,EAAE,CAAC,QAAQ,IAAI,OAAO,EAAE,CAAC,IAAI,CAAC,KAAK,SAAS,EAAE,mBAAmB,IAAI,GAAG,CAAC,CAAA;IACpF,CAAC;;AANH,4BAeC"}
1
+ {"version":3,"file":"Provider.js","sourceRoot":"","sources":["../source/Provider.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,oDAAqC;AAMrC,MAAsB,QAAQ;IACrB,MAAM,CAAU,OAAO,CAAoB;IAClC,IAAI,CAAS;IACb,OAAO,CAAS;IAEhC,YAAuB,OAAgB,EAAE,OAAiB;QACxD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QAEtB,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CACjD,MAAM,CAAC,EAAE,CAAC,QAAQ,KAAK,IAAI,IAAI,OAAO,EAAE,CAAC,IAAI,CAAC,KAAK,SAAS,EAAE,mBAAmB,IAAI,GAAG,CAAC,CAAC,CAAA;IAC9F,CAAC;CAaF;AAvBD,4BAuBC"}
@@ -1,15 +1,17 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
+ /// <reference types="node" />
3
4
  import { PassThrough, type TransformCallback } from 'node:stream';
4
5
  export declare class Scanner extends PassThrough {
5
6
  size: number;
6
7
  type: string;
7
- error: Error | null;
8
+ error?: Error;
8
9
  private readonly hash;
9
10
  private readonly claim?;
10
11
  private readonly accept?;
12
+ private readonly limit?;
11
13
  private position;
12
- private detected;
14
+ private completed;
13
15
  private readonly chunks;
14
16
  constructor(control?: ScanOptions);
15
17
  digest(): string;
@@ -18,9 +20,11 @@ export declare class Scanner extends PassThrough {
18
20
  private complete;
19
21
  private verify;
20
22
  private match;
23
+ private negotiate;
21
24
  private interrupt;
22
25
  }
23
26
  export interface ScanOptions {
24
27
  claim?: string;
25
28
  accept?: string;
29
+ limit?: number;
26
30
  }