@sanity/client 7.26.1 → 8.0.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.
Files changed (128) hide show
  1. package/README.md +5 -377
  2. package/dist/browserUpload-CQgx9YYo.js +86 -0
  3. package/dist/browserUpload-CQgx9YYo.js.map +1 -0
  4. package/dist/browserUpload-icWlVP15.js +86 -0
  5. package/dist/browserUpload-icWlVP15.js.map +1 -0
  6. package/dist/config-a8VajuEY.js +126 -0
  7. package/dist/config-a8VajuEY.js.map +1 -0
  8. package/dist/csm.d.ts +122 -347
  9. package/dist/csm.js +79 -91
  10. package/dist/csm.js.map +1 -1
  11. package/dist/dist-C9ExSk2R.js +73 -0
  12. package/dist/dist-C9ExSk2R.js.map +1 -0
  13. package/dist/dist-Z8cIRxoB.js +69 -0
  14. package/dist/dist-Z8cIRxoB.js.map +1 -0
  15. package/dist/index.d.ts +107 -6758
  16. package/dist/index.js +2822 -2848
  17. package/dist/index.js.map +1 -1
  18. package/dist/{index.d.cts → index.node.d.ts} +4291 -5363
  19. package/dist/index.node.js +3131 -0
  20. package/dist/index.node.js.map +1 -0
  21. package/dist/isRecord-Kfmt-nk-.js +7 -0
  22. package/dist/isRecord-Kfmt-nk-.js.map +1 -0
  23. package/dist/media-library.d.ts +9 -100
  24. package/dist/media-library.js +36 -14
  25. package/dist/media-library.js.map +1 -1
  26. package/dist/request-CJxcN16k.js +372 -0
  27. package/dist/request-CJxcN16k.js.map +1 -0
  28. package/dist/request-k7VS_NnC.js +354 -0
  29. package/dist/request-k7VS_NnC.js.map +1 -0
  30. package/dist/resolveEditInfo-sq7yF78q.js +325 -0
  31. package/dist/resolveEditInfo-sq7yF78q.js.map +1 -0
  32. package/dist/rolldown-runtime-vyAXikos.js +9 -0
  33. package/dist/stega.d.ts +78 -7179
  34. package/dist/stega.js +27 -20
  35. package/dist/stega.js.map +1 -1
  36. package/dist/stegaClean-C18wLWau.js +21 -0
  37. package/dist/stegaClean-C18wLWau.js.map +1 -0
  38. package/dist/stegaEncodeSourceMap-B2fGArSf.js +163 -0
  39. package/dist/stegaEncodeSourceMap-B2fGArSf.js.map +1 -0
  40. package/dist/stegaEncodeSourceMap-DkoIlutY.js +367 -0
  41. package/dist/stegaEncodeSourceMap-DkoIlutY.js.map +1 -0
  42. package/dist/{index.browser.d.cts → types-CUxZSgB2.d.ts} +3956 -5295
  43. package/dist/types-CfGzbXrl.d.ts +108 -0
  44. package/package.json +69 -146
  45. package/src/SanityClient.ts +82 -117
  46. package/src/agent/actions/AgentActionsClient.ts +12 -12
  47. package/src/agent/actions/generate.ts +20 -3
  48. package/src/agent/actions/patch.ts +21 -4
  49. package/src/agent/actions/prompt.ts +17 -4
  50. package/src/agent/actions/transform.ts +21 -4
  51. package/src/agent/actions/translate.ts +21 -4
  52. package/src/assets/AssetsClient.ts +71 -23
  53. package/src/csm/createEditUrl.ts +1 -1
  54. package/src/csm/draftUtils.ts +0 -1
  55. package/src/csm/index.ts +2 -2
  56. package/src/csm/studioPath.ts +2 -1
  57. package/src/csm/types.ts +5 -1
  58. package/src/data/dataMethods.ts +801 -349
  59. package/src/data/eventsource.ts +13 -10
  60. package/src/data/listen.ts +16 -22
  61. package/src/data/live.ts +44 -27
  62. package/src/data/resolveEventSourceFetch.ts +96 -0
  63. package/src/datasets/DatasetsClient.ts +58 -41
  64. package/src/defineCreateClient.ts +35 -23
  65. package/src/http/browserMiddleware.ts +7 -1
  66. package/src/http/browserUpload.ts +162 -0
  67. package/src/http/errors.ts +60 -6
  68. package/src/http/nodeMiddleware.ts +94 -30
  69. package/src/http/request.ts +310 -87
  70. package/src/http/requestOptions.ts +131 -15
  71. package/src/{index.browser.ts → index.node.ts} +9 -4
  72. package/src/index.ts +4 -3
  73. package/src/mediaLibrary/MediaLibraryVideoClient.ts +26 -11
  74. package/src/projects/ProjectsClient.ts +18 -16
  75. package/src/releases/ReleasesClient.ts +34 -31
  76. package/src/stega/index.ts +1 -2
  77. package/src/stega/stegaEncodeSourceMap.ts +5 -0
  78. package/src/stega/types.ts +0 -1
  79. package/src/types.ts +110 -96
  80. package/src/users/UsersClient.ts +10 -14
  81. package/src/util/shareReplayLatest.ts +1 -1
  82. package/src/warnings.ts +6 -1
  83. package/dist/_chunks-cjs/config.cjs +0 -206
  84. package/dist/_chunks-cjs/config.cjs.map +0 -1
  85. package/dist/_chunks-cjs/isRecord.cjs +0 -6
  86. package/dist/_chunks-cjs/isRecord.cjs.map +0 -1
  87. package/dist/_chunks-cjs/resolveEditInfo.cjs +0 -334
  88. package/dist/_chunks-cjs/resolveEditInfo.cjs.map +0 -1
  89. package/dist/_chunks-cjs/stegaClean.cjs +0 -46
  90. package/dist/_chunks-cjs/stegaClean.cjs.map +0 -1
  91. package/dist/_chunks-cjs/stegaEncodeSourceMap.cjs +0 -388
  92. package/dist/_chunks-cjs/stegaEncodeSourceMap.cjs.map +0 -1
  93. package/dist/_chunks-es/config.js +0 -207
  94. package/dist/_chunks-es/config.js.map +0 -1
  95. package/dist/_chunks-es/isRecord.js +0 -7
  96. package/dist/_chunks-es/isRecord.js.map +0 -1
  97. package/dist/_chunks-es/resolveEditInfo.js +0 -335
  98. package/dist/_chunks-es/resolveEditInfo.js.map +0 -1
  99. package/dist/_chunks-es/stegaClean.js +0 -47
  100. package/dist/_chunks-es/stegaClean.js.map +0 -1
  101. package/dist/_chunks-es/stegaEncodeSourceMap.js +0 -389
  102. package/dist/_chunks-es/stegaEncodeSourceMap.js.map +0 -1
  103. package/dist/csm.cjs +0 -99
  104. package/dist/csm.cjs.map +0 -1
  105. package/dist/csm.d.cts +0 -403
  106. package/dist/index.browser.cjs +0 -3106
  107. package/dist/index.browser.cjs.map +0 -1
  108. package/dist/index.browser.d.ts +0 -6841
  109. package/dist/index.browser.js +0 -3082
  110. package/dist/index.browser.js.map +0 -1
  111. package/dist/index.cjs +0 -2947
  112. package/dist/index.cjs.map +0 -1
  113. package/dist/media-library.cjs +0 -20
  114. package/dist/media-library.cjs.map +0 -1
  115. package/dist/media-library.d.cts +0 -117
  116. package/dist/stega.browser.cjs +0 -29
  117. package/dist/stega.browser.cjs.map +0 -1
  118. package/dist/stega.browser.d.cts +0 -7242
  119. package/dist/stega.browser.d.ts +0 -7242
  120. package/dist/stega.browser.js +0 -24
  121. package/dist/stega.browser.js.map +0 -1
  122. package/dist/stega.cjs +0 -29
  123. package/dist/stega.cjs.map +0 -1
  124. package/dist/stega.d.cts +0 -7242
  125. package/src/data/eventsourcePolyfill.ts +0 -7
  126. package/umd/.gitkeep +0 -1
  127. package/umd/sanityClient.js +0 -6536
  128. package/umd/sanityClient.min.js +0 -6
@@ -0,0 +1,108 @@
1
+ import { ContentSourceMap as ContentSourceMap$2, ContentSourceMapDocuments, ContentSourceMapParsedPath, ContentSourceMapParsedPath as ContentSourceMapParsedPath$1, ContentSourceMapParsedPathKeyedSegment, ResolveStudioUrl, StudioBaseRoute, StudioBaseUrl, StudioUrl, StudioUrl as StudioUrl$1 } from "@sanity/client/csm";
2
+ import { ClientConfig, InitializedClientConfig, RawQueryResponse } from "@sanity/client";
3
+ /** @public */
4
+ type ContentSourceMapQueryResponse = RawQueryResponse<unknown> | Pick<RawQueryResponse<unknown>, 'result' | 'resultSourceMap'>;
5
+ /** @public */
6
+ interface StegaConfig {
7
+ /**
8
+ * Enable or disable stega encoded strings in query results
9
+ * ```ts
10
+ {
11
+ enabled: process.env.VERCEL_ENV !== 'production'
12
+ }
13
+ * ```
14
+ * @defaultValue `false`
15
+ */
16
+ enabled?: boolean;
17
+ /**
18
+ * Where the Studio is hosted.
19
+ * If it's embedded in the app, use the base path for example `/studio`.
20
+ * Otherwise provide the full URL to where the Studio is hosted, for example: `https://blog.sanity.studio`.
21
+ *
22
+ */
23
+ studioUrl?: StudioUrl | ResolveStudioUrl;
24
+ filter?: FilterDefault;
25
+ /**
26
+ * Specify a `console.log` compatible logger to see debug logs, which keys are encoded and which are not.
27
+ */
28
+ logger?: Logger;
29
+ /**
30
+ * Set to `true` to omit cross dataset reference specific data from encoded strings
31
+ */
32
+ omitCrossDatasetReferenceData?: boolean;
33
+ }
34
+ /** @public */
35
+ type StegaConfigRequiredKeys = Extract<keyof StegaConfig, 'enabled'>;
36
+ /** @public */
37
+ type InitializedStegaConfig = Omit<StegaConfig, StegaConfigRequiredKeys> & Required<Pick<StegaConfig, StegaConfigRequiredKeys>>;
38
+ /**
39
+ * @public
40
+ * @deprecated -- use `ClientConfig` instead
41
+ */
42
+ interface ClientStegaConfig extends ClientConfig {}
43
+ /**
44
+ * @public
45
+ * @deprecated -- use `InitializedClientConfig` instead
46
+ */
47
+ interface InitializedClientStegaConfig extends InitializedClientConfig {}
48
+ /** @public */
49
+ type FilterDefault = (props: {
50
+ /**
51
+ * The path to the value in the source document, for example if you queried for a document like this:
52
+ * `*[_type == "author"][0]{"slug": slug.current}`
53
+ * Then the `sourcePath` for `result.slug` would be `['slug', 'current']`.
54
+ *
55
+ */
56
+ sourcePath: ContentSourceMapParsedPath;
57
+ /**
58
+ * If `sourcePath` alone isn't enough to tell you if it's safe to contain stega strings, then you can use `sourceDocument`
59
+ * for additional metadata.
60
+ * It'll always have a `_type` property, which can be used to trace it to the Studio Schema that were used initially.
61
+ * It also has `_id` to help you debug and look at the whole document when troubleshooting.
62
+ * Finally, if the document origins in a Cross Dataset Reference you'll also have `_projectId` and `_dataset` properties to help you trace it.
63
+ */
64
+ sourceDocument: ContentSourceMapDocuments[number];
65
+ /**
66
+ * If you don't colocate your Studio Schemas with your GROQ queries it might be hard to make sense of `sourcePath`,
67
+ * as it operates on the original shape of a document.
68
+ * In that case `resultPath` can be used, as it mirrors the path to the value in the result.
69
+ * For example in a query like this:
70
+ * `*[_type == "author"][0]{"slug": slug.current}`
71
+ * The `resultPath` for `result.slug` would be `['slug']`, while `sourcePath` will be `['slug', 'current']`.
72
+ */
73
+ resultPath: ContentSourceMapParsedPath;
74
+ /**
75
+ * You can also use your own string validation logic to determine if it's safe.
76
+ */
77
+ value: string;
78
+ /**
79
+ * If you want to keep the default filtering behavior, but only override it for a specific path, you can use `filterDefault` to do that.
80
+ * For example, here all "icon" documents in a Page Builder skips encoding:
81
+ * ```ts
82
+ {
83
+ filter: (props) => {
84
+ switch (props.sourceDocument._type) {
85
+ case 'icon':
86
+ return false
87
+ default:
88
+ return props.filterDefault(props)
89
+ }
90
+ }
91
+ }
92
+ * ```
93
+ */
94
+ filterDefault: FilterDefault;
95
+ }) => boolean;
96
+ /** @public */
97
+ type Logger = typeof console | Partial<Pick<typeof console, 'debug' | 'error' | 'groupCollapsed' | 'groupEnd' | 'log' | 'table'>>;
98
+ /**
99
+ * @internal
100
+ */
101
+ type Encoder = (context: {
102
+ sourcePath: ContentSourceMapParsedPath;
103
+ sourceDocument: ContentSourceMapDocuments[number];
104
+ resultPath: ContentSourceMapParsedPath;
105
+ value: string;
106
+ }) => string;
107
+ export { ContentSourceMapQueryResponse as a, InitializedClientStegaConfig as c, ResolveStudioUrl as d, StegaConfig as f, StudioUrl$1 as g, StudioBaseUrl as h, ContentSourceMapParsedPathKeyedSegment as i, InitializedStegaConfig as l, StudioBaseRoute as m, ContentSourceMap$2 as n, Encoder as o, StegaConfigRequiredKeys as p, ContentSourceMapParsedPath$1 as r, FilterDefault as s, ClientStegaConfig as t, Logger as u };
108
+ //# sourceMappingURL=types-CfGzbXrl.d.ts.map
package/package.json CHANGED
@@ -1,181 +1,104 @@
1
1
  {
2
2
  "name": "@sanity/client",
3
- "version": "7.26.1",
3
+ "version": "8.0.0",
4
4
  "description": "Client for retrieving, creating and patching data from Sanity.io",
5
5
  "keywords": [
6
- "sanity",
6
+ "api",
7
+ "client",
7
8
  "cms",
8
- "headless",
9
- "realtime",
10
9
  "content",
11
- "client",
12
10
  "fetch",
13
- "api"
11
+ "headless",
12
+ "realtime",
13
+ "sanity"
14
14
  ],
15
15
  "homepage": "https://www.sanity.io/",
16
16
  "bugs": {
17
17
  "url": "https://github.com/sanity-io/client/issues"
18
18
  },
19
+ "license": "MIT",
20
+ "author": "Sanity.io <hello@sanity.io>",
19
21
  "repository": {
20
22
  "type": "git",
21
23
  "url": "git+https://github.com/sanity-io/client.git"
22
24
  },
23
- "license": "MIT",
24
- "author": "Sanity.io <hello@sanity.io>",
25
- "sideEffects": false,
25
+ "files": [
26
+ "dist",
27
+ "src"
28
+ ],
26
29
  "type": "module",
30
+ "sideEffects": false,
31
+ "types": "./dist/index.d.ts",
27
32
  "exports": {
28
33
  ".": {
29
- "source": "./src/index.ts",
30
- "browser": {
31
- "source": "./src/index.browser.ts",
32
- "import": "./dist/index.browser.js",
33
- "require": "./dist/index.browser.cjs"
34
+ "react-server": "./dist/index.js",
35
+ "sanity-function": "./dist/index.js",
36
+ "deno": "./dist/index.js",
37
+ "bun": "./dist/index.js",
38
+ "workerd": "./dist/index.js",
39
+ "worker": "./dist/index.js",
40
+ "node": {
41
+ "import": "./dist/index.node.js",
42
+ "default": "./dist/index.node.js"
34
43
  },
35
- "react-native": {
36
- "import": "./dist/index.browser.js",
37
- "require": "./dist/index.browser.cjs"
38
- },
39
- "sanity-function": "./dist/index.browser.js",
40
- "react-server": "./dist/index.browser.js",
41
- "bun": "./dist/index.browser.js",
42
- "deno": "./dist/index.browser.js",
43
- "edge": "./dist/index.browser.js",
44
- "edge-light": "./dist/index.browser.js",
45
- "worker": "./dist/index.browser.js",
46
- "import": "./dist/index.js",
47
- "require": "./dist/index.cjs",
48
44
  "default": "./dist/index.js"
49
45
  },
50
- "./csm": {
51
- "source": "./src/csm/index.ts",
52
- "import": "./dist/csm.js",
53
- "require": "./dist/csm.cjs",
54
- "default": "./dist/csm.js"
55
- },
56
- "./stega": {
57
- "source": "./src/stega/index.ts",
58
- "browser": {
59
- "source": "./src/stega/index.ts",
60
- "import": "./dist/stega.browser.js",
61
- "require": "./dist/stega.browser.cjs"
62
- },
63
- "import": "./dist/stega.js",
64
- "require": "./dist/stega.cjs",
65
- "default": "./dist/stega.js"
66
- },
67
- "./media-library": {
68
- "source": "./src/media-library.ts",
69
- "import": "./dist/media-library.js",
70
- "require": "./dist/media-library.cjs",
71
- "default": "./dist/media-library.js"
72
- },
46
+ "./csm": "./dist/csm.js",
47
+ "./stega": "./dist/stega.js",
48
+ "./media-library": "./dist/media-library.js",
73
49
  "./package.json": "./package.json"
74
50
  },
75
- "main": "./dist/index.cjs",
76
- "unpkg": "umd/sanityClient.min.js",
77
- "module": "./dist/index.js",
78
- "browser": {
79
- "./dist/index.cjs": "./dist/index.browser.cjs",
80
- "./dist/index.js": "./dist/index.browser.js"
81
- },
82
- "types": "./dist/index.d.ts",
83
- "typesVersions": {
84
- "*": {
85
- "csm": [
86
- "./dist/csm.d.ts"
87
- ],
88
- "stega": [
89
- "./dist/stega.d.ts"
90
- ],
91
- "media-library": [
92
- "./dist/media-library.d.ts"
93
- ]
94
- }
95
- },
96
- "files": [
97
- "dist",
98
- "src",
99
- "umd"
100
- ],
101
- "scripts": {
102
- "benchmark": "npm test -- bench",
103
- "prebuild": "npm run clean",
104
- "build": "pkg build --strict && pkg --strict && npm run rollup && npm run minify",
105
- "check-esm-compatibility": "node scripts/check-esm-compatibility.mjs",
106
- "clean": "npx rimraf dist coverage umd/*.js",
107
- "coverage": "vitest run --coverage",
108
- "lint": "eslint . --max-warnings 0",
109
- "minify": "terser -c -m -- umd/sanityClient.js > umd/sanityClient.min.js",
110
- "prepublishOnly": "npm run build",
111
- "rollup": "NODE_ENV=production rollup -c rollup.config.cjs",
112
- "test": "vitest",
113
- "test:browser": "npm test -- --config ./vitest.browser.config.ts",
114
- "test:bun": "bun test runtimes/bun",
115
- "test:deno": "deno test --allow-read --allow-net --allow-env --fail-fast --import-map=runtimes/deno/import_map.json runtimes/deno",
116
- "test:deno:update_import_map": "deno run --allow-read --allow-write runtimes/deno/update_import_map.ts",
117
- "test:edge-runtime": "npm test -- --config vitest.edge.config.ts",
118
- "test:next": "npm test -- --config ./vitest.next.config.ts",
119
- "test:node-runtimes": "(cd runtimes/node && node --test)"
120
- },
121
- "browserslist": "extends @sanity/browserslist-config",
122
- "prettier": {
123
- "bracketSpacing": false,
124
- "plugins": [
125
- "prettier-plugin-packagejson"
126
- ],
127
- "printWidth": 100,
128
- "semi": false,
129
- "singleQuote": true
130
- },
131
51
  "dependencies": {
132
- "@sanity/eventsource": "^5.0.4",
133
- "get-it": "^8.8.0",
134
- "nanoid": "^3.3.11",
135
- "rxjs": "^7.0.0"
52
+ "eventsource": "^5.0.0",
53
+ "get-it": "^9.4.1",
54
+ "nanoid": "^6.0.1",
55
+ "obug": "^2.1.4",
56
+ "rxjs": "^7.8.2"
136
57
  },
137
58
  "devDependencies": {
59
+ "@changesets/cli": "^2.31.1",
60
+ "@cloudflare/vitest-pool-workers": "^0.20.1",
138
61
  "@edge-runtime/types": "^4.0.0",
139
62
  "@edge-runtime/vm": "^5.0.0",
140
- "@eslint/eslintrc": "^3.3.1",
141
- "@eslint/js": "^9.24.0",
142
- "@rollup/plugin-commonjs": "^28.0.3",
143
- "@rollup/plugin-node-resolve": "^16.0.1",
144
- "@sanity/client-latest": "npm:@sanity/client@latest",
145
- "@sanity/pkg-utils": "^7.2.2",
63
+ "@sanity/pkg-utils": "^12.1.2",
146
64
  "@types/json-diff": "^1.0.3",
147
- "@types/node": "^22.9.0",
148
- "@types/react": "^19.2.17",
149
- "@typescript-eslint/eslint-plugin": "^8.29.1",
150
- "@typescript-eslint/parser": "^8.29.1",
65
+ "@types/node": "^22.20.1",
66
+ "@types/react": "^19.2.18",
151
67
  "@vercel/stega": "1.1.0",
152
- "@vitest/coverage-v8": "3.1.1",
153
- "eslint": "^9.24.0",
154
- "eslint-config-prettier": "^10.1.1",
155
- "eslint-formatter-compact": "^8.40.0",
156
- "eslint-plugin-prettier": "^5.2.6",
157
- "eslint-plugin-simple-import-sort": "^12.1.1",
158
- "eslint-plugin-tsdoc": "^0.4.0",
159
- "eslint-plugin-unused-imports": "^4.1.4",
160
- "globals": "^16.0.0",
161
- "happy-dom": "^12.10.3",
68
+ "@vitest/coverage-v8": "^4.1.10",
69
+ "eventsource-encoder": "^1.0.2",
70
+ "happy-dom": "^20.11.1",
162
71
  "json-diff": "^1.0.6",
163
- "ls-engines": "^0.9.3",
164
- "msw": "^2.7.3",
165
- "next": "15.5.8",
166
- "nock": "^13.5.6",
167
- "pkg-pr-new": "^0.0.60",
168
- "prettier": "^3.5.3",
169
- "prettier-plugin-packagejson": "^2.5.10",
170
- "rimraf": "^5.0.7",
171
- "rollup": "^4.39.0",
172
- "sse-channel": "^4.0.0",
173
- "terser": "^5.39.0",
174
- "typescript": "5.8.3",
175
- "vitest": "3.1.1"
72
+ "ls-engines": "^0.10.1",
73
+ "next": "^16.3.0",
74
+ "oxfmt": "^0.63.0",
75
+ "oxlint": "^1.78.0",
76
+ "oxlint-tsgolint": "^7.0.2001",
77
+ "pkg-pr-new": "^0.0.86",
78
+ "typescript": "7.0.2",
79
+ "vitest": "^4.1.10"
176
80
  },
177
- "packageManager": "npm@11.4.1",
81
+ "browserslist": "extends @sanity/browserslist-config",
178
82
  "engines": {
179
- "node": ">=20"
83
+ "node": ">=22.12.0"
84
+ },
85
+ "inlinedDependencies": {
86
+ "@vercel/stega": "1.1.0"
87
+ },
88
+ "scripts": {
89
+ "build": "pkg build --strict && pkg --strict",
90
+ "coverage": "vitest run --coverage",
91
+ "lint": "oxlint",
92
+ "release": "changeset publish",
93
+ "test": "vitest",
94
+ "test:browser": "vitest run --config ./vitest.browser.config.ts",
95
+ "test:bun": "bun test runtimes/bun",
96
+ "test:deno": "npm pack --pack-destination runtimes/deno && cd runtimes/deno && npm install --no-save --no-package-lock ./sanity-client-*.tgz @types/node && deno test --allow-read --allow-net --allow-env --fail-fast --node-modules-dir=manual .",
97
+ "test:next": "vitest run --config ./vitest.next.config.ts",
98
+ "test:node-runtimes": "(cd runtimes/node && node --test)",
99
+ "test:vercel-edge": "vitest run --config ./vitest.vercel-edge.config.ts",
100
+ "test:workerd": "vitest run --config ./vitest.workerd.config.ts",
101
+ "format": "oxfmt",
102
+ "format:check": "oxfmt --check"
180
103
  }
181
- }
104
+ }