@managemint-solutions/sdk 0.5.0 → 0.7.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 +121 -7
- package/dist/additional-details/dto.d.ts +2 -5
- package/dist/additional-details/dto.js +2 -0
- package/dist/additional-details/dto.js.map +1 -1
- package/dist/additional-details/index.js +5 -6
- package/dist/additional-details/index.js.map +1 -1
- package/dist/additional-details/values.d.ts +2 -2
- package/dist/additional-details/values.js +2 -2
- package/dist/auth-client/dto.d.ts +19 -0
- package/dist/auth-client/dto.js +72 -0
- package/dist/auth-client/dto.js.map +1 -0
- package/dist/auth-client/index.d.ts +38 -0
- package/dist/auth-client/index.js +135 -0
- package/dist/auth-client/index.js.map +1 -0
- package/dist/client.d.ts +5 -2
- package/dist/client.js +6 -0
- package/dist/client.js.map +1 -1
- package/dist/clients/index.js +3 -6
- package/dist/clients/index.js.map +1 -1
- package/dist/errors.d.ts +7 -1
- package/dist/errors.js +12 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/nest/index.d.ts +5 -0
- package/dist/nest/index.js +10 -1
- package/dist/nest/index.js.map +1 -1
- package/dist/notes/dto.d.ts +1 -4
- package/dist/notes/dto.js +2 -0
- package/dist/notes/dto.js.map +1 -1
- package/dist/notes/index.js +3 -5
- package/dist/notes/index.js.map +1 -1
- package/dist/projects/dto.d.ts +38 -0
- package/dist/projects/dto.js +238 -0
- package/dist/projects/dto.js.map +1 -0
- package/dist/projects/index.d.ts +20 -0
- package/dist/projects/index.js +299 -0
- package/dist/projects/index.js.map +1 -0
- package/dist/statuses/dto.d.ts +2 -5
- package/dist/statuses/dto.js +2 -0
- package/dist/statuses/dto.js.map +1 -1
- package/dist/statuses/index.js +3 -4
- package/dist/statuses/index.js.map +1 -1
- package/dist/supporting-files/index.js +3 -3
- package/dist/supporting-files/index.js.map +1 -1
- package/dist/tasks/dto.d.ts +43 -0
- package/dist/tasks/dto.js +288 -0
- package/dist/tasks/dto.js.map +1 -0
- package/dist/tasks/index.d.ts +20 -0
- package/dist/tasks/index.js +241 -0
- package/dist/tasks/index.js.map +1 -0
- package/dist/transforms.d.ts +14 -0
- package/dist/transforms.js +38 -0
- package/dist/transforms.js.map +1 -0
- package/package.json +1 -1
- package/dist/database.types.d.ts +0 -2570
- package/dist/database.types.js +0 -12
- package/dist/database.types.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# ManageMint Solutions SDK
|
|
2
2
|
|
|
3
|
-
Typed Supabase data-access SDK for ManageMint Solutions. Query logic
|
|
4
|
-
|
|
3
|
+
Typed Supabase data-access SDK for ManageMint Solutions. Query logic lives here; consumers
|
|
4
|
+
(api, portal) get responses typed as the shared `@managemint-solutions/entities` types with no casts.
|
|
5
5
|
|
|
6
6
|
## Install
|
|
7
7
|
|
|
@@ -14,7 +14,10 @@ are peer dependencies — the request DTOs (`AddStatusDto`, `UpdateStatusDto`, `
|
|
|
14
14
|
`GetStatusesDto`, `AddAdditionalDetailsDto`, `UpdateAdditionalDetailsDto`,
|
|
15
15
|
`AdditionalDetailsIdDto`, `GetAdditionalDetailsDto`, `AddNoteDto`, `NoteIdDto`,
|
|
16
16
|
`GetNotesDto`, `SupportingFileIdDto`, `GetSupportingFilesDto`, `GetClientsDto`, `ClientIdDto`,
|
|
17
|
-
`CreateClientDto`, `UpdateClientDto`
|
|
17
|
+
`CreateClientDto`, `UpdateClientDto`, `GetProjectsDto`, `ProjectIdDto`, `CreateProjectDto`,
|
|
18
|
+
`UpdateProjectDto`, `GetTasksDto`, `TaskIdDto`, `CreateTaskDto`, `UpdateTaskDto`, `SignInDto`,
|
|
19
|
+
`ExchangeRefreshTokenDto`, `SendPasswordResetEmailDto`, `ExchangeTokenHashDto`,
|
|
20
|
+
`ResetPasswordDto`) ship with their class-validator
|
|
18
21
|
decorators so consumers validate against
|
|
19
22
|
the same rules the SDK's input types describe. `@nestjs/common` (^11) is an optional peer
|
|
20
23
|
dependency, needed only for the `@managemint-solutions/sdk/nest` subpath.
|
|
@@ -124,17 +127,128 @@ await supabase.clients.restore(client.mms_id); // deleted = false + restored_a
|
|
|
124
127
|
email and phone empty, no status, `contract_client` false, `contracted_hours` 0). Every write
|
|
125
128
|
except `remove` re-reads and returns the full record afterwards.
|
|
126
129
|
|
|
130
|
+
```ts
|
|
131
|
+
// Projects are paginated the same way, with extra date-range and client filters.
|
|
132
|
+
const page = await supabase.projects.list({
|
|
133
|
+
page: 1,
|
|
134
|
+
page_size: 10,
|
|
135
|
+
archive: false,
|
|
136
|
+
client_id: clientId, // a UUID, or the base64-JSON option value a select sends
|
|
137
|
+
});
|
|
138
|
+
// `search` matches name/specification; `created_*`, `start_date_*` and `end_date_*` bound the
|
|
139
|
+
// date columns, and `status_id_in` filters by status.
|
|
140
|
+
|
|
141
|
+
const project = await supabase.projects.create({
|
|
142
|
+
name: 'Website rebuild',
|
|
143
|
+
specification: 'Rebuild the marketing site',
|
|
144
|
+
start_date: '2026-04-22',
|
|
145
|
+
end_date: '2026-06-30',
|
|
146
|
+
has_budget: true,
|
|
147
|
+
status_id: statusId,
|
|
148
|
+
client_id: clientId,
|
|
149
|
+
manager_id: userId,
|
|
150
|
+
});
|
|
151
|
+
await supabase.projects.getById(project.mms_id);
|
|
152
|
+
await supabase.projects.update(project.mms_id, { ...project, name: 'Website rebuild v2' });
|
|
153
|
+
await supabase.projects.archive(project.mms_id);
|
|
154
|
+
await supabase.projects.unarchive(project.mms_id);
|
|
155
|
+
await supabase.projects.remove(project.mms_id); // soft delete
|
|
156
|
+
await supabase.projects.restore(project.mms_id);
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Each project carries its embedded `status`, `manager` and `client`; `getById` on a soft-deleted
|
|
160
|
+
project returns the creation audit with the rest blanked (empty name, no specification, dates,
|
|
161
|
+
status, manager or client).
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
// Tasks are paginated too, ordered by priority then newest first.
|
|
165
|
+
const page = await supabase.tasks.list({
|
|
166
|
+
page: 1,
|
|
167
|
+
page_size: 10,
|
|
168
|
+
archive: false,
|
|
169
|
+
project_id: projectId,
|
|
170
|
+
priority_in: [1, 3],
|
|
171
|
+
});
|
|
172
|
+
// `search` matches name/description, and `client_id`, `assigned_to_id`, the date ranges and
|
|
173
|
+
// `status_id_in` narrow it further.
|
|
174
|
+
|
|
175
|
+
const task = await supabase.tasks.create({
|
|
176
|
+
name: 'Draft the proposal',
|
|
177
|
+
description: 'Write the first pass and circulate it',
|
|
178
|
+
start_date: '2026-04-22',
|
|
179
|
+
end_date: '2026-04-30',
|
|
180
|
+
status_id: statusId,
|
|
181
|
+
priority: 2,
|
|
182
|
+
assigned_to_id: userId,
|
|
183
|
+
project_id: projectId,
|
|
184
|
+
client_id: clientId,
|
|
185
|
+
});
|
|
186
|
+
await supabase.tasks.getById(task.mms_id);
|
|
187
|
+
await supabase.tasks.update(task.mms_id, { ...task, priority: 3 });
|
|
188
|
+
await supabase.tasks.archive(task.mms_id);
|
|
189
|
+
await supabase.tasks.unarchive(task.mms_id);
|
|
190
|
+
await supabase.tasks.remove(task.mms_id); // soft delete
|
|
191
|
+
await supabase.tasks.restore(task.mms_id);
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
A task's `task_id` (its per-organization number) is assigned by the database on insert, and each
|
|
195
|
+
task carries its embedded `status`, `assigned_to`, `project` and `client`.
|
|
196
|
+
|
|
127
197
|
The client decodes `{ mms_id, organization_id }` from the JWT itself and scopes every query
|
|
128
|
-
by `organization_id`. `supabase.supabase` is the raw
|
|
198
|
+
by `organization_id`. `supabase.supabase` is the raw `@supabase/supabase-js` client
|
|
129
199
|
(`TypedSupabaseClient`) — the escape hatch for queries not yet covered by a resource.
|
|
130
200
|
|
|
201
|
+
## Auth
|
|
202
|
+
|
|
203
|
+
`SupabaseClient` needs the caller's JWT, which the auth flows are there to produce — so sign-in,
|
|
204
|
+
refresh and the password-reset exchanges live on a separate `SupabaseAuthClient`, built from the
|
|
205
|
+
publishable key alone.
|
|
206
|
+
|
|
207
|
+
```ts
|
|
208
|
+
import { createSupabaseAuthClient } from '@managemint-solutions/sdk';
|
|
209
|
+
|
|
210
|
+
const auth = createSupabaseAuthClient({
|
|
211
|
+
url: process.env.SUPABASE_URL!,
|
|
212
|
+
key: process.env.SUPABASE_PUBLISHABLE_KEY!, // no caller token — these callers are logged out
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const { access_token, refresh_token } = await auth.signIn({ email, password });
|
|
216
|
+
await auth.refreshSession({ refresh_token });
|
|
217
|
+
await auth.signOut();
|
|
218
|
+
|
|
219
|
+
// The redirect URL is passed in; the SDK reads no environment variables.
|
|
220
|
+
await auth.sendPasswordResetEmail({ email }, `${process.env.FRONTEND_URL}/reset-password`);
|
|
221
|
+
await auth.exchangeRecoveryToken({ token_hash }); // recovery link → tokens
|
|
222
|
+
await auth.exchangeConfirmToken({ token_hash }); // signup confirmation link → tokens
|
|
223
|
+
await auth.resetPassword({ password, access_token, refresh_token });
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
`signIn` also stamps `users.last_logged_in` for the user who just signed in, on a throwaway
|
|
227
|
+
client carrying the fresh access token; a failed stamp never fails the login. `signOut` is a
|
|
228
|
+
no-op server-side — the client holds no session — and is kept for parity with the api endpoint
|
|
229
|
+
it replaces. `auth.supabase` is the raw `@supabase/supabase-js` client.
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
import { SupabasePublicClient } from '@managemint-solutions/sdk/nest';
|
|
233
|
+
import { SignInDto, SupabaseAuthClient } from '@managemint-solutions/sdk';
|
|
234
|
+
|
|
235
|
+
@Controller('auth')
|
|
236
|
+
export class AuthController {
|
|
237
|
+
@Post('sign-in')
|
|
238
|
+
signIn(@SupabasePublicClient() auth: SupabaseAuthClient, @Body() body: SignInDto) {
|
|
239
|
+
return auth.signIn(body);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
131
244
|
## Errors
|
|
132
245
|
|
|
133
246
|
Every error the SDK throws is a `SupabaseClientError` carrying the HTTP `status` to respond
|
|
134
247
|
with and the client-facing body, `toResponse()` → `{ error, message }`. Postgrest/Postgres
|
|
135
248
|
errors are translated by `mapPostgrestError` (Postgrest code → status, RLS permission and
|
|
136
249
|
module denials → readable messages), Storage errors by `mapStorageError` (the storage error's
|
|
137
|
-
own HTTP status, or 500 when it has none)
|
|
250
|
+
own HTTP status, or 500 when it has none), Supabase Auth errors by `mapAuthError` (same rule,
|
|
251
|
+
`Authentication Error`); JWT problems are `401 Authentication Error`. Consumers
|
|
138
252
|
return these as-is instead of mapping database errors themselves.
|
|
139
253
|
|
|
140
254
|
## NestJS
|
|
@@ -169,6 +283,6 @@ npm test # jest + ts-jest; specs live in src/<resource>/tests/*.spec.ts
|
|
|
169
283
|
npm run build # tsc -p tsconfig.build.json (excludes specs), CommonJS output in dist/ — the type gate
|
|
170
284
|
```
|
|
171
285
|
|
|
172
|
-
|
|
173
|
-
|
|
286
|
+
The SDK carries no generated database types: the schema of record is the api's
|
|
287
|
+
`supabase/migrations`, and each resource declares the row shape its select string produces.
|
|
174
288
|
Publishing happens on push to `main` via `.github/workflows/release.yml`.
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { type ValidationOptions } from 'class-validator';
|
|
2
2
|
import type { AddAdditionalDetailsDto as AddAdditionalDetailsDtoType, AdditionalDetailsIdDto as AdditionalDetailsIdDtoType, GetAdditionalDetailsDto as GetAdditionalDetailsDtoType, UpdateAdditionalDetailsDto as UpdateAdditionalDetailsDtoType } from '@managemint-solutions/entities/additional-details/dto';
|
|
3
3
|
import { AdditionalDetailsEntityTypes, AdditionalDetailsTypes } from '@managemint-solutions/entities/additional-details/enum';
|
|
4
|
-
import type { TablesInsert } from '../database.types';
|
|
5
4
|
/** Validates `value` against the sibling `type` property (the discriminator). */
|
|
6
5
|
export declare function IsAdditionalDetailsValueByType(typeProperty: string, validationOptions?: ValidationOptions): (object: object, propertyName: string) => void;
|
|
7
|
-
type AdditionalDetailsInsertColumns = Required<Pick<TablesInsert<'additional_details'>, 'key' | 'copyable'>>;
|
|
8
6
|
export declare class AdditionalDetailsIdDto implements AdditionalDetailsIdDtoType {
|
|
9
7
|
readonly additionalDetailsId: string;
|
|
10
8
|
}
|
|
@@ -12,16 +10,15 @@ export declare class GetAdditionalDetailsDto implements GetAdditionalDetailsDtoT
|
|
|
12
10
|
readonly entity: AdditionalDetailsEntityTypes;
|
|
13
11
|
readonly entityId: string;
|
|
14
12
|
}
|
|
15
|
-
export declare class AddAdditionalDetailsDto implements AddAdditionalDetailsDtoType
|
|
13
|
+
export declare class AddAdditionalDetailsDto implements AddAdditionalDetailsDtoType {
|
|
16
14
|
readonly key: string;
|
|
17
15
|
readonly value: string | number | boolean | Date | URL;
|
|
18
16
|
readonly type: AdditionalDetailsTypes;
|
|
19
17
|
readonly copyable: boolean;
|
|
20
18
|
}
|
|
21
|
-
export declare class UpdateAdditionalDetailsDto implements UpdateAdditionalDetailsDtoType
|
|
19
|
+
export declare class UpdateAdditionalDetailsDto implements UpdateAdditionalDetailsDtoType {
|
|
22
20
|
readonly key: string;
|
|
23
21
|
readonly value: string | number | boolean;
|
|
24
22
|
readonly type: AdditionalDetailsTypes;
|
|
25
23
|
readonly copyable: boolean;
|
|
26
24
|
}
|
|
27
|
-
export {};
|
|
@@ -66,6 +66,8 @@ function IsAdditionalDetailsValueByType(typeProperty, validationOptions) {
|
|
|
66
66
|
});
|
|
67
67
|
};
|
|
68
68
|
}
|
|
69
|
+
// class-validator versions of the shared DTO types from @managemint-solutions/entities.
|
|
70
|
+
// Each class `implements` its entities type so the wire contract cannot drift.
|
|
69
71
|
class AdditionalDetailsIdDto {
|
|
70
72
|
additionalDetailsId;
|
|
71
73
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dto.js","sourceRoot":"","sources":["../../src/additional-details/dto.ts"],"names":[],"mappings":";;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"dto.js","sourceRoot":"","sources":["../../src/additional-details/dto.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,12 +19,11 @@ const errors_1 = require("../errors");
|
|
|
19
19
|
const values_1 = require("./values");
|
|
20
20
|
__exportStar(require("./dto"), exports);
|
|
21
21
|
__exportStar(require("./values"), exports);
|
|
22
|
-
// The
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
// declares the parsed string | number | boolean | Date | URL union that castValueByType produces.
|
|
22
|
+
// The public contract is the shared AdditionalDetailsEntity / AdditionalDetailSummary from
|
|
23
|
+
// @managemint-solutions/entities; the casts at the returns declare the shape the select strings
|
|
24
|
+
// below produce (the columns are defined in the api's supabase/migrations). `value` is a `text`
|
|
25
|
+
// column, and castValueByType turns it into the string | number | boolean | Date | URL union the
|
|
26
|
+
// entity declares.
|
|
28
27
|
const ADDITIONAL_DETAILS_SELECT = 'mms_id, created_at, created_by:user_profiles!created_by(*), updated_at, last_updated_by:user_profiles!last_updated_by(*), key, value, type, copyable';
|
|
29
28
|
const ADDITIONAL_DETAILS_SUMMARY_SELECT = 'mms_id, key, value, type, copyable';
|
|
30
29
|
const withCastValue = (detail) => ({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/additional-details/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAcA,sCAA8C;AAC9C,qCAA2D;AAE3D,wCAAsB;AACtB,2CAAyB;AAEzB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/additional-details/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAcA,sCAA8C;AAC9C,qCAA2D;AAE3D,wCAAsB;AACtB,2CAAyB;AAEzB,2FAA2F;AAC3F,gGAAgG;AAChG,gGAAgG;AAChG,iGAAiG;AACjG,mBAAmB;AACnB,MAAM,yBAAyB,GAC7B,sJAA+J,CAAC;AAElK,MAAM,iCAAiC,GAAG,oCAA6C,CAAC;AAExF,MAAM,aAAa,GAAG,CAA6C,MAAS,EAAE,EAAE,CAAC,CAAC;IAChF,GAAG,MAAM;IACT,KAAK,EAAE,IAAA,wBAAe,EAAC,MAAM,CAAC,IAA8B,EAAE,MAAM,CAAC,KAAK,CAAC;CAC5E,CAAC,CAAC;AAEH,MAAa,yBAAyB;IAEjB;IACA;IAFnB,YACmB,QAA6B,EAC7B,IAAiB;QADjB,aAAQ,GAAR,QAAQ,CAAqB;QAC7B,SAAI,GAAJ,IAAI,CAAa;IACjC,CAAC;IAEJ,KAAK,CAAC,OAAO,CAAC,mBAA2B;QACvC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ;aACxC,IAAI,CAAC,oBAAoB,CAAC;aAC1B,MAAM,CAAC,yBAAyB,CAAC;aACjC,EAAE,CAAC,iBAAiB,EAAE,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC;aAChD,EAAE,CAAC,QAAQ,EAAE,mBAAmB,CAAC;aACjC,MAAM,EAAE,CAAC;QACZ,IAAI,KAAK;YAAE,MAAM,IAAA,0BAAiB,EAAC,KAAK,CAAC,CAAC;QAC1C,OAAO,aAAa,CAAC,IAAI,CAAuC,CAAC;IACnE,CAAC;IAED,KAAK,CAAC,IAAI,CACR,MAAoC,EACpC,QAAgB;QAEhB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ;aACxC,IAAI,CAAC,oBAAoB,CAAC;aAC1B,MAAM,CAAC,iCAAiC,CAAC;aACzC,EAAE,CAAC,iBAAiB,EAAE,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC;aAChD,EAAE,CAAC,aAAa,EAAE,MAAM,CAAC;aACzB,EAAE,CAAC,WAAW,EAAE,QAAQ,CAAC;aACzB,KAAK,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;QACtC,IAAI,KAAK;YAAE,MAAM,IAAA,0BAAiB,EAAC,KAAK,CAAC,CAAC;QAC1C,OAAO,IAAI,CAAC,GAAG,CAAC,aAAa,CAAyC,CAAC;IACzE,CAAC;IAED,KAAK,CAAC,MAAM,CACV,MAAoC,EACpC,QAAgB,EAChB,KAA8B;QAE9B,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ;aACxC,IAAI,CAAC,oBAAoB,CAAC;aAC1B,MAAM,CAAC;YACN,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC,eAAe;YAC1C,WAAW,EAAE,MAAM;YACnB,SAAS,EAAE,QAAQ;YACnB,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,KAAK,EAAE,IAAA,uBAAc,EAAC,KAAK,CAAC,KAAK,CAAC;YAClC,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM;SAC7B,CAAC;aACD,MAAM,CAAC,yBAAyB,CAAC;aACjC,MAAM,EAAE,CAAC;QACZ,IAAI,KAAK;YAAE,MAAM,IAAA,0BAAiB,EAAC,KAAK,CAAC,CAAC;QAC1C,OAAO,aAAa,CAAC,IAAI,CAAuC,CAAC;IACnE,CAAC;IAED,KAAK,CAAC,MAAM,CACV,mBAA2B,EAC3B,KAAiC;QAEjC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ;aACxC,IAAI,CAAC,oBAAoB,CAAC;aAC1B,MAAM,CAAC;YACN,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,KAAK,EAAE,IAAA,uBAAc,EAAC,KAAK,CAAC,KAAK,CAAC;YAClC,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACpC,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM;SAClC,CAAC;aACD,EAAE,CAAC,QAAQ,EAAE,mBAAmB,CAAC;aACjC,EAAE,CAAC,iBAAiB,EAAE,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC;aAChD,MAAM,CAAC,yBAAyB,CAAC;aACjC,MAAM,EAAE,CAAC;QACZ,IAAI,KAAK;YAAE,MAAM,IAAA,0BAAiB,EAAC,KAAK,CAAC,CAAC;QAC1C,OAAO,aAAa,CAAC,IAAI,CAAuC,CAAC;IACnE,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,mBAA2B;QACtC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ;aAClC,IAAI,CAAC,oBAAoB,CAAC;aAC1B,MAAM,EAAE;aACR,EAAE,CAAC,QAAQ,EAAE,mBAAmB,CAAC;aACjC,EAAE,CAAC,iBAAiB,EAAE,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACpD,IAAI,KAAK;YAAE,MAAM,IAAA,0BAAiB,EAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;CACF;AArFD,8DAqFC"}
|
|
@@ -5,7 +5,7 @@ import { AdditionalDetailsTypes } from '@managemint-solutions/entities/additiona
|
|
|
5
5
|
*/
|
|
6
6
|
export declare const castValueByType: (type: AdditionalDetailsTypes, value: unknown) => unknown;
|
|
7
7
|
/**
|
|
8
|
-
* What gets written to the `text` column.
|
|
9
|
-
*
|
|
8
|
+
* What gets written to the `text` column. `String()` reproduces the JSON → text coercion
|
|
9
|
+
* PostgREST used to do for number/boolean/string.
|
|
10
10
|
*/
|
|
11
11
|
export declare const serializeValue: (value: string | number | boolean | Date | URL) => string;
|
|
@@ -29,8 +29,8 @@ const castValueByType = (type, value) => {
|
|
|
29
29
|
};
|
|
30
30
|
exports.castValueByType = castValueByType;
|
|
31
31
|
/**
|
|
32
|
-
* What gets written to the `text` column.
|
|
33
|
-
*
|
|
32
|
+
* What gets written to the `text` column. `String()` reproduces the JSON → text coercion
|
|
33
|
+
* PostgREST used to do for number/boolean/string.
|
|
34
34
|
*/
|
|
35
35
|
const serializeValue = (value) => value instanceof Date ? value.toISOString() : String(value);
|
|
36
36
|
exports.serializeValue = serializeValue;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ExchangeRefreshTokenDto as ExchangeRefreshTokenDtoType, ExchangeTokenHashDto as ExchangeTokenHashDtoType, loginDto as LoginDtoType, ResetPasswordDto as ResetPasswordDtoType, SendPasswordResetEmailDto as SendPasswordResetEmailDtoType } from '@managemint-solutions/entities/auth/dto';
|
|
2
|
+
export declare class SignInDto implements LoginDtoType {
|
|
3
|
+
readonly email: string;
|
|
4
|
+
readonly password: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class ExchangeRefreshTokenDto implements ExchangeRefreshTokenDtoType {
|
|
7
|
+
readonly refresh_token: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class SendPasswordResetEmailDto implements SendPasswordResetEmailDtoType {
|
|
10
|
+
readonly email: string;
|
|
11
|
+
}
|
|
12
|
+
export declare class ExchangeTokenHashDto implements ExchangeTokenHashDtoType {
|
|
13
|
+
readonly token_hash: string;
|
|
14
|
+
}
|
|
15
|
+
export declare class ResetPasswordDto implements ResetPasswordDtoType {
|
|
16
|
+
readonly password: string;
|
|
17
|
+
readonly access_token: string;
|
|
18
|
+
readonly refresh_token: string;
|
|
19
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
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.ResetPasswordDto = exports.ExchangeTokenHashDto = exports.SendPasswordResetEmailDto = exports.ExchangeRefreshTokenDto = exports.SignInDto = void 0;
|
|
13
|
+
const class_validator_1 = require("class-validator");
|
|
14
|
+
// class-validator versions of the shared DTO types from @managemint-solutions/entities.
|
|
15
|
+
// Each class `implements` its entities type so the wire contract cannot drift.
|
|
16
|
+
// The entities type is spelled `loginDto` (lowercase); the class keeps the `SignInDto` name.
|
|
17
|
+
class SignInDto {
|
|
18
|
+
email;
|
|
19
|
+
password;
|
|
20
|
+
}
|
|
21
|
+
exports.SignInDto = SignInDto;
|
|
22
|
+
__decorate([
|
|
23
|
+
(0, class_validator_1.IsEmail)({}, { message: 'Email is required' }),
|
|
24
|
+
__metadata("design:type", String)
|
|
25
|
+
], SignInDto.prototype, "email", void 0);
|
|
26
|
+
__decorate([
|
|
27
|
+
(0, class_validator_1.IsString)({ message: 'Password is required' }),
|
|
28
|
+
__metadata("design:type", String)
|
|
29
|
+
], SignInDto.prototype, "password", void 0);
|
|
30
|
+
class ExchangeRefreshTokenDto {
|
|
31
|
+
refresh_token;
|
|
32
|
+
}
|
|
33
|
+
exports.ExchangeRefreshTokenDto = ExchangeRefreshTokenDto;
|
|
34
|
+
__decorate([
|
|
35
|
+
(0, class_validator_1.IsString)({ message: 'Refresh token is required' }),
|
|
36
|
+
__metadata("design:type", String)
|
|
37
|
+
], ExchangeRefreshTokenDto.prototype, "refresh_token", void 0);
|
|
38
|
+
class SendPasswordResetEmailDto {
|
|
39
|
+
email;
|
|
40
|
+
}
|
|
41
|
+
exports.SendPasswordResetEmailDto = SendPasswordResetEmailDto;
|
|
42
|
+
__decorate([
|
|
43
|
+
(0, class_validator_1.IsEmail)({}, { message: 'Email is required' }),
|
|
44
|
+
__metadata("design:type", String)
|
|
45
|
+
], SendPasswordResetEmailDto.prototype, "email", void 0);
|
|
46
|
+
class ExchangeTokenHashDto {
|
|
47
|
+
token_hash;
|
|
48
|
+
}
|
|
49
|
+
exports.ExchangeTokenHashDto = ExchangeTokenHashDto;
|
|
50
|
+
__decorate([
|
|
51
|
+
(0, class_validator_1.IsString)({ message: 'Token hash is required' }),
|
|
52
|
+
__metadata("design:type", String)
|
|
53
|
+
], ExchangeTokenHashDto.prototype, "token_hash", void 0);
|
|
54
|
+
class ResetPasswordDto {
|
|
55
|
+
password;
|
|
56
|
+
access_token;
|
|
57
|
+
refresh_token;
|
|
58
|
+
}
|
|
59
|
+
exports.ResetPasswordDto = ResetPasswordDto;
|
|
60
|
+
__decorate([
|
|
61
|
+
(0, class_validator_1.IsString)({ message: 'Password is required' }),
|
|
62
|
+
__metadata("design:type", String)
|
|
63
|
+
], ResetPasswordDto.prototype, "password", void 0);
|
|
64
|
+
__decorate([
|
|
65
|
+
(0, class_validator_1.IsString)({ message: 'Access token is required' }),
|
|
66
|
+
__metadata("design:type", String)
|
|
67
|
+
], ResetPasswordDto.prototype, "access_token", void 0);
|
|
68
|
+
__decorate([
|
|
69
|
+
(0, class_validator_1.IsString)({ message: 'Refresh token is required' }),
|
|
70
|
+
__metadata("design:type", String)
|
|
71
|
+
], ResetPasswordDto.prototype, "refresh_token", void 0);
|
|
72
|
+
//# sourceMappingURL=dto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dto.js","sourceRoot":"","sources":["../../src/auth-client/dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qDAAoD;AASpD,wFAAwF;AACxF,+EAA+E;AAE/E,6FAA6F;AAC7F,MAAa,SAAS;IAEX,KAAK,CAAU;IAGf,QAAQ,CAAU;CAC5B;AAND,8BAMC;AAJU;IADR,IAAA,yBAAO,EAAC,EAAE,EAAE,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC;;wCACtB;AAGf;IADR,IAAA,0BAAQ,EAAC,EAAE,OAAO,EAAE,sBAAsB,EAAE,CAAC;;2CACnB;AAG7B,MAAa,uBAAuB;IAEzB,aAAa,CAAU;CACjC;AAHD,0DAGC;AADU;IADR,IAAA,0BAAQ,EAAC,EAAE,OAAO,EAAE,2BAA2B,EAAE,CAAC;;8DACnB;AAGlC,MAAa,yBAAyB;IAE3B,KAAK,CAAU;CACzB;AAHD,8DAGC;AADU;IADR,IAAA,yBAAO,EAAC,EAAE,EAAE,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC;;wDACtB;AAG1B,MAAa,oBAAoB;IAEtB,UAAU,CAAU;CAC9B;AAHD,oDAGC;AADU;IADR,IAAA,0BAAQ,EAAC,EAAE,OAAO,EAAE,wBAAwB,EAAE,CAAC;;wDACnB;AAG/B,MAAa,gBAAgB;IAElB,QAAQ,CAAU;IAGlB,YAAY,CAAU;IAGtB,aAAa,CAAU;CACjC;AATD,4CASC;AAPU;IADR,IAAA,0BAAQ,EAAC,EAAE,OAAO,EAAE,sBAAsB,EAAE,CAAC;;kDACnB;AAGlB;IADR,IAAA,0BAAQ,EAAC,EAAE,OAAO,EAAE,0BAA0B,EAAE,CAAC;;sDACnB;AAGtB;IADR,IAAA,0BAAQ,EAAC,EAAE,OAAO,EAAE,2BAA2B,EAAE,CAAC;;uDACnB"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type SupabaseClient as SupabaseJsClient } from '@supabase/supabase-js';
|
|
2
|
+
import type { ExchangeTokenResponse, LoginResponse } from '@managemint-solutions/entities/auth';
|
|
3
|
+
import type { ExchangeRefreshTokenDto, ExchangeTokenHashDto, loginDto, ResetPasswordDto, SendPasswordResetEmailDto } from '@managemint-solutions/entities/auth/dto';
|
|
4
|
+
export * from './dto';
|
|
5
|
+
export type SupabaseAuthClientConfig = {
|
|
6
|
+
url: string;
|
|
7
|
+
key: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* The auth flows, for callers that do not have a JWT yet. `SupabaseClient` needs the caller's
|
|
11
|
+
* token to build its RLS context, so sign-in, refresh and the password-reset exchanges live on
|
|
12
|
+
* this separate client, built from the publishable key alone.
|
|
13
|
+
*/
|
|
14
|
+
export declare class SupabaseAuthClient {
|
|
15
|
+
private readonly config;
|
|
16
|
+
readonly supabase: SupabaseJsClient;
|
|
17
|
+
constructor(config: SupabaseAuthClientConfig);
|
|
18
|
+
signIn(input: loginDto): Promise<LoginResponse>;
|
|
19
|
+
refreshSession(input: ExchangeRefreshTokenDto): Promise<ExchangeTokenResponse>;
|
|
20
|
+
/**
|
|
21
|
+
* Parity with the api: this client never holds a session (`persistSession` is off), so
|
|
22
|
+
* server-side there is nothing to revoke and the call is a no-op. Kept as the api had it.
|
|
23
|
+
*/
|
|
24
|
+
signOut(): Promise<void>;
|
|
25
|
+
/** `redirectTo` is passed in — the SDK reads no environment variables. */
|
|
26
|
+
sendPasswordResetEmail(input: SendPasswordResetEmailDto, redirectTo: string): Promise<void>;
|
|
27
|
+
exchangeRecoveryToken(input: ExchangeTokenHashDto): Promise<ExchangeTokenResponse>;
|
|
28
|
+
exchangeConfirmToken(input: ExchangeTokenHashDto): Promise<ExchangeTokenResponse>;
|
|
29
|
+
resetPassword(input: ResetPasswordDto): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Stamps `users.last_logged_in` as the user who just signed in — the users UPDATE policy
|
|
32
|
+
* allows `auth.uid() = mms_id`, so the write goes through a throwaway client carrying the
|
|
33
|
+
* fresh access token rather than this session-less one. Parity with the api: the result is
|
|
34
|
+
* ignored, a failed stamp must not fail the login.
|
|
35
|
+
*/
|
|
36
|
+
private stampLastLoggedIn;
|
|
37
|
+
}
|
|
38
|
+
export declare const createSupabaseAuthClient: (config: SupabaseAuthClientConfig) => SupabaseAuthClient;
|
|
@@ -0,0 +1,135 @@
|
|
|
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.createSupabaseAuthClient = exports.SupabaseAuthClient = void 0;
|
|
18
|
+
const supabase_js_1 = require("@supabase/supabase-js");
|
|
19
|
+
const errors_1 = require("../errors");
|
|
20
|
+
__exportStar(require("./dto"), exports);
|
|
21
|
+
// The api's "no session/user returned" NotFoundException, as an SDK error.
|
|
22
|
+
const noSession = (message) => new errors_1.SupabaseClientError({ status: 404, error: 'Authentication Error', message });
|
|
23
|
+
const toTokens = (session) => ({
|
|
24
|
+
access_token: session.access_token,
|
|
25
|
+
refresh_token: session.refresh_token,
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* The auth flows, for callers that do not have a JWT yet. `SupabaseClient` needs the caller's
|
|
29
|
+
* token to build its RLS context, so sign-in, refresh and the password-reset exchanges live on
|
|
30
|
+
* this separate client, built from the publishable key alone.
|
|
31
|
+
*/
|
|
32
|
+
class SupabaseAuthClient {
|
|
33
|
+
config;
|
|
34
|
+
supabase; // escape hatch for flows not covered by a method
|
|
35
|
+
constructor(config) {
|
|
36
|
+
this.config = config;
|
|
37
|
+
this.supabase = (0, supabase_js_1.createClient)(config.url, config.key, {
|
|
38
|
+
// Server-side and stateless: nothing is stored, refreshed or read out of a URL.
|
|
39
|
+
auth: { persistSession: false, autoRefreshToken: false, detectSessionInUrl: false },
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
async signIn(input) {
|
|
43
|
+
const { data, error } = await this.supabase.auth.signInWithPassword({
|
|
44
|
+
email: input.email,
|
|
45
|
+
password: input.password,
|
|
46
|
+
});
|
|
47
|
+
if (error)
|
|
48
|
+
throw (0, errors_1.mapAuthError)(error);
|
|
49
|
+
if (!data.session || !data.user) {
|
|
50
|
+
throw noSession('Authentication failed: No session or user data returned');
|
|
51
|
+
}
|
|
52
|
+
await this.stampLastLoggedIn(data.session.access_token, data.user.id);
|
|
53
|
+
return toTokens(data.session);
|
|
54
|
+
}
|
|
55
|
+
async refreshSession(input) {
|
|
56
|
+
const { data, error } = await this.supabase.auth.refreshSession({
|
|
57
|
+
refresh_token: input.refresh_token,
|
|
58
|
+
});
|
|
59
|
+
if (error)
|
|
60
|
+
throw (0, errors_1.mapAuthError)(error);
|
|
61
|
+
if (!data.session)
|
|
62
|
+
throw noSession('Token exchange failed: No session data returned');
|
|
63
|
+
return toTokens(data.session);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Parity with the api: this client never holds a session (`persistSession` is off), so
|
|
67
|
+
* server-side there is nothing to revoke and the call is a no-op. Kept as the api had it.
|
|
68
|
+
*/
|
|
69
|
+
async signOut() {
|
|
70
|
+
const { error } = await this.supabase.auth.signOut();
|
|
71
|
+
if (error)
|
|
72
|
+
throw (0, errors_1.mapAuthError)(error);
|
|
73
|
+
}
|
|
74
|
+
/** `redirectTo` is passed in — the SDK reads no environment variables. */
|
|
75
|
+
async sendPasswordResetEmail(input, redirectTo) {
|
|
76
|
+
const { error } = await this.supabase.auth.resetPasswordForEmail(input.email, { redirectTo });
|
|
77
|
+
if (error)
|
|
78
|
+
throw (0, errors_1.mapAuthError)(error);
|
|
79
|
+
}
|
|
80
|
+
async exchangeRecoveryToken(input) {
|
|
81
|
+
const { data, error } = await this.supabase.auth.verifyOtp({
|
|
82
|
+
type: 'recovery',
|
|
83
|
+
token_hash: input.token_hash,
|
|
84
|
+
});
|
|
85
|
+
if (error)
|
|
86
|
+
throw (0, errors_1.mapAuthError)(error);
|
|
87
|
+
if (!data.session)
|
|
88
|
+
throw noSession('Token exchange failed: No session data returned');
|
|
89
|
+
return toTokens(data.session);
|
|
90
|
+
}
|
|
91
|
+
async exchangeConfirmToken(input) {
|
|
92
|
+
const { data, error } = await this.supabase.auth.verifyOtp({
|
|
93
|
+
type: 'signup',
|
|
94
|
+
token_hash: input.token_hash,
|
|
95
|
+
});
|
|
96
|
+
if (error)
|
|
97
|
+
throw (0, errors_1.mapAuthError)(error);
|
|
98
|
+
if (!data.session)
|
|
99
|
+
throw noSession('Token exchange failed: No session data returned');
|
|
100
|
+
return toTokens(data.session);
|
|
101
|
+
}
|
|
102
|
+
async resetPassword(input) {
|
|
103
|
+
const { error: sessionError } = await this.supabase.auth.setSession({
|
|
104
|
+
access_token: input.access_token,
|
|
105
|
+
refresh_token: input.refresh_token,
|
|
106
|
+
});
|
|
107
|
+
if (sessionError)
|
|
108
|
+
throw (0, errors_1.mapAuthError)(sessionError);
|
|
109
|
+
const { error: updateError } = await this.supabase.auth.updateUser({
|
|
110
|
+
password: input.password,
|
|
111
|
+
});
|
|
112
|
+
if (updateError)
|
|
113
|
+
throw (0, errors_1.mapAuthError)(updateError);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Stamps `users.last_logged_in` as the user who just signed in — the users UPDATE policy
|
|
117
|
+
* allows `auth.uid() = mms_id`, so the write goes through a throwaway client carrying the
|
|
118
|
+
* fresh access token rather than this session-less one. Parity with the api: the result is
|
|
119
|
+
* ignored, a failed stamp must not fail the login.
|
|
120
|
+
*/
|
|
121
|
+
async stampLastLoggedIn(accessToken, userId) {
|
|
122
|
+
const asUser = (0, supabase_js_1.createClient)(this.config.url, this.config.key, {
|
|
123
|
+
global: { headers: { Authorization: `Bearer ${accessToken}` } },
|
|
124
|
+
auth: { persistSession: false, autoRefreshToken: false },
|
|
125
|
+
});
|
|
126
|
+
await asUser
|
|
127
|
+
.from('users')
|
|
128
|
+
.update({ last_logged_in: new Date().toISOString() })
|
|
129
|
+
.eq('mms_id', userId);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
exports.SupabaseAuthClient = SupabaseAuthClient;
|
|
133
|
+
const createSupabaseAuthClient = (config) => new SupabaseAuthClient(config);
|
|
134
|
+
exports.createSupabaseAuthClient = createSupabaseAuthClient;
|
|
135
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth-client/index.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { type SupabaseClient as SupabaseJsClient } from '@supabase/supabase-js';
|
|
2
|
-
import type { Database } from './database.types';
|
|
3
2
|
import { type AuthContext } from './auth';
|
|
4
3
|
import { AdditionalDetailsResource } from './additional-details';
|
|
5
4
|
import { ClientsResource } from './clients';
|
|
6
5
|
import { NotesResource } from './notes';
|
|
6
|
+
import { ProjectsResource } from './projects';
|
|
7
7
|
import { StatusesResource } from './statuses';
|
|
8
8
|
import { SupportingFilesResource } from './supporting-files';
|
|
9
|
-
|
|
9
|
+
import { TasksResource } from './tasks';
|
|
10
|
+
export type TypedSupabaseClient = SupabaseJsClient;
|
|
10
11
|
export type SupabaseClientConfig = {
|
|
11
12
|
url: string;
|
|
12
13
|
key: string;
|
|
@@ -20,6 +21,8 @@ export declare class SupabaseClient {
|
|
|
20
21
|
readonly notes: NotesResource;
|
|
21
22
|
readonly supportingFiles: SupportingFilesResource;
|
|
22
23
|
readonly clients: ClientsResource;
|
|
24
|
+
readonly projects: ProjectsResource;
|
|
25
|
+
readonly tasks: TasksResource;
|
|
23
26
|
constructor(config: SupabaseClientConfig);
|
|
24
27
|
}
|
|
25
28
|
export declare const createSupabaseClient: (config: SupabaseClientConfig) => SupabaseClient;
|
package/dist/client.js
CHANGED
|
@@ -6,8 +6,10 @@ const auth_1 = require("./auth");
|
|
|
6
6
|
const additional_details_1 = require("./additional-details");
|
|
7
7
|
const clients_1 = require("./clients");
|
|
8
8
|
const notes_1 = require("./notes");
|
|
9
|
+
const projects_1 = require("./projects");
|
|
9
10
|
const statuses_1 = require("./statuses");
|
|
10
11
|
const supporting_files_1 = require("./supporting-files");
|
|
12
|
+
const tasks_1 = require("./tasks");
|
|
11
13
|
class SupabaseClient {
|
|
12
14
|
supabase; // escape hatch for not-yet-migrated queries
|
|
13
15
|
auth;
|
|
@@ -16,6 +18,8 @@ class SupabaseClient {
|
|
|
16
18
|
notes;
|
|
17
19
|
supportingFiles;
|
|
18
20
|
clients;
|
|
21
|
+
projects;
|
|
22
|
+
tasks;
|
|
19
23
|
constructor(config) {
|
|
20
24
|
this.auth = (0, auth_1.decodeAuthContext)(config.accessToken);
|
|
21
25
|
this.supabase = (0, supabase_js_1.createClient)(config.url, config.key, {
|
|
@@ -27,6 +31,8 @@ class SupabaseClient {
|
|
|
27
31
|
this.notes = new notes_1.NotesResource(this.supabase, this.auth);
|
|
28
32
|
this.supportingFiles = new supporting_files_1.SupportingFilesResource(this.supabase, this.auth);
|
|
29
33
|
this.clients = new clients_1.ClientsResource(this.supabase, this.auth);
|
|
34
|
+
this.projects = new projects_1.ProjectsResource(this.supabase, this.auth);
|
|
35
|
+
this.tasks = new tasks_1.TasksResource(this.supabase, this.auth);
|
|
30
36
|
}
|
|
31
37
|
}
|
|
32
38
|
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;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":";;;AAAA,uDAA8F;AAC9F,iCAA6D;AAC7D,6DAAiE;AACjE,uCAA4C;AAC5C,mCAAwC;AACxC,yCAA8C;AAC9C,yCAA8C;AAC9C,yDAA6D;AAC7D,mCAAwC;AAaxC,MAAa,cAAc;IAChB,QAAQ,CAAsB,CAAC,4CAA4C;IAC3E,IAAI,CAAc;IAClB,QAAQ,CAAmB;IAC3B,iBAAiB,CAA4B;IAC7C,KAAK,CAAgB;IACrB,eAAe,CAA0B;IACzC,OAAO,CAAkB;IACzB,QAAQ,CAAmB;IAC3B,KAAK,CAAgB;IAE9B,YAAY,MAA4B;QACtC,IAAI,CAAC,IAAI,GAAG,IAAA,wBAAiB,EAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAClD,IAAI,CAAC,QAAQ,GAAG,IAAA,0BAAY,EAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE;YACnD,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;QAC7E,IAAI,CAAC,OAAO,GAAG,IAAI,yBAAe,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7D,IAAI,CAAC,QAAQ,GAAG,IAAI,2BAAgB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/D,IAAI,CAAC,KAAK,GAAG,IAAI,qBAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3D,CAAC;CACF;AAzBD,wCAyBC;AAEM,MAAM,oBAAoB,GAAG,CAAC,MAA4B,EAAkB,EAAE,CACnF,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;AADhB,QAAA,oBAAoB,wBACJ"}
|