@linkpane/mailer-post 0.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/README.md +51 -0
- package/dist/__tests__/client.test.d.ts +2 -0
- package/dist/__tests__/client.test.d.ts.map +1 -0
- package/dist/__tests__/client.test.js +38 -0
- package/dist/__tests__/client.test.js.map +1 -0
- package/dist/client.d.ts +4 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +124 -0
- package/dist/client.js.map +1 -0
- package/dist/helpers.d.ts +4 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +30 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.d.mts +34 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +154 -0
- package/dist/index.mjs.map +1 -0
- package/dist/types.d.ts +27 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist-cjs/__tests__/client.test.js +38 -0
- package/dist-cjs/__tests__/client.test.js.map +1 -0
- package/dist-cjs/client.js +124 -0
- package/dist-cjs/client.js.map +1 -0
- package/dist-cjs/helpers.js +30 -0
- package/dist-cjs/helpers.js.map +1 -0
- package/dist-cjs/index.js +20 -0
- package/dist-cjs/index.js.map +1 -0
- package/dist-cjs/types.js +3 -0
- package/dist-cjs/types.js.map +1 -0
- package/package.json +22 -0
package/README.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# @linkpane/mailer-post
|
|
2
|
+
|
|
3
|
+
Submission-only SDK for Linkpane Mailer forms.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @linkpane/mailer-post
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { submitForm } from '@linkpane/mailer-post'
|
|
15
|
+
|
|
16
|
+
const result = await submitForm({
|
|
17
|
+
apiBaseUrl: 'https://api.linkpane.com',
|
|
18
|
+
pid: '12345',
|
|
19
|
+
slug: 'contact-me',
|
|
20
|
+
data: {
|
|
21
|
+
firstName: 'Ada',
|
|
22
|
+
lastName: 'Lovelace',
|
|
23
|
+
email: 'ada@example.com',
|
|
24
|
+
message: 'Hello from my website'
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
if (!result.ok) {
|
|
29
|
+
console.error(result.message, result.errors)
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Browser Helper
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import { attachToForm } from '@linkpane/mailer-post'
|
|
37
|
+
|
|
38
|
+
const form = document.querySelector('#contact-form')
|
|
39
|
+
attachToForm(form, {
|
|
40
|
+
apiBaseUrl: 'https://api.linkpane.com',
|
|
41
|
+
pid: '12345',
|
|
42
|
+
slug: 'contact-me',
|
|
43
|
+
onSuccess: () => {},
|
|
44
|
+
onError: () => {},
|
|
45
|
+
})
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Notes
|
|
49
|
+
|
|
50
|
+
- Required fields: `email`, `firstName`, `lastName`.
|
|
51
|
+
- For mobile apps, submit through your backend proxy to satisfy Origin rules.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/client.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const helpers_1 = require("../helpers");
|
|
5
|
+
const client_1 = require("../client");
|
|
6
|
+
const dummyFetch = async (url, options) => {
|
|
7
|
+
return {
|
|
8
|
+
ok: true,
|
|
9
|
+
status: 200,
|
|
10
|
+
headers: {
|
|
11
|
+
get: (name) => (name.toLowerCase() === 'content-type' ? 'application/json' : null),
|
|
12
|
+
},
|
|
13
|
+
json: async () => ({ message: 'Form submitted successfully!' }),
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
(0, vitest_1.describe)('buildActionUrl', () => {
|
|
17
|
+
(0, vitest_1.it)('builds the correct endpoint', () => {
|
|
18
|
+
const url = (0, helpers_1.buildActionUrl)({
|
|
19
|
+
apiBaseUrl: 'https://api.linkpane.com/',
|
|
20
|
+
pid: '123',
|
|
21
|
+
slug: 'contact-me',
|
|
22
|
+
});
|
|
23
|
+
(0, vitest_1.expect)(url).toBe('https://api.linkpane.com/mailer/123/form/contact-me');
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
(0, vitest_1.describe)('submitForm', () => {
|
|
27
|
+
(0, vitest_1.it)('returns ok for successful submission', async () => {
|
|
28
|
+
const result = await (0, client_1.submitForm)({
|
|
29
|
+
apiBaseUrl: 'https://api.linkpane.com',
|
|
30
|
+
pid: '123',
|
|
31
|
+
slug: 'contact-me',
|
|
32
|
+
data: { email: 'a@b.com', firstName: 'Ada', lastName: 'Lovelace' },
|
|
33
|
+
fetch: dummyFetch,
|
|
34
|
+
});
|
|
35
|
+
(0, vitest_1.expect)(result.ok).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
//# sourceMappingURL=client.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.test.js","sourceRoot":"","sources":["../../src/__tests__/client.test.ts"],"names":[],"mappings":";;AAAA,mCAA6C;AAC7C,wCAA2C;AAC3C,sCAAsC;AAEtC,MAAM,UAAU,GAAG,KAAK,EAAE,GAAW,EAAE,OAAY,EAAE,EAAE;IACrD,OAAO;QACL,EAAE,EAAE,IAAI;QACR,MAAM,EAAE,GAAG;QACX,OAAO,EAAE;YACP,GAAG,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,cAAc,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC;SAC3F;QACD,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,8BAA8B,EAAE,CAAC;KAChE,CAAA;AACH,CAAC,CAAA;AAED,IAAA,iBAAQ,EAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,IAAA,WAAE,EAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,GAAG,GAAG,IAAA,wBAAc,EAAC;YACzB,UAAU,EAAE,2BAA2B;YACvC,GAAG,EAAE,KAAK;YACV,IAAI,EAAE,YAAY;SACnB,CAAC,CAAA;QACF,IAAA,eAAM,EAAC,GAAG,CAAC,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAA;IACzE,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,IAAA,iBAAQ,EAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,IAAA,WAAE,EAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,MAAM,GAAG,MAAM,IAAA,mBAAU,EAAC;YAC9B,UAAU,EAAE,0BAA0B;YACtC,GAAG,EAAE,KAAK;YACV,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE;YAClE,KAAK,EAAE,UAAiB;SACzB,CAAC,CAAA;QACF,IAAA,eAAM,EAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC9B,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { AttachToFormOptions, SubmitFormParams, SubmitFormResult } from './types';
|
|
2
|
+
export declare function submitForm(params: SubmitFormParams): Promise<SubmitFormResult>;
|
|
3
|
+
export declare function attachToForm(form: HTMLFormElement, options: AttachToFormOptions): () => void;
|
|
4
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AA0BjF,wBAAsB,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAgFpF;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,mBAAmB,cAoC/E"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.submitForm = submitForm;
|
|
4
|
+
exports.attachToForm = attachToForm;
|
|
5
|
+
const helpers_1 = require("./helpers");
|
|
6
|
+
const REQUIRED_FIELDS = ['email', 'firstName', 'lastName'];
|
|
7
|
+
function validateRequiredFields(data) {
|
|
8
|
+
const missing = REQUIRED_FIELDS.filter((field) => {
|
|
9
|
+
const value = data[field];
|
|
10
|
+
if (value === null || typeof value === 'undefined')
|
|
11
|
+
return true;
|
|
12
|
+
if (typeof value === 'string' && value.trim().length === 0)
|
|
13
|
+
return true;
|
|
14
|
+
return false;
|
|
15
|
+
});
|
|
16
|
+
if (missing.length === 0)
|
|
17
|
+
return null;
|
|
18
|
+
return {
|
|
19
|
+
message: 'Missing required fields',
|
|
20
|
+
fields: missing,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function getFetchImpl(explicitFetch) {
|
|
24
|
+
if (explicitFetch)
|
|
25
|
+
return explicitFetch;
|
|
26
|
+
if (typeof fetch !== 'undefined')
|
|
27
|
+
return fetch;
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
async function submitForm(params) {
|
|
31
|
+
const { apiBaseUrl, pid, slug, data, mode = 'json', headers, fetch: explicitFetch, validateRequired = true, } = params;
|
|
32
|
+
if (validateRequired) {
|
|
33
|
+
const validationError = validateRequiredFields(data);
|
|
34
|
+
if (validationError) {
|
|
35
|
+
return { ok: false, message: validationError.message, errors: validationError };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const fetchImpl = getFetchImpl(explicitFetch);
|
|
39
|
+
if (!fetchImpl) {
|
|
40
|
+
return {
|
|
41
|
+
ok: false,
|
|
42
|
+
message: 'Fetch API is not available. Provide a fetch implementation via options.fetch.',
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const url = (0, helpers_1.buildActionUrl)({ apiBaseUrl, pid, slug });
|
|
46
|
+
const requestHeaders = {
|
|
47
|
+
'Content-Type': 'application/json',
|
|
48
|
+
...headers,
|
|
49
|
+
};
|
|
50
|
+
if (mode === 'json') {
|
|
51
|
+
requestHeaders.Accept = 'application/json';
|
|
52
|
+
requestHeaders['X-Requested-With'] = 'XMLHttpRequest';
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const response = await fetchImpl(url, {
|
|
56
|
+
method: 'POST',
|
|
57
|
+
headers: requestHeaders,
|
|
58
|
+
body: JSON.stringify(data),
|
|
59
|
+
});
|
|
60
|
+
const contentType = response.headers?.get?.('content-type') || '';
|
|
61
|
+
if (contentType.includes('application/json')) {
|
|
62
|
+
const payload = await response.json().catch(() => null);
|
|
63
|
+
if (!response.ok) {
|
|
64
|
+
return {
|
|
65
|
+
ok: false,
|
|
66
|
+
message: payload?.message || 'Form submission failed',
|
|
67
|
+
errors: payload?.errors,
|
|
68
|
+
status: response.status,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
ok: true,
|
|
73
|
+
message: payload?.message || 'Form submitted successfully',
|
|
74
|
+
status: response.status,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
return {
|
|
79
|
+
ok: false,
|
|
80
|
+
message: 'Form submission failed',
|
|
81
|
+
status: response.status,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return { ok: true, message: 'Form submitted successfully', status: response.status };
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
return {
|
|
88
|
+
ok: false,
|
|
89
|
+
message: error?.message || 'Form submission failed',
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function attachToForm(form, options) {
|
|
94
|
+
if (!form || typeof form.addEventListener !== 'function') {
|
|
95
|
+
throw new Error('attachToForm expects a valid HTMLFormElement');
|
|
96
|
+
}
|
|
97
|
+
const handler = async (event) => {
|
|
98
|
+
event.preventDefault();
|
|
99
|
+
const data = (0, helpers_1.serializeForm)(form);
|
|
100
|
+
const honeypotField = options.honeypotField;
|
|
101
|
+
if (honeypotField && typeof data[honeypotField] === 'undefined') {
|
|
102
|
+
data[honeypotField] = '';
|
|
103
|
+
}
|
|
104
|
+
const result = await submitForm({
|
|
105
|
+
apiBaseUrl: options.apiBaseUrl,
|
|
106
|
+
pid: options.pid,
|
|
107
|
+
slug: options.slug,
|
|
108
|
+
data,
|
|
109
|
+
mode: options.mode,
|
|
110
|
+
headers: options.headers,
|
|
111
|
+
fetch: options.fetch,
|
|
112
|
+
validateRequired: options.validateRequired,
|
|
113
|
+
});
|
|
114
|
+
if (result.ok) {
|
|
115
|
+
options.onSuccess?.(result);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
options.onError?.(result);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
form.addEventListener('submit', handler);
|
|
122
|
+
return () => form.removeEventListener('submit', handler);
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { SubmitFormParams } from './types';
|
|
2
|
+
export declare function buildActionUrl(params: Pick<SubmitFormParams, 'apiBaseUrl' | 'pid' | 'slug'>): string;
|
|
3
|
+
export declare function serializeForm(form: HTMLFormElement): Record<string, any>;
|
|
4
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAE1C,wBAAgB,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,YAAY,GAAG,KAAK,GAAG,MAAM,CAAC,UAG3F;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,eAAe,uBAsBlD"}
|
package/dist/helpers.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildActionUrl = buildActionUrl;
|
|
4
|
+
exports.serializeForm = serializeForm;
|
|
5
|
+
function buildActionUrl(params) {
|
|
6
|
+
const base = params.apiBaseUrl.replace(/\/+$/, '');
|
|
7
|
+
return `${base}/mailer/${encodeURIComponent(params.pid)}/form/${encodeURIComponent(params.slug)}`;
|
|
8
|
+
}
|
|
9
|
+
function serializeForm(form) {
|
|
10
|
+
if (typeof FormData === 'undefined') {
|
|
11
|
+
throw new Error('FormData is not available in this environment');
|
|
12
|
+
}
|
|
13
|
+
const formData = new FormData(form);
|
|
14
|
+
const data = {};
|
|
15
|
+
for (const [key, value] of formData.entries()) {
|
|
16
|
+
if (Object.prototype.hasOwnProperty.call(data, key)) {
|
|
17
|
+
const existing = data[key];
|
|
18
|
+
if (Array.isArray(existing)) {
|
|
19
|
+
existing.push(value);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
data[key] = [existing, value];
|
|
23
|
+
}
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
data[key] = value;
|
|
27
|
+
}
|
|
28
|
+
return data;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":";;AAEA,wCAGC;AAED,sCAsBC;AA3BD,SAAgB,cAAc,CAAC,MAA6D;IAC1F,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IAClD,OAAO,GAAG,IAAI,WAAW,kBAAkB,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAA;AACnG,CAAC;AAED,SAAgB,aAAa,CAAC,IAAqB;IACjD,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAA;IACnC,MAAM,IAAI,GAAwB,EAAE,CAAA;IAEpC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;QAC9C,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;YACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAA;YAC1B,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC5B,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACtB,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;YAC/B,CAAC;YACD,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;IACnB,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
type SubmissionMode = 'json' | 'redirect';
|
|
2
|
+
type SubmitFormParams = {
|
|
3
|
+
apiBaseUrl: string;
|
|
4
|
+
pid: string;
|
|
5
|
+
slug: string;
|
|
6
|
+
data: Record<string, any>;
|
|
7
|
+
mode?: SubmissionMode;
|
|
8
|
+
headers?: Record<string, string>;
|
|
9
|
+
fetch?: typeof fetch;
|
|
10
|
+
validateRequired?: boolean;
|
|
11
|
+
};
|
|
12
|
+
type SubmitFormResult = {
|
|
13
|
+
ok: true;
|
|
14
|
+
message: string;
|
|
15
|
+
status: number;
|
|
16
|
+
} | {
|
|
17
|
+
ok: false;
|
|
18
|
+
message: string;
|
|
19
|
+
status?: number;
|
|
20
|
+
errors?: any;
|
|
21
|
+
};
|
|
22
|
+
type AttachToFormOptions = Omit<SubmitFormParams, 'data'> & {
|
|
23
|
+
onSuccess?: (result: SubmitFormResult) => void;
|
|
24
|
+
onError?: (result: SubmitFormResult) => void;
|
|
25
|
+
honeypotField?: string;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
declare function buildActionUrl(params: Pick<SubmitFormParams, 'apiBaseUrl' | 'pid' | 'slug'>): string;
|
|
29
|
+
declare function serializeForm(form: HTMLFormElement): Record<string, any>;
|
|
30
|
+
|
|
31
|
+
declare function submitForm(params: SubmitFormParams): Promise<SubmitFormResult>;
|
|
32
|
+
declare function attachToForm(form: HTMLFormElement, options: AttachToFormOptions): () => void;
|
|
33
|
+
|
|
34
|
+
export { type AttachToFormOptions, type SubmissionMode, type SubmitFormParams, type SubmitFormResult, attachToForm, buildActionUrl, serializeForm, submitForm };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA;AACvB,cAAc,WAAW,CAAA;AACzB,cAAc,UAAU,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types"), exports);
|
|
18
|
+
__exportStar(require("./helpers"), exports);
|
|
19
|
+
__exportStar(require("./client"), exports);
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAuB;AACvB,4CAAyB;AACzB,2CAAwB"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// src/helpers.ts
|
|
2
|
+
function buildActionUrl(params) {
|
|
3
|
+
const base = params.apiBaseUrl.replace(/\/+$/, "");
|
|
4
|
+
return `${base}/mailer/${encodeURIComponent(params.pid)}/form/${encodeURIComponent(params.slug)}`;
|
|
5
|
+
}
|
|
6
|
+
function serializeForm(form) {
|
|
7
|
+
if (typeof FormData === "undefined") {
|
|
8
|
+
throw new Error("FormData is not available in this environment");
|
|
9
|
+
}
|
|
10
|
+
const formData = new FormData(form);
|
|
11
|
+
const data = {};
|
|
12
|
+
for (const [key, value] of formData.entries()) {
|
|
13
|
+
if (Object.prototype.hasOwnProperty.call(data, key)) {
|
|
14
|
+
const existing = data[key];
|
|
15
|
+
if (Array.isArray(existing)) {
|
|
16
|
+
existing.push(value);
|
|
17
|
+
} else {
|
|
18
|
+
data[key] = [existing, value];
|
|
19
|
+
}
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
data[key] = value;
|
|
23
|
+
}
|
|
24
|
+
return data;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// src/client.ts
|
|
28
|
+
var REQUIRED_FIELDS = ["email", "firstName", "lastName"];
|
|
29
|
+
function validateRequiredFields(data) {
|
|
30
|
+
const missing = REQUIRED_FIELDS.filter((field) => {
|
|
31
|
+
const value = data[field];
|
|
32
|
+
if (value === null || typeof value === "undefined") return true;
|
|
33
|
+
if (typeof value === "string" && value.trim().length === 0) return true;
|
|
34
|
+
return false;
|
|
35
|
+
});
|
|
36
|
+
if (missing.length === 0) return null;
|
|
37
|
+
return {
|
|
38
|
+
message: "Missing required fields",
|
|
39
|
+
fields: missing
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function getFetchImpl(explicitFetch) {
|
|
43
|
+
if (explicitFetch) return explicitFetch;
|
|
44
|
+
if (typeof fetch !== "undefined") return fetch;
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
async function submitForm(params) {
|
|
48
|
+
const {
|
|
49
|
+
apiBaseUrl,
|
|
50
|
+
pid,
|
|
51
|
+
slug,
|
|
52
|
+
data,
|
|
53
|
+
mode = "json",
|
|
54
|
+
headers,
|
|
55
|
+
fetch: explicitFetch,
|
|
56
|
+
validateRequired = true
|
|
57
|
+
} = params;
|
|
58
|
+
if (validateRequired) {
|
|
59
|
+
const validationError = validateRequiredFields(data);
|
|
60
|
+
if (validationError) {
|
|
61
|
+
return { ok: false, message: validationError.message, errors: validationError };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const fetchImpl = getFetchImpl(explicitFetch);
|
|
65
|
+
if (!fetchImpl) {
|
|
66
|
+
return {
|
|
67
|
+
ok: false,
|
|
68
|
+
message: "Fetch API is not available. Provide a fetch implementation via options.fetch."
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const url = buildActionUrl({ apiBaseUrl, pid, slug });
|
|
72
|
+
const requestHeaders = {
|
|
73
|
+
"Content-Type": "application/json",
|
|
74
|
+
...headers
|
|
75
|
+
};
|
|
76
|
+
if (mode === "json") {
|
|
77
|
+
requestHeaders.Accept = "application/json";
|
|
78
|
+
requestHeaders["X-Requested-With"] = "XMLHttpRequest";
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
const response = await fetchImpl(url, {
|
|
82
|
+
method: "POST",
|
|
83
|
+
headers: requestHeaders,
|
|
84
|
+
body: JSON.stringify(data)
|
|
85
|
+
});
|
|
86
|
+
const contentType = response.headers?.get?.("content-type") || "";
|
|
87
|
+
if (contentType.includes("application/json")) {
|
|
88
|
+
const payload = await response.json().catch(() => null);
|
|
89
|
+
if (!response.ok) {
|
|
90
|
+
return {
|
|
91
|
+
ok: false,
|
|
92
|
+
message: payload?.message || "Form submission failed",
|
|
93
|
+
errors: payload?.errors,
|
|
94
|
+
status: response.status
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
ok: true,
|
|
99
|
+
message: payload?.message || "Form submitted successfully",
|
|
100
|
+
status: response.status
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
if (!response.ok) {
|
|
104
|
+
return {
|
|
105
|
+
ok: false,
|
|
106
|
+
message: "Form submission failed",
|
|
107
|
+
status: response.status
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return { ok: true, message: "Form submitted successfully", status: response.status };
|
|
111
|
+
} catch (error) {
|
|
112
|
+
return {
|
|
113
|
+
ok: false,
|
|
114
|
+
message: error?.message || "Form submission failed"
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function attachToForm(form, options) {
|
|
119
|
+
if (!form || typeof form.addEventListener !== "function") {
|
|
120
|
+
throw new Error("attachToForm expects a valid HTMLFormElement");
|
|
121
|
+
}
|
|
122
|
+
const handler = async (event) => {
|
|
123
|
+
event.preventDefault();
|
|
124
|
+
const data = serializeForm(form);
|
|
125
|
+
const honeypotField = options.honeypotField;
|
|
126
|
+
if (honeypotField && typeof data[honeypotField] === "undefined") {
|
|
127
|
+
data[honeypotField] = "";
|
|
128
|
+
}
|
|
129
|
+
const result = await submitForm({
|
|
130
|
+
apiBaseUrl: options.apiBaseUrl,
|
|
131
|
+
pid: options.pid,
|
|
132
|
+
slug: options.slug,
|
|
133
|
+
data,
|
|
134
|
+
mode: options.mode,
|
|
135
|
+
headers: options.headers,
|
|
136
|
+
fetch: options.fetch,
|
|
137
|
+
validateRequired: options.validateRequired
|
|
138
|
+
});
|
|
139
|
+
if (result.ok) {
|
|
140
|
+
options.onSuccess?.(result);
|
|
141
|
+
} else {
|
|
142
|
+
options.onError?.(result);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
form.addEventListener("submit", handler);
|
|
146
|
+
return () => form.removeEventListener("submit", handler);
|
|
147
|
+
}
|
|
148
|
+
export {
|
|
149
|
+
attachToForm,
|
|
150
|
+
buildActionUrl,
|
|
151
|
+
serializeForm,
|
|
152
|
+
submitForm
|
|
153
|
+
};
|
|
154
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/helpers.ts","../src/client.ts"],"sourcesContent":["import { SubmitFormParams } from './types'\n\nexport function buildActionUrl(params: Pick<SubmitFormParams, 'apiBaseUrl' | 'pid' | 'slug'>) {\n const base = params.apiBaseUrl.replace(/\\/+$/, '')\n return `${base}/mailer/${encodeURIComponent(params.pid)}/form/${encodeURIComponent(params.slug)}`\n}\n\nexport function serializeForm(form: HTMLFormElement) {\n if (typeof FormData === 'undefined') {\n throw new Error('FormData is not available in this environment')\n }\n\n const formData = new FormData(form)\n const data: Record<string, any> = {}\n\n for (const [key, value] of formData.entries()) {\n if (Object.prototype.hasOwnProperty.call(data, key)) {\n const existing = data[key]\n if (Array.isArray(existing)) {\n existing.push(value)\n } else {\n data[key] = [existing, value]\n }\n continue\n }\n data[key] = value\n }\n\n return data\n}\r\n","import { AttachToFormOptions, SubmitFormParams, SubmitFormResult } from './types'\nimport { buildActionUrl, serializeForm } from './helpers'\n\nconst REQUIRED_FIELDS = ['email', 'firstName', 'lastName']\n\nfunction validateRequiredFields(data: Record<string, any>) {\n const missing = REQUIRED_FIELDS.filter((field) => {\n const value = data[field]\n if (value === null || typeof value === 'undefined') return true\n if (typeof value === 'string' && value.trim().length === 0) return true\n return false\n })\n\n if (missing.length === 0) return null\n return {\n message: 'Missing required fields',\n fields: missing,\n }\n}\n\nfunction getFetchImpl(explicitFetch?: typeof fetch) {\n if (explicitFetch) return explicitFetch\n if (typeof fetch !== 'undefined') return fetch\n return null\n}\n\nexport async function submitForm(params: SubmitFormParams): Promise<SubmitFormResult> {\n const {\n apiBaseUrl,\n pid,\n slug,\n data,\n mode = 'json',\n headers,\n fetch: explicitFetch,\n validateRequired = true,\n } = params\n\n if (validateRequired) {\n const validationError = validateRequiredFields(data)\n if (validationError) {\n return { ok: false, message: validationError.message, errors: validationError }\n }\n }\n\n const fetchImpl = getFetchImpl(explicitFetch)\n if (!fetchImpl) {\n return {\n ok: false,\n message: 'Fetch API is not available. Provide a fetch implementation via options.fetch.',\n }\n }\n\n const url = buildActionUrl({ apiBaseUrl, pid, slug })\n\n const requestHeaders: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...headers,\n }\n\n if (mode === 'json') {\n requestHeaders.Accept = 'application/json'\n requestHeaders['X-Requested-With'] = 'XMLHttpRequest'\n }\n\n try {\n const response = await fetchImpl(url, {\n method: 'POST',\n headers: requestHeaders,\n body: JSON.stringify(data),\n })\n\n const contentType = response.headers?.get?.('content-type') || ''\n\n if (contentType.includes('application/json')) {\n const payload = await response.json().catch(() => null)\n if (!response.ok) {\n return {\n ok: false,\n message: payload?.message || 'Form submission failed',\n errors: payload?.errors,\n status: response.status,\n }\n }\n return {\n ok: true,\n message: payload?.message || 'Form submitted successfully',\n status: response.status,\n }\n }\n\n if (!response.ok) {\n return {\n ok: false,\n message: 'Form submission failed',\n status: response.status,\n }\n }\n\n return { ok: true, message: 'Form submitted successfully', status: response.status }\n } catch (error: any) {\n return {\n ok: false,\n message: error?.message || 'Form submission failed',\n }\n }\n}\n\nexport function attachToForm(form: HTMLFormElement, options: AttachToFormOptions) {\n if (!form || typeof form.addEventListener !== 'function') {\n throw new Error('attachToForm expects a valid HTMLFormElement')\n }\n\n const handler = async (event: Event) => {\n event.preventDefault()\n\n const data = serializeForm(form)\n\n const honeypotField = options.honeypotField\n if (honeypotField && typeof data[honeypotField] === 'undefined') {\n data[honeypotField] = ''\n }\n\n const result = await submitForm({\n apiBaseUrl: options.apiBaseUrl,\n pid: options.pid,\n slug: options.slug,\n data,\n mode: options.mode,\n headers: options.headers,\n fetch: options.fetch,\n validateRequired: options.validateRequired,\n })\n\n if (result.ok) {\n options.onSuccess?.(result)\n } else {\n options.onError?.(result)\n }\n }\n\n form.addEventListener('submit', handler)\n\n return () => form.removeEventListener('submit', handler)\n}\r\n"],"mappings":"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","names":[]}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type SubmissionMode = 'json' | 'redirect';
|
|
2
|
+
export type SubmitFormParams = {
|
|
3
|
+
apiBaseUrl: string;
|
|
4
|
+
pid: string;
|
|
5
|
+
slug: string;
|
|
6
|
+
data: Record<string, any>;
|
|
7
|
+
mode?: SubmissionMode;
|
|
8
|
+
headers?: Record<string, string>;
|
|
9
|
+
fetch?: typeof fetch;
|
|
10
|
+
validateRequired?: boolean;
|
|
11
|
+
};
|
|
12
|
+
export type SubmitFormResult = {
|
|
13
|
+
ok: true;
|
|
14
|
+
message: string;
|
|
15
|
+
status: number;
|
|
16
|
+
} | {
|
|
17
|
+
ok: false;
|
|
18
|
+
message: string;
|
|
19
|
+
status?: number;
|
|
20
|
+
errors?: any;
|
|
21
|
+
};
|
|
22
|
+
export type AttachToFormOptions = Omit<SubmitFormParams, 'data'> & {
|
|
23
|
+
onSuccess?: (result: SubmitFormResult) => void;
|
|
24
|
+
onError?: (result: SubmitFormResult) => void;
|
|
25
|
+
honeypotField?: string;
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,UAAU,CAAA;AAEhD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,UAAU,EAAE,MAAM,CAAA;IAClB,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACzB,IAAI,CAAC,EAAE,cAAc,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,gBAAgB,GACxB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,GAAG,CAAA;CAAE,CAAA;AAEjE,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,GAAG;IACjE,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAA;IAC9C,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAA;IAC5C,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const helpers_1 = require("../helpers");
|
|
5
|
+
const client_1 = require("../client");
|
|
6
|
+
const dummyFetch = async (url, options) => {
|
|
7
|
+
return {
|
|
8
|
+
ok: true,
|
|
9
|
+
status: 200,
|
|
10
|
+
headers: {
|
|
11
|
+
get: (name) => (name.toLowerCase() === 'content-type' ? 'application/json' : null),
|
|
12
|
+
},
|
|
13
|
+
json: async () => ({ message: 'Form submitted successfully!' }),
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
(0, vitest_1.describe)('buildActionUrl', () => {
|
|
17
|
+
(0, vitest_1.it)('builds the correct endpoint', () => {
|
|
18
|
+
const url = (0, helpers_1.buildActionUrl)({
|
|
19
|
+
apiBaseUrl: 'https://api.linkpane.com/',
|
|
20
|
+
pid: '123',
|
|
21
|
+
slug: 'contact-me',
|
|
22
|
+
});
|
|
23
|
+
(0, vitest_1.expect)(url).toBe('https://api.linkpane.com/mailer/123/form/contact-me');
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
(0, vitest_1.describe)('submitForm', () => {
|
|
27
|
+
(0, vitest_1.it)('returns ok for successful submission', async () => {
|
|
28
|
+
const result = await (0, client_1.submitForm)({
|
|
29
|
+
apiBaseUrl: 'https://api.linkpane.com',
|
|
30
|
+
pid: '123',
|
|
31
|
+
slug: 'contact-me',
|
|
32
|
+
data: { email: 'a@b.com', firstName: 'Ada', lastName: 'Lovelace' },
|
|
33
|
+
fetch: dummyFetch,
|
|
34
|
+
});
|
|
35
|
+
(0, vitest_1.expect)(result.ok).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
//# sourceMappingURL=client.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.test.js","sourceRoot":"","sources":["../../src/__tests__/client.test.ts"],"names":[],"mappings":";;AAAA,mCAA6C;AAC7C,wCAA2C;AAC3C,sCAAsC;AAEtC,MAAM,UAAU,GAAG,KAAK,EAAE,GAAW,EAAE,OAAY,EAAE,EAAE;IACrD,OAAO;QACL,EAAE,EAAE,IAAI;QACR,MAAM,EAAE,GAAG;QACX,OAAO,EAAE;YACP,GAAG,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,cAAc,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC;SAC3F;QACD,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,8BAA8B,EAAE,CAAC;KAChE,CAAA;AACH,CAAC,CAAA;AAED,IAAA,iBAAQ,EAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,IAAA,WAAE,EAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,GAAG,GAAG,IAAA,wBAAc,EAAC;YACzB,UAAU,EAAE,2BAA2B;YACvC,GAAG,EAAE,KAAK;YACV,IAAI,EAAE,YAAY;SACnB,CAAC,CAAA;QACF,IAAA,eAAM,EAAC,GAAG,CAAC,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAA;IACzE,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,IAAA,iBAAQ,EAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,IAAA,WAAE,EAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,MAAM,GAAG,MAAM,IAAA,mBAAU,EAAC;YAC9B,UAAU,EAAE,0BAA0B;YACtC,GAAG,EAAE,KAAK;YACV,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE;YAClE,KAAK,EAAE,UAAiB;SACzB,CAAC,CAAA;QACF,IAAA,eAAM,EAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC9B,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.submitForm = submitForm;
|
|
4
|
+
exports.attachToForm = attachToForm;
|
|
5
|
+
const helpers_1 = require("./helpers");
|
|
6
|
+
const REQUIRED_FIELDS = ['email', 'firstName', 'lastName'];
|
|
7
|
+
function validateRequiredFields(data) {
|
|
8
|
+
const missing = REQUIRED_FIELDS.filter((field) => {
|
|
9
|
+
const value = data[field];
|
|
10
|
+
if (value === null || typeof value === 'undefined')
|
|
11
|
+
return true;
|
|
12
|
+
if (typeof value === 'string' && value.trim().length === 0)
|
|
13
|
+
return true;
|
|
14
|
+
return false;
|
|
15
|
+
});
|
|
16
|
+
if (missing.length === 0)
|
|
17
|
+
return null;
|
|
18
|
+
return {
|
|
19
|
+
message: 'Missing required fields',
|
|
20
|
+
fields: missing,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function getFetchImpl(explicitFetch) {
|
|
24
|
+
if (explicitFetch)
|
|
25
|
+
return explicitFetch;
|
|
26
|
+
if (typeof fetch !== 'undefined')
|
|
27
|
+
return fetch;
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
async function submitForm(params) {
|
|
31
|
+
const { apiBaseUrl, pid, slug, data, mode = 'json', headers, fetch: explicitFetch, validateRequired = true, } = params;
|
|
32
|
+
if (validateRequired) {
|
|
33
|
+
const validationError = validateRequiredFields(data);
|
|
34
|
+
if (validationError) {
|
|
35
|
+
return { ok: false, message: validationError.message, errors: validationError };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const fetchImpl = getFetchImpl(explicitFetch);
|
|
39
|
+
if (!fetchImpl) {
|
|
40
|
+
return {
|
|
41
|
+
ok: false,
|
|
42
|
+
message: 'Fetch API is not available. Provide a fetch implementation via options.fetch.',
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const url = (0, helpers_1.buildActionUrl)({ apiBaseUrl, pid, slug });
|
|
46
|
+
const requestHeaders = {
|
|
47
|
+
'Content-Type': 'application/json',
|
|
48
|
+
...headers,
|
|
49
|
+
};
|
|
50
|
+
if (mode === 'json') {
|
|
51
|
+
requestHeaders.Accept = 'application/json';
|
|
52
|
+
requestHeaders['X-Requested-With'] = 'XMLHttpRequest';
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const response = await fetchImpl(url, {
|
|
56
|
+
method: 'POST',
|
|
57
|
+
headers: requestHeaders,
|
|
58
|
+
body: JSON.stringify(data),
|
|
59
|
+
});
|
|
60
|
+
const contentType = response.headers?.get?.('content-type') || '';
|
|
61
|
+
if (contentType.includes('application/json')) {
|
|
62
|
+
const payload = await response.json().catch(() => null);
|
|
63
|
+
if (!response.ok) {
|
|
64
|
+
return {
|
|
65
|
+
ok: false,
|
|
66
|
+
message: payload?.message || 'Form submission failed',
|
|
67
|
+
errors: payload?.errors,
|
|
68
|
+
status: response.status,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
ok: true,
|
|
73
|
+
message: payload?.message || 'Form submitted successfully',
|
|
74
|
+
status: response.status,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
return {
|
|
79
|
+
ok: false,
|
|
80
|
+
message: 'Form submission failed',
|
|
81
|
+
status: response.status,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return { ok: true, message: 'Form submitted successfully', status: response.status };
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
return {
|
|
88
|
+
ok: false,
|
|
89
|
+
message: error?.message || 'Form submission failed',
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function attachToForm(form, options) {
|
|
94
|
+
if (!form || typeof form.addEventListener !== 'function') {
|
|
95
|
+
throw new Error('attachToForm expects a valid HTMLFormElement');
|
|
96
|
+
}
|
|
97
|
+
const handler = async (event) => {
|
|
98
|
+
event.preventDefault();
|
|
99
|
+
const data = (0, helpers_1.serializeForm)(form);
|
|
100
|
+
const honeypotField = options.honeypotField;
|
|
101
|
+
if (honeypotField && typeof data[honeypotField] === 'undefined') {
|
|
102
|
+
data[honeypotField] = '';
|
|
103
|
+
}
|
|
104
|
+
const result = await submitForm({
|
|
105
|
+
apiBaseUrl: options.apiBaseUrl,
|
|
106
|
+
pid: options.pid,
|
|
107
|
+
slug: options.slug,
|
|
108
|
+
data,
|
|
109
|
+
mode: options.mode,
|
|
110
|
+
headers: options.headers,
|
|
111
|
+
fetch: options.fetch,
|
|
112
|
+
validateRequired: options.validateRequired,
|
|
113
|
+
});
|
|
114
|
+
if (result.ok) {
|
|
115
|
+
options.onSuccess?.(result);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
options.onError?.(result);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
form.addEventListener('submit', handler);
|
|
122
|
+
return () => form.removeEventListener('submit', handler);
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildActionUrl = buildActionUrl;
|
|
4
|
+
exports.serializeForm = serializeForm;
|
|
5
|
+
function buildActionUrl(params) {
|
|
6
|
+
const base = params.apiBaseUrl.replace(/\/+$/, '');
|
|
7
|
+
return `${base}/mailer/${encodeURIComponent(params.pid)}/form/${encodeURIComponent(params.slug)}`;
|
|
8
|
+
}
|
|
9
|
+
function serializeForm(form) {
|
|
10
|
+
if (typeof FormData === 'undefined') {
|
|
11
|
+
throw new Error('FormData is not available in this environment');
|
|
12
|
+
}
|
|
13
|
+
const formData = new FormData(form);
|
|
14
|
+
const data = {};
|
|
15
|
+
for (const [key, value] of formData.entries()) {
|
|
16
|
+
if (Object.prototype.hasOwnProperty.call(data, key)) {
|
|
17
|
+
const existing = data[key];
|
|
18
|
+
if (Array.isArray(existing)) {
|
|
19
|
+
existing.push(value);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
data[key] = [existing, value];
|
|
23
|
+
}
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
data[key] = value;
|
|
27
|
+
}
|
|
28
|
+
return data;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":";;AAEA,wCAGC;AAED,sCAsBC;AA3BD,SAAgB,cAAc,CAAC,MAA6D;IAC1F,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IAClD,OAAO,GAAG,IAAI,WAAW,kBAAkB,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAA;AACnG,CAAC;AAED,SAAgB,aAAa,CAAC,IAAqB;IACjD,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAA;IACnC,MAAM,IAAI,GAAwB,EAAE,CAAA;IAEpC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;QAC9C,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;YACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAA;YAC1B,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC5B,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACtB,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;YAC/B,CAAC;YACD,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;IACnB,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types"), exports);
|
|
18
|
+
__exportStar(require("./helpers"), exports);
|
|
19
|
+
__exportStar(require("./client"), exports);
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAuB;AACvB,4CAAyB;AACzB,2CAAwB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@linkpane/mailer-post",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Submission-only SDK for Linkpane Mailer forms",
|
|
5
|
+
"main": "dist-cjs/index.js",
|
|
6
|
+
"module": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"sideEffects": false,
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"dist-cjs"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc -p tsconfig.esm.json && tsc -p tsconfig.cjs.json",
|
|
15
|
+
"dev": "tsc -p tsconfig.esm.json --watch",
|
|
16
|
+
"prepublishOnly": "npm run build"
|
|
17
|
+
},
|
|
18
|
+
"license": "Apache-2.0",
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=16"
|
|
21
|
+
}
|
|
22
|
+
}
|