@tummycrypt/acuity-middleware 0.1.0 → 0.1.1
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/dist/adapters/acuity-scraper.d.ts +8 -0
- package/dist/adapters/acuity-scraper.d.ts.map +1 -0
- package/dist/adapters/acuity-scraper.js +8 -0
- package/dist/adapters/acuity-scraper.js.map +1 -0
- package/dist/adapters/types.d.ts +8 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +8 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/core/types.d.ts +10 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/acuity-wizard.d.ts +49 -0
- package/dist/middleware/acuity-wizard.d.ts.map +1 -0
- package/dist/middleware/acuity-wizard.js +265 -0
- package/dist/middleware/acuity-wizard.js.map +1 -0
- package/dist/middleware/browser-service.d.ts +53 -0
- package/dist/middleware/browser-service.d.ts.map +1 -0
- package/dist/middleware/browser-service.js +105 -0
- package/dist/middleware/browser-service.js.map +1 -0
- package/dist/middleware/errors.d.ts +58 -0
- package/dist/middleware/errors.d.ts.map +1 -0
- package/dist/middleware/errors.js +43 -0
- package/dist/middleware/errors.js.map +1 -0
- package/{src/middleware/index.ts → dist/middleware/index.d.ts} +5 -52
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +38 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/logger.d.ts +26 -0
- package/dist/middleware/logger.d.ts.map +1 -0
- package/dist/middleware/logger.js +65 -0
- package/dist/middleware/logger.js.map +1 -0
- package/dist/middleware/remote-adapter.d.ts +45 -0
- package/dist/middleware/remote-adapter.d.ts.map +1 -0
- package/dist/middleware/remote-adapter.js +178 -0
- package/dist/middleware/remote-adapter.js.map +1 -0
- package/dist/middleware/selector-health.d.ts +44 -0
- package/dist/middleware/selector-health.d.ts.map +1 -0
- package/dist/middleware/selector-health.js +144 -0
- package/dist/middleware/selector-health.js.map +1 -0
- package/dist/middleware/selectors.d.ts +108 -0
- package/dist/middleware/selectors.d.ts.map +1 -0
- package/dist/middleware/selectors.js +249 -0
- package/dist/middleware/selectors.js.map +1 -0
- package/dist/middleware/server.d.ts +34 -0
- package/dist/middleware/server.d.ts.map +1 -0
- package/dist/middleware/server.js +377 -0
- package/dist/middleware/server.js.map +1 -0
- package/dist/middleware/service-resolver.d.ts +46 -0
- package/dist/middleware/service-resolver.d.ts.map +1 -0
- package/dist/middleware/service-resolver.js +274 -0
- package/dist/middleware/service-resolver.js.map +1 -0
- package/dist/middleware/slot-parser.d.ts +29 -0
- package/dist/middleware/slot-parser.d.ts.map +1 -0
- package/dist/middleware/slot-parser.js +50 -0
- package/dist/middleware/slot-parser.js.map +1 -0
- package/dist/middleware/steps/__tests__/fixtures.d.ts +14 -0
- package/dist/middleware/steps/__tests__/fixtures.d.ts.map +1 -0
- package/dist/middleware/steps/__tests__/fixtures.js +204 -0
- package/dist/middleware/steps/__tests__/fixtures.js.map +1 -0
- package/dist/middleware/steps/bypass-payment.d.ts +54 -0
- package/dist/middleware/steps/bypass-payment.d.ts.map +1 -0
- package/dist/middleware/steps/bypass-payment.js +164 -0
- package/dist/middleware/steps/bypass-payment.js.map +1 -0
- package/dist/middleware/steps/extract-business.d.ts +93 -0
- package/dist/middleware/steps/extract-business.d.ts.map +1 -0
- package/dist/middleware/steps/extract-business.js +170 -0
- package/dist/middleware/steps/extract-business.js.map +1 -0
- package/dist/middleware/steps/extract.d.ts +41 -0
- package/dist/middleware/steps/extract.d.ts.map +1 -0
- package/dist/middleware/steps/extract.js +128 -0
- package/dist/middleware/steps/extract.js.map +1 -0
- package/dist/middleware/steps/fill-form.d.ts +45 -0
- package/dist/middleware/steps/fill-form.d.ts.map +1 -0
- package/dist/middleware/steps/fill-form.js +262 -0
- package/dist/middleware/steps/fill-form.js.map +1 -0
- package/dist/middleware/steps/index.d.ts +12 -0
- package/dist/middleware/steps/index.d.ts.map +1 -0
- package/dist/middleware/steps/index.js +12 -0
- package/dist/middleware/steps/index.js.map +1 -0
- package/dist/middleware/steps/navigate.d.ts +51 -0
- package/dist/middleware/steps/navigate.d.ts.map +1 -0
- package/dist/middleware/steps/navigate.js +391 -0
- package/dist/middleware/steps/navigate.js.map +1 -0
- package/dist/middleware/steps/read-availability.d.ts +37 -0
- package/dist/middleware/steps/read-availability.d.ts.map +1 -0
- package/dist/middleware/steps/read-availability.js +298 -0
- package/dist/middleware/steps/read-availability.js.map +1 -0
- package/dist/middleware/steps/read-slots.d.ts +33 -0
- package/dist/middleware/steps/read-slots.d.ts.map +1 -0
- package/dist/middleware/steps/read-slots.js +295 -0
- package/dist/middleware/steps/read-slots.js.map +1 -0
- package/dist/middleware/steps/read-via-url.d.ts +39 -0
- package/dist/middleware/steps/read-via-url.d.ts.map +1 -0
- package/dist/middleware/steps/read-via-url.js +141 -0
- package/dist/middleware/steps/read-via-url.js.map +1 -0
- package/dist/middleware/steps/submit.d.ts +22 -0
- package/dist/middleware/steps/submit.d.ts.map +1 -0
- package/dist/middleware/steps/submit.js +112 -0
- package/dist/middleware/steps/submit.js.map +1 -0
- package/dist/middleware/wizard-calendar.d.ts +37 -0
- package/dist/middleware/wizard-calendar.d.ts.map +1 -0
- package/dist/middleware/wizard-calendar.js +177 -0
- package/dist/middleware/wizard-calendar.js.map +1 -0
- package/dist/middleware/wizard-service.d.ts +30 -0
- package/dist/middleware/wizard-service.d.ts.map +1 -0
- package/dist/middleware/wizard-service.js +89 -0
- package/dist/middleware/wizard-service.js.map +1 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.d.ts.map +1 -0
- package/{src/server.ts → dist/server.js} +1 -0
- package/dist/server.js.map +1 -0
- package/package.json +16 -4
- package/.github/workflows/build-paper.yml +0 -39
- package/.github/workflows/ci.yml +0 -37
- package/Dockerfile +0 -53
- package/docs/blog-post.mdx +0 -240
- package/docs/paper/IEEEtran.bst +0 -2409
- package/docs/paper/IEEEtran.cls +0 -6347
- package/docs/paper/acuity-middleware-paper.tex +0 -375
- package/docs/paper/balance.sty +0 -87
- package/docs/paper/references.bib +0 -231
- package/docs/paper.md +0 -400
- package/flake.nix +0 -32
- package/modal-app.py +0 -82
- package/src/adapters/acuity-scraper.ts +0 -543
- package/src/adapters/types.ts +0 -193
- package/src/core/types.ts +0 -325
- package/src/index.ts +0 -75
- package/src/middleware/acuity-wizard.ts +0 -456
- package/src/middleware/browser-service.ts +0 -183
- package/src/middleware/errors.ts +0 -70
- package/src/middleware/remote-adapter.ts +0 -246
- package/src/middleware/selectors.ts +0 -308
- package/src/middleware/server.ts +0 -372
- package/src/middleware/steps/bypass-payment.ts +0 -226
- package/src/middleware/steps/extract.ts +0 -174
- package/src/middleware/steps/fill-form.ts +0 -359
- package/src/middleware/steps/index.ts +0 -27
- package/src/middleware/steps/navigate.ts +0 -537
- package/src/middleware/steps/read-availability.ts +0 -399
- package/src/middleware/steps/read-slots.ts +0 -405
- package/src/middleware/steps/submit.ts +0 -168
- package/tsconfig.json +0 -25
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wizard Step: Extract Confirmation Data
|
|
3
|
+
*
|
|
4
|
+
* Reads the confirmation page to extract booking details:
|
|
5
|
+
* appointment ID, confirmation code, service, date/time, provider.
|
|
6
|
+
* Maps the scraped data to the Booking type.
|
|
7
|
+
*/
|
|
8
|
+
import { Effect } from 'effect';
|
|
9
|
+
import { BrowserService } from '../browser-service.js';
|
|
10
|
+
import { WizardStepError } from '../errors.js';
|
|
11
|
+
import { probe, Selectors } from '../selectors.js';
|
|
12
|
+
// =============================================================================
|
|
13
|
+
// IMPLEMENTATION
|
|
14
|
+
// =============================================================================
|
|
15
|
+
/**
|
|
16
|
+
* Extract booking confirmation data from the current page.
|
|
17
|
+
* Assumes we're already on the confirmation page.
|
|
18
|
+
*/
|
|
19
|
+
export const extractConfirmation = () => Effect.gen(function* () {
|
|
20
|
+
const { acquirePage, screenshot, config } = yield* BrowserService;
|
|
21
|
+
const page = yield* acquirePage;
|
|
22
|
+
// Verify we're on the confirmation page (check selectors, URL, and body text)
|
|
23
|
+
const onConfirmation = yield* probe(page, 'confirmationPage');
|
|
24
|
+
const urlMatch = /\/(confirmation|confirmed|thank-you|complete)/i.test(page.url());
|
|
25
|
+
const bodyMatch = yield* Effect.tryPromise({
|
|
26
|
+
try: () => page.$eval('body', (el) => {
|
|
27
|
+
const text = el.textContent?.toLowerCase() ?? '';
|
|
28
|
+
return text.includes('booking confirmed') ||
|
|
29
|
+
text.includes('appointment confirmed') ||
|
|
30
|
+
text.includes('successfully booked') ||
|
|
31
|
+
text.includes('your appointment is scheduled');
|
|
32
|
+
}).catch(() => false),
|
|
33
|
+
catch: () => false,
|
|
34
|
+
}).pipe(Effect.orElseSucceed(() => false));
|
|
35
|
+
if (!onConfirmation && !urlMatch && !bodyMatch) {
|
|
36
|
+
return yield* Effect.fail(new WizardStepError({
|
|
37
|
+
step: 'extract',
|
|
38
|
+
message: 'Not on confirmation page - cannot extract booking data',
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
// Extract each piece of data
|
|
42
|
+
const appointmentId = yield* extractText(page, Selectors.confirmationId);
|
|
43
|
+
const serviceName = yield* extractText(page, Selectors.confirmationService);
|
|
44
|
+
const datetime = yield* extractText(page, Selectors.confirmationDatetime);
|
|
45
|
+
// Get the full page text as fallback for parsing
|
|
46
|
+
const rawText = yield* Effect.tryPromise({
|
|
47
|
+
try: () => page.textContent('body').then((t) => t?.trim() ?? ''),
|
|
48
|
+
catch: () => '',
|
|
49
|
+
}).pipe(Effect.orElseSucceed(() => ''));
|
|
50
|
+
// Try to extract confirmation code from raw text if not found via selector
|
|
51
|
+
const confirmationCode = appointmentId ?? extractConfirmationFromText(rawText);
|
|
52
|
+
// Take success screenshot for audit trail
|
|
53
|
+
if (config.screenshotOnFailure) {
|
|
54
|
+
yield* screenshot('booking-confirmation').pipe(Effect.ignore);
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
appointmentId,
|
|
58
|
+
confirmationCode,
|
|
59
|
+
serviceName,
|
|
60
|
+
datetime,
|
|
61
|
+
providerName: null, // Not extracted from confirmation page
|
|
62
|
+
rawText,
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
// =============================================================================
|
|
66
|
+
// MAPPING
|
|
67
|
+
// =============================================================================
|
|
68
|
+
/**
|
|
69
|
+
* Map extracted confirmation data + original request into a Booking object.
|
|
70
|
+
*/
|
|
71
|
+
export const toBooking = (confirmation, request, paymentRef, paymentProcessor, service) => ({
|
|
72
|
+
id: confirmation.appointmentId ?? `wizard-${Date.now()}`,
|
|
73
|
+
serviceId: request.serviceId,
|
|
74
|
+
serviceName: confirmation.serviceName ?? service?.name ?? 'Unknown Service',
|
|
75
|
+
providerId: request.providerId,
|
|
76
|
+
providerName: confirmation.providerName ?? undefined,
|
|
77
|
+
datetime: request.datetime,
|
|
78
|
+
endTime: computeEndTime(request.datetime, service?.duration ?? 60),
|
|
79
|
+
duration: service?.duration ?? 60,
|
|
80
|
+
price: service?.price ?? 0,
|
|
81
|
+
currency: service?.currency ?? 'USD',
|
|
82
|
+
client: request.client,
|
|
83
|
+
status: 'confirmed',
|
|
84
|
+
confirmationCode: confirmation.confirmationCode ?? undefined,
|
|
85
|
+
paymentStatus: 'paid',
|
|
86
|
+
paymentRef: `[${paymentProcessor.toUpperCase()}] Transaction: ${paymentRef}`,
|
|
87
|
+
createdAt: new Date().toISOString(),
|
|
88
|
+
});
|
|
89
|
+
// =============================================================================
|
|
90
|
+
// HELPERS
|
|
91
|
+
// =============================================================================
|
|
92
|
+
const extractText = (page, candidates) => Effect.gen(function* () {
|
|
93
|
+
for (const selector of candidates) {
|
|
94
|
+
const text = yield* Effect.tryPromise({
|
|
95
|
+
try: () => page.$eval(selector, (el) => el.textContent?.trim() ?? null).catch(() => null),
|
|
96
|
+
catch: () => null,
|
|
97
|
+
}).pipe(Effect.orElseSucceed(() => null));
|
|
98
|
+
if (text)
|
|
99
|
+
return text;
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
});
|
|
103
|
+
const extractConfirmationFromText = (text) => {
|
|
104
|
+
// Look for patterns like "Confirmation #12345" or "Appointment ID: 12345"
|
|
105
|
+
const patterns = [
|
|
106
|
+
/confirmation\s*#?\s*(\w+)/i,
|
|
107
|
+
/appointment\s*id\s*:?\s*(\w+)/i,
|
|
108
|
+
/booking\s*#?\s*(\w+)/i,
|
|
109
|
+
/reference\s*:?\s*(\w+)/i,
|
|
110
|
+
];
|
|
111
|
+
for (const pattern of patterns) {
|
|
112
|
+
const match = text.match(pattern);
|
|
113
|
+
if (match?.[1])
|
|
114
|
+
return match[1];
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
};
|
|
118
|
+
const computeEndTime = (datetime, durationMinutes) => {
|
|
119
|
+
try {
|
|
120
|
+
const start = new Date(datetime);
|
|
121
|
+
const end = new Date(start.getTime() + durationMinutes * 60 * 1000);
|
|
122
|
+
return end.toISOString();
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return datetime;
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
//# sourceMappingURL=extract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract.js","sourceRoot":"","sources":["../../../src/middleware/steps/extract.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wizard Step: Fill Client Form Fields
|
|
3
|
+
*
|
|
4
|
+
* Fills standard fields (name, email, phone), custom intake fields
|
|
5
|
+
* (radio buttons, "How did you hear" checkboxes, medication, terms),
|
|
6
|
+
* and advances past the client info step to the payment page.
|
|
7
|
+
*
|
|
8
|
+
* Acuity form requirements (verified 2026-02-26):
|
|
9
|
+
* - Standard: firstName, lastName, email, phone
|
|
10
|
+
* - 3 yes/no radio groups (aria-required, NO name/id attrs)
|
|
11
|
+
* - "How did you hear" multi-checkbox (at least 1 required)
|
|
12
|
+
* - Medication textarea (fields[field-16606770])
|
|
13
|
+
* - Terms checkbox (fields[field-13933959])
|
|
14
|
+
* - ALL must be filled before "Continue to Payment" advances
|
|
15
|
+
*/
|
|
16
|
+
import { Effect } from 'effect';
|
|
17
|
+
import { BrowserService } from '../browser-service.js';
|
|
18
|
+
import { WizardStepError } from '../errors.js';
|
|
19
|
+
import type { ClientInfo } from '../../core/types.js';
|
|
20
|
+
export interface FillFormParams {
|
|
21
|
+
readonly client: ClientInfo;
|
|
22
|
+
readonly customFields?: Record<string, string>;
|
|
23
|
+
/** Answer for yes/no radio questions (default: "no") */
|
|
24
|
+
readonly intakeRadioAnswer?: 'yes' | 'no';
|
|
25
|
+
/** Which "How did you hear" checkbox to select (default: "Internet search") */
|
|
26
|
+
readonly howDidYouHear?: string;
|
|
27
|
+
/** Medication text (default: "None") */
|
|
28
|
+
readonly medication?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface FillFormResult {
|
|
31
|
+
readonly fieldsCompleted: string[];
|
|
32
|
+
readonly customFieldsCompleted: string[];
|
|
33
|
+
readonly intakeFieldsCompleted: string[];
|
|
34
|
+
readonly advanced: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Fill the client information form and advance to the payment page.
|
|
38
|
+
*/
|
|
39
|
+
export declare const fillFormFields: (params: FillFormParams) => Effect.Effect<{
|
|
40
|
+
fieldsCompleted: string[];
|
|
41
|
+
customFieldsCompleted: string[];
|
|
42
|
+
intakeFieldsCompleted: string[];
|
|
43
|
+
advanced: boolean;
|
|
44
|
+
}, import("../errors.js").BrowserError | WizardStepError, import("effect/Scope").Scope | BrowserService>;
|
|
45
|
+
//# sourceMappingURL=fill-form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fill-form.d.ts","sourceRoot":"","sources":["../../../src/middleware/steps/fill-form.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAMtD,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/C,wDAAwD;IACxD,QAAQ,CAAC,iBAAiB,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IAC1C,+EAA+E;IAC/E,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,wCAAwC;IACxC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,qBAAqB,EAAE,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,qBAAqB,EAAE,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC3B;AAMD;;GAEG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,cAAc;;;;;wGAsEnD,CAAC"}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wizard Step: Fill Client Form Fields
|
|
3
|
+
*
|
|
4
|
+
* Fills standard fields (name, email, phone), custom intake fields
|
|
5
|
+
* (radio buttons, "How did you hear" checkboxes, medication, terms),
|
|
6
|
+
* and advances past the client info step to the payment page.
|
|
7
|
+
*
|
|
8
|
+
* Acuity form requirements (verified 2026-02-26):
|
|
9
|
+
* - Standard: firstName, lastName, email, phone
|
|
10
|
+
* - 3 yes/no radio groups (aria-required, NO name/id attrs)
|
|
11
|
+
* - "How did you hear" multi-checkbox (at least 1 required)
|
|
12
|
+
* - Medication textarea (fields[field-16606770])
|
|
13
|
+
* - Terms checkbox (fields[field-13933959])
|
|
14
|
+
* - ALL must be filled before "Continue to Payment" advances
|
|
15
|
+
*/
|
|
16
|
+
import { Effect } from 'effect';
|
|
17
|
+
import { BrowserService } from '../browser-service.js';
|
|
18
|
+
import { WizardStepError } from '../errors.js';
|
|
19
|
+
import { resolveSelector, Selectors } from '../selectors.js';
|
|
20
|
+
// =============================================================================
|
|
21
|
+
// IMPLEMENTATION
|
|
22
|
+
// =============================================================================
|
|
23
|
+
/**
|
|
24
|
+
* Fill the client information form and advance to the payment page.
|
|
25
|
+
*/
|
|
26
|
+
export const fillFormFields = (params) => Effect.gen(function* () {
|
|
27
|
+
const { acquirePage } = yield* BrowserService;
|
|
28
|
+
const page = yield* acquirePage;
|
|
29
|
+
const fieldsCompleted = [];
|
|
30
|
+
const intakeFieldsCompleted = [];
|
|
31
|
+
// Fill or verify each standard field
|
|
32
|
+
yield* fillField(page, Selectors.firstNameInput, params.client.firstName, 'firstName');
|
|
33
|
+
fieldsCompleted.push('firstName');
|
|
34
|
+
yield* fillField(page, Selectors.lastNameInput, params.client.lastName, 'lastName');
|
|
35
|
+
fieldsCompleted.push('lastName');
|
|
36
|
+
yield* fillField(page, Selectors.emailInput, params.client.email, 'email');
|
|
37
|
+
fieldsCompleted.push('email');
|
|
38
|
+
if (params.client.phone) {
|
|
39
|
+
yield* fillField(page, Selectors.phoneInput, params.client.phone, 'phone');
|
|
40
|
+
fieldsCompleted.push('phone');
|
|
41
|
+
}
|
|
42
|
+
// Fill custom intake fields (by field ID)
|
|
43
|
+
const customFieldsCompleted = [];
|
|
44
|
+
if (params.customFields) {
|
|
45
|
+
for (const [fieldId, value] of Object.entries(params.customFields)) {
|
|
46
|
+
const filled = yield* fillCustomField(page, fieldId, value);
|
|
47
|
+
if (filled)
|
|
48
|
+
customFieldsCompleted.push(fieldId);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Fill intake radio buttons (yes/no questions)
|
|
52
|
+
const radioAnswer = params.intakeRadioAnswer ?? 'no';
|
|
53
|
+
yield* fillIntakeRadios(page, radioAnswer);
|
|
54
|
+
intakeFieldsCompleted.push('radioButtons');
|
|
55
|
+
// Fill "How did you hear" checkbox
|
|
56
|
+
const hearOption = params.howDidYouHear ?? 'Internet search';
|
|
57
|
+
yield* fillHowDidYouHear(page, hearOption);
|
|
58
|
+
intakeFieldsCompleted.push('howDidYouHear');
|
|
59
|
+
// Fill medication textarea
|
|
60
|
+
const medication = params.medication ?? 'None';
|
|
61
|
+
yield* fillMedication(page, medication);
|
|
62
|
+
intakeFieldsCompleted.push('medication');
|
|
63
|
+
// Fill terms checkbox
|
|
64
|
+
yield* fillTermsCheckbox(page);
|
|
65
|
+
intakeFieldsCompleted.push('termsCheckbox');
|
|
66
|
+
// Click continue/next to advance past client form
|
|
67
|
+
const advanced = yield* advancePastForm(page);
|
|
68
|
+
return {
|
|
69
|
+
fieldsCompleted,
|
|
70
|
+
customFieldsCompleted,
|
|
71
|
+
intakeFieldsCompleted,
|
|
72
|
+
advanced,
|
|
73
|
+
};
|
|
74
|
+
}).pipe(Effect.catchTag('SelectorError', (e) => Effect.fail(new WizardStepError({
|
|
75
|
+
step: 'fill-form',
|
|
76
|
+
message: `Form field not found: ${e.message}`,
|
|
77
|
+
cause: e,
|
|
78
|
+
}))));
|
|
79
|
+
// =============================================================================
|
|
80
|
+
// HELPERS
|
|
81
|
+
// =============================================================================
|
|
82
|
+
/**
|
|
83
|
+
* Fill a form field. If the field already has the correct value
|
|
84
|
+
* (from URL pre-fill), skip it. Otherwise clear and fill.
|
|
85
|
+
*/
|
|
86
|
+
const fillField = (page, candidates, value, fieldName) => Effect.gen(function* () {
|
|
87
|
+
const { element, selector } = yield* resolveSelector(page, candidates, 5000);
|
|
88
|
+
// Check current value
|
|
89
|
+
const currentValue = yield* Effect.tryPromise({
|
|
90
|
+
try: () => page.$eval(selector, (el) => el.value),
|
|
91
|
+
catch: () => '',
|
|
92
|
+
}).pipe(Effect.orElseSucceed(() => ''));
|
|
93
|
+
// Skip if already correct
|
|
94
|
+
if (currentValue.trim().toLowerCase() === value.trim().toLowerCase()) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
// Clear and fill
|
|
98
|
+
yield* Effect.tryPromise({
|
|
99
|
+
try: async () => {
|
|
100
|
+
await element.click({ clickCount: 3 }); // Select all
|
|
101
|
+
await element.fill(value);
|
|
102
|
+
},
|
|
103
|
+
catch: (e) => new WizardStepError({
|
|
104
|
+
step: 'fill-form',
|
|
105
|
+
message: `Failed to fill ${fieldName}: ${e instanceof Error ? e.message : String(e)}`,
|
|
106
|
+
cause: e,
|
|
107
|
+
}),
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
/**
|
|
111
|
+
* Fill a custom Acuity intake field by field ID.
|
|
112
|
+
* Acuity custom fields use `field:XXXX` name pattern.
|
|
113
|
+
*/
|
|
114
|
+
const fillCustomField = (page, fieldId, value) => Effect.gen(function* () {
|
|
115
|
+
const selectors = [
|
|
116
|
+
`[name="fields[field-${fieldId}]"]`,
|
|
117
|
+
`input[id*="${fieldId}"]`,
|
|
118
|
+
`textarea[name*="${fieldId}"]`,
|
|
119
|
+
`[data-field-id="${fieldId}"]`,
|
|
120
|
+
];
|
|
121
|
+
const result = yield* resolveSelector(page, selectors, 2000).pipe(Effect.map((resolved) => resolved), Effect.orElseSucceed(() => null));
|
|
122
|
+
if (!result)
|
|
123
|
+
return false;
|
|
124
|
+
yield* Effect.tryPromise({
|
|
125
|
+
try: async () => {
|
|
126
|
+
const tagName = await result.element.evaluate((el) => el.tagName.toLowerCase());
|
|
127
|
+
if (tagName === 'select') {
|
|
128
|
+
await page.selectOption(result.selector, value);
|
|
129
|
+
}
|
|
130
|
+
else if (tagName === 'textarea') {
|
|
131
|
+
await result.element.fill(value);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
const inputType = await result.element.evaluate((el) => el.type);
|
|
135
|
+
if (inputType === 'checkbox') {
|
|
136
|
+
const checked = await result.element.isChecked();
|
|
137
|
+
if ((value === 'true') !== checked) {
|
|
138
|
+
await result.element.click();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
await result.element.fill(value);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
catch: () => null,
|
|
147
|
+
}).pipe(Effect.orElseSucceed(() => null));
|
|
148
|
+
return true;
|
|
149
|
+
});
|
|
150
|
+
/**
|
|
151
|
+
* Fill intake radio buttons.
|
|
152
|
+
*
|
|
153
|
+
* Acuity's radio buttons have NO name or id attributes — they are purely
|
|
154
|
+
* React-controlled. The proven strategy is to click the <label> element
|
|
155
|
+
* wrapping each radio via Playwright's locator().nth() API, which dispatches
|
|
156
|
+
* OS-level mouse events that React's event delegation handles correctly.
|
|
157
|
+
*/
|
|
158
|
+
const fillIntakeRadios = (page, answer) => Effect.tryPromise({
|
|
159
|
+
try: async () => {
|
|
160
|
+
const selectorKey = answer === 'no' ? Selectors.radioNoLabel : Selectors.radioYesLabel;
|
|
161
|
+
const labelLocator = page.locator(selectorKey[0]);
|
|
162
|
+
const count = await labelLocator.count();
|
|
163
|
+
for (let i = 0; i < count; i++) {
|
|
164
|
+
await labelLocator.nth(i).scrollIntoViewIfNeeded();
|
|
165
|
+
await labelLocator.nth(i).click({ timeout: 5000 });
|
|
166
|
+
await page.waitForTimeout(200);
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
catch: (e) => new WizardStepError({
|
|
170
|
+
step: 'fill-form',
|
|
171
|
+
message: `Failed to fill radio buttons: ${e instanceof Error ? e.message : String(e)}`,
|
|
172
|
+
cause: e,
|
|
173
|
+
}),
|
|
174
|
+
});
|
|
175
|
+
/**
|
|
176
|
+
* Select at least one "How did you hear" checkbox.
|
|
177
|
+
*
|
|
178
|
+
* These checkboxes have plain-text name attributes like "Internet search".
|
|
179
|
+
* Uses the same label-click locator strategy as radio buttons.
|
|
180
|
+
*/
|
|
181
|
+
const fillHowDidYouHear = (page, option) => Effect.tryPromise({
|
|
182
|
+
try: async () => {
|
|
183
|
+
const labelLocator = page.locator(`label:has(input[type="checkbox"][name="${option}"])`);
|
|
184
|
+
const count = await labelLocator.count();
|
|
185
|
+
if (count > 0) {
|
|
186
|
+
await labelLocator.first().scrollIntoViewIfNeeded();
|
|
187
|
+
await labelLocator.first().click({ timeout: 3000 });
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
// Fallback: click the first non-terms checkbox
|
|
191
|
+
const fallback = page.locator('input[type="checkbox"]:not([name*="field-13933959"])');
|
|
192
|
+
const fallbackCount = await fallback.count();
|
|
193
|
+
if (fallbackCount > 0) {
|
|
194
|
+
const parent = page.locator('label:has(input[type="checkbox"]:not([name*="field-13933959"]))');
|
|
195
|
+
await parent.first().scrollIntoViewIfNeeded();
|
|
196
|
+
await parent.first().click({ timeout: 3000 });
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
catch: (e) => new WizardStepError({
|
|
201
|
+
step: 'fill-form',
|
|
202
|
+
message: `Failed to fill "How did you hear": ${e instanceof Error ? e.message : String(e)}`,
|
|
203
|
+
cause: e,
|
|
204
|
+
}),
|
|
205
|
+
});
|
|
206
|
+
/**
|
|
207
|
+
* Fill the medication textarea.
|
|
208
|
+
*/
|
|
209
|
+
const fillMedication = (page, text) => Effect.tryPromise({
|
|
210
|
+
try: async () => {
|
|
211
|
+
for (const selector of Selectors.medicationField) {
|
|
212
|
+
const el = await page.$(selector);
|
|
213
|
+
if (el) {
|
|
214
|
+
await el.fill(text);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
catch: () => undefined,
|
|
220
|
+
}).pipe(Effect.orElseSucceed(() => undefined));
|
|
221
|
+
/**
|
|
222
|
+
* Check the terms agreement checkbox via label click.
|
|
223
|
+
*/
|
|
224
|
+
const fillTermsCheckbox = (page) => Effect.tryPromise({
|
|
225
|
+
try: async () => {
|
|
226
|
+
const isChecked = await page
|
|
227
|
+
.$eval(Selectors.termsCheckbox[0], (el) => el.checked)
|
|
228
|
+
.catch(() => false);
|
|
229
|
+
if (!isChecked) {
|
|
230
|
+
const label = page.locator(`label:has(${Selectors.termsCheckbox[0]})`);
|
|
231
|
+
await label.scrollIntoViewIfNeeded();
|
|
232
|
+
await label.click({ timeout: 3000 });
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
catch: () => undefined,
|
|
236
|
+
}).pipe(Effect.orElseSucceed(() => undefined));
|
|
237
|
+
/**
|
|
238
|
+
* Click "Continue to Payment" to advance past the client form.
|
|
239
|
+
*
|
|
240
|
+
* Verified 2026-02-26: "Continue to Payment" navigates to a SEPARATE
|
|
241
|
+
* payment page at URL .../datetime/<ISO>/payment.
|
|
242
|
+
*/
|
|
243
|
+
const advancePastForm = (page) => Effect.gen(function* () {
|
|
244
|
+
const continueBtn = yield* resolveSelector(page, Selectors.continueToPayment, 5000).pipe(Effect.catchTag('SelectorError', () => Effect.fail(new WizardStepError({
|
|
245
|
+
step: 'fill-form',
|
|
246
|
+
message: '"Continue to Payment" button not found after filling form',
|
|
247
|
+
}))));
|
|
248
|
+
yield* Effect.tryPromise({
|
|
249
|
+
try: async () => {
|
|
250
|
+
await continueBtn.element.click();
|
|
251
|
+
// Wait for navigation to payment page (URL ends in /payment)
|
|
252
|
+
await page.waitForURL((url) => url.href.includes('/payment'), { timeout: 15000 });
|
|
253
|
+
},
|
|
254
|
+
catch: (e) => new WizardStepError({
|
|
255
|
+
step: 'fill-form',
|
|
256
|
+
message: `Failed to advance to payment page: ${e instanceof Error ? e.message : String(e)}`,
|
|
257
|
+
cause: e,
|
|
258
|
+
}),
|
|
259
|
+
});
|
|
260
|
+
return true;
|
|
261
|
+
});
|
|
262
|
+
//# sourceMappingURL=fill-form.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fill-form.js","sourceRoot":"","sources":["../../../src/middleware/steps/fill-form.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wizard Steps - Individual programs for each stage of the Acuity wizard.
|
|
3
|
+
*/
|
|
4
|
+
export { navigateToBooking, type NavigateParams, type NavigateResult } from './navigate.js';
|
|
5
|
+
export { fillFormFields, type FillFormParams, type FillFormResult } from './fill-form.js';
|
|
6
|
+
export { bypassPayment, generateCouponCode, type BypassPaymentResult, } from './bypass-payment.js';
|
|
7
|
+
export { submitBooking, type SubmitResult } from './submit.js';
|
|
8
|
+
export { extractConfirmation, toBooking, type ConfirmationData, } from './extract.js';
|
|
9
|
+
export { readAvailableDates, type ReadAvailabilityParams, type AvailableDateResult, } from './read-availability.js';
|
|
10
|
+
export { readTimeSlots, type ReadSlotsParams, type SlotResult, } from './read-slots.js';
|
|
11
|
+
export { extractBusinessFromPage, extractBusinessFromHtml, extractBusinessServices, fetchBusinessData, businessToServices, type AcuityAppointmentType, type AcuityCalendar, type AcuityBusinessData, } from './extract-business.js';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/middleware/steps/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,iBAAiB,EAAE,KAAK,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAC5F,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC1F,OAAO,EACN,aAAa,EACb,kBAAkB,EAClB,KAAK,mBAAmB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EACN,mBAAmB,EACnB,SAAS,EACT,KAAK,gBAAgB,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EACN,kBAAkB,EAClB,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,GACxB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACN,aAAa,EACb,KAAK,eAAe,EACpB,KAAK,UAAU,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACN,uBAAuB,EACvB,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,kBAAkB,GACvB,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wizard Steps - Individual programs for each stage of the Acuity wizard.
|
|
3
|
+
*/
|
|
4
|
+
export { navigateToBooking } from './navigate.js';
|
|
5
|
+
export { fillFormFields } from './fill-form.js';
|
|
6
|
+
export { bypassPayment, generateCouponCode, } from './bypass-payment.js';
|
|
7
|
+
export { submitBooking } from './submit.js';
|
|
8
|
+
export { extractConfirmation, toBooking, } from './extract.js';
|
|
9
|
+
export { readAvailableDates, } from './read-availability.js';
|
|
10
|
+
export { readTimeSlots, } from './read-slots.js';
|
|
11
|
+
export { extractBusinessFromPage, extractBusinessFromHtml, extractBusinessServices, fetchBusinessData, businessToServices, } from './extract-business.js';
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/middleware/steps/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,iBAAiB,EAA4C,MAAM,eAAe,CAAC;AAC5F,OAAO,EAAE,cAAc,EAA4C,MAAM,gBAAgB,CAAC;AAC1F,OAAO,EACN,aAAa,EACb,kBAAkB,GAElB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAqB,MAAM,aAAa,CAAC;AAC/D,OAAO,EACN,mBAAmB,EACnB,SAAS,GAET,MAAM,cAAc,CAAC;AACtB,OAAO,EACN,kBAAkB,GAGlB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACN,aAAa,GAGb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACN,uBAAuB,EACvB,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,EACjB,kBAAkB,GAIlB,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wizard Step: Navigate Through Acuity Booking Wizard
|
|
3
|
+
*
|
|
4
|
+
* Acuity's React SPA (2026) does NOT support deep-linking via query params.
|
|
5
|
+
* Instead, we click through the 5-step wizard:
|
|
6
|
+
* 1. Service page (massageithaca.as.me) → find service → click "Book"
|
|
7
|
+
* 2. Calendar page → navigate to target month → click target day
|
|
8
|
+
* 3. Time slots → click matching slot → "Select and continue"
|
|
9
|
+
* 4. Land on client form (fields empty — filling is a separate step)
|
|
10
|
+
*
|
|
11
|
+
* URL progression:
|
|
12
|
+
* /schedule/<hash>
|
|
13
|
+
* /schedule/<hash>/appointment/<aptId>/calendar/<calId>
|
|
14
|
+
* /schedule/<hash>/appointment/<aptId>/calendar/<calId>/datetime/<ISO>
|
|
15
|
+
*/
|
|
16
|
+
import { Effect } from 'effect';
|
|
17
|
+
import { BrowserService } from '../browser-service.js';
|
|
18
|
+
import { WizardStepError } from '../errors.js';
|
|
19
|
+
import type { ClientInfo } from '../../core/types.js';
|
|
20
|
+
export interface NavigateParams {
|
|
21
|
+
/** Appointment type name (matched against .appointment-type-name text) */
|
|
22
|
+
readonly serviceName: string;
|
|
23
|
+
/** Target datetime in ISO 8601 (e.g. "2026-03-15T10:00:00-05:00") */
|
|
24
|
+
readonly datetime: string;
|
|
25
|
+
/** Client info (not used for navigation — kept for API compat) */
|
|
26
|
+
readonly client: ClientInfo;
|
|
27
|
+
/** Appointment type ID — if known, verified against URL after "Book" click */
|
|
28
|
+
readonly appointmentTypeId?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface NavigateResult {
|
|
31
|
+
readonly url: string;
|
|
32
|
+
readonly landingStep: 'client-form' | 'service-selection' | 'calendar' | 'time-slots' | 'unknown';
|
|
33
|
+
readonly appointmentTypeId: string | null;
|
|
34
|
+
readonly calendarId: string | null;
|
|
35
|
+
readonly selectedDate: string;
|
|
36
|
+
readonly selectedTime: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Navigate through the Acuity wizard to reach the client form.
|
|
40
|
+
*
|
|
41
|
+
* Flow: Service page → Book → Calendar → Time slot → Select and continue
|
|
42
|
+
*/
|
|
43
|
+
export declare const navigateToBooking: (params: NavigateParams) => Effect.Effect<{
|
|
44
|
+
url: string;
|
|
45
|
+
landingStep: "calendar" | "client-form" | "service-selection" | "time-slots" | "unknown";
|
|
46
|
+
appointmentTypeId: string | null;
|
|
47
|
+
calendarId: string | null;
|
|
48
|
+
selectedDate: string;
|
|
49
|
+
selectedTime: string;
|
|
50
|
+
}, import("../errors.js").BrowserError | WizardStepError, import("effect/Scope").Scope | BrowserService>;
|
|
51
|
+
//# sourceMappingURL=navigate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigate.d.ts","sourceRoot":"","sources":["../../../src/middleware/steps/navigate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAMtD,MAAM,WAAW,cAAc;IAC9B,0EAA0E;IAC1E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,8EAA8E;IAC9E,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,WAAW,EAAE,aAAa,GAAG,mBAAmB,GAAG,UAAU,GAAG,YAAY,GAAG,SAAS,CAAC;IAClG,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC9B;AAMD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,cAAc;;;;;;;wGA8CrD,CAAC"}
|