@betterinternship/core 2.22.0 → 2.23.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.
@@ -1,13 +1,13 @@
1
- export interface IArchiveContext {
2
- sender?: string;
3
- alias: string;
4
- source: string;
5
- to: string[];
6
- cc: string[];
7
- bcc: string[];
8
- subject: string;
9
- content: string;
10
- tags?: Record<string, string>;
11
- configurationSetName?: string;
12
- }
13
- export declare const archiveSentEmail: (context: IArchiveContext, messageId: string | undefined, attempts: number) => Promise<void>;
1
+ export interface IArchiveContext {
2
+ sender?: string;
3
+ alias: string;
4
+ source: string;
5
+ to: string[];
6
+ cc: string[];
7
+ bcc: string[];
8
+ subject: string;
9
+ content: string;
10
+ tags?: Record<string, string>;
11
+ configurationSetName?: string;
12
+ }
13
+ export declare const archiveSentEmail: (context: IArchiveContext, messageId: string | undefined, attempts: number) => Promise<void>;
@@ -1,107 +1,107 @@
1
- import { randomUUID } from 'crypto';
2
- import { ENV } from '../env.js';
3
- let warnedMissingBucket = false;
4
- let warnedMissingCredentials = false;
5
- const getArchiveBucketName = () => {
6
- const bucketName = ENV.EMAIL_ARCHIVE_BUCKET;
7
- if (!bucketName) {
8
- if (!warnedMissingBucket) {
9
- console.warn('[EMAIL_ARCHIVE] EMAIL_ARCHIVE_BUCKET not set; sent emails will not be archived.');
10
- warnedMissingBucket = true;
11
- }
12
- return undefined;
13
- }
14
- if (!ENV.GOOGLE_CLOUD_CREDENTIALS || !ENV.GOOGLE_CLOUD_PROJECT_ID) {
15
- if (!warnedMissingCredentials) {
16
- console.error('[ERROR:EMAIL_ARCHIVE] EMAIL_ARCHIVE_BUCKET is set but GOOGLE_CLOUD_CREDENTIALS/GOOGLE_CLOUD_PROJECT_ID are missing; sent emails will not be archived.');
17
- warnedMissingCredentials = true;
18
- }
19
- return undefined;
20
- }
21
- return bucketName;
22
- };
23
- let _bucket = null;
24
- const getArchiveBucket = async (bucketName) => {
25
- if (!_bucket) {
26
- const { Storage } = await import('@google-cloud/storage');
27
- const credentials = JSON.parse(ENV.GOOGLE_CLOUD_CREDENTIALS);
28
- _bucket = new Storage({
29
- projectId: ENV.GOOGLE_CLOUD_PROJECT_ID,
30
- credentials,
31
- }).bucket(bucketName);
32
- }
33
- return _bucket;
34
- };
35
- const buildObjectKey = (sentAt, idForKey) => {
36
- const iso = sentAt.toISOString();
37
- const [year, month, day] = iso.slice(0, 10).split('-');
38
- const sanitizedTimestamp = iso.replace(/[:.]/g, '-');
39
- const key = `email-archive/${year}/${month}/${day}/${sanitizedTimestamp}_${idForKey}.json`;
40
- return ENV.NODE_ENV !== 'production' ? `debug/${key}` : key;
41
- };
42
- const recordArchiveEvent = async (event) => {
43
- if (!ENV.DATABASE_URL) {
44
- console.warn('[EMAIL_ARCHIVE] DATABASE_URL not set; archive event not recorded.');
45
- return;
46
- }
47
- try {
48
- const { internalDb } = await import('@betterinternship/schema');
49
- await internalDb
50
- .insertInto('internal.email_delivery_events')
51
- .values({
52
- event_type: 'send_success',
53
- recipient_email: event.recipient,
54
- feedback_id: event.feedbackId,
55
- attempts: event.attempts,
56
- correlation_type: event.correlationDetail ? 'email_archive' : null,
57
- correlation_detail: event.correlationDetail,
58
- })
59
- .execute();
60
- }
61
- catch (error) {
62
- console.error('[ERROR:EMAIL_ARCHIVE] Could not record archive event.', error);
63
- }
64
- };
65
- export const archiveSentEmail = async (context, messageId, attempts) => {
66
- const bucketName = getArchiveBucketName();
67
- if (!bucketName)
68
- return;
69
- const sentAt = new Date();
70
- const idForKey = messageId ?? randomUUID();
71
- const key = buildObjectKey(sentAt, idForKey);
72
- const payload = {
73
- message_id: messageId ?? null,
74
- sent_at: sentAt.toISOString(),
75
- service: ENV.EMAIL_ARCHIVE_SERVICE,
76
- attempts,
77
- source: context.source,
78
- sender: context.sender ?? null,
79
- alias: context.alias,
80
- to: context.to,
81
- cc: context.cc,
82
- bcc: context.bcc,
83
- subject: context.subject,
84
- content: context.content,
85
- tags: context.tags,
86
- configuration_set_name: context.configurationSetName ?? null,
87
- };
88
- let uploadedKey = null;
89
- try {
90
- const bucket = await getArchiveBucket(bucketName);
91
- await bucket.file(key).save(JSON.stringify(payload, null, 2), {
92
- contentType: 'application/json',
93
- resumable: false,
94
- });
95
- uploadedKey = key;
96
- }
97
- catch (error) {
98
- console.error('[ERROR:EMAIL_ARCHIVE] Could not upload archive object.', error);
99
- }
100
- await recordArchiveEvent({
101
- recipient: context.to[0],
102
- feedbackId: idForKey,
103
- attempts,
104
- correlationDetail: uploadedKey,
105
- });
106
- };
1
+ import { randomUUID } from 'crypto';
2
+ import { ENV } from '../env.js';
3
+ let warnedMissingBucket = false;
4
+ let warnedMissingCredentials = false;
5
+ const getArchiveBucketName = () => {
6
+ const bucketName = ENV.EMAIL_ARCHIVE_BUCKET;
7
+ if (!bucketName) {
8
+ if (!warnedMissingBucket) {
9
+ console.warn('[EMAIL_ARCHIVE] EMAIL_ARCHIVE_BUCKET not set; sent emails will not be archived.');
10
+ warnedMissingBucket = true;
11
+ }
12
+ return undefined;
13
+ }
14
+ if (!ENV.GOOGLE_CLOUD_CREDENTIALS || !ENV.GOOGLE_CLOUD_PROJECT_ID) {
15
+ if (!warnedMissingCredentials) {
16
+ console.error('[ERROR:EMAIL_ARCHIVE] EMAIL_ARCHIVE_BUCKET is set but GOOGLE_CLOUD_CREDENTIALS/GOOGLE_CLOUD_PROJECT_ID are missing; sent emails will not be archived.');
17
+ warnedMissingCredentials = true;
18
+ }
19
+ return undefined;
20
+ }
21
+ return bucketName;
22
+ };
23
+ let _bucket = null;
24
+ const getArchiveBucket = async (bucketName) => {
25
+ if (!_bucket) {
26
+ const { Storage } = await import('@google-cloud/storage');
27
+ const credentials = JSON.parse(ENV.GOOGLE_CLOUD_CREDENTIALS);
28
+ _bucket = new Storage({
29
+ projectId: ENV.GOOGLE_CLOUD_PROJECT_ID,
30
+ credentials,
31
+ }).bucket(bucketName);
32
+ }
33
+ return _bucket;
34
+ };
35
+ const buildObjectKey = (sentAt, idForKey) => {
36
+ const iso = sentAt.toISOString();
37
+ const [year, month, day] = iso.slice(0, 10).split('-');
38
+ const sanitizedTimestamp = iso.replace(/[:.]/g, '-');
39
+ const key = `email-archive/${year}/${month}/${day}/${sanitizedTimestamp}_${idForKey}.json`;
40
+ return ENV.NODE_ENV !== 'production' ? `debug/${key}` : key;
41
+ };
42
+ const recordArchiveEvent = async (event) => {
43
+ if (!ENV.DATABASE_URL) {
44
+ console.warn('[EMAIL_ARCHIVE] DATABASE_URL not set; archive event not recorded.');
45
+ return;
46
+ }
47
+ try {
48
+ const { internalDb } = await import('@betterinternship/schema');
49
+ await internalDb
50
+ .insertInto('internal.email_delivery_events')
51
+ .values({
52
+ event_type: 'send_success',
53
+ recipient_email: event.recipient,
54
+ feedback_id: event.feedbackId,
55
+ attempts: event.attempts,
56
+ correlation_type: event.correlationDetail ? 'email_archive' : null,
57
+ correlation_detail: event.correlationDetail,
58
+ })
59
+ .execute();
60
+ }
61
+ catch (error) {
62
+ console.error('[ERROR:EMAIL_ARCHIVE] Could not record archive event.', error);
63
+ }
64
+ };
65
+ export const archiveSentEmail = async (context, messageId, attempts) => {
66
+ const bucketName = getArchiveBucketName();
67
+ if (!bucketName)
68
+ return;
69
+ const sentAt = new Date();
70
+ const idForKey = messageId ?? randomUUID();
71
+ const key = buildObjectKey(sentAt, idForKey);
72
+ const payload = {
73
+ message_id: messageId ?? null,
74
+ sent_at: sentAt.toISOString(),
75
+ service: ENV.EMAIL_ARCHIVE_SERVICE,
76
+ attempts,
77
+ source: context.source,
78
+ sender: context.sender ?? null,
79
+ alias: context.alias,
80
+ to: context.to,
81
+ cc: context.cc,
82
+ bcc: context.bcc,
83
+ subject: context.subject,
84
+ content: context.content,
85
+ tags: context.tags,
86
+ configuration_set_name: context.configurationSetName ?? null,
87
+ };
88
+ let uploadedKey = null;
89
+ try {
90
+ const bucket = await getArchiveBucket(bucketName);
91
+ await bucket.file(key).save(JSON.stringify(payload, null, 2), {
92
+ contentType: 'application/json',
93
+ resumable: false,
94
+ });
95
+ uploadedKey = key;
96
+ }
97
+ catch (error) {
98
+ console.error('[ERROR:EMAIL_ARCHIVE] Could not upload archive object.', error);
99
+ }
100
+ await recordArchiveEvent({
101
+ recipient: context.to[0],
102
+ feedbackId: idForKey,
103
+ attempts,
104
+ correlationDetail: uploadedKey,
105
+ });
106
+ };
107
107
  //# sourceMappingURL=archive.js.map
@@ -1,151 +1,151 @@
1
- import { SendEmailCommand, SESClient, } from '@aws-sdk/client-ses';
2
- import { randomUUID } from 'crypto';
3
- import { ENV } from '../env.js';
4
- import { archiveSentEmail } from './archive.js';
5
- let _sesClient = null;
6
- const getSesClient = () => {
7
- if (!_sesClient) {
8
- if (!ENV.AWS_ACCESS_KEY_ID || !ENV.AWS_SECRET_ACCESS_KEY || !ENV.AWS_REGION)
9
- console.error('[ERROR:ENV]: Missing Amazon setup.');
10
- _sesClient = new SESClient({ region: ENV.AWS_REGION, maxAttempts: 1 });
11
- }
12
- return _sesClient;
13
- };
14
- const RETRY_BASE_DELAY_MS = 500;
15
- const RETRY_DELAY_FACTOR = 3;
16
- const getMaxAttempts = () => {
17
- const parsed = parseInt(ENV.EMAIL_SEND_MAX_ATTEMPTS ?? '', 10);
18
- return Number.isFinite(parsed) && parsed >= 1 ? parsed : 3;
19
- };
20
- const getRetryDelayMs = (attempt) => {
21
- const base = RETRY_BASE_DELAY_MS * RETRY_DELAY_FACTOR ** (attempt - 1);
22
- const jitter = base * 0.25 * (Math.random() * 2 - 1);
23
- return Math.round(base + jitter);
24
- };
25
- const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
26
- const isRetryableSendError = (error) => {
27
- const err = error;
28
- if (err.name === 'ThrottlingException')
29
- return true;
30
- if (err.name === 'TooManyRequestsException')
31
- return true;
32
- const status = err.$metadata?.httpStatusCode;
33
- if (status === undefined)
34
- return true;
35
- return status === 429 || status >= 500;
36
- };
37
- const describeError = (error) => {
38
- const err = error;
39
- return `${err.name ?? 'Error'}: ${err.message ?? String(error)}`;
40
- };
41
- const recordSendFailure = async (failure) => {
42
- if (!ENV.DATABASE_URL) {
43
- console.warn('[EMAIL] DATABASE_URL not set; send failure not recorded.');
44
- return;
45
- }
46
- try {
47
- const { internalDb } = await import('@betterinternship/schema');
48
- await internalDb
49
- .insertInto('internal.email_delivery_events')
50
- .values({
51
- event_type: 'send_failure',
52
- recipient_email: failure.recipient,
53
- feedback_id: randomUUID(),
54
- attempts: failure.attempts,
55
- error_message: describeError(failure.error),
56
- })
57
- .execute();
58
- }
59
- catch (error) {
60
- console.error('[ERROR:EMAIL] Could not record send failure.', error);
61
- }
62
- };
63
- const normalizeRecipients = (value) => {
64
- if (!value)
65
- return [];
66
- const list = Array.isArray(value) ? value : [value];
67
- return [
68
- ...new Set(list.map((recipient) => recipient.trim()).filter(Boolean)),
69
- ];
70
- };
71
- const toSesTags = (tags) => Object.entries(tags).map(([name, value]) => ({
72
- Name: name,
73
- Value: value.trim().slice(0, 256).replaceAll(' ', ''),
74
- }));
75
- const sendWithRetries = async (params, logRecipients, archiveContext) => {
76
- const maxAttempts = getMaxAttempts();
77
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
78
- try {
79
- const command = new SendEmailCommand(params);
80
- const result = await getSesClient().send(command);
81
- console.warn('[AWSSES] Email sent to ' + logRecipients.join(', '));
82
- void archiveSentEmail(archiveContext, result.MessageId, attempt).catch((error) => console.error('[ERROR:EMAIL_ARCHIVE] Archive failed.', error));
83
- return {
84
- messageId: result.MessageId,
85
- response: 'Successfully sent via Amazon SES.',
86
- };
87
- }
88
- catch (error) {
89
- if (isRetryableSendError(error) && attempt < maxAttempts) {
90
- const delay = getRetryDelayMs(attempt);
91
- console.error(`[ERROR:AWSSES] Send failed (attempt ${attempt}/${maxAttempts}), retrying in ${delay}ms: ${describeError(error)}`);
92
- await sleep(delay);
93
- continue;
94
- }
95
- console.error(`[ERROR:AWSSES] Send failed permanently after ${attempt} attempt(s) to ${logRecipients.join(', ')}: ${describeError(error)}`);
96
- await recordSendFailure({
97
- recipient: logRecipients[0],
98
- attempts: attempt,
99
- error,
100
- });
101
- return undefined;
102
- }
103
- }
104
- return undefined;
105
- };
106
- export const sendMultiEmail = async ({ sender, subject, to, cc, bcc, content, alias = 'hello', configurationSetName, tags, }) => {
107
- const toRecipients = normalizeRecipients(to);
108
- if (!toRecipients.length)
109
- throw Error('[ERROR:EMAIL] No recipients provided for email.');
110
- const ccRecipients = normalizeRecipients(cc);
111
- const bccRecipients = normalizeRecipients(bcc);
112
- const logRecipients = [...toRecipients, ...ccRecipients, ...bccRecipients];
113
- const source = `"${sender ?? 'BetterInternship'}" <${alias}@betterinternship.com>`;
114
- const params = {
115
- Destination: {
116
- ToAddresses: toRecipients,
117
- CcAddresses: ccRecipients.length ? ccRecipients : undefined,
118
- BccAddresses: bccRecipients.length ? bccRecipients : undefined,
119
- },
120
- Message: {
121
- Subject: { Data: subject },
122
- Body: {
123
- Html: { Data: content },
124
- },
125
- },
126
- Source: source,
127
- ConfigurationSetName: configurationSetName,
128
- Tags: tags ? toSesTags(tags) : undefined,
129
- };
130
- const archiveContext = {
131
- sender,
132
- alias,
133
- source,
134
- to: toRecipients,
135
- cc: ccRecipients,
136
- bcc: bccRecipients,
137
- subject,
138
- content,
139
- tags,
140
- configurationSetName,
141
- };
142
- return await sendWithRetries(params, logRecipients, archiveContext);
143
- };
144
- export const sendSingleEmail = async (params) => {
145
- if (!normalizeRecipients(params.recipient).length) {
146
- console.error('[ERROR:EMAIL] No recipient provided for email.');
147
- return undefined;
148
- }
149
- return await sendMultiEmail({ ...params, to: params.recipient });
150
- };
1
+ import { SendEmailCommand, SESClient, } from '@aws-sdk/client-ses';
2
+ import { randomUUID } from 'crypto';
3
+ import { ENV } from '../env.js';
4
+ import { archiveSentEmail } from './archive.js';
5
+ let _sesClient = null;
6
+ const getSesClient = () => {
7
+ if (!_sesClient) {
8
+ if (!ENV.AWS_ACCESS_KEY_ID || !ENV.AWS_SECRET_ACCESS_KEY || !ENV.AWS_REGION)
9
+ console.error('[ERROR:ENV]: Missing Amazon setup.');
10
+ _sesClient = new SESClient({ region: ENV.AWS_REGION, maxAttempts: 1 });
11
+ }
12
+ return _sesClient;
13
+ };
14
+ const RETRY_BASE_DELAY_MS = 500;
15
+ const RETRY_DELAY_FACTOR = 3;
16
+ const getMaxAttempts = () => {
17
+ const parsed = parseInt(ENV.EMAIL_SEND_MAX_ATTEMPTS ?? '', 10);
18
+ return Number.isFinite(parsed) && parsed >= 1 ? parsed : 3;
19
+ };
20
+ const getRetryDelayMs = (attempt) => {
21
+ const base = RETRY_BASE_DELAY_MS * RETRY_DELAY_FACTOR ** (attempt - 1);
22
+ const jitter = base * 0.25 * (Math.random() * 2 - 1);
23
+ return Math.round(base + jitter);
24
+ };
25
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
26
+ const isRetryableSendError = (error) => {
27
+ const err = error;
28
+ if (err.name === 'ThrottlingException')
29
+ return true;
30
+ if (err.name === 'TooManyRequestsException')
31
+ return true;
32
+ const status = err.$metadata?.httpStatusCode;
33
+ if (status === undefined)
34
+ return true;
35
+ return status === 429 || status >= 500;
36
+ };
37
+ const describeError = (error) => {
38
+ const err = error;
39
+ return `${err.name ?? 'Error'}: ${err.message ?? String(error)}`;
40
+ };
41
+ const recordSendFailure = async (failure) => {
42
+ if (!ENV.DATABASE_URL) {
43
+ console.warn('[EMAIL] DATABASE_URL not set; send failure not recorded.');
44
+ return;
45
+ }
46
+ try {
47
+ const { internalDb } = await import('@betterinternship/schema');
48
+ await internalDb
49
+ .insertInto('internal.email_delivery_events')
50
+ .values({
51
+ event_type: 'send_failure',
52
+ recipient_email: failure.recipient,
53
+ feedback_id: randomUUID(),
54
+ attempts: failure.attempts,
55
+ error_message: describeError(failure.error),
56
+ })
57
+ .execute();
58
+ }
59
+ catch (error) {
60
+ console.error('[ERROR:EMAIL] Could not record send failure.', error);
61
+ }
62
+ };
63
+ const normalizeRecipients = (value) => {
64
+ if (!value)
65
+ return [];
66
+ const list = Array.isArray(value) ? value : [value];
67
+ return [
68
+ ...new Set(list.map((recipient) => recipient.trim()).filter(Boolean)),
69
+ ];
70
+ };
71
+ const toSesTags = (tags) => Object.entries(tags).map(([name, value]) => ({
72
+ Name: name,
73
+ Value: value.trim().slice(0, 256).replaceAll(' ', ''),
74
+ }));
75
+ const sendWithRetries = async (params, logRecipients, archiveContext) => {
76
+ const maxAttempts = getMaxAttempts();
77
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
78
+ try {
79
+ const command = new SendEmailCommand(params);
80
+ const result = await getSesClient().send(command);
81
+ console.warn('[AWSSES] Email sent to ' + logRecipients.join(', '));
82
+ void archiveSentEmail(archiveContext, result.MessageId, attempt).catch((error) => console.error('[ERROR:EMAIL_ARCHIVE] Archive failed.', error));
83
+ return {
84
+ messageId: result.MessageId,
85
+ response: 'Successfully sent via Amazon SES.',
86
+ };
87
+ }
88
+ catch (error) {
89
+ if (isRetryableSendError(error) && attempt < maxAttempts) {
90
+ const delay = getRetryDelayMs(attempt);
91
+ console.error(`[ERROR:AWSSES] Send failed (attempt ${attempt}/${maxAttempts}), retrying in ${delay}ms: ${describeError(error)}`);
92
+ await sleep(delay);
93
+ continue;
94
+ }
95
+ console.error(`[ERROR:AWSSES] Send failed permanently after ${attempt} attempt(s) to ${logRecipients.join(', ')}: ${describeError(error)}`);
96
+ await recordSendFailure({
97
+ recipient: logRecipients[0],
98
+ attempts: attempt,
99
+ error,
100
+ });
101
+ return undefined;
102
+ }
103
+ }
104
+ return undefined;
105
+ };
106
+ export const sendMultiEmail = async ({ sender, subject, to, cc, bcc, content, alias = 'hello', configurationSetName, tags, }) => {
107
+ const toRecipients = normalizeRecipients(to);
108
+ if (!toRecipients.length)
109
+ throw Error('[ERROR:EMAIL] No recipients provided for email.');
110
+ const ccRecipients = normalizeRecipients(cc);
111
+ const bccRecipients = normalizeRecipients(bcc);
112
+ const logRecipients = [...toRecipients, ...ccRecipients, ...bccRecipients];
113
+ const source = `"${sender ?? 'BetterInternship'}" <${alias}@betterinternship.com>`;
114
+ const params = {
115
+ Destination: {
116
+ ToAddresses: toRecipients,
117
+ CcAddresses: ccRecipients.length ? ccRecipients : undefined,
118
+ BccAddresses: bccRecipients.length ? bccRecipients : undefined,
119
+ },
120
+ Message: {
121
+ Subject: { Data: subject },
122
+ Body: {
123
+ Html: { Data: content },
124
+ },
125
+ },
126
+ Source: source,
127
+ ConfigurationSetName: configurationSetName,
128
+ Tags: tags ? toSesTags(tags) : undefined,
129
+ };
130
+ const archiveContext = {
131
+ sender,
132
+ alias,
133
+ source,
134
+ to: toRecipients,
135
+ cc: ccRecipients,
136
+ bcc: bccRecipients,
137
+ subject,
138
+ content,
139
+ tags,
140
+ configurationSetName,
141
+ };
142
+ return await sendWithRetries(params, logRecipients, archiveContext);
143
+ };
144
+ export const sendSingleEmail = async (params) => {
145
+ if (!normalizeRecipients(params.recipient).length) {
146
+ console.error('[ERROR:EMAIL] No recipient provided for email.');
147
+ return undefined;
148
+ }
149
+ return await sendMultiEmail({ ...params, to: params.recipient });
150
+ };
151
151
  //# sourceMappingURL=email.js.map
@@ -19,6 +19,7 @@ export type ClientPhantomField<SourceDomains extends any[]> = Omit<IFormPhantomF
19
19
  options?: EnumValue[];
20
20
  coerce: (s: string) => string | number | boolean | Date | Array<string> | undefined;
21
21
  };
22
+ export declare const isFieldRequired: <SourceDomains extends any[]>(field: ClientField<SourceDomains> | ClientPhantomField<SourceDomains>) => boolean;
22
23
  export interface ClientBlock<SourceDomains extends any[]> {
23
24
  block_type: (typeof BLOCK_TYPES)[number];
24
25
  order: number;
@@ -20,4 +20,5 @@ export const getSchemaClientType = (s) => {
20
20
  return 'time';
21
21
  return 'text';
22
22
  };
23
+ export const isFieldRequired = (field) => !!field.validator && !field.validator.safeParse(field.coerce('')).success;
23
24
  //# sourceMappingURL=fields.client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fields.client.js","sourceRoot":"","sources":["../../../lib/forms/fields.client.ts"],"names":[],"mappings":"AAUA,OAAO,CAAc,MAAM,KAAK,CAAC;AAWjC,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAU,EAAmB,EAAE;IACjE,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC;IACrB,MAAM,IAAI,GAAG,CAAC,CAAC,WAAW,CAAC;IAC3B,IAAI,IAAI,KAAK,OAAO;QAAE,OAAO,OAAO,CAAC;IACrC,IAAI,KAAK,KAAK,MAAM,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,MAAM,CAAC;IACvD,IAAI,KAAK,KAAK,QAAQ,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC7D,IAAI,KAAK,KAAK,MAAM,IAAI,IAAI,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IAC/D,IAAI,KAAK,KAAK,SAAS,IAAI,IAAI,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IAClE,IAAI,CAAC,YAAY,CAAC,CAAC,QAAQ,IAAI,IAAI,KAAK,aAAa;QAAE,OAAO,aAAa,CAAC;IAC5E,IAAI,IAAI,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IAC3C,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,MAAM,CAAC;IACnC,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}
1
+ {"version":3,"file":"fields.client.js","sourceRoot":"","sources":["../../../lib/forms/fields.client.ts"],"names":[],"mappings":"AAUA,OAAO,CAAc,MAAM,KAAK,CAAC;AAWjC,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAU,EAAmB,EAAE;IACjE,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC;IACrB,MAAM,IAAI,GAAG,CAAC,CAAC,WAAW,CAAC;IAC3B,IAAI,IAAI,KAAK,OAAO;QAAE,OAAO,OAAO,CAAC;IACrC,IAAI,KAAK,KAAK,MAAM,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,MAAM,CAAC;IACvD,IAAI,KAAK,KAAK,QAAQ,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC7D,IAAI,KAAK,KAAK,MAAM,IAAI,IAAI,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IAC/D,IAAI,KAAK,KAAK,SAAS,IAAI,IAAI,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IAClE,IAAI,CAAC,YAAY,CAAC,CAAC,QAAQ,IAAI,IAAI,KAAK,aAAa;QAAE,OAAO,aAAa,CAAC;IAC5E,IAAI,IAAI,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IAC3C,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,MAAM,CAAC;IACnC,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AA+CF,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,KAAqE,EACrE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/forms/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/forms/index.ts"],"names":[],"mappings":"AASA,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC"}
@@ -0,0 +1 @@
1
+ export * from './signer-fields.js';
@@ -0,0 +1,2 @@
1
+ export * from './signer-fields.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../lib/partners/forms/index.ts"],"names":[],"mappings":"AASA,cAAc,oBAAoB,CAAC"}
@@ -0,0 +1,20 @@
1
+ export declare const MAX_COMPANY_SIGNATORIES = 2;
2
+ export declare const MAX_UNIVERSITY_SIGNATORIES = 5;
3
+ export type SignerParty = 'company' | 'university';
4
+ export type SignerProp = 'name' | 'title' | 'signature';
5
+ export declare const signerFieldPrefix: (party: SignerParty, index: number) => string;
6
+ export declare const signerFieldAliases: (party: SignerParty, index: number) => string[];
7
+ export declare const signerFieldKeys: (party: SignerParty, index: number, prop: SignerProp) => string[];
8
+ export declare const signatureFieldIdentity: (fieldKey: string) => string | null;
9
+ export interface CompanySignerRequirements {
10
+ name: boolean;
11
+ title: boolean;
12
+ signature: boolean;
13
+ }
14
+ export interface CompanySignatoryRequirements {
15
+ signer1: CompanySignerRequirements;
16
+ signer2: CompanySignerRequirements;
17
+ }
18
+ export declare const deriveCompanySignatoryRequirements: (fieldSchema: unknown) => CompanySignatoryRequirements;
19
+ export declare const requiresSigner1: (req: CompanySignatoryRequirements) => boolean;
20
+ export declare const requiresSigner2: (req: CompanySignatoryRequirements) => boolean;