@managemint-solutions/sdk 0.2.0 → 0.4.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.
- package/README.md +35 -2
- package/dist/client.d.ts +4 -0
- package/dist/client.js +6 -0
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts +7 -0
- package/dist/errors.js +12 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/notes/dto.d.ts +15 -0
- package/dist/notes/dto.js +46 -0
- package/dist/notes/dto.js.map +1 -0
- package/dist/notes/index.d.ts +16 -0
- package/dist/notes/index.js +98 -0
- package/dist/notes/index.js.map +1 -0
- package/dist/supporting-files/dto.d.ts +9 -0
- package/dist/supporting-files/dto.js +39 -0
- package/dist/supporting-files/dto.js.map +1 -0
- package/dist/supporting-files/index.d.ts +16 -0
- package/dist/supporting-files/index.js +130 -0
- package/dist/supporting-files/index.js.map +1 -0
- package/dist/supporting-files/paths.d.ts +12 -0
- package/dist/supporting-files/paths.js +18 -0
- package/dist/supporting-files/paths.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,8 @@ npm install @managemint-solutions/sdk @supabase/supabase-js
|
|
|
12
12
|
`@supabase/supabase-js` (^2.103.0), `class-validator` (^0.15) and `class-transformer` (^0.5)
|
|
13
13
|
are peer dependencies — the request DTOs (`AddStatusDto`, `UpdateStatusDto`, `StatusIdDto`,
|
|
14
14
|
`GetStatusesDto`, `AddAdditionalDetailsDto`, `UpdateAdditionalDetailsDto`,
|
|
15
|
-
`AdditionalDetailsIdDto`, `GetAdditionalDetailsDto`
|
|
15
|
+
`AdditionalDetailsIdDto`, `GetAdditionalDetailsDto`, `AddNoteDto`, `NoteIdDto`,
|
|
16
|
+
`GetNotesDto`, `SupportingFileIdDto`, `GetSupportingFilesDto`) ship with their class-validator
|
|
16
17
|
decorators so consumers validate against
|
|
17
18
|
the same rules the SDK's input types describe. `@nestjs/common` (^11) is an optional peer
|
|
18
19
|
dependency, needed only for the `@managemint-solutions/sdk/nest` subpath.
|
|
@@ -64,6 +65,37 @@ await supabase.additionalDetails.remove(detail.mms_id);
|
|
|
64
65
|
The `value` column is `text`; the SDK serializes on write and casts back on read according to the
|
|
65
66
|
row's `type` (`number` → `Number`, `boolean`, `date` → `Date`, `url` → `URL`).
|
|
66
67
|
|
|
68
|
+
```ts
|
|
69
|
+
import { NotesEntityTypes } from '@managemint-solutions/entities/notes/enum';
|
|
70
|
+
|
|
71
|
+
// Notes hang off another entity too, so reads and writes take (entity, entityId).
|
|
72
|
+
const notes = await supabase.notes.list(NotesEntityTypes.PROJECT, projectId);
|
|
73
|
+
const note = await supabase.notes.create(NotesEntityTypes.PROJECT, projectId, {
|
|
74
|
+
content: 'Called the client to confirm the site visit.',
|
|
75
|
+
});
|
|
76
|
+
await supabase.notes.getById(note.mms_id);
|
|
77
|
+
await supabase.notes.togglePin(note.mms_id); // flips `pinned` and returns the refreshed note
|
|
78
|
+
await supabase.notes.remove(note.mms_id);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Each note carries its author as an embedded `user` (from the `user_profiles` view), and `list`
|
|
82
|
+
returns newest first.
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import { SupportingFilesEntityTypes } from '@managemint-solutions/entities/supporting-files/enum';
|
|
86
|
+
|
|
87
|
+
// Supporting files hang off another entity, and cover Supabase Storage as well as the table.
|
|
88
|
+
const files = await supabase.supportingFiles.list(SupportingFilesEntityTypes.PROJECT, projectId);
|
|
89
|
+
await supabase.supportingFiles.upload(SupportingFilesEntityTypes.PROJECT, projectId, {
|
|
90
|
+
files: uploaded, // web `File`s — uploaded to the `supporting-files` bucket, then rowed up
|
|
91
|
+
});
|
|
92
|
+
const { url, ttl } = await supabase.supportingFiles.getPresignedUrl(files[0].mms_id); // 5 min
|
|
93
|
+
await supabase.supportingFiles.remove(files[0].mms_id); // deletes the row and the object
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Uploads run in batches of 5 and upsert, so re-uploading a file refreshes the object without
|
|
97
|
+
adding a second row; `upload` returns the entity's full file list.
|
|
98
|
+
|
|
67
99
|
The client decodes `{ mms_id, organization_id }` from the JWT itself and scopes every query
|
|
68
100
|
by `organization_id`. `supabase.supabase` is the raw typed `@supabase/supabase-js` client
|
|
69
101
|
(`TypedSupabaseClient`) — the escape hatch for queries not yet covered by a resource.
|
|
@@ -73,7 +105,8 @@ by `organization_id`. `supabase.supabase` is the raw typed `@supabase/supabase-j
|
|
|
73
105
|
Every error the SDK throws is a `SupabaseClientError` carrying the HTTP `status` to respond
|
|
74
106
|
with and the client-facing body, `toResponse()` → `{ error, message }`. Postgrest/Postgres
|
|
75
107
|
errors are translated by `mapPostgrestError` (Postgrest code → status, RLS permission and
|
|
76
|
-
module denials → readable messages)
|
|
108
|
+
module denials → readable messages), Storage errors by `mapStorageError` (the storage error's
|
|
109
|
+
own HTTP status, or 500 when it has none); JWT problems are `401 Authentication Error`. Consumers
|
|
77
110
|
return these as-is instead of mapping database errors themselves.
|
|
78
111
|
|
|
79
112
|
## NestJS
|
package/dist/client.d.ts
CHANGED
|
@@ -2,7 +2,9 @@ import { type SupabaseClient as SupabaseJsClient } from '@supabase/supabase-js';
|
|
|
2
2
|
import type { Database } from './database.types';
|
|
3
3
|
import { type AuthContext } from './auth';
|
|
4
4
|
import { AdditionalDetailsResource } from './additional-details';
|
|
5
|
+
import { NotesResource } from './notes';
|
|
5
6
|
import { StatusesResource } from './statuses';
|
|
7
|
+
import { SupportingFilesResource } from './supporting-files';
|
|
6
8
|
export type TypedSupabaseClient = SupabaseJsClient<Database>;
|
|
7
9
|
export type SupabaseClientConfig = {
|
|
8
10
|
url: string;
|
|
@@ -14,6 +16,8 @@ export declare class SupabaseClient {
|
|
|
14
16
|
readonly auth: AuthContext;
|
|
15
17
|
readonly statuses: StatusesResource;
|
|
16
18
|
readonly additionalDetails: AdditionalDetailsResource;
|
|
19
|
+
readonly notes: NotesResource;
|
|
20
|
+
readonly supportingFiles: SupportingFilesResource;
|
|
17
21
|
constructor(config: SupabaseClientConfig);
|
|
18
22
|
}
|
|
19
23
|
export declare const createSupabaseClient: (config: SupabaseClientConfig) => SupabaseClient;
|
package/dist/client.js
CHANGED
|
@@ -4,12 +4,16 @@ exports.createSupabaseClient = exports.SupabaseClient = void 0;
|
|
|
4
4
|
const supabase_js_1 = require("@supabase/supabase-js");
|
|
5
5
|
const auth_1 = require("./auth");
|
|
6
6
|
const additional_details_1 = require("./additional-details");
|
|
7
|
+
const notes_1 = require("./notes");
|
|
7
8
|
const statuses_1 = require("./statuses");
|
|
9
|
+
const supporting_files_1 = require("./supporting-files");
|
|
8
10
|
class SupabaseClient {
|
|
9
11
|
supabase; // escape hatch for not-yet-migrated queries
|
|
10
12
|
auth;
|
|
11
13
|
statuses;
|
|
12
14
|
additionalDetails;
|
|
15
|
+
notes;
|
|
16
|
+
supportingFiles;
|
|
13
17
|
constructor(config) {
|
|
14
18
|
this.auth = (0, auth_1.decodeAuthContext)(config.accessToken);
|
|
15
19
|
this.supabase = (0, supabase_js_1.createClient)(config.url, config.key, {
|
|
@@ -18,6 +22,8 @@ class SupabaseClient {
|
|
|
18
22
|
});
|
|
19
23
|
this.statuses = new statuses_1.StatusesResource(this.supabase, this.auth);
|
|
20
24
|
this.additionalDetails = new additional_details_1.AdditionalDetailsResource(this.supabase, this.auth);
|
|
25
|
+
this.notes = new notes_1.NotesResource(this.supabase, this.auth);
|
|
26
|
+
this.supportingFiles = new supporting_files_1.SupportingFilesResource(this.supabase, this.auth);
|
|
21
27
|
}
|
|
22
28
|
}
|
|
23
29
|
exports.SupabaseClient = SupabaseClient;
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":";;;AAAA,uDAA8F;AAE9F,iCAA6D;AAC7D,6DAAiE;AACjE,yCAA8C;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":";;;AAAA,uDAA8F;AAE9F,iCAA6D;AAC7D,6DAAiE;AACjE,mCAAwC;AACxC,yCAA8C;AAC9C,yDAA6D;AAU7D,MAAa,cAAc;IAChB,QAAQ,CAAsB,CAAC,4CAA4C;IAC3E,IAAI,CAAc;IAClB,QAAQ,CAAmB;IAC3B,iBAAiB,CAA4B;IAC7C,KAAK,CAAgB;IACrB,eAAe,CAA0B;IAElD,YAAY,MAA4B;QACtC,IAAI,CAAC,IAAI,GAAG,IAAA,wBAAiB,EAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAClD,IAAI,CAAC,QAAQ,GAAG,IAAA,0BAAY,EAAW,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE;YAC7D,MAAM,EAAE,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,MAAM,CAAC,WAAW,EAAE,EAAE,EAAE;YACtE,IAAI,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE;SACzD,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,GAAG,IAAI,2BAAgB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/D,IAAI,CAAC,iBAAiB,GAAG,IAAI,8CAAyB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACjF,IAAI,CAAC,KAAK,GAAG,IAAI,qBAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACzD,IAAI,CAAC,eAAe,GAAG,IAAI,0CAAuB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/E,CAAC;CACF;AAnBD,wCAmBC;AAEM,MAAM,oBAAoB,GAAG,CAAC,MAA4B,EAAkB,EAAE,CACnF,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;AADhB,QAAA,oBAAoB,wBACJ"}
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { StorageError } from '@supabase/storage-js';
|
|
1
2
|
import type { PostgrestError } from '@supabase/supabase-js';
|
|
2
3
|
export type SupabaseClientErrorInit = {
|
|
3
4
|
/** HTTP status the consumer should respond with. */
|
|
@@ -27,3 +28,9 @@ export declare class SupabaseClientError extends Error {
|
|
|
27
28
|
}
|
|
28
29
|
/** Converts a raw Postgrest error into the SupabaseClientError the SDK throws. */
|
|
29
30
|
export declare const mapPostgrestError: (error: PostgrestError) => SupabaseClientError;
|
|
31
|
+
/**
|
|
32
|
+
* Converts a Supabase Storage error into the SupabaseClientError the SDK throws. `StorageError`
|
|
33
|
+
* carries the HTTP `status` only when it came back from the Storage API (`StorageApiError`);
|
|
34
|
+
* network/unknown failures have none, hence the 500 fallback.
|
|
35
|
+
*/
|
|
36
|
+
export declare const mapStorageError: (error: StorageError, message?: string) => SupabaseClientError;
|
package/dist/errors.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.mapPostgrestError = exports.SupabaseClientError = void 0;
|
|
3
|
+
exports.mapStorageError = exports.mapPostgrestError = exports.SupabaseClientError = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Every error the SDK throws. It already carries the HTTP status and the body the
|
|
6
6
|
* consumer sends back to the client (`toResponse()`), so the api needs no mapping.
|
|
@@ -129,4 +129,15 @@ const mapPostgrestError = (error) => new SupabaseClientError({
|
|
|
129
129
|
code: error.code,
|
|
130
130
|
}, { cause: error });
|
|
131
131
|
exports.mapPostgrestError = mapPostgrestError;
|
|
132
|
+
/**
|
|
133
|
+
* Converts a Supabase Storage error into the SupabaseClientError the SDK throws. `StorageError`
|
|
134
|
+
* carries the HTTP `status` only when it came back from the Storage API (`StorageApiError`);
|
|
135
|
+
* network/unknown failures have none, hence the 500 fallback.
|
|
136
|
+
*/
|
|
137
|
+
const mapStorageError = (error, message = error.message) => new SupabaseClientError({
|
|
138
|
+
status: error.status ?? 500,
|
|
139
|
+
error: 'Storage Error',
|
|
140
|
+
message,
|
|
141
|
+
}, { cause: error });
|
|
142
|
+
exports.mapStorageError = mapStorageError;
|
|
132
143
|
//# sourceMappingURL=errors.js.map
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,4 +3,6 @@ export * from './auth';
|
|
|
3
3
|
export * from './errors';
|
|
4
4
|
export * from './statuses';
|
|
5
5
|
export * from './additional-details';
|
|
6
|
+
export * from './notes';
|
|
7
|
+
export * from './supporting-files';
|
|
6
8
|
export type { Database, Tables, TablesInsert, TablesUpdate, Json } from './database.types';
|
package/dist/index.js
CHANGED
|
@@ -19,4 +19,6 @@ __exportStar(require("./auth"), exports);
|
|
|
19
19
|
__exportStar(require("./errors"), exports);
|
|
20
20
|
__exportStar(require("./statuses"), exports);
|
|
21
21
|
__exportStar(require("./additional-details"), exports);
|
|
22
|
+
__exportStar(require("./notes"), exports);
|
|
23
|
+
__exportStar(require("./supporting-files"), exports);
|
|
22
24
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,yCAAuB;AACvB,2CAAyB;AACzB,6CAA2B;AAC3B,uDAAqC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,yCAAuB;AACvB,2CAAyB;AACzB,6CAA2B;AAC3B,uDAAqC;AACrC,0CAAwB;AACxB,qDAAmC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AddNoteDto as AddNoteDtoType, GetNotesDto as GetNotesDtoType, NoteIdDto as NoteIdDtoType } from '@managemint-solutions/entities/notes/dto';
|
|
2
|
+
import { NotesEntityTypes } from '@managemint-solutions/entities/notes/enum';
|
|
3
|
+
import type { TablesInsert } from '../database.types';
|
|
4
|
+
type NotesInsertColumns = Required<Pick<TablesInsert<'notes'>, 'content'>>;
|
|
5
|
+
export declare class NoteIdDto implements NoteIdDtoType {
|
|
6
|
+
readonly noteId: string;
|
|
7
|
+
}
|
|
8
|
+
export declare class GetNotesDto implements GetNotesDtoType {
|
|
9
|
+
readonly entity: NotesEntityTypes;
|
|
10
|
+
readonly entityId: string;
|
|
11
|
+
}
|
|
12
|
+
export declare class AddNoteDto implements AddNoteDtoType, NotesInsertColumns {
|
|
13
|
+
readonly content: string;
|
|
14
|
+
}
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.AddNoteDto = exports.GetNotesDto = exports.NoteIdDto = void 0;
|
|
13
|
+
const class_validator_1 = require("class-validator");
|
|
14
|
+
const enum_1 = require("@managemint-solutions/entities/notes/enum");
|
|
15
|
+
class NoteIdDto {
|
|
16
|
+
noteId;
|
|
17
|
+
}
|
|
18
|
+
exports.NoteIdDto = NoteIdDto;
|
|
19
|
+
__decorate([
|
|
20
|
+
(0, class_validator_1.IsUUID)('4', { message: 'Invalid note ID format' }),
|
|
21
|
+
__metadata("design:type", String)
|
|
22
|
+
], NoteIdDto.prototype, "noteId", void 0);
|
|
23
|
+
class GetNotesDto {
|
|
24
|
+
entity;
|
|
25
|
+
entityId;
|
|
26
|
+
}
|
|
27
|
+
exports.GetNotesDto = GetNotesDto;
|
|
28
|
+
__decorate([
|
|
29
|
+
(0, class_validator_1.IsEnum)(enum_1.NotesEntityTypes, { message: 'Invalid entity type' }),
|
|
30
|
+
__metadata("design:type", String)
|
|
31
|
+
], GetNotesDto.prototype, "entity", void 0);
|
|
32
|
+
__decorate([
|
|
33
|
+
(0, class_validator_1.IsUUID)('4', { message: 'Invalid entity ID format' }),
|
|
34
|
+
__metadata("design:type", String)
|
|
35
|
+
], GetNotesDto.prototype, "entityId", void 0);
|
|
36
|
+
class AddNoteDto {
|
|
37
|
+
content;
|
|
38
|
+
}
|
|
39
|
+
exports.AddNoteDto = AddNoteDto;
|
|
40
|
+
__decorate([
|
|
41
|
+
(0, class_validator_1.IsString)({ message: 'Invalid content' }),
|
|
42
|
+
(0, class_validator_1.MinLength)(1, { message: 'Content cannot be empty' }),
|
|
43
|
+
(0, class_validator_1.MaxLength)(255, { message: 'Content cannot exceed 255 characters' }),
|
|
44
|
+
__metadata("design:type", String)
|
|
45
|
+
], AddNoteDto.prototype, "content", void 0);
|
|
46
|
+
//# sourceMappingURL=dto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dto.js","sourceRoot":"","sources":["../../src/notes/dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qDAAiF;AAMjF,oEAA6E;AAQ7E,MAAa,SAAS;IAEX,MAAM,CAAU;CAC1B;AAHD,8BAGC;AADU;IADR,IAAA,wBAAM,EAAC,GAAG,EAAE,EAAE,OAAO,EAAE,wBAAwB,EAAE,CAAC;;yCAC1B;AAG3B,MAAa,WAAW;IAEb,MAAM,CAAoB;IAG1B,QAAQ,CAAU;CAC5B;AAND,kCAMC;AAJU;IADR,IAAA,wBAAM,EAAC,uBAAgB,EAAE,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC;;2CAC1B;AAG1B;IADR,IAAA,wBAAM,EAAC,GAAG,EAAE,EAAE,OAAO,EAAE,0BAA0B,EAAE,CAAC;;6CAC1B;AAG7B,MAAa,UAAU;IAIZ,OAAO,CAAU;CAC3B;AALD,gCAKC;AADU;IAHR,IAAA,0BAAQ,EAAC,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC;IACxC,IAAA,2BAAS,EAAC,CAAC,EAAE,EAAE,OAAO,EAAE,yBAAyB,EAAE,CAAC;IACpD,IAAA,2BAAS,EAAC,GAAG,EAAE,EAAE,OAAO,EAAE,sCAAsC,EAAE,CAAC;;2CAC1C"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { NoteEntity } from '@managemint-solutions/entities/notes';
|
|
2
|
+
import type { AddNoteDto } from '@managemint-solutions/entities/notes/dto';
|
|
3
|
+
import { NotesEntityTypes } from '@managemint-solutions/entities/notes/enum';
|
|
4
|
+
import type { AuthContext } from '../auth';
|
|
5
|
+
import type { TypedSupabaseClient } from '../client';
|
|
6
|
+
export * from './dto';
|
|
7
|
+
export declare class NotesResource {
|
|
8
|
+
private readonly supabase;
|
|
9
|
+
private readonly auth;
|
|
10
|
+
constructor(supabase: TypedSupabaseClient, auth: AuthContext);
|
|
11
|
+
getById(noteId: string): Promise<NoteEntity>;
|
|
12
|
+
list(entity: NotesEntityTypes, entityId: string): Promise<NoteEntity[]>;
|
|
13
|
+
create(entity: NotesEntityTypes, entityId: string, input: AddNoteDto): Promise<NoteEntity>;
|
|
14
|
+
togglePin(noteId: string): Promise<NoteEntity>;
|
|
15
|
+
remove(noteId: string): Promise<void>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.NotesResource = void 0;
|
|
18
|
+
const errors_1 = require("../errors");
|
|
19
|
+
__exportStar(require("./dto"), exports);
|
|
20
|
+
// The query is typed by the generated Database schema (so the select string and the insert/update
|
|
21
|
+
// payloads are checked); the public contract is the shared NoteEntity from
|
|
22
|
+
// @managemint-solutions/entities. The two shapes legitimately differ, hence `as unknown as`: the
|
|
23
|
+
// embedded user_profiles row is an all-nullable view row where the entity declares UserIdentity,
|
|
24
|
+
// and created_at is an ISO string where the entity declares Date.
|
|
25
|
+
const NOTE_SELECT = 'mms_id, created_at, content, pinned, user:user_profiles!user_id(*)';
|
|
26
|
+
class NotesResource {
|
|
27
|
+
supabase;
|
|
28
|
+
auth;
|
|
29
|
+
constructor(supabase, auth) {
|
|
30
|
+
this.supabase = supabase;
|
|
31
|
+
this.auth = auth;
|
|
32
|
+
}
|
|
33
|
+
async getById(noteId) {
|
|
34
|
+
const { data, error } = await this.supabase
|
|
35
|
+
.from('notes')
|
|
36
|
+
.select(NOTE_SELECT)
|
|
37
|
+
.eq('organization_id', this.auth.organization_id)
|
|
38
|
+
.eq('mms_id', noteId)
|
|
39
|
+
.single();
|
|
40
|
+
if (error)
|
|
41
|
+
throw (0, errors_1.mapPostgrestError)(error);
|
|
42
|
+
return data;
|
|
43
|
+
}
|
|
44
|
+
async list(entity, entityId) {
|
|
45
|
+
const { data, error } = await this.supabase
|
|
46
|
+
.from('notes')
|
|
47
|
+
.select(NOTE_SELECT)
|
|
48
|
+
.eq('organization_id', this.auth.organization_id)
|
|
49
|
+
.eq('entity_type', entity)
|
|
50
|
+
.eq('entity_id', entityId)
|
|
51
|
+
.order('created_at', { ascending: false });
|
|
52
|
+
if (error)
|
|
53
|
+
throw (0, errors_1.mapPostgrestError)(error);
|
|
54
|
+
return data;
|
|
55
|
+
}
|
|
56
|
+
async create(entity, entityId, input) {
|
|
57
|
+
const { data, error } = await this.supabase
|
|
58
|
+
.from('notes')
|
|
59
|
+
.insert({
|
|
60
|
+
content: input.content,
|
|
61
|
+
entity_type: entity,
|
|
62
|
+
entity_id: entityId,
|
|
63
|
+
organization_id: this.auth.organization_id,
|
|
64
|
+
user_id: this.auth.mms_id,
|
|
65
|
+
})
|
|
66
|
+
.select(NOTE_SELECT)
|
|
67
|
+
.single();
|
|
68
|
+
if (error)
|
|
69
|
+
throw (0, errors_1.mapPostgrestError)(error);
|
|
70
|
+
return data;
|
|
71
|
+
}
|
|
72
|
+
async togglePin(noteId) {
|
|
73
|
+
const existing = await this.getById(noteId);
|
|
74
|
+
const { error } = await this.supabase
|
|
75
|
+
.from('notes')
|
|
76
|
+
.update({
|
|
77
|
+
pinned: !existing.pinned,
|
|
78
|
+
updated_at: new Date().toISOString(),
|
|
79
|
+
last_updated_by: this.auth.mms_id,
|
|
80
|
+
})
|
|
81
|
+
.eq('mms_id', noteId)
|
|
82
|
+
.eq('organization_id', this.auth.organization_id);
|
|
83
|
+
if (error)
|
|
84
|
+
throw (0, errors_1.mapPostgrestError)(error);
|
|
85
|
+
return this.getById(noteId);
|
|
86
|
+
}
|
|
87
|
+
async remove(noteId) {
|
|
88
|
+
const { error } = await this.supabase
|
|
89
|
+
.from('notes')
|
|
90
|
+
.delete()
|
|
91
|
+
.eq('mms_id', noteId)
|
|
92
|
+
.eq('organization_id', this.auth.organization_id);
|
|
93
|
+
if (error)
|
|
94
|
+
throw (0, errors_1.mapPostgrestError)(error);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
exports.NotesResource = NotesResource;
|
|
98
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/notes/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { GetSupportingFilesDto as GetSupportingFilesDtoType, SupportingFileIdDto as SupportingFileIdDtoType } from '@managemint-solutions/entities/supporting-files/dto';
|
|
2
|
+
import { SupportingFilesEntityTypes } from '@managemint-solutions/entities/supporting-files/enum';
|
|
3
|
+
export declare class SupportingFileIdDto implements SupportingFileIdDtoType {
|
|
4
|
+
readonly supportingFileId: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class GetSupportingFilesDto implements GetSupportingFilesDtoType {
|
|
7
|
+
readonly entity: SupportingFilesEntityTypes;
|
|
8
|
+
readonly entityId: string;
|
|
9
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.GetSupportingFilesDto = exports.SupportingFileIdDto = void 0;
|
|
13
|
+
const class_validator_1 = require("class-validator");
|
|
14
|
+
const enum_1 = require("@managemint-solutions/entities/supporting-files/enum");
|
|
15
|
+
// class-validator versions of the shared DTO types from @managemint-solutions/entities.
|
|
16
|
+
// Each class `implements` its entities type so the wire contract cannot drift. There is no class
|
|
17
|
+
// for the upload payload — it arrives as multipart and is not validated by class-validator.
|
|
18
|
+
class SupportingFileIdDto {
|
|
19
|
+
supportingFileId;
|
|
20
|
+
}
|
|
21
|
+
exports.SupportingFileIdDto = SupportingFileIdDto;
|
|
22
|
+
__decorate([
|
|
23
|
+
(0, class_validator_1.IsUUID)('4', { message: 'Invalid supporting file ID format' }),
|
|
24
|
+
__metadata("design:type", String)
|
|
25
|
+
], SupportingFileIdDto.prototype, "supportingFileId", void 0);
|
|
26
|
+
class GetSupportingFilesDto {
|
|
27
|
+
entity;
|
|
28
|
+
entityId;
|
|
29
|
+
}
|
|
30
|
+
exports.GetSupportingFilesDto = GetSupportingFilesDto;
|
|
31
|
+
__decorate([
|
|
32
|
+
(0, class_validator_1.IsEnum)(enum_1.SupportingFilesEntityTypes, { message: 'Invalid entity type' }),
|
|
33
|
+
__metadata("design:type", String)
|
|
34
|
+
], GetSupportingFilesDto.prototype, "entity", void 0);
|
|
35
|
+
__decorate([
|
|
36
|
+
(0, class_validator_1.IsUUID)('4', { message: 'Invalid entity ID format' }),
|
|
37
|
+
__metadata("design:type", String)
|
|
38
|
+
], GetSupportingFilesDto.prototype, "entityId", void 0);
|
|
39
|
+
//# sourceMappingURL=dto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dto.js","sourceRoot":"","sources":["../../src/supporting-files/dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qDAAiD;AAKjD,+EAAkG;AAElG,wFAAwF;AACxF,iGAAiG;AACjG,4FAA4F;AAE5F,MAAa,mBAAmB;IAErB,gBAAgB,CAAU;CACpC;AAHD,kDAGC;AADU;IADR,IAAA,wBAAM,EAAC,GAAG,EAAE,EAAE,OAAO,EAAE,mCAAmC,EAAE,CAAC;;6DAC3B;AAGrC,MAAa,qBAAqB;IAEvB,MAAM,CAA8B;IAGpC,QAAQ,CAAU;CAC5B;AAND,sDAMC;AAJU;IADR,IAAA,wBAAM,EAAC,iCAA0B,EAAE,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC;;qDAC1B;AAGpC;IADR,IAAA,wBAAM,EAAC,GAAG,EAAE,EAAE,OAAO,EAAE,0BAA0B,EAAE,CAAC;;uDAC1B"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { SupportingFileEntity, SupportingFilePresignedUrl } from '@managemint-solutions/entities/supporting-files';
|
|
2
|
+
import type { UploadSupportingFilesDto } from '@managemint-solutions/entities/supporting-files/dto';
|
|
3
|
+
import { SupportingFilesEntityTypes } from '@managemint-solutions/entities/supporting-files/enum';
|
|
4
|
+
import type { AuthContext } from '../auth';
|
|
5
|
+
import type { TypedSupabaseClient } from '../client';
|
|
6
|
+
export * from './dto';
|
|
7
|
+
export * from './paths';
|
|
8
|
+
export declare class SupportingFilesResource {
|
|
9
|
+
private readonly supabase;
|
|
10
|
+
private readonly auth;
|
|
11
|
+
constructor(supabase: TypedSupabaseClient, auth: AuthContext);
|
|
12
|
+
getPresignedUrl(supportingFileId: string): Promise<SupportingFilePresignedUrl>;
|
|
13
|
+
list(entity: SupportingFilesEntityTypes, entityId: string): Promise<SupportingFileEntity[]>;
|
|
14
|
+
upload(entity: SupportingFilesEntityTypes, entityId: string, input: UploadSupportingFilesDto): Promise<SupportingFileEntity[]>;
|
|
15
|
+
remove(supportingFileId: string): Promise<void>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.SupportingFilesResource = void 0;
|
|
18
|
+
const errors_1 = require("../errors");
|
|
19
|
+
const paths_1 = require("./paths");
|
|
20
|
+
__exportStar(require("./dto"), exports);
|
|
21
|
+
__exportStar(require("./paths"), exports);
|
|
22
|
+
/** Storage bucket every supporting file lives in. */
|
|
23
|
+
const BUCKET = 'supporting-files';
|
|
24
|
+
/** How long a presigned download URL stays valid. */
|
|
25
|
+
const SIGNED_URL_TTL_SECONDS = 300;
|
|
26
|
+
/** Uploads run concurrently in batches of this size. */
|
|
27
|
+
const UPLOAD_BATCH_SIZE = 5;
|
|
28
|
+
// The queries are typed by the generated Database schema; the public contract is the shared
|
|
29
|
+
// SupportingFileEntity from @managemint-solutions/entities. The row's `extension` is `text` where
|
|
30
|
+
// the entity declares SupportingFilesExtensions, hence the cast at the return.
|
|
31
|
+
class SupportingFilesResource {
|
|
32
|
+
supabase;
|
|
33
|
+
auth;
|
|
34
|
+
constructor(supabase, auth) {
|
|
35
|
+
this.supabase = supabase;
|
|
36
|
+
this.auth = auth;
|
|
37
|
+
}
|
|
38
|
+
async getPresignedUrl(supportingFileId) {
|
|
39
|
+
const { data, error } = await this.supabase
|
|
40
|
+
.from('supporting_files')
|
|
41
|
+
.select('name, extension, entity_type, entity_id')
|
|
42
|
+
.eq('mms_id', supportingFileId)
|
|
43
|
+
.eq('organization_id', this.auth.organization_id)
|
|
44
|
+
.single();
|
|
45
|
+
if (error)
|
|
46
|
+
throw (0, errors_1.mapPostgrestError)(error);
|
|
47
|
+
const { data: signed, error: signedError } = await this.supabase.storage
|
|
48
|
+
.from(BUCKET)
|
|
49
|
+
.createSignedUrl((0, paths_1.storagePath)(data.entity_type, data.entity_id, data.name, data.extension), SIGNED_URL_TTL_SECONDS);
|
|
50
|
+
if (signedError)
|
|
51
|
+
throw (0, errors_1.mapStorageError)(signedError);
|
|
52
|
+
return { url: signed.signedUrl, ttl: SIGNED_URL_TTL_SECONDS };
|
|
53
|
+
}
|
|
54
|
+
async list(entity, entityId) {
|
|
55
|
+
const { data, error } = await this.supabase
|
|
56
|
+
.from('supporting_files')
|
|
57
|
+
.select('mms_id, name, extension')
|
|
58
|
+
.eq('entity_type', entity)
|
|
59
|
+
.eq('entity_id', entityId)
|
|
60
|
+
.eq('organization_id', this.auth.organization_id)
|
|
61
|
+
.order('created_at', { ascending: false });
|
|
62
|
+
if (error)
|
|
63
|
+
throw (0, errors_1.mapPostgrestError)(error);
|
|
64
|
+
return data;
|
|
65
|
+
}
|
|
66
|
+
async upload(entity, entityId, input) {
|
|
67
|
+
const { data: existing, error: existingError } = await this.supabase
|
|
68
|
+
.from('supporting_files')
|
|
69
|
+
.select('name, extension')
|
|
70
|
+
.eq('entity_type', entity)
|
|
71
|
+
.eq('entity_id', entityId)
|
|
72
|
+
.eq('organization_id', this.auth.organization_id);
|
|
73
|
+
if (existingError)
|
|
74
|
+
throw (0, errors_1.mapPostgrestError)(existingError);
|
|
75
|
+
const existingFileNames = existing.map((file) => `${file.name}.${file.extension}`);
|
|
76
|
+
// Every file is written to the bucket, duplicates included — an upsert refreshes the object.
|
|
77
|
+
for (let index = 0; index < input.files.length; index += UPLOAD_BATCH_SIZE) {
|
|
78
|
+
await Promise.all(input.files.slice(index, index + UPLOAD_BATCH_SIZE).map(async (file) => {
|
|
79
|
+
const { error } = await this.supabase.storage
|
|
80
|
+
.from(BUCKET)
|
|
81
|
+
.upload(`${entity}/${entityId}/${file.name}`, file, {
|
|
82
|
+
cacheControl: '3600',
|
|
83
|
+
upsert: true,
|
|
84
|
+
});
|
|
85
|
+
if (error)
|
|
86
|
+
throw (0, errors_1.mapStorageError)(error, `Failed to upload file: ${file.name}`);
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
// Only files without an existing row get one — the rest were refreshed in place above.
|
|
90
|
+
const newFiles = input.files.filter((file) => !existingFileNames.includes(file.name));
|
|
91
|
+
if (newFiles.length > 0) {
|
|
92
|
+
const { error } = await this.supabase.from('supporting_files').insert(newFiles.map((file) => ({
|
|
93
|
+
...(0, paths_1.splitFileName)(file.name),
|
|
94
|
+
entity_type: entity,
|
|
95
|
+
entity_id: entityId,
|
|
96
|
+
organization_id: this.auth.organization_id,
|
|
97
|
+
created_at: new Date().toISOString(),
|
|
98
|
+
created_by: this.auth.mms_id,
|
|
99
|
+
})));
|
|
100
|
+
if (error)
|
|
101
|
+
throw (0, errors_1.mapPostgrestError)(error);
|
|
102
|
+
}
|
|
103
|
+
return this.list(entity, entityId);
|
|
104
|
+
}
|
|
105
|
+
async remove(supportingFileId) {
|
|
106
|
+
const { data, error } = await this.supabase
|
|
107
|
+
.from('supporting_files')
|
|
108
|
+
.select('entity_type, entity_id, name, extension')
|
|
109
|
+
.eq('mms_id', supportingFileId)
|
|
110
|
+
.eq('organization_id', this.auth.organization_id)
|
|
111
|
+
.single();
|
|
112
|
+
if (error)
|
|
113
|
+
throw (0, errors_1.mapPostgrestError)(error);
|
|
114
|
+
const { error: deleteError } = await this.supabase
|
|
115
|
+
.from('supporting_files')
|
|
116
|
+
.delete()
|
|
117
|
+
.eq('mms_id', supportingFileId)
|
|
118
|
+
.eq('organization_id', this.auth.organization_id);
|
|
119
|
+
if (deleteError)
|
|
120
|
+
throw (0, errors_1.mapPostgrestError)(deleteError);
|
|
121
|
+
const { error: storageError } = await this.supabase.storage
|
|
122
|
+
.from(BUCKET)
|
|
123
|
+
.remove([(0, paths_1.storagePath)(data.entity_type, data.entity_id, data.name, data.extension)]);
|
|
124
|
+
if (storageError) {
|
|
125
|
+
throw (0, errors_1.mapStorageError)(storageError, `Failed to delete file: ${data.name}.${data.extension}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
exports.SupportingFilesResource = SupportingFilesResource;
|
|
130
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/supporting-files/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splits an uploaded file name into the `name` / `extension` columns.
|
|
3
|
+
*
|
|
4
|
+
* This mirrors the api exactly, quirks included: only the segment before the *first* dot becomes
|
|
5
|
+
* the name, so `report.final.pdf` stores as name `report`, extension `pdf`.
|
|
6
|
+
*/
|
|
7
|
+
export declare const splitFileName: (fileName: string) => {
|
|
8
|
+
name: string;
|
|
9
|
+
extension: string;
|
|
10
|
+
};
|
|
11
|
+
/** Where an object lives in the `supporting-files` bucket. */
|
|
12
|
+
export declare const storagePath: (entityType: string, entityId: string, name: string, extension: string) => string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.storagePath = exports.splitFileName = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Splits an uploaded file name into the `name` / `extension` columns.
|
|
6
|
+
*
|
|
7
|
+
* This mirrors the api exactly, quirks included: only the segment before the *first* dot becomes
|
|
8
|
+
* the name, so `report.final.pdf` stores as name `report`, extension `pdf`.
|
|
9
|
+
*/
|
|
10
|
+
const splitFileName = (fileName) => ({
|
|
11
|
+
name: fileName.split('.')[0],
|
|
12
|
+
extension: fileName.split('.').pop() ?? '',
|
|
13
|
+
});
|
|
14
|
+
exports.splitFileName = splitFileName;
|
|
15
|
+
/** Where an object lives in the `supporting-files` bucket. */
|
|
16
|
+
const storagePath = (entityType, entityId, name, extension) => `${entityType}/${entityId}/${name}.${extension}`;
|
|
17
|
+
exports.storagePath = storagePath;
|
|
18
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/supporting-files/paths.ts"],"names":[],"mappings":";;;AAAA;;;;;GAKG;AACI,MAAM,aAAa,GAAG,CAAC,QAAgB,EAAuC,EAAE,CAAC,CAAC;IACvF,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC5B,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE;CAC3C,CAAC,CAAC;AAHU,QAAA,aAAa,iBAGvB;AAEH,8DAA8D;AACvD,MAAM,WAAW,GAAG,CACzB,UAAkB,EAClB,QAAgB,EAChB,IAAY,EACZ,SAAiB,EACT,EAAE,CAAC,GAAG,UAAU,IAAI,QAAQ,IAAI,IAAI,IAAI,SAAS,EAAE,CAAC;AALjD,QAAA,WAAW,eAKsC"}
|
package/package.json
CHANGED