@sanity/form-toolkit 1.1.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/LICENSE +21 -0
- package/README.md +179 -0
- package/dist/index.d.mts +100 -0
- package/dist/index.d.ts +100 -0
- package/dist/index.js +150 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +151 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +94 -0
- package/sanity.json +8 -0
- package/src/form-schema/index.ts +27 -0
- package/src/form-schema/schema-types/form-field.ts +146 -0
- package/src/form-schema/schema-types/form.ts +13 -0
- package/src/form-schema/schema-types/index.ts +8 -0
- package/src/formium/index.ts +52 -0
- package/src/hubspot/components/option.tsx +17 -0
- package/src/hubspot/create-handler.ts +6 -0
- package/src/hubspot/fetch-hubspot-data.ts +33 -0
- package/src/hubspot/index.ts +50 -0
- package/src/index.ts +16 -0
- package/src/mailchimp/components/option.tsx +30 -0
- package/src/mailchimp/create-handler.ts +39 -0
- package/src/mailchimp/index.ts +42 -0
- package/src/shared/create-handler.ts +109 -0
- package/v2-incompatible.js +11 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Chris LaRocque
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
## Usage
|
|
2
|
+
|
|
3
|
+
# @sanity/form-toolkit
|
|
4
|
+
|
|
5
|
+
Plugin for integrating 3rd party form services or building your own forms with Sanity.
|
|
6
|
+
|
|
7
|
+
> This is a **Sanity Studio v3** plugin.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install @sanity/form-toolkit
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## HubSpot
|
|
16
|
+
|
|
17
|
+
The HubSpot integration fetches all forms in a HubSpot project and adds them as options in a selectable list.
|
|
18
|
+
|
|
19
|
+
### Usage
|
|
20
|
+
|
|
21
|
+
This plugin requires you to set up your own API route to fetch against HubSpot's API. You'll need to also create a Private App in HubSpot to create and pass a Private App access token to the provided fetch function. Learn how to create a Private App and get an access token [here](https://developers.hubspot.com/docs/guides/apps/private-apps/overview).
|
|
22
|
+
|
|
23
|
+
There's an "out of the box" handler for Next.js API routes:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
// pages/api/hubspot.ts
|
|
27
|
+
import {hubSpotHandler} from '@sanity/form-toolkit'
|
|
28
|
+
|
|
29
|
+
const handler = hubSpotHandler({
|
|
30
|
+
token: process.env.HUBSPOT_TOKEN ?? '',
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
export default handler
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Or add `fetchHubSpotData` to an API route in your non-Next framework
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
// my-nuxt-app/server/api/hubspot.ts
|
|
40
|
+
import {fetchHubSpotData} from '@sanity/form-toolkit'
|
|
41
|
+
|
|
42
|
+
export default defineEventHandler(async (event) => {
|
|
43
|
+
const req = event.node.req
|
|
44
|
+
const res = event.node.res
|
|
45
|
+
const data = await fetchHubSpotData({
|
|
46
|
+
token: process.env.HUBSPOT_TOKEN ?? '',
|
|
47
|
+
})
|
|
48
|
+
res.writeHead(200, {'Content-Type': 'application/json'})
|
|
49
|
+
res.end(JSON.stringify(data))
|
|
50
|
+
})
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Add it as a plugin in `sanity.config.ts` (or .js):
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import {defineConfig} from 'sanity'
|
|
57
|
+
import {hubSpotInput} from '@sanity/form-toolkit'
|
|
58
|
+
|
|
59
|
+
export default defineConfig({
|
|
60
|
+
//...
|
|
61
|
+
plugins: [
|
|
62
|
+
hubSpotInput({
|
|
63
|
+
url: 'your-api-endpoint',
|
|
64
|
+
}),
|
|
65
|
+
],
|
|
66
|
+
})
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Finally, add the field type to the schema you'd like to use it in
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
// schemaTypes/post.ts
|
|
73
|
+
export default defineType({
|
|
74
|
+
name: 'post',
|
|
75
|
+
title: 'Post',
|
|
76
|
+
type: 'document',
|
|
77
|
+
fields: [
|
|
78
|
+
//...rest of schma
|
|
79
|
+
defineField({
|
|
80
|
+
name: 'hubSpot',
|
|
81
|
+
type: 'hubSpotForm',
|
|
82
|
+
}),
|
|
83
|
+
],
|
|
84
|
+
})
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Mailchimp
|
|
88
|
+
|
|
89
|
+
The Mailchimp integration fetches all signup forms across all lists in your Mailchimp account and syncs the URL for the selected form.
|
|
90
|
+
|
|
91
|
+
### Usage
|
|
92
|
+
|
|
93
|
+
This plugin requires you to set up your own API route to fetch against Mailchimp's API. You'll need to pass an API key and server prefix to the underlying Mailchimp marketing client. Learn how to get a Mailchimp API key [here](https://mailchimp.com/help/about-api-keys/).
|
|
94
|
+
|
|
95
|
+
There's an "out of the box" handler for Next.js API routes:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
// pages/api/mailchimp.ts
|
|
99
|
+
import {mailchimpHandler} from '@sanity/form-toolkit'
|
|
100
|
+
|
|
101
|
+
const handler = mailchimpHandler({
|
|
102
|
+
key: process.env.MAILCHIMP_KEY ?? '',
|
|
103
|
+
server: process.env.MAILCHIMP_SERVER_PREFIX ?? '',
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
export default handler
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Or add `fetchMailchimpData` to an API route in your non-Next framework
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
// my-nuxt-app/server/api/mailchimp.ts
|
|
113
|
+
import {fetchMailchimpData} from '@sanity/form-toolkit'
|
|
114
|
+
|
|
115
|
+
export default defineEventHandler(async (event) => {
|
|
116
|
+
const req = event.node.req
|
|
117
|
+
const res = event.node.res
|
|
118
|
+
const data = await fetchMailchimpData({
|
|
119
|
+
key: process.env.MAILCHIMP_KEY ?? '',
|
|
120
|
+
server: process.env.MAILCHIMP_SERVER_PREFIX ?? '',
|
|
121
|
+
})
|
|
122
|
+
res.writeHead(200, {'Content-Type': 'application/json'})
|
|
123
|
+
res.end(JSON.stringify(data))
|
|
124
|
+
})
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Add it as a plugin in `sanity.config.ts` (or .js):
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
import {defineConfig} from 'sanity'
|
|
131
|
+
import {mailchimpInput} from '@sanity/form-toolkit'
|
|
132
|
+
|
|
133
|
+
export default defineConfig({
|
|
134
|
+
//...
|
|
135
|
+
plugins: [
|
|
136
|
+
mailchimpInput({
|
|
137
|
+
url: 'your-api-endpoint',
|
|
138
|
+
}),
|
|
139
|
+
],
|
|
140
|
+
})
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Finally, add the field type to the schema you'd like to use it in
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
// schemaTypes/post.ts
|
|
147
|
+
export default defineType({
|
|
148
|
+
name: 'post',
|
|
149
|
+
title: 'Post',
|
|
150
|
+
type: 'document',
|
|
151
|
+
fields: [
|
|
152
|
+
//...rest of schma
|
|
153
|
+
defineField({
|
|
154
|
+
name: 'mailchimp',
|
|
155
|
+
type: 'mailchimpForm',
|
|
156
|
+
}),
|
|
157
|
+
],
|
|
158
|
+
})
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
|
|
163
|
+
[MIT](LICENSE) © Chris LaRocque
|
|
164
|
+
|
|
165
|
+
## Develop & test
|
|
166
|
+
|
|
167
|
+
This plugin uses [@sanity/plugin-kit](https://github.com/sanity-io/plugin-kit)
|
|
168
|
+
with default configuration for build & watch scripts.
|
|
169
|
+
|
|
170
|
+
See [Testing a plugin in Sanity Studio](https://github.com/sanity-io/plugin-kit#testing-a-plugin-in-sanity-studio)
|
|
171
|
+
on how to run this plugin with hotreload in the studio.
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
### Release new version
|
|
175
|
+
|
|
176
|
+
Run ["CI & Release" workflow](https://github.com/sanity-io/form-toolkit/actions/workflows/main.yml).
|
|
177
|
+
Make sure to select the main branch and check "Release new version".
|
|
178
|
+
|
|
179
|
+
Semantic release will only release on configured branches, so it is safe to run release on any branch.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import {EventHandler} from 'h3'
|
|
2
|
+
import {EventHandlerRequest} from 'h3'
|
|
3
|
+
import {IncomingMessage} from 'http'
|
|
4
|
+
import {Plugin as Plugin_2} from 'sanity'
|
|
5
|
+
import {ServerResponse} from 'http'
|
|
6
|
+
|
|
7
|
+
export declare function fetchHubSpotData({token}: {token: string}): Promise<MappedResult[] | null>
|
|
8
|
+
|
|
9
|
+
export declare function fetchMailchimpData({
|
|
10
|
+
key,
|
|
11
|
+
server,
|
|
12
|
+
}: {
|
|
13
|
+
key: string
|
|
14
|
+
server: string
|
|
15
|
+
}): Promise<unknown>
|
|
16
|
+
|
|
17
|
+
declare type HubSpotForm = {
|
|
18
|
+
id: string
|
|
19
|
+
name: string
|
|
20
|
+
[key: string]: unknown
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export declare const hubSpotHandler: ({token}: {token: string}) =>
|
|
24
|
+
| ((req: IncomingMessage, res: ServerResponse) => Promise<void>)
|
|
25
|
+
| EventHandler<EventHandlerRequest, Promise<unknown>>
|
|
26
|
+
| {
|
|
27
|
+
GET: ({request}: {request: Request}) => Promise<Response>
|
|
28
|
+
loader?: undefined
|
|
29
|
+
get?: undefined
|
|
30
|
+
}
|
|
31
|
+
| {
|
|
32
|
+
loader: ({request}: {request: Request}) => Promise<Response>
|
|
33
|
+
GET?: undefined
|
|
34
|
+
get?: undefined
|
|
35
|
+
}
|
|
36
|
+
| {
|
|
37
|
+
get: ({request}: {request: Request}) => Promise<{
|
|
38
|
+
body: string
|
|
39
|
+
headers: {
|
|
40
|
+
'Content-Type': string
|
|
41
|
+
}
|
|
42
|
+
}>
|
|
43
|
+
GET?: undefined
|
|
44
|
+
loader?: undefined
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export declare const hubSpotInput: Plugin_2<HubSpotInputConfig>
|
|
48
|
+
|
|
49
|
+
declare interface HubSpotInputConfig {
|
|
50
|
+
url: string | URL
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export declare const mailchimpHandler: (keys: {key: string; server: string}) =>
|
|
54
|
+
| ((req: IncomingMessage, res: ServerResponse) => Promise<void>)
|
|
55
|
+
| EventHandler<EventHandlerRequest, Promise<unknown>>
|
|
56
|
+
| {
|
|
57
|
+
GET: ({request}: {request: Request}) => Promise<Response>
|
|
58
|
+
loader?: undefined
|
|
59
|
+
get?: undefined
|
|
60
|
+
}
|
|
61
|
+
| {
|
|
62
|
+
loader: ({request}: {request: Request}) => Promise<Response>
|
|
63
|
+
GET?: undefined
|
|
64
|
+
get?: undefined
|
|
65
|
+
}
|
|
66
|
+
| {
|
|
67
|
+
get: ({request}: {request: Request}) => Promise<{
|
|
68
|
+
body: string
|
|
69
|
+
headers: {
|
|
70
|
+
'Content-Type': string
|
|
71
|
+
}
|
|
72
|
+
}>
|
|
73
|
+
GET?: undefined
|
|
74
|
+
loader?: undefined
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Usage in `sanity.config.ts` (or .js)
|
|
79
|
+
*
|
|
80
|
+
* ```ts
|
|
81
|
+
* import {defineConfig} from 'sanity'
|
|
82
|
+
* import {formiumInput} from 'sanity-plugin-form-toolkit'
|
|
83
|
+
*
|
|
84
|
+
* export default defineConfig({
|
|
85
|
+
* // ...
|
|
86
|
+
* plugins: [formiumInput()],
|
|
87
|
+
* })
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export declare const mailchimpInput: Plugin_2<MailchimpInputConfig>
|
|
91
|
+
|
|
92
|
+
declare interface MailchimpInputConfig {
|
|
93
|
+
url: string | URL
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
declare type MappedResult = HubSpotForm & {
|
|
97
|
+
value: string
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export {}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import {EventHandler} from 'h3'
|
|
2
|
+
import {EventHandlerRequest} from 'h3'
|
|
3
|
+
import {IncomingMessage} from 'http'
|
|
4
|
+
import {Plugin as Plugin_2} from 'sanity'
|
|
5
|
+
import {ServerResponse} from 'http'
|
|
6
|
+
|
|
7
|
+
export declare function fetchHubSpotData({token}: {token: string}): Promise<MappedResult[] | null>
|
|
8
|
+
|
|
9
|
+
export declare function fetchMailchimpData({
|
|
10
|
+
key,
|
|
11
|
+
server,
|
|
12
|
+
}: {
|
|
13
|
+
key: string
|
|
14
|
+
server: string
|
|
15
|
+
}): Promise<unknown>
|
|
16
|
+
|
|
17
|
+
declare type HubSpotForm = {
|
|
18
|
+
id: string
|
|
19
|
+
name: string
|
|
20
|
+
[key: string]: unknown
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export declare const hubSpotHandler: ({token}: {token: string}) =>
|
|
24
|
+
| ((req: IncomingMessage, res: ServerResponse) => Promise<void>)
|
|
25
|
+
| EventHandler<EventHandlerRequest, Promise<unknown>>
|
|
26
|
+
| {
|
|
27
|
+
GET: ({request}: {request: Request}) => Promise<Response>
|
|
28
|
+
loader?: undefined
|
|
29
|
+
get?: undefined
|
|
30
|
+
}
|
|
31
|
+
| {
|
|
32
|
+
loader: ({request}: {request: Request}) => Promise<Response>
|
|
33
|
+
GET?: undefined
|
|
34
|
+
get?: undefined
|
|
35
|
+
}
|
|
36
|
+
| {
|
|
37
|
+
get: ({request}: {request: Request}) => Promise<{
|
|
38
|
+
body: string
|
|
39
|
+
headers: {
|
|
40
|
+
'Content-Type': string
|
|
41
|
+
}
|
|
42
|
+
}>
|
|
43
|
+
GET?: undefined
|
|
44
|
+
loader?: undefined
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export declare const hubSpotInput: Plugin_2<HubSpotInputConfig>
|
|
48
|
+
|
|
49
|
+
declare interface HubSpotInputConfig {
|
|
50
|
+
url: string | URL
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export declare const mailchimpHandler: (keys: {key: string; server: string}) =>
|
|
54
|
+
| ((req: IncomingMessage, res: ServerResponse) => Promise<void>)
|
|
55
|
+
| EventHandler<EventHandlerRequest, Promise<unknown>>
|
|
56
|
+
| {
|
|
57
|
+
GET: ({request}: {request: Request}) => Promise<Response>
|
|
58
|
+
loader?: undefined
|
|
59
|
+
get?: undefined
|
|
60
|
+
}
|
|
61
|
+
| {
|
|
62
|
+
loader: ({request}: {request: Request}) => Promise<Response>
|
|
63
|
+
GET?: undefined
|
|
64
|
+
get?: undefined
|
|
65
|
+
}
|
|
66
|
+
| {
|
|
67
|
+
get: ({request}: {request: Request}) => Promise<{
|
|
68
|
+
body: string
|
|
69
|
+
headers: {
|
|
70
|
+
'Content-Type': string
|
|
71
|
+
}
|
|
72
|
+
}>
|
|
73
|
+
GET?: undefined
|
|
74
|
+
loader?: undefined
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Usage in `sanity.config.ts` (or .js)
|
|
79
|
+
*
|
|
80
|
+
* ```ts
|
|
81
|
+
* import {defineConfig} from 'sanity'
|
|
82
|
+
* import {formiumInput} from 'sanity-plugin-form-toolkit'
|
|
83
|
+
*
|
|
84
|
+
* export default defineConfig({
|
|
85
|
+
* // ...
|
|
86
|
+
* plugins: [formiumInput()],
|
|
87
|
+
* })
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export declare const mailchimpInput: Plugin_2<MailchimpInputConfig>
|
|
91
|
+
|
|
92
|
+
declare interface MailchimpInputConfig {
|
|
93
|
+
url: string | URL
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
declare type MappedResult = HubSpotForm & {
|
|
97
|
+
value: string
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export {}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: !0 });
|
|
3
|
+
var sanityPluginAsyncList = require("@sanity/sanity-plugin-async-list"), sanity = require("sanity"), jsxRuntime = require("react/jsx-runtime"), ui = require("@sanity/ui"), h3 = require("h3"), mailchimp = require("@mailchimp/mailchimp_marketing");
|
|
4
|
+
function _interopDefaultCompat(e) {
|
|
5
|
+
return e && typeof e == "object" && "default" in e ? e : { default: e };
|
|
6
|
+
}
|
|
7
|
+
var mailchimp__default = /* @__PURE__ */ _interopDefaultCompat(mailchimp);
|
|
8
|
+
const Option$1 = (option) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { "data-as": "button", padding: 3, radius: 2, tone: "inherit", children: [
|
|
9
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 2, textOverflow: "ellipsis", children: option.name }),
|
|
10
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Card, { paddingTop: 2, tone: "inherit", style: { background: "inherit" }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, textOverflow: "ellipsis", children: `ID: ${option.value}` }) })
|
|
11
|
+
] }), hubSpotInput = sanity.definePlugin((options) => ({
|
|
12
|
+
name: "sanity-plugin-form-toolkit_hubspot-input",
|
|
13
|
+
plugins: [
|
|
14
|
+
sanityPluginAsyncList.asyncList({
|
|
15
|
+
schemaType: "hubSpotForm",
|
|
16
|
+
loader: async () => await (await fetch(options.url)).json(),
|
|
17
|
+
autocompleteProps: {
|
|
18
|
+
renderOption: (option) => Option$1(option),
|
|
19
|
+
renderValue(value, option) {
|
|
20
|
+
return option?.name ?? value;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
]
|
|
25
|
+
})), detectFramework = () => {
|
|
26
|
+
if (process.env.NEXT_RUNTIME)
|
|
27
|
+
return "nextjs";
|
|
28
|
+
if (process.env.NUXT_ENV)
|
|
29
|
+
return "nuxt";
|
|
30
|
+
if (process.env.SVELTEKIT_ENV)
|
|
31
|
+
return "sveltekit";
|
|
32
|
+
if (process.env.REMIX_ENV)
|
|
33
|
+
return "remix";
|
|
34
|
+
if (process.env.ASTRO_ENV)
|
|
35
|
+
return "astro";
|
|
36
|
+
throw new Error("Unable to detect framework.");
|
|
37
|
+
}, createHandler = (handlerFunc) => {
|
|
38
|
+
const framework = detectFramework(), handlerLogic = async ({
|
|
39
|
+
// eslint-disable-next-line
|
|
40
|
+
req,
|
|
41
|
+
res
|
|
42
|
+
}) => {
|
|
43
|
+
try {
|
|
44
|
+
const data = await handlerFunc();
|
|
45
|
+
return res && (res.writeHead(200, { "Content-Type": "application/json" }), res.end(JSON.stringify(data))), data;
|
|
46
|
+
} catch (error) {
|
|
47
|
+
return error instanceof Error ? (res && (res.writeHead(500, { "Content-Type": "application/json" }), res.end(JSON.stringify({ error: error.message }))), { error: error.message }) : (res && (res.writeHead(500, { "Content-Type": "application/json" }), res.end(JSON.stringify({ error: "An unexpected error occurred" }))), { error: "An unexpected error occurred" });
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
if (framework === "nextjs")
|
|
51
|
+
return async (req, res) => {
|
|
52
|
+
res.setHeader("Access-Control-Allow-Origin", "*"), res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"), res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization"), await handlerLogic({ req, res });
|
|
53
|
+
};
|
|
54
|
+
if (framework === "nuxt")
|
|
55
|
+
return h3.defineEventHandler(async (event) => {
|
|
56
|
+
const req = event.node.req, res = event.node.res;
|
|
57
|
+
return handlerLogic({ req, res });
|
|
58
|
+
});
|
|
59
|
+
if (framework === "sveltekit")
|
|
60
|
+
return {
|
|
61
|
+
GET: async ({ request }) => {
|
|
62
|
+
const result = await handlerLogic({ req: request });
|
|
63
|
+
return new Response(JSON.stringify(result), {
|
|
64
|
+
headers: { "Content-Type": "application/json" }
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
if (framework === "remix")
|
|
69
|
+
return {
|
|
70
|
+
loader: async ({ request }) => {
|
|
71
|
+
const result = await handlerLogic({ req: request });
|
|
72
|
+
return new Response(JSON.stringify(result), {
|
|
73
|
+
headers: { "Content-Type": "application/json" }
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
if (framework === "astro")
|
|
78
|
+
return {
|
|
79
|
+
get: async ({ request }) => {
|
|
80
|
+
const result = await handlerLogic({ req: request });
|
|
81
|
+
return {
|
|
82
|
+
body: JSON.stringify(result),
|
|
83
|
+
headers: { "Content-Type": "application/json" }
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
throw new Error(`Unsupported framework: ${framework}`);
|
|
88
|
+
};
|
|
89
|
+
async function fetchHubSpotData({ token }) {
|
|
90
|
+
try {
|
|
91
|
+
const apiResponse = await fetch("https://api.hubapi.com/marketing/v3/forms/?limit=9999", {
|
|
92
|
+
headers: {
|
|
93
|
+
Authorization: `Bearer ${token}`
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
if (!apiResponse.ok)
|
|
97
|
+
return console.error(`Failed to fetch data: ${apiResponse.statusText}`), null;
|
|
98
|
+
const { results } = await apiResponse.json();
|
|
99
|
+
return results.map((result) => ({
|
|
100
|
+
...result,
|
|
101
|
+
value: result.id
|
|
102
|
+
}));
|
|
103
|
+
} catch (e) {
|
|
104
|
+
return console.error(e), null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const hubSpotHandler = ({ token }) => createHandler(() => fetchHubSpotData({ token })), Option = (option) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { "data-as": "button", padding: 3, radius: 2, tone: "inherit", children: [
|
|
108
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 2, textOverflow: "ellipsis", children: `${option.form.header.text ? `${option.form.header.text} - ` : ""}${option.value}` }),
|
|
109
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Card, { paddingTop: 2, tone: "inherit", style: { background: "inherit" }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, textOverflow: "ellipsis", children: `${option.list.name} - ${option.list.stats.member_count} member${option.list.stats.member_count == 1 ? "" : "s"}` }) })
|
|
110
|
+
] }), mailchimpInput = sanity.definePlugin((options) => ({
|
|
111
|
+
name: "sanity-plugin-form-toolkit_mailchimp-input",
|
|
112
|
+
plugins: [
|
|
113
|
+
sanityPluginAsyncList.asyncList({
|
|
114
|
+
schemaType: "mailchimpForm",
|
|
115
|
+
loader: async () => await (await fetch(options.url)).json(),
|
|
116
|
+
autocompleteProps: {
|
|
117
|
+
//@ts-expect-error incorrect typing on props?
|
|
118
|
+
renderOption: (option) => Option(option)
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
]
|
|
122
|
+
}));
|
|
123
|
+
async function fetchMailchimpData({
|
|
124
|
+
key,
|
|
125
|
+
server
|
|
126
|
+
}) {
|
|
127
|
+
mailchimp__default.default.setConfig({
|
|
128
|
+
apiKey: key,
|
|
129
|
+
server
|
|
130
|
+
});
|
|
131
|
+
const signupForms = [], { lists } = await mailchimp__default.default.lists.getAllLists();
|
|
132
|
+
for (const list of lists) {
|
|
133
|
+
const { signup_forms } = await mailchimp__default.default.lists.getListSignupForms(list.id);
|
|
134
|
+
for (const form of signup_forms)
|
|
135
|
+
signupForms.push({
|
|
136
|
+
list,
|
|
137
|
+
form,
|
|
138
|
+
value: form.signup_form_url
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
return signupForms;
|
|
142
|
+
}
|
|
143
|
+
const mailchimpHandler = (keys) => createHandler(() => fetchMailchimpData(keys));
|
|
144
|
+
exports.fetchHubSpotData = fetchHubSpotData;
|
|
145
|
+
exports.fetchMailchimpData = fetchMailchimpData;
|
|
146
|
+
exports.hubSpotHandler = hubSpotHandler;
|
|
147
|
+
exports.hubSpotInput = hubSpotInput;
|
|
148
|
+
exports.mailchimpHandler = mailchimpHandler;
|
|
149
|
+
exports.mailchimpInput = mailchimpInput;
|
|
150
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/hubspot/components/option.tsx","../src/hubspot/index.ts","../src/shared/create-handler.ts","../src/hubspot/fetch-hubspot-data.ts","../src/hubspot/create-handler.ts","../src/mailchimp/components/option.tsx","../src/mailchimp/index.ts","../src/mailchimp/create-handler.ts"],"sourcesContent":["import {Card, Text} from '@sanity/ui'\nimport type {ReactElement} from 'react'\n\nexport const Option = (option: {value: string; name: string}): ReactElement => {\n return (\n <Card data-as=\"button\" padding={3} radius={2} tone=\"inherit\">\n <Text size={2} textOverflow=\"ellipsis\">\n {option.name}\n </Text>\n <Card paddingTop={2} tone=\"inherit\" style={{background: 'inherit'}}>\n <Text size={1} textOverflow=\"ellipsis\">\n {`ID: ${option.value}`}\n </Text>\n </Card>\n </Card>\n )\n}\n","import {asyncList} from '@sanity/sanity-plugin-async-list'\nimport {definePlugin} from 'sanity'\n\nimport {Option} from './components/option'\n\ninterface HubSpotInputConfig {\n url: string | URL\n}\n\n/**\n * Usage in `sanity.config.ts` (or .js)\n *\n * ```ts\n * import {defineConfig} from 'sanity'\n * import {hubSpotInput} from '@sanity/sanity-plugin-form-toolkit'\n *\n * export default defineConfig({\n * // ...\n * plugins: [\n * hubSpotInput({\n * url: 'http://localhost:3000/api/hubspot'\n * })\n * ],\n * })\n * ```\n */\ntype ExtendedOption = {value: string; name: string}\n\nexport const hubSpotInput = definePlugin<HubSpotInputConfig>((options) => {\n return {\n name: 'sanity-plugin-form-toolkit_hubspot-input',\n plugins: [\n asyncList({\n schemaType: 'hubSpotForm',\n loader: async () => {\n const data = await fetch(options.url)\n const body = await data.json()\n return body\n },\n autocompleteProps: {\n renderOption: (option) => Option(option as ExtendedOption),\n renderValue(value, option) {\n // @ts-expect-error can't extend default type?\n return option?.name ?? value\n },\n },\n }),\n ],\n }\n})\n","import {defineEventHandler, H3Event} from 'h3' // For Nuxt.js/Nitro\nimport type {IncomingMessage, ServerResponse} from 'http'\n\n// Utility function to detect the framework at runtime\nconst detectFramework = (): string => {\n if (process.env.NEXT_RUNTIME) {\n return 'nextjs'\n } else if (process.env.NUXT_ENV) {\n return 'nuxt'\n } else if (process.env.SVELTEKIT_ENV) {\n return 'sveltekit'\n } else if (process.env.REMIX_ENV) {\n return 'remix'\n } else if (process.env.ASTRO_ENV) {\n return 'astro'\n }\n throw new Error('Unable to detect framework.')\n}\n\n// Create a generic handler with predefined logic\nconst createHandler = (handlerFunc: () => Promise<unknown>) => {\n const framework = detectFramework()\n\n // Handler logic to fetch Mailchimp data\n const handlerLogic = async ({\n // eslint-disable-next-line\n req,\n res,\n }: {\n req: IncomingMessage | Request\n res?: ServerResponse\n }): Promise<unknown> => {\n try {\n const data = await handlerFunc()\n\n if (res) {\n // Send response directly for frameworks like Next.js and Nuxt.js\n res.writeHead(200, {'Content-Type': 'application/json'})\n res.end(JSON.stringify(data))\n }\n\n // Return the response for frameworks like SvelteKit, Remix, and Astro\n return data\n } catch (error) {\n if (error instanceof Error) {\n if (res) {\n res.writeHead(500, {'Content-Type': 'application/json'})\n res.end(JSON.stringify({error: error.message}))\n }\n return {error: error.message}\n }\n // Handle non-Error types (e.g., strings, objects)\n if (res) {\n res.writeHead(500, {'Content-Type': 'application/json'})\n res.end(JSON.stringify({error: 'An unexpected error occurred'}))\n }\n return {error: 'An unexpected error occurred'}\n }\n }\n\n // Framework-specific implementations\n if (framework === 'nextjs') {\n return async (req: IncomingMessage, res: ServerResponse) => {\n // Set CORS headers\n res.setHeader('Access-Control-Allow-Origin', '*') // Allow all origins\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS') // Allowed HTTP methods\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization') // Allowed headers\n\n await handlerLogic({req, res})\n }\n } else if (framework === 'nuxt') {\n return defineEventHandler(async (event: H3Event) => {\n const req = event.node.req\n const res = event.node.res\n return handlerLogic({req, res})\n })\n } else if (framework === 'sveltekit') {\n return {\n GET: async ({request}: {request: Request}) => {\n const result = await handlerLogic({req: request})\n return new Response(JSON.stringify(result), {\n headers: {'Content-Type': 'application/json'},\n })\n },\n }\n } else if (framework === 'remix') {\n return {\n loader: async ({request}: {request: Request}) => {\n const result = await handlerLogic({req: request})\n return new Response(JSON.stringify(result), {\n headers: {'Content-Type': 'application/json'},\n })\n },\n }\n } else if (framework === 'astro') {\n return {\n get: async ({request}: {request: Request}) => {\n const result = await handlerLogic({req: request})\n return {\n body: JSON.stringify(result),\n headers: {'Content-Type': 'application/json'},\n }\n },\n }\n }\n throw new Error(`Unsupported framework: ${framework}`)\n}\n\nexport default createHandler\n","type HubSpotForm = {\n id: string\n name: string\n [key: string]: unknown // Additional properties from the API response\n}\n\ntype MappedResult = HubSpotForm & {\n value: string\n}\nexport async function fetchHubSpotData({token}: {token: string}): Promise<MappedResult[] | null> {\n try {\n const apiResponse = await fetch('https://api.hubapi.com/marketing/v3/forms/?limit=9999', {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n })\n\n if (!apiResponse.ok) {\n console.error(`Failed to fetch data: ${apiResponse.statusText}`)\n return null\n }\n\n const {results}: {results: HubSpotForm[]} = await apiResponse.json()\n\n return results.map((result) => ({\n ...result,\n value: result.id,\n }))\n } catch (e: unknown) {\n console.error(e)\n return null // Explicitly return null on error\n }\n}\n","import createHandler from '../shared/create-handler'\nimport {fetchHubSpotData} from './fetch-hubspot-data'\n\nexport const hubSpotHandler = ({token}: {token: string}) => {\n return createHandler(() => fetchHubSpotData({token}))\n}\n","import {Card, Text} from '@sanity/ui'\nimport type {ReactElement} from 'react'\n\nexport const Option = (option: {\n value: string\n form: {\n header: {\n text?: string\n }\n }\n list: {\n name: string\n stats: {\n member_count: number\n }\n }\n}): ReactElement => {\n return (\n <Card data-as=\"button\" padding={3} radius={2} tone=\"inherit\">\n <Text size={2} textOverflow=\"ellipsis\">\n {`${option.form.header.text ? `${option.form.header.text} - ` : ``}${option.value}`}\n </Text>\n <Card paddingTop={2} tone=\"inherit\" style={{background: 'inherit'}}>\n <Text size={1} textOverflow=\"ellipsis\">\n {`${option.list.name} - ${option.list.stats.member_count} member${option.list.stats.member_count == 1 ? '' : 's'}`}\n </Text>\n </Card>\n </Card>\n )\n}\n","import {asyncList} from '@sanity/sanity-plugin-async-list'\nimport {definePlugin} from 'sanity'\n\nimport {Option} from './components/option'\n\ninterface MailchimpInputConfig {\n url: string | URL\n}\n\n/**\n * Usage in `sanity.config.ts` (or .js)\n *\n * ```ts\n * import {defineConfig} from 'sanity'\n * import {formiumInput} from 'sanity-plugin-form-toolkit'\n *\n * export default defineConfig({\n * // ...\n * plugins: [formiumInput()],\n * })\n * ```\n */\n\nexport const mailchimpInput = definePlugin<MailchimpInputConfig>((options) => {\n return {\n name: 'sanity-plugin-form-toolkit_mailchimp-input',\n plugins: [\n asyncList({\n schemaType: 'mailchimpForm',\n loader: async () => {\n const data = await fetch(options.url)\n const body = await data.json()\n return body\n },\n autocompleteProps: {\n //@ts-expect-error incorrect typing on props?\n renderOption: (option) => Option(option),\n },\n }),\n ],\n }\n})\n","import mailchimp from '@mailchimp/mailchimp_marketing'\n\nimport createHandler from '../shared/create-handler'\n\n// Fetch from Mailchimp's API\nexport async function fetchMailchimpData({\n key,\n server,\n}: {\n key: string\n server: string\n}): Promise<unknown> {\n mailchimp.setConfig({\n apiKey: key,\n server: server,\n })\n const signupForms = []\n // @ts-expect-error bad typing for mailchimp\n const {lists} = await mailchimp.lists.getAllLists()\n for (const list of lists) {\n // @ts-expect-error bad typing for mailchimp\n // eslint-disable-next-line camelcase\n const {signup_forms} = await mailchimp.lists.getListSignupForms(list.id)\n // eslint-disable-next-line camelcase\n for (const form of signup_forms) {\n signupForms.push({\n list,\n form,\n value: form.signup_form_url,\n })\n }\n }\n return signupForms\n}\n\n// Create the Mailchimp handler for a specific key and server\nexport const mailchimpHandler = (keys: {key: string; server: string}) => {\n return createHandler(() => fetchMailchimpData(keys))\n}\n"],"names":["Option","jsxs","Card","jsx","Text","definePlugin","asyncList","defineEventHandler","mailchimp"],"mappings":"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"}
|