caplets 0.8.0 → 0.9.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 CHANGED
@@ -28,7 +28,7 @@ the agent chooses that server and asks to search, list, inspect, or call them.
28
28
 
29
29
  ## What It Does
30
30
 
31
- - Reads downstream MCP server definitions, native OpenAPI endpoint definitions, native GraphQL endpoint definitions, and explicit HTTP API action definitions from `~/.caplets/config.json`.
31
+ - Reads downstream MCP server definitions, native OpenAPI endpoint definitions, native GraphQL endpoint definitions, and explicit HTTP API action definitions from the user config file.
32
32
  - Registers one generated MCP tool for each enabled MCP server, OpenAPI endpoint, GraphQL endpoint, or HTTP API.
33
33
  - Uses the configured server ID as the generated tool name.
34
34
  - Uses the configured `name` and `description` as the capability card shown to agents.
@@ -59,7 +59,7 @@ pnpm build
59
59
 
60
60
  ## Configure
61
61
 
62
- Create a starter `~/.caplets/config.json`:
62
+ Create a starter user config at `${XDG_CONFIG_HOME:-~/.config}/caplets/config.json` on Unix-like platforms or `%APPDATA%\caplets\config.json` on Windows:
63
63
 
64
64
  ```sh
65
65
  caplets init
@@ -143,7 +143,7 @@ you want Caplets to expose:
143
143
  }
144
144
  ```
145
145
 
146
- The default config path can be overridden with `CAPLETS_CONFIG`:
146
+ The default config path is `${XDG_CONFIG_HOME:-~/.config}/caplets/config.json` on Unix-like platforms and `%APPDATA%\caplets\config.json` on Windows. It can be overridden with `CAPLETS_CONFIG`:
147
147
 
148
148
  ```sh
149
149
  CAPLETS_CONFIG=/path/to/config.json caplets init
@@ -279,11 +279,13 @@ caplets install spiritledsoftware/caplets github linear
279
279
  ```
280
280
 
281
281
  `caplets install` accepts a GitHub `owner/repo` shorthand, a Git URL, or a local repository path.
282
- It installs into your user Caplets root, which is `~/.caplets` by default or the parent directory
283
- of `CAPLETS_CONFIG` when that environment variable is set. Existing Caplets are not overwritten
284
- unless `--force` is passed.
282
+ It installs into your user Caplets root, which is `${XDG_CONFIG_HOME:-~/.config}/caplets` on Unix-like platforms,
283
+ `%APPDATA%\caplets` on Windows, or the parent directory of `CAPLETS_CONFIG` when that environment variable is set.
284
+ Existing Caplets are not overwritten unless `--force` is passed.
285
285
 
286
- Caplets always loads user Caplet files from `~/.caplets`. Project `./.caplets/config.json`
286
+ On Unix-like platforms, relative `XDG_CONFIG_HOME` and `XDG_STATE_HOME` values are ignored.
287
+
288
+ Caplets always loads user Caplet files from the user Caplets root. Project `./.caplets/config.json`
287
289
  is still loaded as project config, but project Markdown Caplet files are executable
288
290
  configuration and are ignored unless explicitly trusted:
289
291
 
@@ -511,10 +513,11 @@ For headless terminals:
511
513
  caplets auth login <server> --no-open
512
514
  ```
513
515
 
514
- OAuth/OIDC tokens are stored under `~/.caplets/auth/<server>.json` with owner-only file
515
- permissions where the platform supports them. Caplets supports well-known OAuth/OIDC
516
- discovery and dynamic client registration when advertised. When a token expires, run
517
- `caplets auth login <server>` again.
516
+ OAuth/OIDC tokens are stored under `${XDG_STATE_HOME:-~/.local/state}/caplets/auth/<server>.json`
517
+ on Unix-like platforms and `%LOCALAPPDATA%\caplets\auth\<server>.json` on Windows.
518
+ Token files use owner-only file permissions where the platform supports them. Caplets supports
519
+ well-known OAuth/OIDC discovery and dynamic client registration when advertised. When a token expires,
520
+ run `caplets auth login <server>` again.
518
521
 
519
522
  To inspect or remove stored OAuth credentials:
520
523
 
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { createRequire } from "node:module";
3
3
  import minproc, { stdin, stdout, default as process$1 } from "node:process";
4
4
  import { execFileSync } from "node:child_process";
5
- import minpath, { basename, dirname, extname, isAbsolute, join, parse, relative, resolve, sep } from "node:path";
5
+ import minpath, { basename, dirname, extname, isAbsolute, join, parse, posix, relative, resolve, win32 } from "node:path";
6
6
  import { accessSync, chmodSync, constants, cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, renameSync, rmSync, statSync, watch, writeFileSync } from "node:fs";
7
7
  import { createInterface } from "node:readline/promises";
8
8
  import { createServer } from "node:http";
@@ -9619,7 +9619,7 @@ const { program, createCommand, createArgument, createOption, CommanderError, In
9619
9619
  })))(), 1)).default;
9620
9620
  //#endregion
9621
9621
  //#region package.json
9622
- var version = "0.8.0";
9622
+ var version = "0.9.0";
9623
9623
  //#endregion
9624
9624
  //#region node_modules/.pnpm/pkce-challenge@5.0.1/node_modules/pkce-challenge/dist/index.node.js
9625
9625
  let crypto;
@@ -10658,6 +10658,41 @@ async function registerClient(authorizationServerUrl, { metadata, clientMetadata
10658
10658
  return OAuthClientInformationFullSchema.parse(await response.json());
10659
10659
  }
10660
10660
  //#endregion
10661
+ //#region src/config/paths.ts
10662
+ function defaultConfigBaseDir(env = process.env, home = homedir(), platform = process.platform) {
10663
+ if (platform === "win32") return env.APPDATA && win32.isAbsolute(env.APPDATA) ? env.APPDATA : win32.join(home, "AppData", "Roaming");
10664
+ return env.XDG_CONFIG_HOME && posix.isAbsolute(env.XDG_CONFIG_HOME) ? env.XDG_CONFIG_HOME : posix.join(home, ".config");
10665
+ }
10666
+ function defaultStateBaseDir(env = process.env, home = homedir(), platform = process.platform) {
10667
+ if (platform === "win32") return env.LOCALAPPDATA && win32.isAbsolute(env.LOCALAPPDATA) ? env.LOCALAPPDATA : win32.join(home, "AppData", "Local");
10668
+ return env.XDG_STATE_HOME && posix.isAbsolute(env.XDG_STATE_HOME) ? env.XDG_STATE_HOME : posix.join(home, ".local", "state");
10669
+ }
10670
+ function defaultConfigPath(env = process.env, home = homedir(), platform = process.platform) {
10671
+ return (platform === "win32" ? win32.join : posix.join)(defaultConfigBaseDir(env, home, platform), "caplets", "config.json");
10672
+ }
10673
+ function defaultAuthDir(env = process.env, home = homedir(), platform = process.platform) {
10674
+ return (platform === "win32" ? win32.join : posix.join)(defaultStateBaseDir(env, home, platform), "caplets", "auth");
10675
+ }
10676
+ const DEFAULT_CONFIG_PATH = defaultConfigPath();
10677
+ const DEFAULT_AUTH_DIR = defaultAuthDir();
10678
+ const PROJECT_CONFIG_FILE = join(".caplets", "config.json");
10679
+ const TRUST_PROJECT_CAPLETS_ENV = "CAPLETS_TRUST_PROJECT_CAPLETS";
10680
+ function resolveConfigPath(path) {
10681
+ return path ?? DEFAULT_CONFIG_PATH;
10682
+ }
10683
+ function resolveProjectConfigPath(cwd = process.cwd()) {
10684
+ return join(cwd, PROJECT_CONFIG_FILE);
10685
+ }
10686
+ function resolveCapletsRoot(configPath = resolveConfigPath()) {
10687
+ return dirname(configPath);
10688
+ }
10689
+ function resolveProjectCapletsRoot(cwd = process.cwd()) {
10690
+ return join(cwd, ".caplets");
10691
+ }
10692
+ function isTrustedEnvEnabled(value) {
10693
+ return value === "1" || value?.toLowerCase() === "true" || value?.toLowerCase() === "yes";
10694
+ }
10695
+ //#endregion
10661
10696
  //#region src/errors.ts
10662
10697
  var CapletsError = class extends Error {
10663
10698
  code;
@@ -10708,11 +10743,12 @@ function errorResult(error, fallback) {
10708
10743
  }
10709
10744
  //#endregion
10710
10745
  //#region src/auth/store.ts
10711
- function authStorePath(server, authDir = join(homedir(), ".caplets", "auth")) {
10746
+ function authStorePath(server, authDir = DEFAULT_AUTH_DIR) {
10712
10747
  if (!server || server.includes("/") || server.includes("\\") || server.includes("..")) throw new CapletsError("REQUEST_INVALID", `Invalid auth store server name ${server}`);
10713
10748
  const authRoot = resolve(authDir);
10714
10749
  const candidate = resolve(authRoot, `${server}.json`);
10715
- if (candidate !== authRoot && candidate.startsWith(`${authRoot}${sep}`)) return candidate;
10750
+ const relativePath = relative(authRoot, candidate);
10751
+ if (relativePath && !relativePath.startsWith("..") && !isAbsolute(relativePath)) return candidate;
10716
10752
  throw new CapletsError("REQUEST_INVALID", `Invalid auth store server name ${server}`);
10717
10753
  }
10718
10754
  function readTokenBundle(server, authDir) {
@@ -10780,11 +10816,13 @@ var FileOAuthProvider = class {
10780
10816
  verifier = base64url(randomBytes(32));
10781
10817
  stateValue = base64url(randomBytes(24));
10782
10818
  clientInfo;
10819
+ clientMetadataUrl;
10783
10820
  constructor(server, redirectUrl, onRedirect, authDir) {
10784
10821
  this.server = server;
10785
10822
  this.redirectUrl = redirectUrl;
10786
10823
  this.onRedirect = onRedirect;
10787
10824
  this.authDir = authDir;
10825
+ if ((this.server.auth?.type === "oauth2" || this.server.auth?.type === "oidc") && this.server.auth.clientMetadataUrl) this.clientMetadataUrl = this.server.auth.clientMetadataUrl;
10788
10826
  }
10789
10827
  get clientMetadata() {
10790
10828
  return {
@@ -10884,10 +10922,19 @@ async function runOAuthFlow(server, options = {}) {
10884
10922
  authorizationCode: completion.code,
10885
10923
  ...scope ? { scope } : {}
10886
10924
  });
10925
+ } catch (error) {
10926
+ throw normalizeMcpOAuthError(server, error);
10887
10927
  } finally {
10888
10928
  await callback.close();
10889
10929
  }
10890
10930
  }
10931
+ function normalizeMcpOAuthError(server, error) {
10932
+ if ((server.auth?.type === "oauth2" || server.auth?.type === "oidc") && !server.auth.clientId && !server.auth.clientMetadataUrl && error instanceof Error && error.message.includes("does not support dynamic client registration")) return new CapletsError("AUTH_FAILED", "OAuth is not available for this server without a host-specific OAuth app or PAT auth", {
10933
+ server: server.server,
10934
+ nextAction: "configure_bearer_auth_or_host_oauth_app"
10935
+ });
10936
+ return error;
10937
+ }
10891
10938
  async function runGenericOAuthFlow(target, options = {}) {
10892
10939
  if (target.auth?.type !== "oauth2" && target.auth?.type !== "oidc") throw new CapletsError("REQUEST_INVALID", `${target.server} is not configured for OAuth`);
10893
10940
  const authConfig = target.auth;
@@ -11057,6 +11104,11 @@ async function resolveGenericClient(target, authConfig, metadata, redirectUri, a
11057
11104
  ...authConfig.clientSecret ? { clientSecret: authConfig.clientSecret } : {},
11058
11105
  dynamic: false
11059
11106
  };
11107
+ if (authConfig.clientMetadataUrl) return {
11108
+ clientId: authConfig.clientMetadataUrl,
11109
+ ...authConfig.clientSecret ? { clientSecret: authConfig.clientSecret } : {},
11110
+ dynamic: false
11111
+ };
11060
11112
  if (!metadata.registration_endpoint) throw new CapletsError("AUTH_FAILED", "OAuth clientId is required without dynamic registration", { server: target.server });
11061
11113
  const response = await fetchJson(metadata.registration_endpoint, target.requestTimeoutMs, {
11062
11114
  method: "POST",
@@ -11125,8 +11177,9 @@ function assertAllowedAuthUrl(value, label, allowLoopbackHttp = false) {
11125
11177
  throw new CapletsError("AUTH_FAILED", `${label} must use https except loopback development URLs`);
11126
11178
  }
11127
11179
  function assertTokenBundleMatchesTarget(bundle, target, authConfig) {
11180
+ const configuredClientId = authConfig.clientId ?? authConfig.clientMetadataUrl;
11128
11181
  const expectedOrigin = protectedResourceOrigin(target, authConfig);
11129
- if (bundle.authType !== authConfig.type || expectedOrigin && bundle.protectedResourceOrigin !== expectedOrigin || authConfig.clientId && bundle.clientId !== authConfig.clientId || authConfig.issuer && bundle.issuer !== authConfig.issuer) throw new CapletsError("AUTH_REQUIRED", `OAuth credentials for ${target.server} do not match the configured backend`, {
11182
+ if (bundle.authType !== authConfig.type || expectedOrigin && bundle.protectedResourceOrigin !== expectedOrigin || configuredClientId && bundle.clientId !== configuredClientId || authConfig.issuer && bundle.issuer !== authConfig.issuer) throw new CapletsError("AUTH_REQUIRED", `OAuth credentials for ${target.server} do not match the configured backend`, {
11130
11183
  server: target.server,
11131
11184
  backend: target.backend,
11132
11185
  authType: authConfig.type,
@@ -18762,6 +18815,7 @@ const capletRemoteAuthSchema = discriminatedUnion("type", [
18762
18815
  resourceMetadataUrl: string().min(1).optional(),
18763
18816
  authorizationServerMetadataUrl: string().min(1).optional(),
18764
18817
  openidConfigurationUrl: string().min(1).optional(),
18818
+ clientMetadataUrl: string().min(1).optional(),
18765
18819
  clientId: string().min(1).optional(),
18766
18820
  clientSecret: string().min(1).optional(),
18767
18821
  scopes: array(string().min(1)).optional(),
@@ -18775,6 +18829,7 @@ const capletRemoteAuthSchema = discriminatedUnion("type", [
18775
18829
  resourceMetadataUrl: string().min(1).optional(),
18776
18830
  authorizationServerMetadataUrl: string().min(1).optional(),
18777
18831
  openidConfigurationUrl: string().min(1).optional(),
18832
+ clientMetadataUrl: string().min(1).optional(),
18778
18833
  clientId: string().min(1).optional(),
18779
18834
  clientSecret: string().min(1).optional(),
18780
18835
  scopes: array(string().min(1)).optional(),
@@ -18799,6 +18854,7 @@ const capletEndpointAuthSchema = discriminatedUnion("type", [
18799
18854
  resourceMetadataUrl: string().min(1).optional(),
18800
18855
  authorizationServerMetadataUrl: string().min(1).optional(),
18801
18856
  openidConfigurationUrl: string().min(1).optional(),
18857
+ clientMetadataUrl: string().min(1).optional(),
18802
18858
  clientId: string().min(1).optional(),
18803
18859
  clientSecret: string().min(1).optional(),
18804
18860
  scopes: array(string().min(1)).optional(),
@@ -18812,6 +18868,7 @@ const capletEndpointAuthSchema = discriminatedUnion("type", [
18812
18868
  resourceMetadataUrl: string().min(1).optional(),
18813
18869
  authorizationServerMetadataUrl: string().min(1).optional(),
18814
18870
  openidConfigurationUrl: string().min(1).optional(),
18871
+ clientMetadataUrl: string().min(1).optional(),
18815
18872
  clientId: string().min(1).optional(),
18816
18873
  clientSecret: string().min(1).optional(),
18817
18874
  scopes: array(string().min(1)).optional(),
@@ -18855,10 +18912,11 @@ const capletMcpServerSchema = object$1({
18855
18912
  path: ["url"],
18856
18913
  message: "remote url must use https except loopback development urls"
18857
18914
  });
18858
- if (server.auth?.type === "oauth2") for (const field of [
18915
+ if (server.auth?.type === "oauth2" || server.auth?.type === "oidc") for (const field of [
18859
18916
  "authorizationUrl",
18860
18917
  "tokenUrl",
18861
18918
  "issuer",
18919
+ "clientMetadataUrl",
18862
18920
  "redirectUri"
18863
18921
  ]) {
18864
18922
  const value = server.auth[field];
@@ -19161,27 +19219,6 @@ function hasEnvReference$1(value) {
19161
19219
  return /\$\{[A-Za-z_][A-Za-z0-9_]*\}|\$env:[A-Za-z_][A-Za-z0-9_]*/.test(value);
19162
19220
  }
19163
19221
  //#endregion
19164
- //#region src/config/paths.ts
19165
- const DEFAULT_CONFIG_PATH = join(homedir(), ".caplets", "config.json");
19166
- const DEFAULT_AUTH_DIR = join(homedir(), ".caplets", "auth");
19167
- const PROJECT_CONFIG_FILE = join(".caplets", "config.json");
19168
- const TRUST_PROJECT_CAPLETS_ENV = "CAPLETS_TRUST_PROJECT_CAPLETS";
19169
- function resolveConfigPath(path) {
19170
- return path ?? DEFAULT_CONFIG_PATH;
19171
- }
19172
- function resolveProjectConfigPath(cwd = process.cwd()) {
19173
- return join(cwd, PROJECT_CONFIG_FILE);
19174
- }
19175
- function resolveCapletsRoot(configPath = resolveConfigPath()) {
19176
- return dirname(configPath);
19177
- }
19178
- function resolveProjectCapletsRoot(cwd = process.cwd()) {
19179
- return join(cwd, ".caplets");
19180
- }
19181
- function isTrustedEnvEnabled(value) {
19182
- return value === "1" || value?.toLowerCase() === "true" || value?.toLowerCase() === "yes";
19183
- }
19184
- //#endregion
19185
19222
  //#region src/config.ts
19186
19223
  const NON_INTERPOLATED_SERVER_FIELDS = new Set([
19187
19224
  "name",
@@ -19207,6 +19244,7 @@ const remoteAuthSchema = discriminatedUnion("type", [
19207
19244
  resourceMetadataUrl: string().url().optional(),
19208
19245
  authorizationServerMetadataUrl: string().url().optional(),
19209
19246
  openidConfigurationUrl: string().url().optional(),
19247
+ clientMetadataUrl: string().url().optional(),
19210
19248
  clientId: string().min(1).optional(),
19211
19249
  clientSecret: string().min(1).optional(),
19212
19250
  scopes: array(string().min(1)).optional(),
@@ -19220,6 +19258,7 @@ const remoteAuthSchema = discriminatedUnion("type", [
19220
19258
  resourceMetadataUrl: string().url().optional(),
19221
19259
  authorizationServerMetadataUrl: string().url().optional(),
19222
19260
  openidConfigurationUrl: string().url().optional(),
19261
+ clientMetadataUrl: string().url().optional(),
19223
19262
  clientId: string().min(1).optional(),
19224
19263
  clientSecret: string().min(1).optional(),
19225
19264
  scopes: array(string().min(1)).optional(),
@@ -19234,6 +19273,7 @@ const oauthLikeAuthSchema = union([object$1({
19234
19273
  resourceMetadataUrl: string().url().optional(),
19235
19274
  authorizationServerMetadataUrl: string().url().optional(),
19236
19275
  openidConfigurationUrl: string().url().optional(),
19276
+ clientMetadataUrl: string().url().optional(),
19237
19277
  clientId: string().min(1).optional(),
19238
19278
  clientSecret: string().min(1).optional(),
19239
19279
  scopes: array(string().min(1)).optional(),
@@ -19246,6 +19286,7 @@ const oauthLikeAuthSchema = union([object$1({
19246
19286
  resourceMetadataUrl: string().url().optional(),
19247
19287
  authorizationServerMetadataUrl: string().url().optional(),
19248
19288
  openidConfigurationUrl: string().url().optional(),
19289
+ clientMetadataUrl: string().url().optional(),
19249
19290
  clientId: string().min(1).optional(),
19250
19291
  clientSecret: string().min(1).optional(),
19251
19292
  scopes: array(string().min(1)).optional(),
@@ -19896,12 +19937,14 @@ function formatCapletList(rows) {
19896
19937
  }
19897
19938
  function resolveCliConfigPaths(envConfigPath, authDir) {
19898
19939
  const configPath = resolveConfigPath(envConfigPath);
19940
+ const effectiveAuthDir = authDir ?? DEFAULT_AUTH_DIR;
19899
19941
  return {
19900
19942
  userConfig: configPath,
19901
19943
  projectConfig: resolveProjectConfigPath(),
19902
19944
  userRoot: resolveCapletsRoot(configPath),
19945
+ stateRoot: dirname(effectiveAuthDir),
19903
19946
  projectRoot: resolveProjectCapletsRoot(),
19904
- authDir: authDir ?? DEFAULT_AUTH_DIR,
19947
+ authDir: effectiveAuthDir,
19905
19948
  envConfig: envConfigPath ?? null,
19906
19949
  projectCapletsTrusted: isTrustedProjectCapletsEnabled()
19907
19950
  };
@@ -19911,6 +19954,7 @@ function formatConfigPaths(paths) {
19911
19954
  `userConfig: ${paths.userConfig}`,
19912
19955
  `projectConfig: ${paths.projectConfig}`,
19913
19956
  `userRoot: ${paths.userRoot}`,
19957
+ `stateRoot: ${paths.stateRoot}`,
19914
19958
  `projectRoot: ${paths.projectRoot}`,
19915
19959
  `authDir: ${paths.authDir}`,
19916
19960
  `envConfig: ${paths.envConfig ?? "unset"}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "caplets",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Progressive disclosure gateway for MCP servers.",
5
5
  "keywords": [
6
6
  "caplets",
@@ -149,6 +149,10 @@
149
149
  "type": "string",
150
150
  "minLength": 1
151
151
  },
152
+ "clientMetadataUrl": {
153
+ "type": "string",
154
+ "minLength": 1
155
+ },
152
156
  "clientId": {
153
157
  "type": "string",
154
158
  "minLength": 1
@@ -203,6 +207,10 @@
203
207
  "type": "string",
204
208
  "minLength": 1
205
209
  },
210
+ "clientMetadataUrl": {
211
+ "type": "string",
212
+ "minLength": 1
213
+ },
206
214
  "clientId": {
207
215
  "type": "string",
208
216
  "minLength": 1
@@ -353,6 +361,10 @@
353
361
  "type": "string",
354
362
  "minLength": 1
355
363
  },
364
+ "clientMetadataUrl": {
365
+ "type": "string",
366
+ "minLength": 1
367
+ },
356
368
  "clientId": {
357
369
  "type": "string",
358
370
  "minLength": 1
@@ -407,6 +419,10 @@
407
419
  "type": "string",
408
420
  "minLength": 1
409
421
  },
422
+ "clientMetadataUrl": {
423
+ "type": "string",
424
+ "minLength": 1
425
+ },
410
426
  "clientId": {
411
427
  "type": "string",
412
428
  "minLength": 1
@@ -591,6 +607,10 @@
591
607
  "type": "string",
592
608
  "minLength": 1
593
609
  },
610
+ "clientMetadataUrl": {
611
+ "type": "string",
612
+ "minLength": 1
613
+ },
594
614
  "clientId": {
595
615
  "type": "string",
596
616
  "minLength": 1
@@ -645,6 +665,10 @@
645
665
  "type": "string",
646
666
  "minLength": 1
647
667
  },
668
+ "clientMetadataUrl": {
669
+ "type": "string",
670
+ "minLength": 1
671
+ },
648
672
  "clientId": {
649
673
  "type": "string",
650
674
  "minLength": 1
@@ -788,6 +812,10 @@
788
812
  "type": "string",
789
813
  "minLength": 1
790
814
  },
815
+ "clientMetadataUrl": {
816
+ "type": "string",
817
+ "minLength": 1
818
+ },
791
819
  "clientId": {
792
820
  "type": "string",
793
821
  "minLength": 1
@@ -842,6 +870,10 @@
842
870
  "type": "string",
843
871
  "minLength": 1
844
872
  },
873
+ "clientMetadataUrl": {
874
+ "type": "string",
875
+ "minLength": 1
876
+ },
845
877
  "clientId": {
846
878
  "type": "string",
847
879
  "minLength": 1
@@ -168,6 +168,10 @@
168
168
  "type": "string",
169
169
  "format": "uri"
170
170
  },
171
+ "clientMetadataUrl": {
172
+ "type": "string",
173
+ "format": "uri"
174
+ },
171
175
  "clientId": {
172
176
  "type": "string",
173
177
  "minLength": 1
@@ -222,6 +226,10 @@
222
226
  "type": "string",
223
227
  "format": "uri"
224
228
  },
229
+ "clientMetadataUrl": {
230
+ "type": "string",
231
+ "format": "uri"
232
+ },
225
233
  "clientId": {
226
234
  "type": "string",
227
235
  "minLength": 1
@@ -403,6 +411,10 @@
403
411
  "type": "string",
404
412
  "format": "uri"
405
413
  },
414
+ "clientMetadataUrl": {
415
+ "type": "string",
416
+ "format": "uri"
417
+ },
406
418
  "clientId": {
407
419
  "type": "string",
408
420
  "minLength": 1
@@ -457,6 +469,10 @@
457
469
  "type": "string",
458
470
  "format": "uri"
459
471
  },
472
+ "clientMetadataUrl": {
473
+ "type": "string",
474
+ "format": "uri"
475
+ },
460
476
  "clientId": {
461
477
  "type": "string",
462
478
  "minLength": 1
@@ -670,6 +686,10 @@
670
686
  "type": "string",
671
687
  "format": "uri"
672
688
  },
689
+ "clientMetadataUrl": {
690
+ "type": "string",
691
+ "format": "uri"
692
+ },
673
693
  "clientId": {
674
694
  "type": "string",
675
695
  "minLength": 1
@@ -724,6 +744,10 @@
724
744
  "type": "string",
725
745
  "format": "uri"
726
746
  },
747
+ "clientMetadataUrl": {
748
+ "type": "string",
749
+ "format": "uri"
750
+ },
727
751
  "clientId": {
728
752
  "type": "string",
729
753
  "minLength": 1
@@ -896,6 +920,10 @@
896
920
  "type": "string",
897
921
  "format": "uri"
898
922
  },
923
+ "clientMetadataUrl": {
924
+ "type": "string",
925
+ "format": "uri"
926
+ },
899
927
  "clientId": {
900
928
  "type": "string",
901
929
  "minLength": 1
@@ -950,6 +978,10 @@
950
978
  "type": "string",
951
979
  "format": "uri"
952
980
  },
981
+ "clientMetadataUrl": {
982
+ "type": "string",
983
+ "format": "uri"
984
+ },
953
985
  "clientId": {
954
986
  "type": "string",
955
987
  "minLength": 1