Suite of AT Protocol TypeScript libraries built on web standards
20
fork

Configure Feed

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

feat: lex permission sets

+83 -1
+38 -1
lex/build/def-builder.ts
··· 14 14 LexiconObject, 15 15 LexiconParameters, 16 16 LexiconPayload, 17 + LexiconPermissionSet, 17 18 LexiconProcedure, 18 19 LexiconQuery, 19 20 LexiconRecord, ··· 135 136 if (def == null) return; 136 137 137 138 switch (def.type) { 139 + case "permission-set": 140 + return this.addPermissionSet(hash, def); 138 141 case "procedure": 139 142 return this.addProcedure(hash, def); 140 143 case "query": ··· 158 161 }); 159 162 } 160 163 } 164 + } 165 + 166 + private async addPermissionSet( 167 + hash: string, 168 + def: LexiconPermissionSet, 169 + ): Promise<void> { 170 + const permissions = def.permissions.map((permissionDef) => { 171 + const options = stringifyOptions( 172 + permissionDef, 173 + undefined, 174 + ["resource", "type"], 175 + ); 176 + return this.pure( 177 + `l.permission(${JSON.stringify(permissionDef.resource)}${ 178 + options ? `, ${options}` : "" 179 + })`, 180 + ); 181 + }); 182 + const options = stringifyOptions(def, [ 183 + "title", 184 + "title:lang", 185 + "detail", 186 + "detail:lang", 187 + ]); 188 + 189 + await this.addSchema(hash, def, { 190 + schema: this.pure( 191 + `l.permissionSet($nsid, [${permissions.join(",")}]${ 192 + options ? `, ${options}` : "" 193 + })`, 194 + ), 195 + }); 161 196 } 162 197 163 198 private async addProcedure( ··· 924 959 function stringifyOptions<O extends Record<string, unknown>>( 925 960 obj: O, 926 961 include?: (keyof O)[], 962 + exclude?: (keyof O)[], 927 963 ): string { 928 964 const filtered = Object.entries(obj).filter( 929 965 ([k, v]) => 930 966 v !== undefined && 931 967 v !== null && 932 - (!include || include.includes(k as keyof O)), 968 + (!include || include.includes(k as keyof O)) && 969 + (!exclude || !exclude.includes(k as keyof O)), 933 970 ); 934 971 return filtered.length ? JSON.stringify(Object.fromEntries(filtered)) : ""; 935 972 }
+45
lex/tests/method-generation_test.ts
··· 136 136 ); 137 137 }); 138 138 139 + Deno.test("permission-set defs generate permissionSet schema", async () => { 140 + const doc = lexiconDocumentSchema.parse({ 141 + lexicon: 1, 142 + id: "com.example.auth.full", 143 + defs: { 144 + main: { 145 + type: "permission-set", 146 + permissions: [ 147 + { 148 + type: "permission", 149 + resource: "rpc", 150 + aud: "did:web:example.com", 151 + }, 152 + ], 153 + title: "Full access", 154 + detail: "Allows access to all RPC methods.", 155 + }, 156 + }, 157 + }); 158 + 159 + const project = new Project({ useInMemoryFileSystem: true }); 160 + const file = project.createSourceFile("/com/example/auth/full.defs.ts"); 161 + const indexer = new DummyIndexer([doc]); 162 + const builder = new LexDefBuilder({}, file, doc, indexer); 163 + await builder.build(); 164 + 165 + const output = file.getFullText(); 166 + assertStringIncludes(output, "const main = l.permissionSet($nsid, ["); 167 + assertStringIncludes( 168 + output, 169 + 'l.permission("rpc", {"aud":"did:web:example.com"})', 170 + ); 171 + assertStringIncludes( 172 + output, 173 + '{"title":"Full access","detail":"Allows access to all RPC methods."}', 174 + ); 175 + assert(!output.includes('"resource":"rpc"')); 176 + assert(!output.includes('"type":"permission"')); 177 + assert(!output.includes("main.assert.bind(main)")); 178 + assert(!output.includes("main.ifMatches.bind(main)")); 179 + assert(!output.includes("main.matches.bind(main)")); 180 + assert(!output.includes("main.parse.bind(main)")); 181 + assert(!output.includes("main.safeParse.bind(main)")); 182 + }); 183 + 139 184 Deno.test("object defs generate typedObject with $type metadata", async () => { 140 185 const doc = lexiconDocumentSchema.parse({ 141 186 lexicon: 1,