prototypey.org - atproto lexicon typescript toolkit - mirror https://github.com/tylersayshi/prototypey
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

add inference for permission sets

authored by

JP Hastings-Spital and committed by
Tyler Lawson
dbcc9bde e6580ac4

+401 -23
+72 -23
packages/prototypey/core/infer.ts
··· 9 9 ? InferArray<T> 10 10 : T extends { type: "params" } 11 11 ? InferParams<T> 12 - : T extends { type: "union" } 13 - ? InferUnion<T> 14 - : T extends { type: "token" } 15 - ? InferToken<T> 16 - : T extends { type: "ref" } 17 - ? InferRef<T> 18 - : T extends { type: "unknown" } 19 - ? unknown 20 - : T extends { type: "null" } 21 - ? null 22 - : T extends { type: "boolean" } 23 - ? boolean 24 - : T extends { type: "integer" } 25 - ? number 26 - : T extends { type: "string" } 27 - ? string 28 - : T extends { type: "bytes" } 29 - ? Uint8Array 30 - : T extends { type: "cid-link" } 31 - ? string 32 - : T extends { type: "blob" } 33 - ? Blob 34 - : never; 12 + : T extends { type: "permission-set" } 13 + ? InferPermissionSet<T> 14 + : T extends { type: "union" } 15 + ? InferUnion<T> 16 + : T extends { type: "token" } 17 + ? InferToken<T> 18 + : T extends { type: "ref" } 19 + ? InferRef<T> 20 + : T extends { type: "unknown" } 21 + ? unknown 22 + : T extends { type: "null" } 23 + ? null 24 + : T extends { type: "boolean" } 25 + ? boolean 26 + : T extends { type: "integer" } 27 + ? number 28 + : T extends { type: "string" } 29 + ? string 30 + : T extends { type: "bytes" } 31 + ? Uint8Array 32 + : T extends { type: "cid-link" } 33 + ? string 34 + : T extends { type: "blob" } 35 + ? Blob 36 + : never; 35 37 36 38 type InferToken<T> = T extends { enum: readonly (infer U)[] } ? U : string; 37 39 ··· 85 87 : unknown; 86 88 87 89 type InferParams<T> = InferObject<T>; 90 + 91 + type InferPermissionEntry<T> = T extends { resource: "repo" } 92 + ? Prettify< 93 + { type: "permission"; resource: "repo"; collection: string[] } & (T extends 94 + { action: infer A } 95 + ? { action: A } 96 + : {}) 97 + > 98 + : T extends { resource: "rpc" } 99 + ? Prettify< 100 + { type: "permission"; resource: "rpc" } & (T extends { lxm: infer L } 101 + ? { lxm: L } 102 + : {}) & 103 + (T extends { aud: infer A } ? { aud: A } : {}) & 104 + (T extends { inheritAud: infer I } ? { inheritAud: I } : {}) 105 + > 106 + : T extends { resource: "blob" } 107 + ? { type: "permission"; resource: "blob"; accept: string[] } 108 + : T extends { resource: "account" } 109 + ? Prettify< 110 + { 111 + type: "permission"; 112 + resource: "account"; 113 + attr: T extends { attr: infer A } ? A : string; 114 + } & (T extends { action: infer Act } ? { action: Act } : {}) 115 + > 116 + : T extends { resource: "identity" } 117 + ? { 118 + type: "permission"; 119 + resource: "identity"; 120 + attr: T extends { attr: infer A } ? A : string; 121 + } 122 + : { type: "permission"; resource: string }; 123 + 124 + type InferPermissions<T> = T extends readonly [infer Head, ...infer Tail] 125 + ? [InferPermissionEntry<Head>, ...InferPermissions<Tail>] 126 + : T extends readonly (infer Item)[] 127 + ? InferPermissionEntry<Item>[] 128 + : never; 129 + 130 + type InferPermissionSet<T> = Prettify< 131 + { 132 + title: T extends { title: infer V } ? V : string; 133 + detail: T extends { detail: infer V } ? V : string; 134 + permissions: T extends { permissions: infer P } ? InferPermissions<P> : []; 135 + } & (T extends { description: infer D } ? { description: D } : {}) 136 + >; 88 137 89 138 type InferRecord<T> = T extends { record: infer R } 90 139 ? R extends { type: "object" }
+140
packages/prototypey/core/tests/from-json-infer.test.ts
··· 1224 1224 displayName?: string | undefined 1225 1225 }`); 1226 1226 }); 1227 + 1228 + // ============================================================================ 1229 + // PERMISSION SET TESTS 1230 + // ============================================================================ 1231 + 1232 + test("fromJSON InferPermissionSet handles basic permission set", () => { 1233 + const lexicon = fromJSON({ 1234 + id: "com.example.authCore", 1235 + defs: { 1236 + main: { 1237 + type: "permission-set", 1238 + key: "literal:self", 1239 + title: "Core functionality", 1240 + detail: "Grants core access", 1241 + permissions: [ 1242 + { 1243 + type: "permission", 1244 + resource: "repo", 1245 + collection: ["com.example.post"], 1246 + action: ["create", "update"], 1247 + }, 1248 + ], 1249 + }, 1250 + }, 1251 + }); 1252 + 1253 + attest(lexicon["~infer"]).type.toString.snap(`{ 1254 + $type: "com.example.authCore" 1255 + title: "Core functionality" 1256 + detail: "Grants core access" 1257 + permissions: { 1258 + type: "permission" 1259 + resource: "repo" 1260 + collection: string[] 1261 + action: ("create" | "update")[] 1262 + }[] 1263 + }`); 1264 + }); 1265 + 1266 + test("fromJSON InferPermissionSet handles multiple permission types", () => { 1267 + const lexicon = fromJSON({ 1268 + id: "com.example.fullPerms", 1269 + defs: { 1270 + main: { 1271 + type: "permission-set", 1272 + key: "literal:self", 1273 + title: "Full permissions", 1274 + detail: "All permission types", 1275 + permissions: [ 1276 + { 1277 + type: "permission", 1278 + resource: "repo", 1279 + collection: ["com.example.post"], 1280 + action: ["create"], 1281 + }, 1282 + { 1283 + type: "permission", 1284 + resource: "rpc", 1285 + lxm: ["com.example.doThing"], 1286 + aud: "did:web:example.com", 1287 + }, 1288 + { 1289 + type: "permission", 1290 + resource: "blob", 1291 + accept: ["image/*"], 1292 + }, 1293 + { 1294 + type: "permission", 1295 + resource: "account", 1296 + attr: "email", 1297 + action: "read", 1298 + }, 1299 + { 1300 + type: "permission", 1301 + resource: "identity", 1302 + attr: "handle", 1303 + }, 1304 + ], 1305 + }, 1306 + }, 1307 + }); 1308 + 1309 + attest(lexicon["~infer"]).type.toString.snap(`{ 1310 + $type: "com.example.fullPerms" 1311 + title: "Full permissions" 1312 + detail: "All permission types" 1313 + permissions: ( 1314 + | { 1315 + type: "permission" 1316 + resource: "blob" 1317 + accept: string[] 1318 + } 1319 + | { 1320 + type: "permission" 1321 + resource: "repo" 1322 + collection: string[] 1323 + action: "create"[] 1324 + } 1325 + | { 1326 + type: "permission" 1327 + resource: "rpc" 1328 + lxm: "com.example.doThing"[] 1329 + aud: "did:web:example.com" 1330 + } 1331 + | { 1332 + type: "permission" 1333 + resource: "account" 1334 + attr: "email" 1335 + action: "read" 1336 + } 1337 + | { 1338 + type: "permission" 1339 + resource: "identity" 1340 + attr: "handle" 1341 + } 1342 + )[] 1343 + }`); 1344 + }); 1345 + 1346 + test("fromJSON InferPermissionSet handles empty permissions", () => { 1347 + const lexicon = fromJSON({ 1348 + id: "com.example.empty", 1349 + defs: { 1350 + main: { 1351 + type: "permission-set", 1352 + key: "literal:self", 1353 + title: "Empty", 1354 + detail: "No permissions", 1355 + permissions: [], 1356 + }, 1357 + }, 1358 + }); 1359 + 1360 + attest(lexicon["~infer"]).type.toString.snap(`{ 1361 + $type: "com.example.empty" 1362 + title: "Empty" 1363 + detail: "No permissions" 1364 + permissions: never[] 1365 + }`); 1366 + });
+189
packages/prototypey/core/tests/infer.test.ts
··· 866 866 author?: "[Reference not found: #user]" | undefined 867 867 }`); 868 868 }); 869 + 870 + // ============================================================================ 871 + // PERMISSION SET TESTS 872 + // ============================================================================ 873 + 874 + test("InferPermissionSet handles basic permission set with repo permissions", () => { 875 + const lexicon = lx.lexicon("com.example.authCore", { 876 + main: lx.permissionSet({ 877 + title: "Core functionality", 878 + detail: "Grants core access", 879 + permissions: [ 880 + lx.repoPermission({ 881 + collection: ["com.example.post"], 882 + action: ["create", "update"], 883 + }), 884 + ], 885 + }), 886 + }); 887 + 888 + attest(lexicon["~infer"]).type.toString.snap(`{ 889 + $type: "com.example.authCore" 890 + title: string 891 + detail: string 892 + permissions: ( 893 + | { 894 + type: "permission" 895 + resource: "blob" 896 + accept: string[] 897 + } 898 + | { 899 + type: "permission" 900 + resource: "repo" 901 + collection: string[] 902 + } 903 + | { type: "permission"; resource: "rpc"; lxm: string[] } 904 + | { 905 + type: "permission" 906 + resource: "account" 907 + attr: "repo" | "email" 908 + } 909 + | { 910 + type: "permission" 911 + resource: "identity" 912 + attr: "handle" | "*" 913 + } 914 + )[] 915 + }`); 916 + }); 917 + 918 + test("InferPermissionSet handles multiple permission types", () => { 919 + const lexicon = lx.lexicon("com.example.fullPerms", { 920 + main: lx.permissionSet({ 921 + title: "Full permissions", 922 + detail: "All permission types", 923 + permissions: [ 924 + lx.repoPermission({ 925 + collection: ["com.example.post"], 926 + action: ["create"], 927 + }), 928 + lx.rpcPermission({ 929 + lxm: ["com.example.doThing"], 930 + aud: "did:web:example.com", 931 + }), 932 + lx.blobPermission({ 933 + accept: ["image/*"], 934 + }), 935 + lx.accountPermission({ 936 + attr: "email", 937 + action: "read", 938 + }), 939 + lx.identityPermission({ 940 + attr: "handle", 941 + }), 942 + ], 943 + }), 944 + }); 945 + 946 + attest(lexicon["~infer"]).type.toString.snap(`{ 947 + $type: "com.example.fullPerms" 948 + title: string 949 + detail: string 950 + permissions: ( 951 + | { 952 + type: "permission" 953 + resource: "blob" 954 + accept: string[] 955 + } 956 + | { 957 + type: "permission" 958 + resource: "repo" 959 + collection: string[] 960 + } 961 + | { type: "permission"; resource: "rpc"; lxm: string[] } 962 + | { 963 + type: "permission" 964 + resource: "account" 965 + attr: "repo" | "email" 966 + } 967 + | { 968 + type: "permission" 969 + resource: "identity" 970 + attr: "handle" | "*" 971 + } 972 + )[] 973 + }`); 974 + }); 975 + 976 + test("InferPermissionSet handles permission set with description", () => { 977 + const lexicon = lx.lexicon("com.example.withDesc", { 978 + main: lx.permissionSet({ 979 + title: "With description", 980 + detail: "Has a description field", 981 + description: "A human-readable description", 982 + permissions: [ 983 + lx.repoPermission({ 984 + collection: ["com.example.post"], 985 + }), 986 + ], 987 + }), 988 + }); 989 + 990 + attest(lexicon["~infer"]).type.toString.snap(`{ 991 + $type: "com.example.withDesc" 992 + title: string 993 + detail: string 994 + permissions: ( 995 + | { 996 + type: "permission" 997 + resource: "blob" 998 + accept: string[] 999 + } 1000 + | { 1001 + type: "permission" 1002 + resource: "repo" 1003 + collection: string[] 1004 + } 1005 + | { type: "permission"; resource: "rpc"; lxm: string[] } 1006 + | { 1007 + type: "permission" 1008 + resource: "account" 1009 + attr: "repo" | "email" 1010 + } 1011 + | { 1012 + type: "permission" 1013 + resource: "identity" 1014 + attr: "handle" | "*" 1015 + } 1016 + )[] 1017 + }`); 1018 + }); 1019 + 1020 + test("InferPermissionSet handles empty permissions array", () => { 1021 + const lexicon = lx.lexicon("com.example.empty", { 1022 + main: lx.permissionSet({ 1023 + title: "Empty", 1024 + detail: "No permissions", 1025 + permissions: [], 1026 + }), 1027 + }); 1028 + 1029 + attest(lexicon["~infer"]).type.toString.snap(`{ 1030 + $type: "com.example.empty" 1031 + title: string 1032 + detail: string 1033 + permissions: ( 1034 + | { 1035 + type: "permission" 1036 + resource: "blob" 1037 + accept: string[] 1038 + } 1039 + | { 1040 + type: "permission" 1041 + resource: "repo" 1042 + collection: string[] 1043 + } 1044 + | { type: "permission"; resource: "rpc"; lxm: string[] } 1045 + | { 1046 + type: "permission" 1047 + resource: "account" 1048 + attr: "repo" | "email" 1049 + } 1050 + | { 1051 + type: "permission" 1052 + resource: "identity" 1053 + attr: "handle" | "*" 1054 + } 1055 + )[] 1056 + }`); 1057 + });