@maravilla-labs/platform 0.5.1 → 0.6.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/dist/config.d.ts +116 -8
- package/dist/config.js +159 -2
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +6 -568
- package/dist/index.js +62 -0
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
- package/src/config.ts +313 -8
- package/src/remote-client.ts +81 -5
- package/src/types.ts +64 -654
- package/tests/policy-builder.test.ts +186 -0
- package/tests/types.test-d.ts +94 -0
- package/tsconfig.test.json +8 -0
package/src/types.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
// The typed document shape (`id`/`_id` row identity) is canonical in
|
|
2
|
+
// `@maravilla-labs/types`. Re-export so platform call sites can use it.
|
|
3
|
+
import type { DbDocument } from '@maravilla-labs/types';
|
|
4
|
+
export type { DbDocument } from '@maravilla-labs/types';
|
|
5
|
+
|
|
1
6
|
/**
|
|
2
7
|
* Key-Value namespace interface for storing and retrieving data.
|
|
3
8
|
* Similar to Cloudflare Workers KV API for familiar developer experience.
|
|
4
|
-
*
|
|
9
|
+
*
|
|
5
10
|
* @example
|
|
6
11
|
* ```typescript
|
|
7
12
|
* const platform = getPlatform();
|
|
@@ -161,7 +166,7 @@ export interface Database {
|
|
|
161
166
|
* );
|
|
162
167
|
* ```
|
|
163
168
|
*/
|
|
164
|
-
find(collection: string, filter?: any, options?: DbFindOptions): Promise<
|
|
169
|
+
find<T = Record<string, unknown>>(collection: string, filter?: any, options?: DbFindOptions): Promise<DbDocument<T>[]>;
|
|
165
170
|
|
|
166
171
|
/**
|
|
167
172
|
* Find a single document in a collection.
|
|
@@ -178,7 +183,7 @@ export interface Database {
|
|
|
178
183
|
* }
|
|
179
184
|
* ```
|
|
180
185
|
*/
|
|
181
|
-
findOne(collection: string, filter: any): Promise<
|
|
186
|
+
findOne<T = Record<string, unknown>>(collection: string, filter: any): Promise<DbDocument<T> | null>;
|
|
182
187
|
|
|
183
188
|
/**
|
|
184
189
|
* Insert a single document into a collection.
|
|
@@ -790,657 +795,62 @@ export interface PresenceService {
|
|
|
790
795
|
}
|
|
791
796
|
|
|
792
797
|
// ── Auth Types ──
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
user: AuthUser;
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
/**
|
|
853
|
-
* Custom registration field defined in project auth settings.
|
|
854
|
-
*/
|
|
855
|
-
export interface AuthField {
|
|
856
|
-
/** Field key (used as form field name) */
|
|
857
|
-
key: string;
|
|
858
|
-
/** Display label */
|
|
859
|
-
label: string;
|
|
860
|
-
/** Field type: text, email, phone, date, number, select, boolean, url, textarea */
|
|
861
|
-
field_type: string;
|
|
862
|
-
/** Whether the field is required */
|
|
863
|
-
required: boolean;
|
|
864
|
-
/** Whether the field appears on the registration form */
|
|
865
|
-
show_on_register: boolean;
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
/**
|
|
869
|
-
* Options for registering a new user.
|
|
870
|
-
*/
|
|
871
|
-
export interface RegisterOptions {
|
|
872
|
-
/** User's email address */
|
|
873
|
-
email: string;
|
|
874
|
-
/** Password (minimum 8 characters) */
|
|
875
|
-
password: string;
|
|
876
|
-
/** Optional profile data (custom fields) */
|
|
877
|
-
profile?: Record<string, any>;
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
/**
|
|
881
|
-
* Options for logging in.
|
|
882
|
-
*/
|
|
883
|
-
export interface LoginOptions {
|
|
884
|
-
/** User's email address */
|
|
885
|
-
email: string;
|
|
886
|
-
/** User's password */
|
|
887
|
-
password: string;
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
/**
|
|
891
|
-
* Filter options for listing users.
|
|
892
|
-
*/
|
|
893
|
-
export interface UserListFilter {
|
|
894
|
-
/** Max results per page (default 50) */
|
|
895
|
-
limit?: number;
|
|
896
|
-
/** Number of results to skip */
|
|
897
|
-
offset?: number;
|
|
898
|
-
/** Filter by account status */
|
|
899
|
-
status?: 'active' | 'suspended' | 'deactivated';
|
|
900
|
-
/** Filter by email (partial match) */
|
|
901
|
-
email_contains?: string;
|
|
902
|
-
/** Filter by group ID */
|
|
903
|
-
group_id?: string;
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
/**
|
|
907
|
-
* Paginated user list response.
|
|
908
|
-
*/
|
|
909
|
-
export interface UserListResponse {
|
|
910
|
-
/** Users in this page */
|
|
911
|
-
users: AuthUser[];
|
|
912
|
-
/** Total number of matching users */
|
|
913
|
-
total: number;
|
|
914
|
-
/** Page size */
|
|
915
|
-
limit: number;
|
|
916
|
-
/** Offset */
|
|
917
|
-
offset: number;
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
/**
|
|
921
|
-
* Options for updating a user.
|
|
922
|
-
*/
|
|
923
|
-
export interface UpdateUserOptions {
|
|
924
|
-
/** New email address */
|
|
925
|
-
email?: string;
|
|
926
|
-
/** New status */
|
|
927
|
-
status?: 'active' | 'suspended' | 'deactivated';
|
|
928
|
-
/** Profile data to merge */
|
|
929
|
-
profile?: Record<string, any>;
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
// ── Groups ──
|
|
933
|
-
|
|
934
|
-
export interface AuthGroup {
|
|
935
|
-
id: string;
|
|
936
|
-
name: string;
|
|
937
|
-
description: string | null;
|
|
938
|
-
permissions: string[];
|
|
939
|
-
member_count: number;
|
|
940
|
-
created_at: number;
|
|
941
|
-
updated_at: number;
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
export interface CreateGroupOptions {
|
|
945
|
-
name: string;
|
|
946
|
-
description?: string;
|
|
947
|
-
permissions?: string[];
|
|
948
|
-
}
|
|
949
|
-
|
|
950
|
-
export interface UpdateGroupOptions {
|
|
951
|
-
name?: string;
|
|
952
|
-
description?: string;
|
|
953
|
-
permissions?: string[];
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
export interface GroupPermission {
|
|
957
|
-
resource_name: string;
|
|
958
|
-
actions: string[];
|
|
959
|
-
}
|
|
960
|
-
|
|
961
|
-
// ── Circles ──
|
|
962
|
-
|
|
963
|
-
export interface AuthCircle {
|
|
964
|
-
id: string;
|
|
965
|
-
name: string;
|
|
966
|
-
metadata: Record<string, any> | null;
|
|
967
|
-
member_count: number;
|
|
968
|
-
created_at: number;
|
|
969
|
-
updated_at: number;
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
export interface CreateCircleOptions {
|
|
973
|
-
name: string;
|
|
974
|
-
metadata?: Record<string, any>;
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
export interface UpdateCircleOptions {
|
|
978
|
-
name?: string;
|
|
979
|
-
metadata?: Record<string, any>;
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
export interface AddCircleMemberOptions {
|
|
983
|
-
user_id: string;
|
|
984
|
-
relationship: string;
|
|
985
|
-
is_primary_contact?: boolean;
|
|
986
|
-
}
|
|
987
|
-
|
|
988
|
-
export interface CircleMembership {
|
|
989
|
-
user_id: string;
|
|
990
|
-
email: string;
|
|
991
|
-
relationship: string;
|
|
992
|
-
is_primary_contact: boolean;
|
|
993
|
-
joined_at: number;
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
// ── Resources ──
|
|
997
|
-
|
|
998
|
-
export type ResourceServiceType =
|
|
999
|
-
| 'kv'
|
|
1000
|
-
| 'database'
|
|
1001
|
-
| 'realtime'
|
|
1002
|
-
| 'media'
|
|
1003
|
-
| 'vector'
|
|
1004
|
-
| 'storage'
|
|
1005
|
-
| 'queue'
|
|
1006
|
-
| 'push'
|
|
1007
|
-
| 'workflow'
|
|
1008
|
-
| 'transforms';
|
|
1009
|
-
|
|
1010
|
-
export interface Resource {
|
|
1011
|
-
id: string;
|
|
1012
|
-
resource_name: string;
|
|
1013
|
-
title: string;
|
|
1014
|
-
description: string | null;
|
|
1015
|
-
actions: string[];
|
|
1016
|
-
policy: string | null;
|
|
1017
|
-
service_type: ResourceServiceType | null;
|
|
1018
|
-
read_filter: string | null;
|
|
1019
|
-
created_at: number;
|
|
1020
|
-
updated_at: number;
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
export interface CreateResourceOptions {
|
|
1024
|
-
resource_name: string;
|
|
1025
|
-
title: string;
|
|
1026
|
-
description?: string;
|
|
1027
|
-
actions?: string[];
|
|
1028
|
-
policy?: string;
|
|
1029
|
-
service_type?: ResourceServiceType;
|
|
1030
|
-
read_filter?: string;
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
export interface UpdateResourceOptions {
|
|
1034
|
-
title?: string;
|
|
1035
|
-
description?: string;
|
|
1036
|
-
actions?: string[];
|
|
1037
|
-
policy?: string;
|
|
1038
|
-
service_type?: ResourceServiceType;
|
|
1039
|
-
read_filter?: string;
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
// ── Relation types ──
|
|
1043
|
-
|
|
1044
|
-
export interface RelationType {
|
|
1045
|
-
id: string;
|
|
1046
|
-
relation_name: string;
|
|
1047
|
-
title: string;
|
|
1048
|
-
description: string | null;
|
|
1049
|
-
category: string;
|
|
1050
|
-
icon: string | null;
|
|
1051
|
-
color: string | null;
|
|
1052
|
-
inverse_relation_id: string | null;
|
|
1053
|
-
implies_stewardship: boolean;
|
|
1054
|
-
requires_minor: boolean;
|
|
1055
|
-
bidirectional: boolean;
|
|
1056
|
-
is_system: boolean;
|
|
1057
|
-
created_at: number;
|
|
1058
|
-
updated_at: number;
|
|
1059
|
-
}
|
|
1060
|
-
|
|
1061
|
-
export interface CreateRelationTypeOptions {
|
|
1062
|
-
relation_name: string;
|
|
1063
|
-
title: string;
|
|
1064
|
-
description?: string;
|
|
1065
|
-
category?: string;
|
|
1066
|
-
icon?: string;
|
|
1067
|
-
color?: string;
|
|
1068
|
-
inverse_relation_id?: string;
|
|
1069
|
-
implies_stewardship?: boolean;
|
|
1070
|
-
requires_minor?: boolean;
|
|
1071
|
-
bidirectional?: boolean;
|
|
1072
|
-
is_system?: boolean;
|
|
1073
|
-
}
|
|
1074
|
-
|
|
1075
|
-
export interface UpdateRelationTypeOptions {
|
|
1076
|
-
title?: string;
|
|
1077
|
-
description?: string;
|
|
1078
|
-
category?: string;
|
|
1079
|
-
icon?: string;
|
|
1080
|
-
color?: string;
|
|
1081
|
-
inverse_relation_id?: string;
|
|
1082
|
-
implies_stewardship?: boolean;
|
|
1083
|
-
requires_minor?: boolean;
|
|
1084
|
-
bidirectional?: boolean;
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
// ── Auth config (extended) ──
|
|
1088
|
-
|
|
1089
|
-
export interface AuthConfig {
|
|
1090
|
-
fields: AuthField[];
|
|
1091
|
-
oauth_providers: any[];
|
|
1092
|
-
branding: Record<string, any>;
|
|
1093
|
-
password_policy: Record<string, any>;
|
|
1094
|
-
session_config: Record<string, any>;
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
// ── Stewardship ──
|
|
1098
|
-
|
|
1099
|
-
export type DelegationMode = 'full' | 'scoped';
|
|
1100
|
-
export type StewardshipStatus = 'active' | 'suspended' | 'revoked' | 'expired';
|
|
1101
|
-
|
|
1102
|
-
export interface ScopedPermission {
|
|
1103
|
-
resource: string;
|
|
1104
|
-
actions: string[];
|
|
1105
|
-
}
|
|
1106
|
-
|
|
1107
|
-
export interface StewardshipOverride {
|
|
1108
|
-
id: string;
|
|
1109
|
-
steward_id: string;
|
|
1110
|
-
ward_id: string;
|
|
1111
|
-
delegation_mode: DelegationMode;
|
|
1112
|
-
scoped_permissions: ScopedPermission[];
|
|
1113
|
-
valid_from: number | null;
|
|
1114
|
-
valid_until: number | null;
|
|
1115
|
-
status: StewardshipStatus;
|
|
1116
|
-
reason: string | null;
|
|
1117
|
-
source: string;
|
|
1118
|
-
source_circle_id: string | null;
|
|
1119
|
-
source_relation_type_id: string | null;
|
|
1120
|
-
created_at: number;
|
|
1121
|
-
updated_at: number;
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
|
-
export interface CreateStewardshipOverrideOptions {
|
|
1125
|
-
steward_id: string;
|
|
1126
|
-
ward_id: string;
|
|
1127
|
-
delegation_mode?: DelegationMode;
|
|
1128
|
-
scoped_permissions?: ScopedPermission[];
|
|
1129
|
-
valid_from?: number;
|
|
1130
|
-
valid_until?: number;
|
|
1131
|
-
reason?: string;
|
|
1132
|
-
}
|
|
1133
|
-
|
|
1134
|
-
export interface StewardshipResolution {
|
|
1135
|
-
stewards: StewardshipOverride[];
|
|
1136
|
-
wards: StewardshipOverride[];
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
export interface ActAsContext {
|
|
1140
|
-
steward_id: string;
|
|
1141
|
-
ward_id: string;
|
|
1142
|
-
delegation_mode: DelegationMode;
|
|
1143
|
-
scoped_permissions: ScopedPermission[];
|
|
1144
|
-
session_token: string;
|
|
1145
|
-
expires_at: number;
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
export interface StewardshipAuditEntry {
|
|
1149
|
-
id: string;
|
|
1150
|
-
performed_by: string;
|
|
1151
|
-
on_behalf_of: string;
|
|
1152
|
-
action: string;
|
|
1153
|
-
resource: string | null;
|
|
1154
|
-
details: Record<string, any> | null;
|
|
1155
|
-
created_at: number;
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1158
|
-
/**
|
|
1159
|
-
* Sub-namespace exposed at `platform.auth.stewardship` mirroring the
|
|
1160
|
-
* runtime's `globalThis.platform.auth.stewardship.*` surface.
|
|
1161
|
-
*/
|
|
1162
|
-
export interface AuthStewardshipApi {
|
|
1163
|
-
resolve(userId: string): Promise<StewardshipResolution>;
|
|
1164
|
-
createOverride(opts: CreateStewardshipOverrideOptions): Promise<StewardshipOverride>;
|
|
1165
|
-
revoke(id: string): Promise<void>;
|
|
1166
|
-
checkPermission(stewardId: string, wardId: string, resource: string, action: string): Promise<boolean>;
|
|
1167
|
-
createActAs(stewardId: string, wardId: string): Promise<ActAsContext>;
|
|
1168
|
-
listAudit(userId: string, options?: { limit?: number; offset?: number }): Promise<StewardshipAuditEntry[]>;
|
|
1169
|
-
}
|
|
1170
|
-
|
|
1171
|
-
/**
|
|
1172
|
-
* Auth service for end-user authentication and user management.
|
|
1173
|
-
*
|
|
1174
|
-
* @example
|
|
1175
|
-
* ```typescript
|
|
1176
|
-
* const platform = getPlatform();
|
|
1177
|
-
*
|
|
1178
|
-
* // Register a new user
|
|
1179
|
-
* const user = await platform.auth.register({
|
|
1180
|
-
* email: 'user@example.com',
|
|
1181
|
-
* password: 'securePassword123'
|
|
1182
|
-
* });
|
|
1183
|
-
*
|
|
1184
|
-
* // Login
|
|
1185
|
-
* const session = await platform.auth.login({
|
|
1186
|
-
* email: 'user@example.com',
|
|
1187
|
-
* password: 'securePassword123'
|
|
1188
|
-
* });
|
|
1189
|
-
* // session.access_token — short-lived JWT
|
|
1190
|
-
* // session.refresh_token — single-use refresh token
|
|
1191
|
-
*
|
|
1192
|
-
* // Validate a token (e.g. from Authorization header or cookie)
|
|
1193
|
-
* const user = await platform.auth.validate(session.access_token);
|
|
1194
|
-
*
|
|
1195
|
-
* // Protect a route with withAuth middleware
|
|
1196
|
-
* export default {
|
|
1197
|
-
* fetch: platform.auth.withAuth(async (request) => {
|
|
1198
|
-
* // request.user is guaranteed to be set
|
|
1199
|
-
* return new Response(`Hello ${request.user.email}`);
|
|
1200
|
-
* })
|
|
1201
|
-
* };
|
|
1202
|
-
* ```
|
|
1203
|
-
*/
|
|
1204
|
-
export interface AuthService {
|
|
1205
|
-
/**
|
|
1206
|
-
* Register a new user with email and password.
|
|
1207
|
-
* @returns The created user (not yet email-verified)
|
|
1208
|
-
*/
|
|
1209
|
-
register(options: RegisterOptions): Promise<AuthUser>;
|
|
1210
|
-
|
|
1211
|
-
/**
|
|
1212
|
-
* Authenticate a user and create a session.
|
|
1213
|
-
* @returns Session with access token, refresh token, and user info
|
|
1214
|
-
*/
|
|
1215
|
-
login(options: LoginOptions): Promise<AuthSession>;
|
|
1216
|
-
|
|
1217
|
-
/**
|
|
1218
|
-
* Validate an access token and return the authenticated user.
|
|
1219
|
-
* @param accessToken - JWT access token from login or refresh
|
|
1220
|
-
* @throws If the token is invalid or expired
|
|
1221
|
-
*/
|
|
1222
|
-
validate(accessToken: string): Promise<AuthUser>;
|
|
1223
|
-
|
|
1224
|
-
/**
|
|
1225
|
-
* Refresh a session using a refresh token (single-use).
|
|
1226
|
-
* @param refreshToken - The refresh token from a previous login/refresh
|
|
1227
|
-
* @returns New session with fresh access and refresh tokens
|
|
1228
|
-
*/
|
|
1229
|
-
refresh(refreshToken: string): Promise<AuthSession>;
|
|
1230
|
-
|
|
1231
|
-
/**
|
|
1232
|
-
* Revoke a specific session.
|
|
1233
|
-
*/
|
|
1234
|
-
logout(sessionId: string): Promise<void>;
|
|
1235
|
-
|
|
1236
|
-
/**
|
|
1237
|
-
* Get a user by ID.
|
|
1238
|
-
* @returns The user, or null if not found
|
|
1239
|
-
*/
|
|
1240
|
-
getUser(userId: string): Promise<AuthUser | null>;
|
|
1241
|
-
|
|
1242
|
-
/**
|
|
1243
|
-
* List users with optional filtering and pagination.
|
|
1244
|
-
*/
|
|
1245
|
-
listUsers(filter?: UserListFilter): Promise<UserListResponse>;
|
|
1246
|
-
|
|
1247
|
-
/**
|
|
1248
|
-
* Update a user's email, status, or profile data.
|
|
1249
|
-
*/
|
|
1250
|
-
updateUser(userId: string, update: UpdateUserOptions): Promise<AuthUser>;
|
|
1251
|
-
|
|
1252
|
-
/**
|
|
1253
|
-
* Delete a user and all their sessions.
|
|
1254
|
-
*/
|
|
1255
|
-
deleteUser(userId: string): Promise<void>;
|
|
1256
|
-
|
|
1257
|
-
/**
|
|
1258
|
-
* Create an email verification token.
|
|
1259
|
-
* @returns The verification token (caller decides how to deliver it)
|
|
1260
|
-
*/
|
|
1261
|
-
sendVerification(userId: string): Promise<{ token: string }>;
|
|
1262
|
-
|
|
1263
|
-
/**
|
|
1264
|
-
* Verify an email address using a verification token.
|
|
1265
|
-
*/
|
|
1266
|
-
verifyEmail(token: string): Promise<void>;
|
|
1267
|
-
|
|
1268
|
-
/**
|
|
1269
|
-
* Create a password reset token for an email address.
|
|
1270
|
-
* @returns The reset token (caller decides how to deliver it)
|
|
1271
|
-
*/
|
|
1272
|
-
sendPasswordReset(email: string): Promise<{ token: string }>;
|
|
1273
|
-
|
|
1274
|
-
/**
|
|
1275
|
-
* Reset a password using a reset token.
|
|
1276
|
-
*/
|
|
1277
|
-
resetPassword(token: string, newPassword: string): Promise<void>;
|
|
1278
|
-
|
|
1279
|
-
/**
|
|
1280
|
-
* Change a user's password (requires old password).
|
|
1281
|
-
*/
|
|
1282
|
-
changePassword(userId: string, oldPassword: string, newPassword: string): Promise<void>;
|
|
1283
|
-
|
|
1284
|
-
/**
|
|
1285
|
-
* Get the configured registration fields for this project.
|
|
1286
|
-
*/
|
|
1287
|
-
getFieldConfig(): Promise<{ fields: AuthField[] }>;
|
|
1288
|
-
|
|
1289
|
-
/**
|
|
1290
|
-
* Start an OAuth flow by generating an authorization URL.
|
|
1291
|
-
* Redirect the user to the returned URL to begin authentication.
|
|
1292
|
-
*
|
|
1293
|
-
* @param provider - Provider name: "google", "github", "okta", or "custom_oidc"
|
|
1294
|
-
* @param options - Optional configuration
|
|
1295
|
-
* @returns Object with `auth_url` (redirect target) and `state` (for CSRF verification)
|
|
1296
|
-
*/
|
|
1297
|
-
getOAuthUrl(provider: string, options?: { redirectUri?: string }): Promise<{ auth_url: string; state: string }>;
|
|
1298
|
-
|
|
1299
|
-
/**
|
|
1300
|
-
* Complete an OAuth flow by exchanging the authorization code.
|
|
1301
|
-
* Call this after the provider redirects back with a code and state.
|
|
1302
|
-
*
|
|
1303
|
-
* @param provider - Provider name
|
|
1304
|
-
* @param params - The code and state from the OAuth callback
|
|
1305
|
-
* @returns Either a session (user authenticated) or a link_required result
|
|
1306
|
-
*/
|
|
1307
|
-
handleOAuthCallback(provider: string, params: { code: string; state: string }): Promise<
|
|
1308
|
-
| AuthSession
|
|
1309
|
-
| { type: 'LinkRequired'; email: string; provider: string; provider_id: string; existing_user_id: string }
|
|
1310
|
-
>;
|
|
1311
|
-
|
|
1312
|
-
/**
|
|
1313
|
-
* Middleware helper that validates auth and injects `request.user`.
|
|
1314
|
-
* Returns 401 JSON response if no valid token is found.
|
|
1315
|
-
*
|
|
1316
|
-
* Extracts token from `Authorization: Bearer <token>` header
|
|
1317
|
-
* or `__session` cookie.
|
|
1318
|
-
*
|
|
1319
|
-
* @example
|
|
1320
|
-
* ```typescript
|
|
1321
|
-
* export default {
|
|
1322
|
-
* fetch: platform.auth.withAuth(async (request) => {
|
|
1323
|
-
* const data = await platform.db.items.find({ owner: request.user.id });
|
|
1324
|
-
* return Response.json(data);
|
|
1325
|
-
* })
|
|
1326
|
-
* };
|
|
1327
|
-
* ```
|
|
1328
|
-
*/
|
|
1329
|
-
withAuth<T extends (request: Request & { user: AuthUser }) => Promise<Response>>(
|
|
1330
|
-
handler: T
|
|
1331
|
-
): (request: Request) => Promise<Response>;
|
|
1332
|
-
|
|
1333
|
-
// ── Groups (RBAC) ──
|
|
1334
|
-
|
|
1335
|
-
createGroup(options: CreateGroupOptions): Promise<AuthGroup>;
|
|
1336
|
-
listGroups(): Promise<AuthGroup[]>;
|
|
1337
|
-
getGroup(groupId: string): Promise<AuthGroup | null>;
|
|
1338
|
-
/**
|
|
1339
|
-
* Look up a group by its declarative name (the same name used in
|
|
1340
|
-
* `maravilla.config.ts`'s `groups: [...]` block). Returns null if the
|
|
1341
|
-
* auth-settings reconciler hasn't created it yet. Apps that want to
|
|
1342
|
-
* add a user to a group typically only know the name, so use this
|
|
1343
|
-
* first to resolve the id, then call `addUserToGroup`.
|
|
1344
|
-
*/
|
|
1345
|
-
getGroupByName(name: string): Promise<AuthGroup | null>;
|
|
1346
|
-
updateGroup(groupId: string, options: UpdateGroupOptions): Promise<AuthGroup>;
|
|
1347
|
-
deleteGroup(groupId: string): Promise<void>;
|
|
1348
|
-
addUserToGroup(userId: string, groupId: string): Promise<void>;
|
|
1349
|
-
removeUserFromGroup(userId: string, groupId: string): Promise<void>;
|
|
1350
|
-
getUserGroups(userId: string): Promise<AuthGroup[]>;
|
|
1351
|
-
getGroupMembers(groupId: string): Promise<AuthUser[]>;
|
|
1352
|
-
getGroupPermissions(groupId: string): Promise<GroupPermission[]>;
|
|
1353
|
-
setGroupPermissions(groupId: string, permissions: GroupPermission[]): Promise<void>;
|
|
1354
|
-
|
|
1355
|
-
// ── Circles ──
|
|
1356
|
-
|
|
1357
|
-
createCircle(options: CreateCircleOptions): Promise<AuthCircle>;
|
|
1358
|
-
listCircles(): Promise<AuthCircle[]>;
|
|
1359
|
-
getCircle(circleId: string): Promise<AuthCircle | null>;
|
|
1360
|
-
updateCircle(circleId: string, options: UpdateCircleOptions): Promise<AuthCircle>;
|
|
1361
|
-
deleteCircle(circleId: string): Promise<void>;
|
|
1362
|
-
addCircleMember(circleId: string, options: AddCircleMemberOptions): Promise<void>;
|
|
1363
|
-
removeCircleMember(circleId: string, userId: string): Promise<void>;
|
|
1364
|
-
getCircleMembers(circleId: string): Promise<CircleMembership[]>;
|
|
1365
|
-
getUserCircles(userId: string): Promise<AuthCircle[]>;
|
|
1366
|
-
|
|
1367
|
-
// ── Resources ──
|
|
1368
|
-
|
|
1369
|
-
createResource(options: CreateResourceOptions): Promise<Resource>;
|
|
1370
|
-
listResources(): Promise<Resource[]>;
|
|
1371
|
-
updateResource(resourceId: string, options: UpdateResourceOptions): Promise<Resource>;
|
|
1372
|
-
deleteResource(resourceId: string): Promise<void>;
|
|
1373
|
-
|
|
1374
|
-
// ── Relation types ──
|
|
1375
|
-
|
|
1376
|
-
createRelationType(options: CreateRelationTypeOptions): Promise<RelationType>;
|
|
1377
|
-
listRelationTypes(): Promise<RelationType[]>;
|
|
1378
|
-
updateRelationType(id: string, options: UpdateRelationTypeOptions): Promise<RelationType>;
|
|
1379
|
-
deleteRelationType(id: string): Promise<void>;
|
|
1380
|
-
|
|
1381
|
-
// ── Profile ──
|
|
1382
|
-
|
|
1383
|
-
getProfile(userId: string): Promise<Record<string, any>>;
|
|
1384
|
-
setProfile(userId: string, data: Record<string, any>): Promise<void>;
|
|
1385
|
-
|
|
1386
|
-
// ── Auth config ──
|
|
1387
|
-
|
|
1388
|
-
getAuthConfig(): Promise<AuthConfig>;
|
|
1389
|
-
setAuthConfig(config: AuthConfig): Promise<void>;
|
|
1390
|
-
|
|
1391
|
-
// ── Stewardship (sub-namespace mirroring the runtime bridge) ──
|
|
1392
|
-
|
|
1393
|
-
readonly stewardship: AuthStewardshipApi;
|
|
1394
|
-
|
|
1395
|
-
// ── Request-scoped identity + authorization ──
|
|
1396
|
-
//
|
|
1397
|
-
// These methods operate on the **current request's** caller context.
|
|
1398
|
-
// They're meaningful inside the platform runtime (one isolate serving a
|
|
1399
|
-
// Deno request). When called from a remote client — code running outside
|
|
1400
|
-
// the runtime — they throw, because there is no per-request context to
|
|
1401
|
-
// bind.
|
|
1402
|
-
|
|
1403
|
-
/**
|
|
1404
|
-
* Explicitly bind the caller for the remainder of this request.
|
|
1405
|
-
* Pass a JWT to validate + bind, or `null` / `""` to clear.
|
|
1406
|
-
*
|
|
1407
|
-
* `login()` already binds implicitly on success; reach for `setCurrentUser`
|
|
1408
|
-
* when you receive a JWT from an inbound `Authorization` header or cookie
|
|
1409
|
-
* and want subsequent KV/DB/realtime/media ops to run as that user.
|
|
1410
|
-
*
|
|
1411
|
-
* Not available on remote clients — throws.
|
|
1412
|
-
*/
|
|
1413
|
-
setCurrentUser(token: string | null): Promise<void>;
|
|
1414
|
-
|
|
1415
|
-
/**
|
|
1416
|
-
* Snapshot of the currently bound caller. Returns an anonymous caller
|
|
1417
|
-
* (`is_anonymous: true`) when no identity has been bound.
|
|
1418
|
-
*
|
|
1419
|
-
* Not available on remote clients — throws.
|
|
1420
|
-
*/
|
|
1421
|
-
getCurrentUser(): AuthCaller;
|
|
1422
|
-
|
|
1423
|
-
/**
|
|
1424
|
-
* Ask the policy engine whether the bound caller would be allowed to
|
|
1425
|
-
* perform `action` on `resourceId`, given the supplied `node` payload.
|
|
1426
|
-
* Returns a boolean — never throws on denial.
|
|
1427
|
-
*
|
|
1428
|
-
* The check runs the exact same evaluator that gates direct KV/DB/
|
|
1429
|
-
* realtime/media ops, so `can(...)` is authoritative.
|
|
1430
|
-
*
|
|
1431
|
-
* @example
|
|
1432
|
-
* ```typescript
|
|
1433
|
-
* const ok = await platform.auth.can("delete", "documents", {
|
|
1434
|
-
* owner: doc.owner,
|
|
1435
|
-
* status: doc.status,
|
|
1436
|
-
* });
|
|
1437
|
-
* if (!ok) return new Response("Forbidden", { status: 403 });
|
|
1438
|
-
* ```
|
|
1439
|
-
*
|
|
1440
|
-
* Not available on remote clients — throws.
|
|
1441
|
-
*/
|
|
1442
|
-
can(action: string, resourceId: string, node?: Record<string, unknown> | null): Promise<boolean>;
|
|
1443
|
-
}
|
|
798
|
+
//
|
|
799
|
+
// The auth/policy/relations type surface is canonical in
|
|
800
|
+
// `@maravilla-labs/types` (the leaf package). We re-export every symbol
|
|
801
|
+
// here so existing `import { ... } from './types.js'` / from
|
|
802
|
+
// `@maravilla-labs/platform` call sites keep working unchanged, and so
|
|
803
|
+
// `RemoteAuthService implements AuthService` references the single source
|
|
804
|
+
// of truth. DRY: do not redeclare these locally.
|
|
805
|
+
//
|
|
806
|
+
// `AuthService` is also imported (not just re-exported) because the
|
|
807
|
+
// `Platform` interface below references it within this module's scope.
|
|
808
|
+
import type { AuthService } from '@maravilla-labs/types';
|
|
809
|
+
export type {
|
|
810
|
+
AuthUser,
|
|
811
|
+
AuthCaller,
|
|
812
|
+
AuthSession,
|
|
813
|
+
AuthField,
|
|
814
|
+
RegisterOptions,
|
|
815
|
+
LoginOptions,
|
|
816
|
+
CreateManagedUserOptions,
|
|
817
|
+
UserListFilter,
|
|
818
|
+
UserListResponse,
|
|
819
|
+
UpdateUserOptions,
|
|
820
|
+
AuthGroup,
|
|
821
|
+
CreateGroupOptions,
|
|
822
|
+
UpdateGroupOptions,
|
|
823
|
+
GroupPermission,
|
|
824
|
+
AuthCircle,
|
|
825
|
+
CreateCircleOptions,
|
|
826
|
+
UpdateCircleOptions,
|
|
827
|
+
AddCircleMemberOptions,
|
|
828
|
+
CircleMembership,
|
|
829
|
+
ResourceServiceType,
|
|
830
|
+
Resource,
|
|
831
|
+
CreateResourceOptions,
|
|
832
|
+
UpdateResourceOptions,
|
|
833
|
+
RelationType,
|
|
834
|
+
CreateRelationTypeOptions,
|
|
835
|
+
UpdateRelationTypeOptions,
|
|
836
|
+
Relation,
|
|
837
|
+
AddRelationOptions,
|
|
838
|
+
RelationListDirection,
|
|
839
|
+
ListRelationsOptions,
|
|
840
|
+
AuthConfig,
|
|
841
|
+
DelegationMode,
|
|
842
|
+
StewardshipStatus,
|
|
843
|
+
ScopedPermission,
|
|
844
|
+
StewardshipOverride,
|
|
845
|
+
CreateStewardshipOverrideOptions,
|
|
846
|
+
StewardshipResolution,
|
|
847
|
+
ActAsContext,
|
|
848
|
+
StewardshipAuditEntry,
|
|
849
|
+
AuthStewardshipApi,
|
|
850
|
+
PolicyExplain,
|
|
851
|
+
CanCheck,
|
|
852
|
+
AuthService,
|
|
853
|
+
} from '@maravilla-labs/types';
|
|
1444
854
|
|
|
1445
855
|
/**
|
|
1446
856
|
* Per-request opt-out toggle for the Layer 2 policy evaluator.
|