sanity-plugin-iframe-pane 2.3.1 → 2.3.2-canary.2

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 (40) hide show
  1. package/README.md +15 -5
  2. package/lib/_chunks/is-valid-secret-57fea7e5.js +35 -0
  3. package/lib/_chunks/is-valid-secret-57fea7e5.js.map +1 -0
  4. package/lib/_chunks/is-valid-secret-7b704c76.cjs +41 -0
  5. package/lib/_chunks/is-valid-secret-7b704c76.cjs.map +1 -0
  6. package/lib/_chunks/types-107599a1.js +34 -0
  7. package/lib/_chunks/types-107599a1.js.map +1 -0
  8. package/lib/_chunks/types-4a29b6ac.cjs +38 -0
  9. package/lib/_chunks/types-4a29b6ac.cjs.map +1 -0
  10. package/lib/index.cjs +462 -154
  11. package/lib/index.cjs.js +3 -1
  12. package/lib/index.cjs.map +1 -1
  13. package/lib/index.d.ts +38 -11
  14. package/lib/index.js +462 -158
  15. package/lib/index.js.map +1 -1
  16. package/lib/is-valid-secret.cjs +8 -0
  17. package/lib/is-valid-secret.cjs.js +4 -0
  18. package/lib/is-valid-secret.cjs.map +1 -0
  19. package/lib/is-valid-secret.d.ts +41 -0
  20. package/lib/is-valid-secret.js +2 -0
  21. package/lib/is-valid-secret.js.map +1 -0
  22. package/lib/preview-url.cjs +77 -0
  23. package/lib/preview-url.cjs.js +4 -0
  24. package/lib/preview-url.cjs.map +1 -0
  25. package/lib/preview-url.d.ts +17 -0
  26. package/lib/preview-url.js +72 -0
  27. package/lib/preview-url.js.map +1 -0
  28. package/package.json +34 -10
  29. package/src/DisplayUrl.tsx +21 -0
  30. package/src/GetUrlSecret.tsx +80 -0
  31. package/src/Iframe.tsx +272 -158
  32. package/src/Toolbar.tsx +153 -0
  33. package/src/defineUrlResolver.tsx +31 -0
  34. package/src/index.ts +3 -5
  35. package/src/is-valid-secret.ts +2 -0
  36. package/src/isValidSecret.tsx +67 -0
  37. package/src/preview-url.ts +2 -0
  38. package/src/previewUrl.ts +62 -0
  39. package/src/types.ts +17 -0
  40. package/src/utils.ts +45 -0
package/README.md CHANGED
@@ -48,11 +48,11 @@ A basic example of a custom `defaultDocumentNode` function, to only show the Ifr
48
48
  // ./src/defaultDocumentNode.ts
49
49
 
50
50
  import {DefaultDocumentNodeResolver} from 'sanity/desk'
51
- import Iframe from 'sanity-plugin-iframe-pane'
52
- import {SanityDocument} from 'sanity'
51
+ import {Iframe} from 'sanity-plugin-iframe-pane'
52
+ import {SanityDocumentLike} from 'sanity'
53
53
 
54
54
  // Customise this function to show the correct URL based on the current document
55
- function getPreviewUrl(doc: SanityDocument) {
55
+ function getPreviewUrl(doc: SanityDocumentLike) {
56
56
  return doc?.slug?.current
57
57
  ? `${window.location.host}/${doc.slug.current}`
58
58
  : `${window.location.host}`
@@ -96,11 +96,11 @@ defaultSize: `mobile`, // default `desktop`
96
96
  // Optional: Add a reload button, or reload on new document revisions
97
97
  reload: {
98
98
  button: true, // default `undefined`
99
- revision: true, // boolean | number. default `undefined`. If a number is provided, add a delay (in ms) before the automatic reload on document revision
99
+ revision: true, // boolean | number. default `undefined`. If a number is provided, add a delay (in ms) before the automatic reload on document revision. If `true` then a curated delay is used. Use `0` to have zero delay.`
100
100
  },
101
101
 
102
102
  // Optional: Display a spinner while the iframe is loading
103
- loader: true // boolean | string. default `undefined`. If a string is provided, it will be display below the spinner (e.g. Loading…)
103
+ loader: true // boolean | string. default `'Loading…'`. If a string is provided, it will be display below the spinner (e.g. Loading…)
104
104
 
105
105
  // Optional: Pass attributes to the underlying `iframe` element:
106
106
  // See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe
@@ -111,6 +111,16 @@ attributes: {
111
111
  }
112
112
  ```
113
113
 
114
+ ## `sanity-plugin-iframe-pane/preview-url`
115
+
116
+ This plugin also exports a `preview-url` tool, which can be used to generate a URL for the current document.
117
+
118
+ SCREENSHOT OF OPEN PREVIEW BUTTON
119
+
120
+ ## `sanity-plugin-iframe-pane/is-valid-secret`
121
+
122
+ If the `urlSecretId` feature is used, to secure preview URLs, this plugin also exports a `is-valid-secret` tool, which can be used to validate a secret inside an API handler. In Next.js you would typically do this before calling `draftMode().enable()` or `res.setPreviewData()`.
123
+
114
124
  ## License
115
125
 
116
126
  MIT-licensed. See LICENSE.
@@ -0,0 +1,35 @@
1
+ var name = "sanity-plugin-iframe-pane";
2
+ const SECRET_TTL = 60 * 60;
3
+ const fetchSecretQuery = /* groq */"*[_id == $id && dateTime(_updatedAt) > dateTime(now()) - ".concat(SECRET_TTL, "][0]{secret, _updatedAt}");
4
+ const tag = name;
5
+ const apiVersion = "2023-08-08";
6
+ async function isValidSecret(client, urlSecretId, urlSecret) {
7
+ if (!urlSecret) {
8
+ throw new TypeError("`urlSecret` is required");
9
+ }
10
+ if (!urlSecretId) {
11
+ throw new TypeError("`urlSecretId` is required");
12
+ }
13
+ if (!urlSecretId.includes(".")) {
14
+ throw new TypeError("`urlSecretId` must have a dot prefix, `".concat(urlSecretId, "` is not secure, add a prefix, for example `preview.").concat(urlSecretId, "` "));
15
+ }
16
+ if (!client) {
17
+ throw new TypeError("`client` is required");
18
+ }
19
+ if (!client.config().token) {
20
+ throw new TypeError("`client` must have a `token` specified");
21
+ }
22
+ const customClient = client.withConfig({
23
+ apiVersion,
24
+ useCdn: false,
25
+ perspective: "raw"
26
+ });
27
+ const data = await customClient.fetch(fetchSecretQuery, {
28
+ id: urlSecretId
29
+ }, {
30
+ tag
31
+ });
32
+ return (data == null ? void 0 : data.secret) === urlSecret;
33
+ }
34
+ export { SECRET_TTL, apiVersion, fetchSecretQuery, isValidSecret, tag };
35
+ //# sourceMappingURL=is-valid-secret-57fea7e5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-valid-secret-57fea7e5.js","sources":["../../src/isValidSecret.tsx"],"sourcesContent":["import {name} from '../package.json'\n\nexport type UrlSecretId = `${string}.${string}`\n\n// updated within the hour, if it's older it'll create a new secret or return null\nexport const SECRET_TTL = 60 * 60\n\nexport const fetchSecretQuery = /* groq */ `*[_id == $id && dateTime(_updatedAt) > dateTime(now()) - ${SECRET_TTL}][0]{secret, _updatedAt}`\nexport type FetchSecretResponse = {\n secret: string | null\n _updatedAt: string | null\n} | null\n\nexport const tag = name\n\nexport const apiVersion = '2023-08-08'\n\nexport type SanityClientLike = {\n config(): {token?: string}\n withConfig(config: {apiVersion?: string; useCdn?: boolean; perspective: 'raw'}): SanityClientLike\n fetch<\n R,\n Q = {\n [key: string]: any\n },\n >(\n query: string,\n params: Q,\n options: {tag?: string},\n ): Promise<R>\n}\nexport async function isValidSecret(\n client: SanityClientLike,\n urlSecretId: UrlSecretId,\n urlSecret: string,\n): Promise<boolean> {\n if (!urlSecret) {\n throw new TypeError('`urlSecret` is required')\n }\n if (!urlSecretId) {\n throw new TypeError('`urlSecretId` is required')\n }\n if (!urlSecretId.includes('.')) {\n throw new TypeError(\n `\\`urlSecretId\\` must have a dot prefix, \\`${urlSecretId}\\` is not secure, add a prefix, for example \\`preview.${urlSecretId}\\` `,\n )\n }\n if (!client) {\n throw new TypeError('`client` is required')\n }\n if (!client.config().token) {\n throw new TypeError('`client` must have a `token` specified')\n }\n\n const customClient = client.withConfig({\n apiVersion,\n useCdn: false,\n perspective: 'raw',\n })\n const data = await customClient.fetch<FetchSecretResponse>(\n fetchSecretQuery,\n {id: urlSecretId},\n {tag},\n )\n\n return data?.secret === urlSecret\n}\n"],"names":["SECRET_TTL","fetchSecretQuery","concat","tag","name","apiVersion","isValidSecret","client","urlSecretId","urlSecret","TypeError","includes","config","token","customClient","withConfig","useCdn","perspective","data","fetch","id","secret"],"mappings":";AAKO,MAAMA,aAAa,EAAK,GAAA,EAAA;AAElB,MAAAC,gBAAA,GAAA,sEAAAC,MAAA,CAA0FF,UAAA,6BAAA;AAMhG,MAAMG,GAAM,GAAAC,IAAA;AAEZ,MAAMC,UAAa,GAAA,YAAA;AAgBJ,eAAAC,aAAAA,CACpBC,MACA,EAAAC,WAAA,EACAC,SACkB,EAAA;EAClB,IAAI,CAACA,SAAW,EAAA;IACR,MAAA,IAAIC,UAAU,yBAAyB,CAAA;EAC/C;EACA,IAAI,CAACF,WAAa,EAAA;IACV,MAAA,IAAIE,UAAU,2BAA2B,CAAA;EACjD;EACA,IAAI,CAACF,WAAA,CAAYG,QAAS,CAAA,GAAG,CAAG,EAAA;IAC9B,MAAM,IAAID,SAAA,2CAAAR,MAAA,CACqCM,WAAoE,0DAAAN,MAAA,CAAAM,WAAA,OAAA,CACnH;EACF;EACA,IAAI,CAACD,MAAQ,EAAA;IACL,MAAA,IAAIG,UAAU,sBAAsB,CAAA;EAC5C;EACA,IAAI,CAACH,MAAA,CAAOK,MAAO,CAAA,CAAA,CAAEC,KAAO,EAAA;IACpB,MAAA,IAAIH,UAAU,wCAAwC,CAAA;EAC9D;EAEM,MAAAI,YAAA,GAAeP,OAAOQ,UAAW,CAAA;IACrCV,UAAA;IACAW,MAAQ,EAAA,KAAA;IACRC,WAAa,EAAA;EAAA,CACd,CAAA;EACK,MAAAC,IAAA,GAAO,MAAMJ,YAAa,CAAAK,KAAA,CAC9BlB,gBAAA,EACA;IAACmB,IAAIZ;EAAW,CAAA,EAChB;IAACL;EAAG,CAAA,CACN;EAEA,OAAA,CAAOe,6BAAMG,MAAW,MAAAZ,SAAA;AAC1B;"}
@@ -0,0 +1,41 @@
1
+ 'use strict';
2
+
3
+ var name = "sanity-plugin-iframe-pane";
4
+ const SECRET_TTL = 60 * 60;
5
+ const fetchSecretQuery = /* groq */"*[_id == $id && dateTime(_updatedAt) > dateTime(now()) - ".concat(SECRET_TTL, "][0]{secret, _updatedAt}");
6
+ const tag = name;
7
+ const apiVersion = "2023-08-08";
8
+ async function isValidSecret(client, urlSecretId, urlSecret) {
9
+ if (!urlSecret) {
10
+ throw new TypeError("`urlSecret` is required");
11
+ }
12
+ if (!urlSecretId) {
13
+ throw new TypeError("`urlSecretId` is required");
14
+ }
15
+ if (!urlSecretId.includes(".")) {
16
+ throw new TypeError("`urlSecretId` must have a dot prefix, `".concat(urlSecretId, "` is not secure, add a prefix, for example `preview.").concat(urlSecretId, "` "));
17
+ }
18
+ if (!client) {
19
+ throw new TypeError("`client` is required");
20
+ }
21
+ if (!client.config().token) {
22
+ throw new TypeError("`client` must have a `token` specified");
23
+ }
24
+ const customClient = client.withConfig({
25
+ apiVersion,
26
+ useCdn: false,
27
+ perspective: "raw"
28
+ });
29
+ const data = await customClient.fetch(fetchSecretQuery, {
30
+ id: urlSecretId
31
+ }, {
32
+ tag
33
+ });
34
+ return (data == null ? void 0 : data.secret) === urlSecret;
35
+ }
36
+ exports.SECRET_TTL = SECRET_TTL;
37
+ exports.apiVersion = apiVersion;
38
+ exports.fetchSecretQuery = fetchSecretQuery;
39
+ exports.isValidSecret = isValidSecret;
40
+ exports.tag = tag;
41
+ //# sourceMappingURL=is-valid-secret-7b704c76.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-valid-secret-7b704c76.cjs","sources":["../../src/isValidSecret.tsx"],"sourcesContent":["import {name} from '../package.json'\n\nexport type UrlSecretId = `${string}.${string}`\n\n// updated within the hour, if it's older it'll create a new secret or return null\nexport const SECRET_TTL = 60 * 60\n\nexport const fetchSecretQuery = /* groq */ `*[_id == $id && dateTime(_updatedAt) > dateTime(now()) - ${SECRET_TTL}][0]{secret, _updatedAt}`\nexport type FetchSecretResponse = {\n secret: string | null\n _updatedAt: string | null\n} | null\n\nexport const tag = name\n\nexport const apiVersion = '2023-08-08'\n\nexport type SanityClientLike = {\n config(): {token?: string}\n withConfig(config: {apiVersion?: string; useCdn?: boolean; perspective: 'raw'}): SanityClientLike\n fetch<\n R,\n Q = {\n [key: string]: any\n },\n >(\n query: string,\n params: Q,\n options: {tag?: string},\n ): Promise<R>\n}\nexport async function isValidSecret(\n client: SanityClientLike,\n urlSecretId: UrlSecretId,\n urlSecret: string,\n): Promise<boolean> {\n if (!urlSecret) {\n throw new TypeError('`urlSecret` is required')\n }\n if (!urlSecretId) {\n throw new TypeError('`urlSecretId` is required')\n }\n if (!urlSecretId.includes('.')) {\n throw new TypeError(\n `\\`urlSecretId\\` must have a dot prefix, \\`${urlSecretId}\\` is not secure, add a prefix, for example \\`preview.${urlSecretId}\\` `,\n )\n }\n if (!client) {\n throw new TypeError('`client` is required')\n }\n if (!client.config().token) {\n throw new TypeError('`client` must have a `token` specified')\n }\n\n const customClient = client.withConfig({\n apiVersion,\n useCdn: false,\n perspective: 'raw',\n })\n const data = await customClient.fetch<FetchSecretResponse>(\n fetchSecretQuery,\n {id: urlSecretId},\n {tag},\n )\n\n return data?.secret === urlSecret\n}\n"],"names":["SECRET_TTL","fetchSecretQuery","concat","tag","name","apiVersion","isValidSecret","client","urlSecretId","urlSecret","TypeError","includes","config","token","customClient","withConfig","useCdn","perspective","data","fetch","id","secret"],"mappings":";;;AAKO,MAAMA,aAAa,EAAK,GAAA,EAAA;AAElB,MAAAC,gBAAA,GAAA,sEAAAC,MAAA,CAA0FF,UAAA,6BAAA;AAMhG,MAAMG,GAAM,GAAAC,IAAA;AAEZ,MAAMC,UAAa,GAAA,YAAA;AAgBJ,eAAAC,aAAAA,CACpBC,MACA,EAAAC,WAAA,EACAC,SACkB,EAAA;EAClB,IAAI,CAACA,SAAW,EAAA;IACR,MAAA,IAAIC,UAAU,yBAAyB,CAAA;EAC/C;EACA,IAAI,CAACF,WAAa,EAAA;IACV,MAAA,IAAIE,UAAU,2BAA2B,CAAA;EACjD;EACA,IAAI,CAACF,WAAA,CAAYG,QAAS,CAAA,GAAG,CAAG,EAAA;IAC9B,MAAM,IAAID,SAAA,2CAAAR,MAAA,CACqCM,WAAoE,0DAAAN,MAAA,CAAAM,WAAA,OAAA,CACnH;EACF;EACA,IAAI,CAACD,MAAQ,EAAA;IACL,MAAA,IAAIG,UAAU,sBAAsB,CAAA;EAC5C;EACA,IAAI,CAACH,MAAA,CAAOK,MAAO,CAAA,CAAA,CAAEC,KAAO,EAAA;IACpB,MAAA,IAAIH,UAAU,wCAAwC,CAAA;EAC9D;EAEM,MAAAI,YAAA,GAAeP,OAAOQ,UAAW,CAAA;IACrCV,UAAA;IACAW,MAAQ,EAAA,KAAA;IACRC,WAAa,EAAA;EAAA,CACd,CAAA;EACK,MAAAC,IAAA,GAAO,MAAMJ,YAAa,CAAAK,KAAA,CAC9BlB,gBAAA,EACA;IAACmB,IAAIZ;EAAW,CAAA,EAChB;IAACL;EAAG,CAAA,CACN;EAEA,OAAA,CAAOe,6BAAMG,MAAW,MAAAZ,SAAA;AAC1B;;;;;"}
@@ -0,0 +1,34 @@
1
+ import { tag, SECRET_TTL } from './is-valid-secret-57fea7e5.js';
2
+ function getExpiresAt(_updatedAt) {
3
+ return new Date(_updatedAt.getTime() + 1e3 * SECRET_TTL);
4
+ }
5
+ function generateUrlSecret() {
6
+ if (typeof crypto !== "undefined") {
7
+ const array = new Uint8Array(16);
8
+ crypto.getRandomValues(array);
9
+ let key = "";
10
+ for (let i = 0; i < array.length; i++) {
11
+ key += array[i].toString(16).padStart(2, "0");
12
+ }
13
+ key = btoa(key).replace(/\+/g, "-").replace(/\//g, "_").replace(/[=]+$/, "");
14
+ return key;
15
+ }
16
+ return Math.random().toString(36).slice(2);
17
+ }
18
+ async function patchUrlSecret(client, urlSecretId, signal) {
19
+ const newSecret = generateUrlSecret();
20
+ const patch = client.patch(urlSecretId).set({
21
+ secret: newSecret
22
+ });
23
+ await client.transaction().createIfNotExists({
24
+ _id: urlSecretId,
25
+ _type: urlSecretId
26
+ }).patch(patch).commit({
27
+ tag,
28
+ signal
29
+ });
30
+ return newSecret;
31
+ }
32
+ const MissingSlug = Symbol("MissingSlug");
33
+ export { MissingSlug, getExpiresAt, patchUrlSecret };
34
+ //# sourceMappingURL=types-107599a1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-107599a1.js","sources":["../../src/utils.ts","../../src/types.ts"],"sourcesContent":["import type {SanityClient} from 'sanity'\n\nimport {SECRET_TTL, tag, UrlSecretId} from './isValidSecret'\n\nexport function getExpiresAt(_updatedAt: Date) {\n return new Date(_updatedAt.getTime() + 1000 * SECRET_TTL)\n}\n\nfunction generateUrlSecret() {\n // Try using WebCrypto if available\n if (typeof crypto !== 'undefined') {\n // Generate a random array of 16 bytes\n const array = new Uint8Array(16)\n crypto.getRandomValues(array)\n\n // Convert the array to a URL-safe string\n let key = ''\n for (let i = 0; i < array.length; i++) {\n // Convert each byte to a 2-digit hexadecimal number\n key += array[i].toString(16).padStart(2, '0')\n }\n\n // Replace '+' and '/' from base64url to '-' and '_'\n key = btoa(key).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/[=]+$/, '')\n\n return key\n }\n // If not fallback to Math.random\n return Math.random().toString(36).slice(2)\n}\n\nexport async function patchUrlSecret(\n client: SanityClient,\n urlSecretId: UrlSecretId,\n signal?: AbortSignal,\n): Promise<string> {\n const newSecret = generateUrlSecret()\n const patch = client.patch(urlSecretId).set({secret: newSecret})\n await client\n .transaction()\n .createIfNotExists({_id: urlSecretId, _type: urlSecretId})\n .patch(patch)\n .commit({tag, signal})\n return newSecret\n}\n","export const MissingSlug = Symbol('MissingSlug')\n\nexport type UrlState = string | typeof MissingSlug\n\nexport type IframeSizeKey = keyof SizeProps\n\nexport type Size = 'desktop' | 'mobile'\n\nexport type SizeProps = {\n // eslint-disable-next-line no-unused-vars\n [key in Size]: {\n width: string | number\n height: string | number\n }\n}\n\nexport type SetError = (error: unknown) => void\n"],"names":["getExpiresAt","_updatedAt","Date","getTime","SECRET_TTL","generateUrlSecret","crypto","array","Uint8Array","getRandomValues","key","i","length","toString","padStart","btoa","replace","Math","random","slice","patchUrlSecret","client","urlSecretId","signal","newSecret","patch","set","secret","transaction","createIfNotExists","_id","_type","commit","tag","MissingSlug","Symbol"],"mappings":";AAIO,SAASA,aAAaC,UAAkB,EAAA;EAC7C,OAAO,IAAIC,IAAK,CAAAD,UAAA,CAAWE,OAAQ,CAAA,CAAA,GAAI,MAAOC,UAAU,CAAA;AAC1D;AAEA,SAASC,iBAAoBA,CAAA,EAAA;EAEvB,IAAA,OAAOC,WAAW,WAAa,EAAA;IAE3B,MAAAC,KAAA,GAAQ,IAAIC,UAAA,CAAW,EAAE,CAAA;IAC/BF,MAAA,CAAOG,gBAAgBF,KAAK,CAAA;IAG5B,IAAIG,GAAM,GAAA,EAAA;IACV,KAAA,IAASC,CAAI,GAAA,CAAA,EAAGA,CAAI,GAAAJ,KAAA,CAAMK,QAAQD,CAAK,EAAA,EAAA;MAE9BD,GAAA,IAAAH,KAAA,CAAMI,CAAC,CAAE,CAAAE,QAAA,CAAS,EAAE,CAAE,CAAAC,QAAA,CAAS,GAAG,GAAG,CAAA;IAC9C;IAGAJ,GAAA,GAAMK,IAAK,CAAAL,GAAG,CAAE,CAAAM,OAAA,CAAQ,KAAO,EAAA,GAAG,CAAE,CAAAA,OAAA,CAAQ,KAAO,EAAA,GAAG,CAAE,CAAAA,OAAA,CAAQ,SAAS,EAAE,CAAA;IAEpE,OAAAN,GAAA;EACT;EAEA,OAAOO,KAAKC,MAAO,EAAA,CAAEL,SAAS,EAAE,CAAA,CAAEM,MAAM,CAAC,CAAA;AAC3C;AAEsB,eAAAC,cAAAA,CACpBC,MACA,EAAAC,WAAA,EACAC,MACiB,EAAA;EACjB,MAAMC,YAAYnB,iBAAkB,EAAA;EAC9B,MAAAoB,KAAA,GAAQJ,OAAOI,KAAM,CAAAH,WAAW,EAAEI,GAAI,CAAA;IAACC,MAAQ,EAAAH;EAAA,CAAU,CAAA;EAC/D,MAAMH,OACHO,WAAY,EAAA,CACZC,kBAAkB;IAACC,GAAA,EAAKR;IAAaS,KAAO,EAAAT;EAAY,CAAA,CAAA,CACxDG,MAAMA,KAAK,CAAA,CACXO,OAAO;IAACC,GAAA;IAAKV;GAAO,CAAA;EAChB,OAAAC,SAAA;AACT;AC5Ca,MAAAU,WAAA,GAAcC,OAAO,aAAa,CAAA;"}
@@ -0,0 +1,38 @@
1
+ 'use strict';
2
+
3
+ var isValidSecret = require('./is-valid-secret-7b704c76.cjs');
4
+ function getExpiresAt(_updatedAt) {
5
+ return new Date(_updatedAt.getTime() + 1e3 * isValidSecret.SECRET_TTL);
6
+ }
7
+ function generateUrlSecret() {
8
+ if (typeof crypto !== "undefined") {
9
+ const array = new Uint8Array(16);
10
+ crypto.getRandomValues(array);
11
+ let key = "";
12
+ for (let i = 0; i < array.length; i++) {
13
+ key += array[i].toString(16).padStart(2, "0");
14
+ }
15
+ key = btoa(key).replace(/\+/g, "-").replace(/\//g, "_").replace(/[=]+$/, "");
16
+ return key;
17
+ }
18
+ return Math.random().toString(36).slice(2);
19
+ }
20
+ async function patchUrlSecret(client, urlSecretId, signal) {
21
+ const newSecret = generateUrlSecret();
22
+ const patch = client.patch(urlSecretId).set({
23
+ secret: newSecret
24
+ });
25
+ await client.transaction().createIfNotExists({
26
+ _id: urlSecretId,
27
+ _type: urlSecretId
28
+ }).patch(patch).commit({
29
+ tag: isValidSecret.tag,
30
+ signal
31
+ });
32
+ return newSecret;
33
+ }
34
+ const MissingSlug = Symbol("MissingSlug");
35
+ exports.MissingSlug = MissingSlug;
36
+ exports.getExpiresAt = getExpiresAt;
37
+ exports.patchUrlSecret = patchUrlSecret;
38
+ //# sourceMappingURL=types-4a29b6ac.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-4a29b6ac.cjs","sources":["../../src/utils.ts","../../src/types.ts"],"sourcesContent":["import type {SanityClient} from 'sanity'\n\nimport {SECRET_TTL, tag, UrlSecretId} from './isValidSecret'\n\nexport function getExpiresAt(_updatedAt: Date) {\n return new Date(_updatedAt.getTime() + 1000 * SECRET_TTL)\n}\n\nfunction generateUrlSecret() {\n // Try using WebCrypto if available\n if (typeof crypto !== 'undefined') {\n // Generate a random array of 16 bytes\n const array = new Uint8Array(16)\n crypto.getRandomValues(array)\n\n // Convert the array to a URL-safe string\n let key = ''\n for (let i = 0; i < array.length; i++) {\n // Convert each byte to a 2-digit hexadecimal number\n key += array[i].toString(16).padStart(2, '0')\n }\n\n // Replace '+' and '/' from base64url to '-' and '_'\n key = btoa(key).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/[=]+$/, '')\n\n return key\n }\n // If not fallback to Math.random\n return Math.random().toString(36).slice(2)\n}\n\nexport async function patchUrlSecret(\n client: SanityClient,\n urlSecretId: UrlSecretId,\n signal?: AbortSignal,\n): Promise<string> {\n const newSecret = generateUrlSecret()\n const patch = client.patch(urlSecretId).set({secret: newSecret})\n await client\n .transaction()\n .createIfNotExists({_id: urlSecretId, _type: urlSecretId})\n .patch(patch)\n .commit({tag, signal})\n return newSecret\n}\n","export const MissingSlug = Symbol('MissingSlug')\n\nexport type UrlState = string | typeof MissingSlug\n\nexport type IframeSizeKey = keyof SizeProps\n\nexport type Size = 'desktop' | 'mobile'\n\nexport type SizeProps = {\n // eslint-disable-next-line no-unused-vars\n [key in Size]: {\n width: string | number\n height: string | number\n }\n}\n\nexport type SetError = (error: unknown) => void\n"],"names":["getExpiresAt","_updatedAt","Date","getTime","SECRET_TTL","generateUrlSecret","crypto","array","Uint8Array","getRandomValues","key","i","length","toString","padStart","btoa","replace","Math","random","slice","patchUrlSecret","client","urlSecretId","signal","newSecret","patch","set","secret","transaction","createIfNotExists","_id","_type","commit","tag","MissingSlug","Symbol"],"mappings":";;;AAIO,SAASA,aAAaC,UAAkB,EAAA;EAC7C,OAAO,IAAIC,IAAK,CAAAD,UAAA,CAAWE,OAAQ,CAAA,CAAA,GAAI,MAAOC,aAAAA,CAAAA,UAAU,CAAA;AAC1D;AAEA,SAASC,iBAAoBA,CAAA,EAAA;EAEvB,IAAA,OAAOC,WAAW,WAAa,EAAA;IAE3B,MAAAC,KAAA,GAAQ,IAAIC,UAAA,CAAW,EAAE,CAAA;IAC/BF,MAAA,CAAOG,gBAAgBF,KAAK,CAAA;IAG5B,IAAIG,GAAM,GAAA,EAAA;IACV,KAAA,IAASC,CAAI,GAAA,CAAA,EAAGA,CAAI,GAAAJ,KAAA,CAAMK,QAAQD,CAAK,EAAA,EAAA;MAE9BD,GAAA,IAAAH,KAAA,CAAMI,CAAC,CAAE,CAAAE,QAAA,CAAS,EAAE,CAAE,CAAAC,QAAA,CAAS,GAAG,GAAG,CAAA;IAC9C;IAGAJ,GAAA,GAAMK,IAAK,CAAAL,GAAG,CAAE,CAAAM,OAAA,CAAQ,KAAO,EAAA,GAAG,CAAE,CAAAA,OAAA,CAAQ,KAAO,EAAA,GAAG,CAAE,CAAAA,OAAA,CAAQ,SAAS,EAAE,CAAA;IAEpE,OAAAN,GAAA;EACT;EAEA,OAAOO,KAAKC,MAAO,EAAA,CAAEL,SAAS,EAAE,CAAA,CAAEM,MAAM,CAAC,CAAA;AAC3C;AAEsB,eAAAC,cAAAA,CACpBC,MACA,EAAAC,WAAA,EACAC,MACiB,EAAA;EACjB,MAAMC,YAAYnB,iBAAkB,EAAA;EAC9B,MAAAoB,KAAA,GAAQJ,OAAOI,KAAM,CAAAH,WAAW,EAAEI,GAAI,CAAA;IAACC,MAAQ,EAAAH;EAAA,CAAU,CAAA;EAC/D,MAAMH,OACHO,WAAY,EAAA,CACZC,kBAAkB;IAACC,GAAA,EAAKR;IAAaS,KAAO,EAAAT;EAAY,CAAA,CAAA,CACxDG,MAAMA,KAAK,CAAA,CACXO,OAAO;IAAAC,GAAA,EAACA,aAAA,CAAAA,GAAA;IAAKV;GAAO,CAAA;EAChB,OAAAC,SAAA;AACT;AC5Ca,MAAAU,WAAA,GAAcC,OAAO,aAAa,CAAA;;;"}