@foir/sdk 0.21.0 → 0.23.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/CHANGELOG.md +135 -1
- package/README.md +15 -15
- package/dist/app/client.d.ts +93 -86
- package/dist/app/contract/proto/apps/v1/apps_pb.d.ts +14 -13
- package/dist/app/dispatch.d.ts +5 -5
- package/dist/app/errors.d.ts +17 -15
- package/dist/app/index.d.ts +4 -4
- package/dist/app/naming.d.ts +1 -1
- package/dist/app/ticket.d.ts +2 -2
- package/dist/app/vocabulary.generated.d.ts +2 -2
- package/dist/app-contract.js +3 -3
- package/dist/app.js +92 -90
- package/dist/auth/access.d.ts +19 -19
- package/dist/auth/auth.d.ts +251 -117
- package/dist/auth/grant-table.generated.d.ts +5 -4
- package/dist/auth/hosted.d.ts +38 -14
- package/dist/auth/index.d.ts +9 -9
- package/dist/auth/operations.d.ts +153 -33
- package/dist/auth/ops.d.ts +39 -21
- package/dist/auth/session-client.d.ts +3 -3
- package/dist/auth-session.js +3 -3
- package/dist/auth.js +400 -250
- package/dist/client.js +5 -8
- package/dist/codegen/preset.d.ts +1 -1
- package/dist/data/builtins.d.ts +26 -26
- package/dist/data/client.d.ts +3 -3
- package/dist/data/decimal.d.ts +1 -1
- package/dist/data/index.d.ts +1 -1
- package/dist/data/manifest.d.ts +1 -1
- package/dist/data/schema.d.ts +2 -2
- package/dist/data/transport.d.ts +14 -13
- package/dist/data/ws-transport.d.ts +1 -1
- package/dist/data.js +8 -11
- package/dist/graphql/content-client.d.ts +13 -13
- package/dist/index.js +1 -4
- package/dist/live/drift.d.ts +1 -1
- package/dist/media/screen-capture.d.ts +1 -1
- package/dist/next/index.d.ts +2 -2
- package/dist/next/session.d.ts +10 -10
- package/dist/next.js +78 -60
- package/dist/placement/index.d.ts +13 -13
- package/dist/placement.js +127 -116
- package/dist/push.js +62 -44
- package/dist/react/FoirFeedback.d.ts +2 -2
- package/dist/react/FoirProvider.d.ts +24 -24
- package/dist/react/SignIn.d.ts +4 -4
- package/dist/react/UserButton.d.ts +1 -1
- package/dist/react/feedback-notes.d.ts +8 -6
- package/dist/react/index.d.ts +3 -3
- package/dist/react.js +238 -209
- package/dist/realtime/index.d.ts +1 -1
- package/dist/server/callback-client.d.ts +4 -4
- package/dist/server/events-client.d.ts +21 -21
- package/dist/server/operation-types.d.ts +8 -8
- package/dist/server/require-scoped-token.d.ts +3 -3
- package/dist/server/types.d.ts +2 -2
- package/dist/server/verify-scoped-token.d.ts +3 -3
- package/dist/server.js +130 -126
- package/dist/transport/foir-http.d.ts +14 -14
- package/dist/transport/key-kind.d.ts +1 -12
- package/dist/types/index.d.ts +2 -2
- package/package.json +1 -1
package/dist/react.js
CHANGED
|
@@ -18,10 +18,7 @@ import { print as print2 } from "graphql";
|
|
|
18
18
|
var KEY_PREFIXES = [
|
|
19
19
|
["foir_pub_", "publishable"],
|
|
20
20
|
["foir_srv_", "server"],
|
|
21
|
-
["foir_adm_", "admin"]
|
|
22
|
-
["pk_", "publishable"],
|
|
23
|
-
["sk_", "older"],
|
|
24
|
-
["tc_", "older"]
|
|
21
|
+
["foir_adm_", "admin"]
|
|
25
22
|
];
|
|
26
23
|
function foirKeyKind(apiKey) {
|
|
27
24
|
if (typeof apiKey !== "string") return void 0;
|
|
@@ -205,8 +202,8 @@ var FoirAuthDowngradedError = class extends FoirRequestError {
|
|
|
205
202
|
downgrade;
|
|
206
203
|
constructor(downgrade) {
|
|
207
204
|
super(
|
|
208
|
-
`[foir] your
|
|
209
|
-
{ graphQLErrors: [{ message: "
|
|
205
|
+
`[foir] your user token was ${downgrade.userToken} (${downgrade.reason}), so the request was served as ${downgrade.servedAs}`,
|
|
206
|
+
{ graphQLErrors: [{ message: "user token rejected", extensions: { code: "AUTH_DOWNGRADED" } }] }
|
|
210
207
|
);
|
|
211
208
|
this.name = "FoirAuthDowngradedError";
|
|
212
209
|
this.downgrade = downgrade;
|
|
@@ -214,7 +211,7 @@ var FoirAuthDowngradedError = class extends FoirRequestError {
|
|
|
214
211
|
};
|
|
215
212
|
var FoirSessionExpiredError = class extends FoirRequestError {
|
|
216
213
|
constructor(options) {
|
|
217
|
-
super("[foir] the
|
|
214
|
+
super("[foir] the user session has expired and could not be refreshed: sign in again", {
|
|
218
215
|
cause: options?.cause,
|
|
219
216
|
graphQLErrors: [{ message: "session expired", extensions: { code: "SESSION_EXPIRED" } }]
|
|
220
217
|
});
|
|
@@ -231,7 +228,7 @@ function reportAuthDowngrade(envelope) {
|
|
|
231
228
|
if (warnedDowngrade === downgrade.reason) return;
|
|
232
229
|
warnedDowngrade = downgrade.reason;
|
|
233
230
|
console.warn(
|
|
234
|
-
`[foir] your
|
|
231
|
+
`[foir] your user token was ${downgrade.userToken} (${downgrade.reason}) \u2014 this request was served as ${downgrade.servedAs}, so auth-targeted content resolved to its anonymous variant. ` + (downgrade.reason === "expired" ? "Re-exchange the token and retry." : "Check which credential you are sending.")
|
|
235
232
|
);
|
|
236
233
|
}
|
|
237
234
|
function refusePrunedDocument(json, options) {
|
|
@@ -950,42 +947,63 @@ var AUTH_OPS = {
|
|
|
950
947
|
authConfig: "authConfig",
|
|
951
948
|
authProviders: "authProviders",
|
|
952
949
|
defaultAuthProvider: "defaultAuthProvider",
|
|
953
|
-
|
|
950
|
+
signupContext: "signupContext",
|
|
954
951
|
// Post-credential self reads.
|
|
955
952
|
currentUser: "currentUser",
|
|
956
953
|
myProviderToken: "myProviderToken",
|
|
957
|
-
// What the calling credential may do, and for a signed-in
|
|
954
|
+
// What the calling credential may do, and for a signed-in user the roles
|
|
958
955
|
// they hold. `./access` reads it.
|
|
959
956
|
whoami: "whoami",
|
|
960
957
|
// Methods.
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
958
|
+
login: "login",
|
|
959
|
+
register: "register",
|
|
960
|
+
requestOTP: "requestOTP",
|
|
961
|
+
loginWithOTP: "loginWithOTP",
|
|
965
962
|
// Session lifecycle.
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
// Password management and account lifecycle
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
963
|
+
refreshToken: "refreshToken",
|
|
964
|
+
logout: "logout",
|
|
965
|
+
joinWaitlist: "joinWaitlist",
|
|
966
|
+
// Password management and account lifecycle.
|
|
967
|
+
requestPasswordReset: "requestPasswordReset",
|
|
968
|
+
resetPassword: "resetPassword",
|
|
969
|
+
updatePassword: "updatePassword",
|
|
970
|
+
verifyEmail: "verifyEmail",
|
|
974
971
|
deleteMyAccount: "deleteMyAccount",
|
|
975
|
-
// The
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
//
|
|
980
|
-
//
|
|
972
|
+
// The user's own profile, and the apps they have agreed may act for them.
|
|
973
|
+
updateMyProfile: "updateMyProfile",
|
|
974
|
+
myAuthorizedApps: "myAuthorizedApps",
|
|
975
|
+
revokeAuthorizedApp: "revokeAuthorizedApp",
|
|
976
|
+
// Where they are signed in, their personal access tokens, and the
|
|
977
|
+
// providers they sign in with.
|
|
978
|
+
mySessions: "mySessions",
|
|
979
|
+
endMySession: "endMySession",
|
|
980
|
+
signOutEverywhere: "signOutEverywhere",
|
|
981
|
+
createPersonalAccessToken: "createPersonalAccessToken",
|
|
982
|
+
mySignInMethods: "mySignInMethods",
|
|
983
|
+
connectSignInMethod: "connectSignInMethod",
|
|
984
|
+
disconnectSignInMethod: "disconnectSignInMethod",
|
|
985
|
+
// Their second factors. A change needs one proven first, by a step-up.
|
|
986
|
+
myFactors: "myFactors",
|
|
987
|
+
beginStepUp: "beginStepUp",
|
|
988
|
+
completeStepUp: "completeStepUp",
|
|
989
|
+
beginFactorEnrollment: "beginFactorEnrollment",
|
|
990
|
+
completeFactorEnrollment: "completeFactorEnrollment",
|
|
991
|
+
removeFactor: "removeFactor",
|
|
992
|
+
makeRecoveryCodes: "makeRecoveryCodes",
|
|
993
|
+
// The organizations the caller may stand in. Nothing selects one: a request
|
|
994
|
+
// names the organization it acts in (`orgId` or `orgUrl` below), and the
|
|
995
|
+
// platform checks the caller stands there every time.
|
|
981
996
|
myOrganizations: "myOrganizations",
|
|
982
|
-
selectMyOrganization: "selectMyOrganization",
|
|
983
997
|
// Founding one. Present in a manifest only when the project opted in.
|
|
984
|
-
|
|
998
|
+
registerOrganization: "registerOrganization",
|
|
985
999
|
// External identity providers.
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1000
|
+
loginWithProvider: "loginWithProvider",
|
|
1001
|
+
providerCallback: "providerCallback",
|
|
1002
|
+
providerVerifyOTP: "providerVerifyOTP",
|
|
1003
|
+
// A provider sign-in that names an address somebody already holds, waiting
|
|
1004
|
+
// for the code sent to it.
|
|
1005
|
+
confirmProviderLink: "confirmProviderLink",
|
|
1006
|
+
resendProviderLinkCode: "resendProviderLinkCode"
|
|
989
1007
|
};
|
|
990
1008
|
function authClientConfig(env, options) {
|
|
991
1009
|
const apiKey = resolveFoirApiKey(env);
|
|
@@ -1048,28 +1066,28 @@ function stripUndefined(args) {
|
|
|
1048
1066
|
// src/auth/auth.ts
|
|
1049
1067
|
var TOKEN_KEY = "foir:token";
|
|
1050
1068
|
var REFRESH_KEY = "foir:refreshToken";
|
|
1051
|
-
var
|
|
1069
|
+
var USER_ID_KEY = "foir:userId";
|
|
1052
1070
|
var EMAIL_KEY = "foir:email";
|
|
1053
|
-
async function
|
|
1054
|
-
return authOp(env, AUTH_OPS.
|
|
1071
|
+
async function login(env, vars) {
|
|
1072
|
+
return authOp(env, AUTH_OPS.login, vars);
|
|
1055
1073
|
}
|
|
1056
|
-
async function
|
|
1057
|
-
return authOp(env, AUTH_OPS.
|
|
1074
|
+
async function register(env, vars) {
|
|
1075
|
+
return authOp(env, AUTH_OPS.register, vars);
|
|
1058
1076
|
}
|
|
1059
|
-
async function
|
|
1060
|
-
return authOp(env, AUTH_OPS.
|
|
1077
|
+
async function requestOTP(env, email) {
|
|
1078
|
+
return authOp(env, AUTH_OPS.requestOTP, { email });
|
|
1061
1079
|
}
|
|
1062
|
-
async function
|
|
1063
|
-
return authOp(env, AUTH_OPS.
|
|
1080
|
+
async function loginWithOTP(env, vars) {
|
|
1081
|
+
return authOp(env, AUTH_OPS.loginWithOTP, vars);
|
|
1064
1082
|
}
|
|
1065
|
-
async function
|
|
1066
|
-
return authOp(env, AUTH_OPS.
|
|
1083
|
+
async function refreshTokens(env, refreshToken) {
|
|
1084
|
+
return authOp(env, AUTH_OPS.refreshToken, { refreshToken });
|
|
1067
1085
|
}
|
|
1068
|
-
async function
|
|
1069
|
-
return authOp(env, AUTH_OPS.
|
|
1086
|
+
async function loginWithProvider(env, input) {
|
|
1087
|
+
return authOp(env, AUTH_OPS.loginWithProvider, { input });
|
|
1070
1088
|
}
|
|
1071
|
-
async function
|
|
1072
|
-
return authOp(env, AUTH_OPS.
|
|
1089
|
+
async function providerCallback(env, input) {
|
|
1090
|
+
return authOp(env, AUTH_OPS.providerCallback, { input });
|
|
1073
1091
|
}
|
|
1074
1092
|
async function getAuthProviders(env) {
|
|
1075
1093
|
return authOp(env, AUTH_OPS.authProviders);
|
|
@@ -1077,42 +1095,42 @@ async function getAuthProviders(env) {
|
|
|
1077
1095
|
async function saveSession(adapter, result) {
|
|
1078
1096
|
await adapter.set(TOKEN_KEY, result.token);
|
|
1079
1097
|
await adapter.set(REFRESH_KEY, result.refreshToken);
|
|
1080
|
-
if (!result.
|
|
1081
|
-
return await
|
|
1098
|
+
if (!result.userId) {
|
|
1099
|
+
return await getSessionUser(adapter) ?? { id: "", email: "" };
|
|
1082
1100
|
}
|
|
1083
|
-
await adapter.set(
|
|
1101
|
+
await adapter.set(USER_ID_KEY, result.userId);
|
|
1084
1102
|
await adapter.set(EMAIL_KEY, result.email);
|
|
1085
|
-
return { id: result.
|
|
1103
|
+
return { id: result.userId, email: result.email };
|
|
1086
1104
|
}
|
|
1087
1105
|
async function clearSession(adapter) {
|
|
1088
1106
|
await adapter.unset(TOKEN_KEY);
|
|
1089
1107
|
await adapter.unset(REFRESH_KEY);
|
|
1090
|
-
await adapter.unset(
|
|
1108
|
+
await adapter.unset(USER_ID_KEY);
|
|
1091
1109
|
await adapter.unset(EMAIL_KEY);
|
|
1092
1110
|
}
|
|
1093
1111
|
async function getSessionToken(adapter) {
|
|
1094
1112
|
return await adapter.get(TOKEN_KEY) ?? null;
|
|
1095
1113
|
}
|
|
1096
|
-
async function
|
|
1097
|
-
const id = await adapter.get(
|
|
1114
|
+
async function getSessionUser(adapter) {
|
|
1115
|
+
const id = await adapter.get(USER_ID_KEY) ?? null;
|
|
1098
1116
|
const email = await adapter.get(EMAIL_KEY) ?? null;
|
|
1099
1117
|
if (!id) return null;
|
|
1100
1118
|
return { id, email: email ?? "" };
|
|
1101
1119
|
}
|
|
1102
|
-
async function
|
|
1103
|
-
return saveSession(adapter, await
|
|
1120
|
+
async function signInWithPassword(adapter, env, vars) {
|
|
1121
|
+
return saveSession(adapter, await login(env, vars));
|
|
1104
1122
|
}
|
|
1105
|
-
async function
|
|
1106
|
-
return saveSession(adapter, await
|
|
1123
|
+
async function signUpWithPassword(adapter, env, vars) {
|
|
1124
|
+
return saveSession(adapter, await register(env, vars));
|
|
1107
1125
|
}
|
|
1108
|
-
async function
|
|
1109
|
-
return saveSession(adapter, await
|
|
1126
|
+
async function signInWithOTP(adapter, env, vars) {
|
|
1127
|
+
return saveSession(adapter, await loginWithOTP(env, vars));
|
|
1110
1128
|
}
|
|
1111
1129
|
async function refreshSession(adapter, env) {
|
|
1112
1130
|
const refreshToken = await adapter.get(REFRESH_KEY) ?? null;
|
|
1113
1131
|
if (!refreshToken) return null;
|
|
1114
1132
|
try {
|
|
1115
|
-
const result = await
|
|
1133
|
+
const result = await refreshTokens(env, refreshToken);
|
|
1116
1134
|
await saveSession(adapter, result);
|
|
1117
1135
|
return { token: result.token, refreshToken: result.refreshToken };
|
|
1118
1136
|
} catch {
|
|
@@ -1179,122 +1197,125 @@ async function authedOp(adapter, env, op, args) {
|
|
|
1179
1197
|
|
|
1180
1198
|
// src/auth/grant-table.generated.ts
|
|
1181
1199
|
var GRANT_TABLE = [
|
|
1182
|
-
["records:read",
|
|
1183
|
-
["records:create",
|
|
1184
|
-
["records:write",
|
|
1185
|
-
["records:delete",
|
|
1186
|
-
["records:publish",
|
|
1187
|
-
["records:attribute",
|
|
1188
|
-
["search:read",
|
|
1189
|
-
["embeddings:read",
|
|
1190
|
-
["embeddings:write",
|
|
1191
|
-
["schemas:read",
|
|
1192
|
-
["drafts:read",
|
|
1193
|
-
["files:read",
|
|
1194
|
-
["files:write",
|
|
1195
|
-
["files:delete",
|
|
1196
|
-
["notifications:read",
|
|
1197
|
-
["notifications:write",
|
|
1198
|
-
["notifications:consent",
|
|
1199
|
-
["pushcredentials:read",
|
|
1200
|
-
["pushcredentials:write",
|
|
1201
|
-
["notes:read",
|
|
1202
|
-
["notes:write",
|
|
1203
|
-
["notes:create",
|
|
1204
|
-
["approvals:read",
|
|
1205
|
-
["approvals:write",
|
|
1206
|
-
["rooms:read",
|
|
1207
|
-
["rooms:write",
|
|
1208
|
-
["presence:read",
|
|
1209
|
-
["operations:read",
|
|
1210
|
-
["operations:execute",
|
|
1211
|
-
["operations:write",
|
|
1212
|
-
["operations:complete",
|
|
1213
|
-
["status:write",
|
|
1214
|
-
["appconfig:read",
|
|
1215
|
-
["schedules:read",
|
|
1216
|
-
["schedules:write",
|
|
1217
|
-
["hooks:read",
|
|
1218
|
-
["hooks:write",
|
|
1219
|
-
["
|
|
1220
|
-
["
|
|
1221
|
-
["domains:read",
|
|
1222
|
-
["domains:write",
|
|
1223
|
-
["secrets:read",
|
|
1224
|
-
["secrets:list",
|
|
1225
|
-
["secrets:put",
|
|
1226
|
-
["secrets:delete",
|
|
1227
|
-
["appsecrets:read",
|
|
1228
|
-
["appsecrets:list",
|
|
1229
|
-
["appsecrets:put",
|
|
1230
|
-
["appsecrets:delete",
|
|
1231
|
-
["opsecrets:read",
|
|
1232
|
-
["opsecrets:write",
|
|
1233
|
-
["settings:read",
|
|
1234
|
-
["settings:write",
|
|
1235
|
-
["designtokens:read",
|
|
1236
|
-
["designtokens:write",
|
|
1237
|
-
["models:read",
|
|
1238
|
-
["models:write",
|
|
1239
|
-
["configs:read",
|
|
1240
|
-
["configs:write",
|
|
1241
|
-
["apps:read",
|
|
1242
|
-
["apps:write",
|
|
1243
|
-
["events:read",
|
|
1244
|
-
["targeting:debug",
|
|
1245
|
-
["visitors:forward",
|
|
1246
|
-
["apikeys:read",
|
|
1247
|
-
["apikeys:write",
|
|
1248
|
-
["organizations:read",
|
|
1249
|
-
["organizations:write",
|
|
1250
|
-
["organizations:create",
|
|
1251
|
-
["organizations:delete",
|
|
1252
|
-
["organizations:reach",
|
|
1253
|
-
["members:read",
|
|
1254
|
-
["members:write",
|
|
1255
|
-
["roles:read",
|
|
1256
|
-
["roles:write",
|
|
1257
|
-
["projects:read",
|
|
1258
|
-
["projects:write",
|
|
1259
|
-
["project:
|
|
1260
|
-
["
|
|
1261
|
-
["projects:
|
|
1262
|
-
["
|
|
1263
|
-
["tenants:
|
|
1264
|
-
["tenants:
|
|
1265
|
-
["
|
|
1266
|
-
["
|
|
1267
|
-
["
|
|
1268
|
-
["billing:
|
|
1269
|
-
["
|
|
1270
|
-
["
|
|
1271
|
-
["controlkeys:
|
|
1272
|
-
["
|
|
1273
|
-
["tenanthooks:
|
|
1274
|
-
["
|
|
1275
|
-
["
|
|
1276
|
-
["
|
|
1277
|
-
["platform:
|
|
1278
|
-
["platform:
|
|
1279
|
-
["
|
|
1280
|
-
["users:
|
|
1281
|
-
["users:
|
|
1282
|
-
["users:
|
|
1283
|
-
["users:
|
|
1284
|
-
["
|
|
1285
|
-
["identities:
|
|
1286
|
-
["
|
|
1287
|
-
["usersecrets:
|
|
1288
|
-
["usersecrets:
|
|
1289
|
-
["usersecrets:
|
|
1290
|
-
["
|
|
1291
|
-
["
|
|
1292
|
-
["signinproviders:
|
|
1200
|
+
["records:read", "model", ["own", "all"], []],
|
|
1201
|
+
["records:create", "model", [], []],
|
|
1202
|
+
["records:write", "model", ["own", "all"], []],
|
|
1203
|
+
["records:delete", "model", ["own", "all"], []],
|
|
1204
|
+
["records:publish", "model", ["own", "all"], []],
|
|
1205
|
+
["records:attribute", "model", [], []],
|
|
1206
|
+
["search:read", "model", [], []],
|
|
1207
|
+
["embeddings:read", "none", [], []],
|
|
1208
|
+
["embeddings:write", "none", [], []],
|
|
1209
|
+
["schemas:read", "none", [], []],
|
|
1210
|
+
["drafts:read", "none", [], []],
|
|
1211
|
+
["files:read", "none", ["own", "all"], []],
|
|
1212
|
+
["files:write", "none", ["own", "all"], []],
|
|
1213
|
+
["files:delete", "none", ["own", "all"], []],
|
|
1214
|
+
["notifications:read", "none", ["own", "all"], []],
|
|
1215
|
+
["notifications:write", "none", ["own", "named", "all"], []],
|
|
1216
|
+
["notifications:consent", "none", [], []],
|
|
1217
|
+
["pushcredentials:read", "none", [], []],
|
|
1218
|
+
["pushcredentials:write", "none", [], []],
|
|
1219
|
+
["notes:read", "none", ["own", "all"], []],
|
|
1220
|
+
["notes:write", "none", ["own", "all"], []],
|
|
1221
|
+
["notes:create", "none", [], []],
|
|
1222
|
+
["approvals:read", "none", [], []],
|
|
1223
|
+
["approvals:write", "none", [], []],
|
|
1224
|
+
["rooms:read", "model", [], []],
|
|
1225
|
+
["rooms:write", "model", [], []],
|
|
1226
|
+
["presence:read", "model", [], []],
|
|
1227
|
+
["operations:read", "none", [], []],
|
|
1228
|
+
["operations:execute", "operation", [], []],
|
|
1229
|
+
["operations:write", "none", [], []],
|
|
1230
|
+
["operations:complete", "none", [], []],
|
|
1231
|
+
["status:write", "none", [], []],
|
|
1232
|
+
["appconfig:read", "none", [], []],
|
|
1233
|
+
["schedules:read", "none", [], []],
|
|
1234
|
+
["schedules:write", "none", [], []],
|
|
1235
|
+
["hooks:read", "none", [], []],
|
|
1236
|
+
["hooks:write", "none", [], []],
|
|
1237
|
+
["authclients:read", "none", [], []],
|
|
1238
|
+
["authclients:write", "none", [], []],
|
|
1239
|
+
["domains:read", "none", [], []],
|
|
1240
|
+
["domains:write", "none", [], []],
|
|
1241
|
+
["secrets:read", "none", [], []],
|
|
1242
|
+
["secrets:list", "none", [], []],
|
|
1243
|
+
["secrets:put", "none", [], []],
|
|
1244
|
+
["secrets:delete", "none", [], []],
|
|
1245
|
+
["appsecrets:read", "none", [], []],
|
|
1246
|
+
["appsecrets:list", "none", [], []],
|
|
1247
|
+
["appsecrets:put", "none", [], []],
|
|
1248
|
+
["appsecrets:delete", "none", [], []],
|
|
1249
|
+
["opsecrets:read", "none", [], []],
|
|
1250
|
+
["opsecrets:write", "none", [], []],
|
|
1251
|
+
["settings:read", "none", [], []],
|
|
1252
|
+
["settings:write", "none", [], []],
|
|
1253
|
+
["designtokens:read", "none", [], []],
|
|
1254
|
+
["designtokens:write", "none", [], []],
|
|
1255
|
+
["models:read", "none", [], []],
|
|
1256
|
+
["models:write", "none", [], []],
|
|
1257
|
+
["configs:read", "none", [], []],
|
|
1258
|
+
["configs:write", "none", [], []],
|
|
1259
|
+
["apps:read", "none", [], []],
|
|
1260
|
+
["apps:write", "none", [], []],
|
|
1261
|
+
["events:read", "none", [], []],
|
|
1262
|
+
["targeting:debug", "none", [], []],
|
|
1263
|
+
["visitors:forward", "none", [], []],
|
|
1264
|
+
["apikeys:read", "none", [], []],
|
|
1265
|
+
["apikeys:write", "none", [], []],
|
|
1266
|
+
["organizations:read", "none", [], []],
|
|
1267
|
+
["organizations:write", "none", [], []],
|
|
1268
|
+
["organizations:create", "none", [], []],
|
|
1269
|
+
["organizations:delete", "none", [], []],
|
|
1270
|
+
["organizations:reach", "none", [], []],
|
|
1271
|
+
["members:read", "none", [], []],
|
|
1272
|
+
["members:write", "none", [], []],
|
|
1273
|
+
["roles:read", "none", [], []],
|
|
1274
|
+
["roles:write", "none", [], []],
|
|
1275
|
+
["projects:read", "none", [], []],
|
|
1276
|
+
["projects:write", "none", [], []],
|
|
1277
|
+
["project:stand", "none", [], []],
|
|
1278
|
+
["project:manage", "none", [], ["project:stand", "records:read.all", "records:create", "records:write.all", "records:delete.all", "records:publish.all", "records:attribute", "search:read", "embeddings:read", "embeddings:write", "schemas:read", "drafts:read", "files:read.all", "files:write.all", "files:delete.all", "users:read.all", "identities:read", "users:create", "identities:delete", "users:write.all", "users:setup", "users:delete.all", "notifications:read.all", "notifications:write.all", "notifications:consent", "pushcredentials:read", "pushcredentials:write", "notes:read.all", "notes:write.all", "notes:create", "approvals:read", "approvals:write", "rooms:read", "rooms:write", "presence:read", "operations:read", "operations:execute", "operations:write", "appconfig:read", "schedules:read", "schedules:write", "hooks:read", "hooks:write", "auth:login_with_foir", "authclients:read", "authclients:write", "domains:read", "domains:write", "secrets:read", "secrets:list", "secrets:put", "secrets:delete", "appsecrets:read", "appsecrets:list", "appsecrets:put", "appsecrets:delete", "usersecrets:read", "usersecrets:list", "usersecrets:put", "usersecrets:delete", "opsecrets:read", "opsecrets:write", "settings:read", "settings:write", "designtokens:read", "designtokens:write", "models:read", "models:write", "configs:read", "configs:write", "signinproviders:read", "signinproviders:write", "apps:read", "apps:write", "events:read", "targeting:debug", "visitors:forward", "apikeys:read", "apikeys:write", "organizations:read", "organizations:create", "organizations:delete", "organizations:write", "organizations:reach", "members:read", "members:write", "roles:read", "roles:write", "projects:read", "projects:write", "audit:read"]],
|
|
1279
|
+
["projects:create", "none", [], []],
|
|
1280
|
+
["projects:delete", "none", [], []],
|
|
1281
|
+
["tenants:read", "none", [], []],
|
|
1282
|
+
["tenants:write", "none", [], []],
|
|
1283
|
+
["tenants:delete", "none", [], []],
|
|
1284
|
+
["audit:read", "none", [], []],
|
|
1285
|
+
["export:run", "none", [], []],
|
|
1286
|
+
["billing:read", "none", [], []],
|
|
1287
|
+
["billing:manage", "none", [], []],
|
|
1288
|
+
["usage:read", "none", [], []],
|
|
1289
|
+
["controlkeys:read", "none", [], []],
|
|
1290
|
+
["controlkeys:write", "none", [], []],
|
|
1291
|
+
["tenanthooks:read", "none", [], []],
|
|
1292
|
+
["tenanthooks:write", "none", [], []],
|
|
1293
|
+
["apps:install", "none", [], []],
|
|
1294
|
+
["tenant:manage", "none", [], ["project:manage", "projects:create", "projects:delete", "tenants:read", "tenants:write", "tenants:delete", "export:run", "billing:read", "billing:manage", "usage:read", "controlkeys:read", "controlkeys:write", "tenanthooks:read", "tenanthooks:write", "apps:install"]],
|
|
1295
|
+
["platform:read", "none", [], []],
|
|
1296
|
+
["platform:manage", "none", [], ["tenant:manage", "platform:read", "platform:create_workspace"]],
|
|
1297
|
+
["platform:create_workspace", "none", [], []],
|
|
1298
|
+
["users:read", "none", ["own", "named", "all"], []],
|
|
1299
|
+
["users:write", "none", ["own", "all"], []],
|
|
1300
|
+
["users:setup", "none", [], []],
|
|
1301
|
+
["users:delete", "none", ["own", "all"], []],
|
|
1302
|
+
["users:create", "none", [], []],
|
|
1303
|
+
["identities:read", "none", [], []],
|
|
1304
|
+
["identities:delete", "none", [], []],
|
|
1305
|
+
["usersecrets:read", "none", [], []],
|
|
1306
|
+
["usersecrets:list", "none", [], []],
|
|
1307
|
+
["usersecrets:put", "none", [], []],
|
|
1308
|
+
["usersecrets:delete", "none", [], []],
|
|
1309
|
+
["auth:login_with_foir", "none", [], []],
|
|
1310
|
+
["signinproviders:read", "none", [], []],
|
|
1311
|
+
["signinproviders:write", "none", [], []]
|
|
1293
1312
|
];
|
|
1294
1313
|
|
|
1295
1314
|
// src/auth/grants.ts
|
|
1296
1315
|
var WILDCARD = "*";
|
|
1297
1316
|
var RESOURCE_WILDCARD = ":*";
|
|
1317
|
+
var FIELD_PERMISSIONS = ["records:read", "records:write"];
|
|
1318
|
+
var FIELD_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
1298
1319
|
var index;
|
|
1299
1320
|
function catalogue() {
|
|
1300
1321
|
if (!index) {
|
|
@@ -1335,15 +1356,23 @@ function parseGrant(s) {
|
|
|
1335
1356
|
let target = "";
|
|
1336
1357
|
if (rest.startsWith(":")) {
|
|
1337
1358
|
target = rest.slice(1);
|
|
1338
|
-
if (
|
|
1359
|
+
if (permission[1] === "none") return null;
|
|
1339
1360
|
if (target === "" || /[: \t\n*]/.test(target)) return null;
|
|
1361
|
+
const dot = target.indexOf(".");
|
|
1362
|
+
if (permission[1] === "model" && dot >= 0) {
|
|
1363
|
+
if (!FIELD_PERMISSIONS.includes(name) || dot === 0 || !FIELD_KEY.test(target.slice(dot + 1))) return null;
|
|
1364
|
+
}
|
|
1340
1365
|
}
|
|
1341
1366
|
return { permission, reach, target };
|
|
1342
1367
|
}
|
|
1343
1368
|
return null;
|
|
1344
1369
|
}
|
|
1345
1370
|
function covers(held, required) {
|
|
1346
|
-
|
|
1371
|
+
if (held.permission !== required.permission || reachRank[held.reach] < reachRank[required.reach]) return false;
|
|
1372
|
+
if (required.permission[1] === "model" && required.target.includes(".")) {
|
|
1373
|
+
return held.target === required.target || held.target === "" && held.reach === "all";
|
|
1374
|
+
}
|
|
1375
|
+
return held.target === "" || held.target === required.target;
|
|
1347
1376
|
}
|
|
1348
1377
|
function resourceWildcard(held) {
|
|
1349
1378
|
if (!held.endsWith(RESOURCE_WILDCARD)) return null;
|
|
@@ -1373,15 +1402,15 @@ function holds(held, required) {
|
|
|
1373
1402
|
|
|
1374
1403
|
// src/auth/access.ts
|
|
1375
1404
|
function accessFrom(who) {
|
|
1376
|
-
const
|
|
1377
|
-
if (!
|
|
1405
|
+
const user = who?.credential?.user;
|
|
1406
|
+
if (!user?.id) return null;
|
|
1378
1407
|
return {
|
|
1379
|
-
|
|
1380
|
-
roles: Array.isArray(
|
|
1408
|
+
userId: user.id,
|
|
1409
|
+
roles: Array.isArray(user.roles) ? [...user.roles] : null,
|
|
1381
1410
|
scopes: [...who?.authority?.effective ?? []]
|
|
1382
1411
|
};
|
|
1383
1412
|
}
|
|
1384
|
-
async function
|
|
1413
|
+
async function userAccess(env, options) {
|
|
1385
1414
|
return accessFrom(await authOp(env, AUTH_OPS.whoami, void 0, options));
|
|
1386
1415
|
}
|
|
1387
1416
|
async function getSessionAccess(adapter, env) {
|
|
@@ -1461,14 +1490,14 @@ function createFoirSessionClient(config) {
|
|
|
1461
1490
|
} catch {
|
|
1462
1491
|
return cached;
|
|
1463
1492
|
}
|
|
1464
|
-
if (!json.access_token || !json.
|
|
1493
|
+
if (!json.access_token || !json.user_id) return cached;
|
|
1465
1494
|
const expiresIn = typeof json.expires_in === "number" ? json.expires_in : 0;
|
|
1466
1495
|
const next = {
|
|
1467
1496
|
token: json.access_token,
|
|
1468
1497
|
expiresAt: Date.now() + expiresIn * 1e3,
|
|
1469
|
-
user: {
|
|
1498
|
+
user: { userId: json.user_id, email: json.email ?? "" }
|
|
1470
1499
|
};
|
|
1471
|
-
const changed = cached?.user.
|
|
1500
|
+
const changed = cached?.user.userId !== next.user.userId;
|
|
1472
1501
|
cached = next;
|
|
1473
1502
|
scheduleRefresh(next.expiresAt);
|
|
1474
1503
|
if (changed) emit(next.user);
|
|
@@ -1569,13 +1598,13 @@ function FoirProvider({
|
|
|
1569
1598
|
const adapterRef = useRef(adapter ?? createLocalStorageAdapter());
|
|
1570
1599
|
if (adapter && adapter !== adapterRef.current) adapterRef.current = adapter;
|
|
1571
1600
|
const [status, setStatus] = useState("loading");
|
|
1572
|
-
const [
|
|
1601
|
+
const [user, setUser] = useState(null);
|
|
1573
1602
|
const [access, setAccess] = useState(null);
|
|
1574
1603
|
const [accessStatus, setAccessStatus] = useState("idle");
|
|
1575
1604
|
const accessRead = useRef(0);
|
|
1576
1605
|
const accessPending = useRef(null);
|
|
1577
1606
|
const apply = useCallback((c) => {
|
|
1578
|
-
|
|
1607
|
+
setUser(c);
|
|
1579
1608
|
setStatus(c ? "authenticated" : "unauthenticated");
|
|
1580
1609
|
accessRead.current += 1;
|
|
1581
1610
|
setAccess(null);
|
|
@@ -1600,10 +1629,10 @@ function FoirProvider({
|
|
|
1600
1629
|
void (async () => {
|
|
1601
1630
|
if (hosted) {
|
|
1602
1631
|
const u = await hosted.getUser();
|
|
1603
|
-
if (!cancelled) apply(u ? { id: u.
|
|
1632
|
+
if (!cancelled) apply(u ? { id: u.userId, email: u.email } : null);
|
|
1604
1633
|
return;
|
|
1605
1634
|
}
|
|
1606
|
-
const c = await
|
|
1635
|
+
const c = await getSessionUser(adapterRef.current);
|
|
1607
1636
|
if (!cancelled) apply(c);
|
|
1608
1637
|
})();
|
|
1609
1638
|
return () => {
|
|
@@ -1618,7 +1647,7 @@ function FoirProvider({
|
|
|
1618
1647
|
(action) => {
|
|
1619
1648
|
if (hosted) {
|
|
1620
1649
|
throw new Error(
|
|
1621
|
-
`[foir] ${action}() is not available in hostedSession mode \u2014 the
|
|
1650
|
+
`[foir] ${action}() is not available in hostedSession mode \u2014 the user signs in at your Foir login domain. Redirect to hostedSignInUrl() instead.`
|
|
1622
1651
|
);
|
|
1623
1652
|
}
|
|
1624
1653
|
},
|
|
@@ -1627,16 +1656,16 @@ function FoirProvider({
|
|
|
1627
1656
|
const signIn = useCallback(
|
|
1628
1657
|
async (vars) => {
|
|
1629
1658
|
assertTokenMode("signIn");
|
|
1630
|
-
const c = await
|
|
1659
|
+
const c = await signInWithPassword(adapterRef.current, envRef.current, vars);
|
|
1631
1660
|
apply(c);
|
|
1632
1661
|
return c;
|
|
1633
1662
|
},
|
|
1634
1663
|
[apply, assertTokenMode]
|
|
1635
1664
|
);
|
|
1636
|
-
const
|
|
1665
|
+
const register2 = useCallback(
|
|
1637
1666
|
async (vars) => {
|
|
1638
1667
|
assertTokenMode("register");
|
|
1639
|
-
const c = await
|
|
1668
|
+
const c = await signUpWithPassword(adapterRef.current, envRef.current, vars);
|
|
1640
1669
|
apply(c);
|
|
1641
1670
|
return c;
|
|
1642
1671
|
},
|
|
@@ -1645,14 +1674,14 @@ function FoirProvider({
|
|
|
1645
1674
|
const requestOtp = useCallback(
|
|
1646
1675
|
(email) => {
|
|
1647
1676
|
assertTokenMode("requestOtp");
|
|
1648
|
-
return
|
|
1677
|
+
return requestOTP(envRef.current, email);
|
|
1649
1678
|
},
|
|
1650
1679
|
[assertTokenMode]
|
|
1651
1680
|
);
|
|
1652
1681
|
const signInWithOtp = useCallback(
|
|
1653
1682
|
async (vars) => {
|
|
1654
1683
|
assertTokenMode("signInWithOtp");
|
|
1655
|
-
const c = await
|
|
1684
|
+
const c = await signInWithOTP(adapterRef.current, envRef.current, vars);
|
|
1656
1685
|
apply(c);
|
|
1657
1686
|
return c;
|
|
1658
1687
|
},
|
|
@@ -1661,7 +1690,7 @@ function FoirProvider({
|
|
|
1661
1690
|
const signInWithProvider = useCallback(
|
|
1662
1691
|
async (providerKey, opts) => {
|
|
1663
1692
|
assertTokenMode("signInWithProvider");
|
|
1664
|
-
const res = await
|
|
1693
|
+
const res = await loginWithProvider(envRef.current, {
|
|
1665
1694
|
providerKey,
|
|
1666
1695
|
...opts
|
|
1667
1696
|
});
|
|
@@ -1674,7 +1703,7 @@ function FoirProvider({
|
|
|
1674
1703
|
const completeProviderLogin = useCallback(
|
|
1675
1704
|
async (input) => {
|
|
1676
1705
|
assertTokenMode("completeProviderLogin");
|
|
1677
|
-
const result = await
|
|
1706
|
+
const result = await providerCallback(envRef.current, input);
|
|
1678
1707
|
const c = await saveSession(adapterRef.current, result);
|
|
1679
1708
|
apply(c);
|
|
1680
1709
|
return c;
|
|
@@ -1710,7 +1739,7 @@ function FoirProvider({
|
|
|
1710
1739
|
const pending = (async () => {
|
|
1711
1740
|
try {
|
|
1712
1741
|
const next = hosted ? await hosted.getToken().then(
|
|
1713
|
-
(bearerToken) => bearerToken ?
|
|
1742
|
+
(bearerToken) => bearerToken ? userAccess(envRef.current, { bearerToken }) : null
|
|
1714
1743
|
) : await getSessionAccess(adapterRef.current, envRef.current);
|
|
1715
1744
|
if (accessRead.current !== read) return;
|
|
1716
1745
|
setAccess(next);
|
|
@@ -1745,7 +1774,7 @@ function FoirProvider({
|
|
|
1745
1774
|
const value = useMemo(
|
|
1746
1775
|
() => ({
|
|
1747
1776
|
status,
|
|
1748
|
-
|
|
1777
|
+
user,
|
|
1749
1778
|
access,
|
|
1750
1779
|
accessStatus,
|
|
1751
1780
|
loadAccess,
|
|
@@ -1753,7 +1782,7 @@ function FoirProvider({
|
|
|
1753
1782
|
env,
|
|
1754
1783
|
adapter: adapterRef.current,
|
|
1755
1784
|
signIn,
|
|
1756
|
-
register,
|
|
1785
|
+
register: register2,
|
|
1757
1786
|
requestOtp,
|
|
1758
1787
|
signInWithOtp,
|
|
1759
1788
|
signInWithProvider,
|
|
@@ -1766,14 +1795,14 @@ function FoirProvider({
|
|
|
1766
1795
|
}),
|
|
1767
1796
|
[
|
|
1768
1797
|
status,
|
|
1769
|
-
|
|
1798
|
+
user,
|
|
1770
1799
|
access,
|
|
1771
1800
|
accessStatus,
|
|
1772
1801
|
loadAccess,
|
|
1773
1802
|
ensureAccess,
|
|
1774
1803
|
env,
|
|
1775
1804
|
signIn,
|
|
1776
|
-
|
|
1805
|
+
register2,
|
|
1777
1806
|
requestOtp,
|
|
1778
1807
|
signInWithOtp,
|
|
1779
1808
|
signInWithProvider,
|
|
@@ -1795,16 +1824,16 @@ function useFoirContext() {
|
|
|
1795
1824
|
return ctx;
|
|
1796
1825
|
}
|
|
1797
1826
|
function useFoirSession() {
|
|
1798
|
-
const { status,
|
|
1827
|
+
const { status, user } = useFoirContext();
|
|
1799
1828
|
return {
|
|
1800
1829
|
status,
|
|
1801
|
-
|
|
1830
|
+
user,
|
|
1802
1831
|
isLoading: status === "loading",
|
|
1803
1832
|
isAuthenticated: status === "authenticated"
|
|
1804
1833
|
};
|
|
1805
1834
|
}
|
|
1806
1835
|
function useFoirUser() {
|
|
1807
|
-
return useFoirContext().
|
|
1836
|
+
return useFoirContext().user;
|
|
1808
1837
|
}
|
|
1809
1838
|
function useFoirAccess() {
|
|
1810
1839
|
const { status, access, accessStatus, loadAccess, ensureAccess } = useFoirContext();
|
|
@@ -1827,7 +1856,7 @@ function useFoirAccess() {
|
|
|
1827
1856
|
function useFoirAuth() {
|
|
1828
1857
|
const {
|
|
1829
1858
|
signIn,
|
|
1830
|
-
register,
|
|
1859
|
+
register: register2,
|
|
1831
1860
|
requestOtp,
|
|
1832
1861
|
signInWithOtp,
|
|
1833
1862
|
signInWithProvider,
|
|
@@ -1840,7 +1869,7 @@ function useFoirAuth() {
|
|
|
1840
1869
|
} = useFoirContext();
|
|
1841
1870
|
return {
|
|
1842
1871
|
signIn,
|
|
1843
|
-
register,
|
|
1872
|
+
register: register2,
|
|
1844
1873
|
requestOtp,
|
|
1845
1874
|
signInWithOtp,
|
|
1846
1875
|
signInWithProvider,
|
|
@@ -1948,8 +1977,8 @@ function SignIn({
|
|
|
1948
1977
|
if (hostedUrl) {
|
|
1949
1978
|
return /* @__PURE__ */ jsx3("div", { className, "data-foir-signin": true, children: /* @__PURE__ */ jsx3("a", { href: hostedUrl, "data-foir-hosted-login": true, style: styled ? submitStyle : void 0, children: "Sign in" }) });
|
|
1950
1979
|
}
|
|
1951
|
-
const finish = (
|
|
1952
|
-
onSignIn?.(
|
|
1980
|
+
const finish = (user) => {
|
|
1981
|
+
onSignIn?.(user);
|
|
1953
1982
|
if (afterSignInUrl && typeof window !== "undefined") {
|
|
1954
1983
|
window.location.assign(afterSignInUrl);
|
|
1955
1984
|
}
|
|
@@ -2225,7 +2254,7 @@ async function uploadFeedbackAttachment(client, screenshot, fetchImpl = globalTh
|
|
|
2225
2254
|
const files = client.ns.files;
|
|
2226
2255
|
if (!files) {
|
|
2227
2256
|
throw new Error(
|
|
2228
|
-
"[foir] this client cannot reach the files namespace, so a screenshot cannot be uploaded. Attaching one needs `files:write` on the key and on the signed-in
|
|
2257
|
+
"[foir] this client cannot reach the files namespace, so a screenshot cannot be uploaded. Attaching one needs `files:write` on the key and on the signed-in user's role."
|
|
2229
2258
|
);
|
|
2230
2259
|
}
|
|
2231
2260
|
const ticket = readUploadTicket(
|
|
@@ -2617,7 +2646,7 @@ function failureCopy(fault) {
|
|
|
2617
2646
|
function reportFault(fault, err, action) {
|
|
2618
2647
|
if (fault.kind === "scope") {
|
|
2619
2648
|
console.error(
|
|
2620
|
-
`[foir] <FoirFeedback>: the API refused with "missing required scope: ${fault.scope}". This is not a bad API key: the key reached the surface. The signed-in
|
|
2649
|
+
`[foir] <FoirFeedback>: the API refused with "missing required scope: ${fault.scope}". This is not a bad API key: the key reached the surface. The signed-in USER's role does not grant ${fault.scope}, and a new project's default user role does not carry the notes scopes. Add it to the role that user holds, or to the project's default user role, and this works with no code change.`,
|
|
2621
2650
|
err
|
|
2622
2651
|
);
|
|
2623
2652
|
return;
|