@quatrain/cloudwrapper 1.1.13 → 1.1.15

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/LICENSE.md ADDED
@@ -0,0 +1,15 @@
1
+ # LICENSE UPDATE NOTICE
2
+
3
+ As of 01/01/2026, Quatrain Core is licensed under the **GNU Affero General Public License v3.0 (AGPL v3)**.
4
+ Previous versions remain under the MIT License.
5
+
6
+ ## Why AGPL?
7
+
8
+ We believe in open collaboration for the development ecosystem. The AGPL ensures that any modification or deployment of this BaaS stack, including over a network, benefits the entire community.
9
+
10
+ ## Commercial Services & Enterprise Usage
11
+
12
+ We provide official deployment services, technical training, and certification for Quatrain Core.
13
+ For organizations requiring a non-copyleft license (commercial license) or custom proprietary integrations, please contact the copyright holder: **Quatrain Technologies**.
14
+
15
+ Copyright © 2024-2026 Quatrain Technologies. All Rights Reserved.
package/README.md ADDED
@@ -0,0 +1,172 @@
1
+ # @quatrain/cloudwrapper
2
+
3
+ Foundation package for cloud function wrappers. This package provides abstract base classes and type definitions for building cloud function triggers across different platforms (Firebase, Supabase, etc.).
4
+
5
+ ## Features
6
+
7
+ - Abstract base class for cloud wrapper implementations
8
+ - Type definitions for database and storage triggers
9
+ - Event payload types for cloud functions
10
+ - Static logger with "Cloud" namespace
11
+ - Platform-agnostic trigger definitions
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install @quatrain/cloudwrapper
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ### Extending AbstractCloudWrapper
22
+
23
+ ```typescript
24
+ import { AbstractCloudWrapper } from '@quatrain/cloudwrapper'
25
+
26
+ class MyCloudWrapper extends AbstractCloudWrapper {
27
+ constructor(params: any) {
28
+ super(params)
29
+ // Your initialization logic
30
+ }
31
+
32
+ // Implement your cloud-specific methods
33
+ }
34
+
35
+ const wrapper = new MyCloudWrapper({
36
+ projectId: 'my-project',
37
+ region: 'us-central1',
38
+ })
39
+ ```
40
+
41
+ ### Using CloudWrapper Logger
42
+
43
+ ```typescript
44
+ import { CloudWrapper } from '@quatrain/cloudwrapper'
45
+
46
+ CloudWrapper.logger.info('Cloud function initialized')
47
+ CloudWrapper.logger.debug('Processing event...')
48
+ CloudWrapper.logger.error('Error occurred:', error)
49
+ ```
50
+
51
+ ### Database Trigger Definition
52
+
53
+ ```typescript
54
+ import { DatabaseTriggerType } from '@quatrain/cloudwrapper'
55
+ import { BackendAction } from '@quatrain/backend'
56
+
57
+ const userTrigger: DatabaseTriggerType = {
58
+ name: 'onUserCreate',
59
+ event: BackendAction.CREATE,
60
+ script: async (payload) => {
61
+ // Handle user creation
62
+ console.log('New user:', payload.after)
63
+ },
64
+ model: 'User',
65
+ path: '/users/{userId}',
66
+ schema: 'public', // Optional
67
+ }
68
+ ```
69
+
70
+ ### Storage Trigger Definition
71
+
72
+ ```typescript
73
+ import {
74
+ StorageTriggerType,
75
+ StorageEventPayloadType,
76
+ } from '@quatrain/cloudwrapper'
77
+ import { BackendAction } from '@quatrain/backend'
78
+
79
+ const fileTrigger: StorageTriggerType = {
80
+ name: 'onFileUpload',
81
+ event: BackendAction.CREATE,
82
+ script: async (payload: StorageEventPayloadType) => {
83
+ const file = payload.after
84
+ console.log('File uploaded:', file?.fullPath)
85
+ console.log('Size:', file?.size, 'bytes')
86
+ },
87
+ }
88
+ ```
89
+
90
+ ### Multiple Events
91
+
92
+ ```typescript
93
+ import { DatabaseTriggerType } from '@quatrain/cloudwrapper'
94
+ import { BackendAction } from '@quatrain/backend'
95
+
96
+ const multiEventTrigger: DatabaseTriggerType = {
97
+ name: 'onPostChange',
98
+ event: [BackendAction.CREATE, BackendAction.UPDATE],
99
+ script: async (payload) => {
100
+ const before = payload.before
101
+ const after = payload.after
102
+
103
+ if (!before) {
104
+ console.log('Post created')
105
+ } else {
106
+ console.log('Post updated')
107
+ }
108
+ },
109
+ model: 'Post',
110
+ path: '/posts/{postId}',
111
+ }
112
+ ```
113
+
114
+ ## Type Definitions
115
+
116
+ ### DatabaseTriggerType
117
+
118
+ Defines triggers for database operations (create, update, delete).
119
+
120
+ ```typescript
121
+ interface DatabaseTriggerType {
122
+ name: string
123
+ event: BackendAction | BackendAction[]
124
+ script: Function
125
+ model: string // Database model/table name
126
+ path: string // Path pattern for the trigger
127
+ schema?: string // Optional database schema
128
+ }
129
+ ```
130
+
131
+ ### StorageTriggerType
132
+
133
+ Defines triggers for storage operations (file upload, update, delete).
134
+
135
+ ```typescript
136
+ interface StorageTriggerType {
137
+ name: string
138
+ event: BackendAction | BackendAction[]
139
+ script: Function
140
+ }
141
+ ```
142
+
143
+ ### StorageEventPayloadType
144
+
145
+ Payload structure for storage events.
146
+
147
+ ```typescript
148
+ interface StorageEventPayloadType {
149
+ before: FileType | undefined // File state before event
150
+ after: FileType | undefined // File state after event
151
+ context: any // Additional context
152
+ }
153
+ ```
154
+
155
+ ## Platform Adapters
156
+
157
+ This package serves as the foundation. Specific implementations are available:
158
+
159
+ - **[@quatrain/cloudwrapper-firebase](../cloudwrapper-firebase)** - Firebase Functions adapter
160
+ - **[@quatrain/cloudwrapper-supabase](../cloudwrapper-supabase)** - Supabase Edge Functions adapter
161
+
162
+ ## BackendAction Enum
163
+
164
+ Triggers use the `BackendAction` enum from `@quatrain/backend`:
165
+
166
+ - `BackendAction.CREATE` - Resource creation
167
+ - `BackendAction.UPDATE` - Resource modification
168
+ - `BackendAction.DELETE` - Resource deletion
169
+
170
+ ## License
171
+
172
+ AGPL-3.0-only
@@ -1,3 +1,4 @@
1
1
  import { Core } from '@quatrain/core';
2
2
  export declare class CloudWrapper extends Core {
3
+ static logger: any;
3
4
  }
@@ -1,7 +1,10 @@
1
1
  "use strict";
2
+ var _a;
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
3
4
  exports.CloudWrapper = void 0;
4
5
  const core_1 = require("@quatrain/core");
5
6
  class CloudWrapper extends core_1.Core {
6
7
  }
7
8
  exports.CloudWrapper = CloudWrapper;
9
+ _a = CloudWrapper;
10
+ CloudWrapper.logger = _a.addLogger('Cloud');
package/lib/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { AbstractCloudWrapper } from './AbstractCloudWrapper';
2
2
  import { CloudWrapper } from './CloudWrapper';
3
3
  import { DatabaseTriggerType } from './types/DatabaseTriggerType';
4
- export { AbstractCloudWrapper, CloudWrapper, DatabaseTriggerType };
4
+ import { StorageTriggerType } from './types/StorageTriggerType';
5
+ import { StorageEventPayloadType } from './types/StorageEventPayloadType';
6
+ export { AbstractCloudWrapper, CloudWrapper, DatabaseTriggerType, StorageTriggerType, StorageEventPayloadType, };
@@ -1,9 +1,6 @@
1
- import { BackendAction } from '@quatrain/backend';
2
- export type DatabaseTriggerType = {
3
- name: string;
4
- event: BackendAction | BackendAction[];
1
+ import { GenericTriggerType } from './GenericTriggerType';
2
+ export interface DatabaseTriggerType extends GenericTriggerType {
5
3
  schema?: string;
6
4
  model: string;
7
5
  path: string;
8
- script: Function;
9
- };
6
+ }
@@ -0,0 +1,5 @@
1
+ export interface GenericEventPayloadType {
2
+ before: any;
3
+ after: any;
4
+ context: any;
5
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ import { BackendAction } from '@quatrain/backend';
2
+ export type GenericTriggerType = {
3
+ name: string;
4
+ event: BackendAction | BackendAction[];
5
+ script: Function;
6
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ import { GenericEventPayloadType } from './GenericEventPayloadType';
2
+ import { FileType } from '@quatrain/storage';
3
+ export interface StorageEventPayloadType extends GenericEventPayloadType {
4
+ before: FileType | undefined;
5
+ after: FileType | undefined;
6
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,3 @@
1
+ import { GenericTriggerType } from './GenericTriggerType';
2
+ export interface StorageTriggerType extends GenericTriggerType {
3
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,40 +1,43 @@
1
1
  {
2
- "name": "@quatrain/cloudwrapper",
3
- "version": "1.1.13",
4
- "license": "MIT",
5
- "description": "Cloud wrappers commons",
6
- "main": "lib/index.js",
7
- "types": "lib/index.d.ts",
8
- "files": [
9
- "lib/",
10
- "README.md"
11
- ],
12
- "author": "Quatrain Développement SAS <developers@quatrain.com>",
13
- "peerDependencies": {
14
- "@quatrain/backend": "^1.1.12",
15
- "@quatrain/core": "^1.1.14"
16
- },
17
- "devDependencies": {
18
- "@tsconfig/recommended": "^1.0.1",
19
- "@types/jest": "^27.0.3",
20
- "@types/node": "^22.10.1",
21
- "jest": "^27.4.7",
22
- "jest-node-exports-resolver": "^1.1.6",
23
- "jest-serial-runner": "^1.2.1",
24
- "trace-unhandled": "^2.0.1",
25
- "ts-jest": "^27.1.2",
26
- "ts-node": "^10.9.1",
27
- "typescript": "^5.1.5"
28
- },
29
- "scripts": {
30
- "test-ci": "jest --runInBand",
31
- "build": "tsc",
32
- "wbuild": "tsc --watch",
33
- "bump-to": "yarn version",
34
- "hash": "node ../../bin/hashFolder.js",
35
- "hash:persist": "yarn hash > .hash_latest.txt",
36
- "hash:compare": "yarn hash > .hash_newest.txt && cmp -s .hash_latest.txt .hash_newest.txt",
37
- "publish": "yarn hash:compare || yarn publish:process",
38
- "publish:process": "yarn version patch && yarn build && yarn npm publish --access public && yarn hash:persist"
39
- }
40
- }
2
+ "name": "@quatrain/cloudwrapper",
3
+ "version": "1.1.15",
4
+ "license": "AGPL-3.0-only",
5
+ "description": "Cloud wrappers commons",
6
+ "main": "lib/index.js",
7
+ "types": "lib/index.d.ts",
8
+ "bun": "src/index.ts",
9
+ "files": [
10
+ "LICENSE.md",
11
+ "src/",
12
+ "lib/",
13
+ "README.md"
14
+ ],
15
+ "author": "Quatrain Développement SAS <developers@quatrain.com>",
16
+ "peerDependencies": {
17
+ "@quatrain/backend": "^1.1.26",
18
+ "@quatrain/core": "^1.1.42"
19
+ },
20
+ "devDependencies": {
21
+ "@tsconfig/recommended": "^1.0.1",
22
+ "@types/jest": "^30.0.0",
23
+ "@types/node": "^22.10.1",
24
+ "jest": "^30.2.0",
25
+ "jest-node-exports-resolver": "^1.1.6",
26
+ "jest-serial-runner": "^1.2.1",
27
+ "trace-unhandled": "^2.0.1",
28
+ "ts-jest": "^29.4.1",
29
+ "ts-node": "^10.9.1",
30
+ "typescript": "^5.2.2"
31
+ },
32
+ "scripts": {
33
+ "test-ci": "jest --runInBand",
34
+ "build": "tsc",
35
+ "wbuild": "tsc --watch",
36
+ "bump-to": "yarn version"
37
+ },
38
+ "dependencies": {
39
+ "@quatrain/backend": "^1.1.26",
40
+ "@quatrain/core": "^1.1.42",
41
+ "@quatrain/storage": "^1.1"
42
+ }
43
+ }
@@ -0,0 +1,7 @@
1
+ export class AbstractCloudWrapper {
2
+ protected _params: any
3
+
4
+ constructor(params: any) {
5
+ this._params = params
6
+ }
7
+ }
@@ -0,0 +1,232 @@
1
+ import { AbstractCloudWrapper } from './AbstractCloudWrapper'
2
+ import { CloudWrapper } from './CloudWrapper'
3
+ import {
4
+ DatabaseTriggerType,
5
+ StorageTriggerType,
6
+ StorageEventPayloadType,
7
+ } from './index'
8
+ import { BackendAction } from '@quatrain/backend'
9
+
10
+ describe('CloudWrapper Package', () => {
11
+ describe('AbstractCloudWrapper', () => {
12
+ it('should create instance with params', () => {
13
+ const params = { config: 'test-config', apiKey: 'test-key' }
14
+ const wrapper = new AbstractCloudWrapper(params)
15
+
16
+ expect(wrapper).toBeInstanceOf(AbstractCloudWrapper)
17
+ // Access protected property through any for testing
18
+ expect((wrapper as any)._params).toEqual(params)
19
+ })
20
+
21
+ it('should store empty params', () => {
22
+ const wrapper = new AbstractCloudWrapper({})
23
+
24
+ expect((wrapper as any)._params).toEqual({})
25
+ })
26
+
27
+ it('should store undefined params as undefined', () => {
28
+ const wrapper = new AbstractCloudWrapper(undefined)
29
+
30
+ expect((wrapper as any)._params).toBeUndefined()
31
+ })
32
+ })
33
+
34
+ describe('CloudWrapper', () => {
35
+ it('should extend Core class', () => {
36
+ // CloudWrapper extends Core, so it should have Core properties
37
+ expect(CloudWrapper).toBeDefined()
38
+ expect(typeof CloudWrapper).toBe('function')
39
+ })
40
+
41
+ it('should have logger property', () => {
42
+ expect(CloudWrapper.logger).toBeDefined()
43
+ expect(CloudWrapper.logger).toHaveProperty('debug')
44
+ expect(CloudWrapper.logger).toHaveProperty('info')
45
+ expect(CloudWrapper.logger).toHaveProperty('warn')
46
+ expect(CloudWrapper.logger).toHaveProperty('error')
47
+ })
48
+
49
+ it('should create logger with "Cloud" namespace', () => {
50
+ // The logger is created with 'Cloud' namespace
51
+ expect(CloudWrapper.logger).toBeDefined()
52
+ })
53
+ })
54
+
55
+ describe('Type Exports', () => {
56
+ describe('DatabaseTriggerType', () => {
57
+ it('should be importable', () => {
58
+ // Type check - if this compiles, the type exists
59
+ const trigger: DatabaseTriggerType = {
60
+ name: 'test-trigger',
61
+ event: BackendAction.CREATE,
62
+ script: () => {},
63
+ model: 'User',
64
+ path: '/users/{userId}',
65
+ schema: 'public',
66
+ }
67
+
68
+ expect(trigger).toBeDefined()
69
+ expect(trigger.name).toBe('test-trigger')
70
+ expect(trigger.model).toBe('User')
71
+ expect(trigger.path).toBe('/users/{userId}')
72
+ expect(trigger.schema).toBe('public')
73
+ })
74
+
75
+ it('should work without optional schema', () => {
76
+ const trigger: DatabaseTriggerType = {
77
+ name: 'test-trigger',
78
+ event: BackendAction.UPDATE,
79
+ script: () => {},
80
+ model: 'Post',
81
+ path: '/posts/{postId}',
82
+ }
83
+
84
+ expect(trigger).toBeDefined()
85
+ expect(trigger.schema).toBeUndefined()
86
+ })
87
+
88
+ it('should support array of events', () => {
89
+ const trigger: DatabaseTriggerType = {
90
+ name: 'multi-event-trigger',
91
+ event: [BackendAction.CREATE, BackendAction.UPDATE],
92
+ script: () => {},
93
+ model: 'Comment',
94
+ path: '/comments/{commentId}',
95
+ }
96
+
97
+ expect(trigger).toBeDefined()
98
+ expect(Array.isArray(trigger.event)).toBe(true)
99
+ })
100
+ })
101
+
102
+ describe('StorageTriggerType', () => {
103
+ it('should be importable', () => {
104
+ const trigger: StorageTriggerType = {
105
+ name: 'storage-trigger',
106
+ event: BackendAction.CREATE,
107
+ script: () => {},
108
+ }
109
+
110
+ expect(trigger).toBeDefined()
111
+ expect(trigger.name).toBe('storage-trigger')
112
+ })
113
+
114
+ it('should extend GenericTriggerType', () => {
115
+ // StorageTriggerType should have all GenericTriggerType properties
116
+ const trigger: StorageTriggerType = {
117
+ name: 'file-upload',
118
+ event: [
119
+ BackendAction.CREATE,
120
+ BackendAction.UPDATE,
121
+ BackendAction.DELETE,
122
+ ],
123
+ script: () => {},
124
+ }
125
+
126
+ expect(trigger.name).toBeDefined()
127
+ expect(trigger.event).toBeDefined()
128
+ expect(trigger.script).toBeDefined()
129
+ })
130
+ })
131
+
132
+ describe('StorageEventPayloadType', () => {
133
+ it('should be importable', () => {
134
+ const payload: StorageEventPayloadType = {
135
+ before: undefined,
136
+ after: {
137
+ name: 'test.jpg',
138
+ bucket: 'uploads',
139
+ fullPath: '/uploads/test.jpg',
140
+ contentType: 'image/jpeg',
141
+ size: 1024,
142
+ timeCreated: new Date(),
143
+ updated: new Date(),
144
+ },
145
+ context: {},
146
+ }
147
+
148
+ expect(payload).toBeDefined()
149
+ expect(payload.before).toBeUndefined()
150
+ expect(payload.after).toBeDefined()
151
+ })
152
+
153
+ it('should support before and after file objects', () => {
154
+ const fileData = {
155
+ name: 'document.pdf',
156
+ bucket: 'documents',
157
+ fullPath: '/documents/document.pdf',
158
+ contentType: 'application/pdf',
159
+ size: 2048,
160
+ timeCreated: new Date(),
161
+ updated: new Date(),
162
+ }
163
+
164
+ const payload: StorageEventPayloadType = {
165
+ before: fileData,
166
+ after: { ...fileData, size: 3072 }, // Modified size
167
+ context: { userId: 'user-123' },
168
+ }
169
+
170
+ expect(payload.before?.size).toBe(2048)
171
+ expect(payload.after?.size).toBe(3072)
172
+ expect(payload.context.userId).toBe('user-123')
173
+ })
174
+
175
+ it('should allow undefined before for create events', () => {
176
+ const payload: StorageEventPayloadType = {
177
+ before: undefined,
178
+ after: {
179
+ name: 'new-file.txt',
180
+ bucket: 'files',
181
+ fullPath: '/files/new-file.txt',
182
+ contentType: 'text/plain',
183
+ size: 512,
184
+ timeCreated: new Date(),
185
+ updated: new Date(),
186
+ },
187
+ context: {},
188
+ }
189
+
190
+ expect(payload.before).toBeUndefined()
191
+ expect(payload.after).toBeDefined()
192
+ })
193
+
194
+ it('should allow undefined after for delete events', () => {
195
+ const payload: StorageEventPayloadType = {
196
+ before: {
197
+ name: 'deleted-file.txt',
198
+ bucket: 'files',
199
+ fullPath: '/files/deleted-file.txt',
200
+ contentType: 'text/plain',
201
+ size: 256,
202
+ timeCreated: new Date(),
203
+ updated: new Date(),
204
+ },
205
+ after: undefined,
206
+ context: {},
207
+ }
208
+
209
+ expect(payload.before).toBeDefined()
210
+ expect(payload.after).toBeUndefined()
211
+ })
212
+ })
213
+ })
214
+
215
+ describe('Module Exports', () => {
216
+ it('should export AbstractCloudWrapper', () => {
217
+ expect(AbstractCloudWrapper).toBeDefined()
218
+ expect(typeof AbstractCloudWrapper).toBe('function')
219
+ })
220
+
221
+ it('should export CloudWrapper', () => {
222
+ expect(CloudWrapper).toBeDefined()
223
+ expect(typeof CloudWrapper).toBe('function')
224
+ })
225
+
226
+ it('should export all type definitions', () => {
227
+ // If these imports work, the exports are correct
228
+ // TypeScript will catch any export issues at compile time
229
+ expect(true).toBe(true)
230
+ })
231
+ })
232
+ })
@@ -0,0 +1,5 @@
1
+ import { Core } from '@quatrain/core'
2
+
3
+ export class CloudWrapper extends Core {
4
+ static logger = this.addLogger('Cloud')
5
+ }
package/src/index.ts ADDED
@@ -0,0 +1,13 @@
1
+ import { AbstractCloudWrapper } from './AbstractCloudWrapper'
2
+ import { CloudWrapper } from './CloudWrapper'
3
+ import { DatabaseTriggerType } from './types/DatabaseTriggerType'
4
+ import { StorageTriggerType } from './types/StorageTriggerType'
5
+ import { StorageEventPayloadType } from './types/StorageEventPayloadType'
6
+
7
+ export {
8
+ AbstractCloudWrapper,
9
+ CloudWrapper,
10
+ DatabaseTriggerType,
11
+ StorageTriggerType,
12
+ StorageEventPayloadType,
13
+ }
@@ -0,0 +1,7 @@
1
+ import { GenericTriggerType } from './GenericTriggerType'
2
+
3
+ export interface DatabaseTriggerType extends GenericTriggerType {
4
+ schema?: string
5
+ model: string
6
+ path: string
7
+ }
@@ -0,0 +1,5 @@
1
+ export interface GenericEventPayloadType {
2
+ before: any
3
+ after: any
4
+ context: any
5
+ }
@@ -0,0 +1,7 @@
1
+ import { BackendAction } from '@quatrain/backend'
2
+
3
+ export type GenericTriggerType = {
4
+ name: string
5
+ event: BackendAction | BackendAction[]
6
+ script: Function
7
+ }
@@ -0,0 +1,7 @@
1
+ import { GenericEventPayloadType } from './GenericEventPayloadType'
2
+ import { FileType } from '@quatrain/storage'
3
+
4
+ export interface StorageEventPayloadType extends GenericEventPayloadType {
5
+ before: FileType | undefined
6
+ after: FileType | undefined
7
+ }
@@ -0,0 +1,3 @@
1
+ import { GenericTriggerType } from './GenericTriggerType'
2
+
3
+ export interface StorageTriggerType extends GenericTriggerType {}