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.
- package/README.md +15 -5
- package/lib/_chunks/is-valid-secret-57fea7e5.js +35 -0
- package/lib/_chunks/is-valid-secret-57fea7e5.js.map +1 -0
- package/lib/_chunks/is-valid-secret-7b704c76.cjs +41 -0
- package/lib/_chunks/is-valid-secret-7b704c76.cjs.map +1 -0
- package/lib/_chunks/types-107599a1.js +34 -0
- package/lib/_chunks/types-107599a1.js.map +1 -0
- package/lib/_chunks/types-4a29b6ac.cjs +38 -0
- package/lib/_chunks/types-4a29b6ac.cjs.map +1 -0
- package/lib/index.cjs +462 -154
- package/lib/index.cjs.js +3 -1
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.ts +38 -11
- package/lib/index.js +462 -158
- package/lib/index.js.map +1 -1
- package/lib/is-valid-secret.cjs +8 -0
- package/lib/is-valid-secret.cjs.js +4 -0
- package/lib/is-valid-secret.cjs.map +1 -0
- package/lib/is-valid-secret.d.ts +41 -0
- package/lib/is-valid-secret.js +2 -0
- package/lib/is-valid-secret.js.map +1 -0
- package/lib/preview-url.cjs +77 -0
- package/lib/preview-url.cjs.js +4 -0
- package/lib/preview-url.cjs.map +1 -0
- package/lib/preview-url.d.ts +17 -0
- package/lib/preview-url.js +72 -0
- package/lib/preview-url.js.map +1 -0
- package/package.json +34 -10
- package/src/DisplayUrl.tsx +21 -0
- package/src/GetUrlSecret.tsx +80 -0
- package/src/Iframe.tsx +272 -158
- package/src/Toolbar.tsx +153 -0
- package/src/defineUrlResolver.tsx +31 -0
- package/src/index.ts +3 -5
- package/src/is-valid-secret.ts +2 -0
- package/src/isValidSecret.tsx +67 -0
- package/src/preview-url.ts +2 -0
- package/src/previewUrl.ts +62 -0
- package/src/types.ts +17 -0
- 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 {
|
|
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:
|
|
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 `
|
|
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;;;"}
|