@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.
Files changed (148) hide show
  1. package/dist/adapters/acuity-scraper.d.ts +8 -0
  2. package/dist/adapters/acuity-scraper.d.ts.map +1 -0
  3. package/dist/adapters/acuity-scraper.js +8 -0
  4. package/dist/adapters/acuity-scraper.js.map +1 -0
  5. package/dist/adapters/types.d.ts +8 -0
  6. package/dist/adapters/types.d.ts.map +1 -0
  7. package/dist/adapters/types.js +8 -0
  8. package/dist/adapters/types.js.map +1 -0
  9. package/dist/core/types.d.ts +10 -0
  10. package/dist/core/types.d.ts.map +1 -0
  11. package/dist/core/types.js +2 -0
  12. package/dist/core/types.js.map +1 -0
  13. package/dist/index.d.ts +17 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +18 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/middleware/acuity-wizard.d.ts +49 -0
  18. package/dist/middleware/acuity-wizard.d.ts.map +1 -0
  19. package/dist/middleware/acuity-wizard.js +265 -0
  20. package/dist/middleware/acuity-wizard.js.map +1 -0
  21. package/dist/middleware/browser-service.d.ts +53 -0
  22. package/dist/middleware/browser-service.d.ts.map +1 -0
  23. package/dist/middleware/browser-service.js +105 -0
  24. package/dist/middleware/browser-service.js.map +1 -0
  25. package/dist/middleware/errors.d.ts +58 -0
  26. package/dist/middleware/errors.d.ts.map +1 -0
  27. package/dist/middleware/errors.js +43 -0
  28. package/dist/middleware/errors.js.map +1 -0
  29. package/{src/middleware/index.ts → dist/middleware/index.d.ts} +5 -52
  30. package/dist/middleware/index.d.ts.map +1 -0
  31. package/dist/middleware/index.js +38 -0
  32. package/dist/middleware/index.js.map +1 -0
  33. package/dist/middleware/logger.d.ts +26 -0
  34. package/dist/middleware/logger.d.ts.map +1 -0
  35. package/dist/middleware/logger.js +65 -0
  36. package/dist/middleware/logger.js.map +1 -0
  37. package/dist/middleware/remote-adapter.d.ts +45 -0
  38. package/dist/middleware/remote-adapter.d.ts.map +1 -0
  39. package/dist/middleware/remote-adapter.js +178 -0
  40. package/dist/middleware/remote-adapter.js.map +1 -0
  41. package/dist/middleware/selector-health.d.ts +44 -0
  42. package/dist/middleware/selector-health.d.ts.map +1 -0
  43. package/dist/middleware/selector-health.js +144 -0
  44. package/dist/middleware/selector-health.js.map +1 -0
  45. package/dist/middleware/selectors.d.ts +108 -0
  46. package/dist/middleware/selectors.d.ts.map +1 -0
  47. package/dist/middleware/selectors.js +249 -0
  48. package/dist/middleware/selectors.js.map +1 -0
  49. package/dist/middleware/server.d.ts +34 -0
  50. package/dist/middleware/server.d.ts.map +1 -0
  51. package/dist/middleware/server.js +377 -0
  52. package/dist/middleware/server.js.map +1 -0
  53. package/dist/middleware/service-resolver.d.ts +46 -0
  54. package/dist/middleware/service-resolver.d.ts.map +1 -0
  55. package/dist/middleware/service-resolver.js +274 -0
  56. package/dist/middleware/service-resolver.js.map +1 -0
  57. package/dist/middleware/slot-parser.d.ts +29 -0
  58. package/dist/middleware/slot-parser.d.ts.map +1 -0
  59. package/dist/middleware/slot-parser.js +50 -0
  60. package/dist/middleware/slot-parser.js.map +1 -0
  61. package/dist/middleware/steps/__tests__/fixtures.d.ts +14 -0
  62. package/dist/middleware/steps/__tests__/fixtures.d.ts.map +1 -0
  63. package/dist/middleware/steps/__tests__/fixtures.js +204 -0
  64. package/dist/middleware/steps/__tests__/fixtures.js.map +1 -0
  65. package/dist/middleware/steps/bypass-payment.d.ts +54 -0
  66. package/dist/middleware/steps/bypass-payment.d.ts.map +1 -0
  67. package/dist/middleware/steps/bypass-payment.js +164 -0
  68. package/dist/middleware/steps/bypass-payment.js.map +1 -0
  69. package/dist/middleware/steps/extract-business.d.ts +93 -0
  70. package/dist/middleware/steps/extract-business.d.ts.map +1 -0
  71. package/dist/middleware/steps/extract-business.js +170 -0
  72. package/dist/middleware/steps/extract-business.js.map +1 -0
  73. package/dist/middleware/steps/extract.d.ts +41 -0
  74. package/dist/middleware/steps/extract.d.ts.map +1 -0
  75. package/dist/middleware/steps/extract.js +128 -0
  76. package/dist/middleware/steps/extract.js.map +1 -0
  77. package/dist/middleware/steps/fill-form.d.ts +45 -0
  78. package/dist/middleware/steps/fill-form.d.ts.map +1 -0
  79. package/dist/middleware/steps/fill-form.js +262 -0
  80. package/dist/middleware/steps/fill-form.js.map +1 -0
  81. package/dist/middleware/steps/index.d.ts +12 -0
  82. package/dist/middleware/steps/index.d.ts.map +1 -0
  83. package/dist/middleware/steps/index.js +12 -0
  84. package/dist/middleware/steps/index.js.map +1 -0
  85. package/dist/middleware/steps/navigate.d.ts +51 -0
  86. package/dist/middleware/steps/navigate.d.ts.map +1 -0
  87. package/dist/middleware/steps/navigate.js +391 -0
  88. package/dist/middleware/steps/navigate.js.map +1 -0
  89. package/dist/middleware/steps/read-availability.d.ts +37 -0
  90. package/dist/middleware/steps/read-availability.d.ts.map +1 -0
  91. package/dist/middleware/steps/read-availability.js +298 -0
  92. package/dist/middleware/steps/read-availability.js.map +1 -0
  93. package/dist/middleware/steps/read-slots.d.ts +33 -0
  94. package/dist/middleware/steps/read-slots.d.ts.map +1 -0
  95. package/dist/middleware/steps/read-slots.js +295 -0
  96. package/dist/middleware/steps/read-slots.js.map +1 -0
  97. package/dist/middleware/steps/read-via-url.d.ts +39 -0
  98. package/dist/middleware/steps/read-via-url.d.ts.map +1 -0
  99. package/dist/middleware/steps/read-via-url.js +141 -0
  100. package/dist/middleware/steps/read-via-url.js.map +1 -0
  101. package/dist/middleware/steps/submit.d.ts +22 -0
  102. package/dist/middleware/steps/submit.d.ts.map +1 -0
  103. package/dist/middleware/steps/submit.js +112 -0
  104. package/dist/middleware/steps/submit.js.map +1 -0
  105. package/dist/middleware/wizard-calendar.d.ts +37 -0
  106. package/dist/middleware/wizard-calendar.d.ts.map +1 -0
  107. package/dist/middleware/wizard-calendar.js +177 -0
  108. package/dist/middleware/wizard-calendar.js.map +1 -0
  109. package/dist/middleware/wizard-service.d.ts +30 -0
  110. package/dist/middleware/wizard-service.d.ts.map +1 -0
  111. package/dist/middleware/wizard-service.js +89 -0
  112. package/dist/middleware/wizard-service.js.map +1 -0
  113. package/dist/server.d.ts +6 -0
  114. package/dist/server.d.ts.map +1 -0
  115. package/{src/server.ts → dist/server.js} +1 -0
  116. package/dist/server.js.map +1 -0
  117. package/package.json +16 -4
  118. package/.github/workflows/build-paper.yml +0 -39
  119. package/.github/workflows/ci.yml +0 -37
  120. package/Dockerfile +0 -53
  121. package/docs/blog-post.mdx +0 -240
  122. package/docs/paper/IEEEtran.bst +0 -2409
  123. package/docs/paper/IEEEtran.cls +0 -6347
  124. package/docs/paper/acuity-middleware-paper.tex +0 -375
  125. package/docs/paper/balance.sty +0 -87
  126. package/docs/paper/references.bib +0 -231
  127. package/docs/paper.md +0 -400
  128. package/flake.nix +0 -32
  129. package/modal-app.py +0 -82
  130. package/src/adapters/acuity-scraper.ts +0 -543
  131. package/src/adapters/types.ts +0 -193
  132. package/src/core/types.ts +0 -325
  133. package/src/index.ts +0 -75
  134. package/src/middleware/acuity-wizard.ts +0 -456
  135. package/src/middleware/browser-service.ts +0 -183
  136. package/src/middleware/errors.ts +0 -70
  137. package/src/middleware/remote-adapter.ts +0 -246
  138. package/src/middleware/selectors.ts +0 -308
  139. package/src/middleware/server.ts +0 -372
  140. package/src/middleware/steps/bypass-payment.ts +0 -226
  141. package/src/middleware/steps/extract.ts +0 -174
  142. package/src/middleware/steps/fill-form.ts +0 -359
  143. package/src/middleware/steps/index.ts +0 -27
  144. package/src/middleware/steps/navigate.ts +0 -537
  145. package/src/middleware/steps/read-availability.ts +0 -399
  146. package/src/middleware/steps/read-slots.ts +0 -405
  147. package/src/middleware/steps/submit.ts +0 -168
  148. package/tsconfig.json +0 -25
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Middleware Error Types
3
+ *
4
+ * Effect TS error types for the Acuity wizard middleware.
5
+ * Bridges to fp-ts SchedulingError at the adapter boundary.
6
+ */
7
+ import { type SchedulingError } from '../core/types.js';
8
+ declare const BrowserError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
9
+ readonly _tag: "BrowserError";
10
+ } & Readonly<A>;
11
+ export declare class BrowserError extends BrowserError_base<{
12
+ readonly reason: 'PLAYWRIGHT_MISSING' | 'LAUNCH_FAILED' | 'PAGE_FAILED' | 'SCREENSHOT_FAILED' | 'NAVIGATION_FAILED';
13
+ readonly cause?: unknown;
14
+ }> {
15
+ }
16
+ declare const SelectorError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
17
+ readonly _tag: "SelectorError";
18
+ } & Readonly<A>;
19
+ export declare class SelectorError extends SelectorError_base<{
20
+ readonly candidates: readonly string[];
21
+ readonly message: string;
22
+ }> {
23
+ }
24
+ declare const WizardStepError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
25
+ readonly _tag: "WizardStepError";
26
+ } & Readonly<A>;
27
+ export declare class WizardStepError extends WizardStepError_base<{
28
+ readonly step: 'navigate' | 'fill-form' | 'bypass-payment' | 'submit' | 'extract' | 'read-availability' | 'read-slots' | 'extract-business';
29
+ readonly message: string;
30
+ readonly screenshot?: Buffer;
31
+ readonly cause?: unknown;
32
+ }> {
33
+ }
34
+ declare const CouponError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
35
+ readonly _tag: "CouponError";
36
+ } & Readonly<A>;
37
+ export declare class CouponError extends CouponError_base<{
38
+ readonly code: string;
39
+ readonly message: string;
40
+ }> {
41
+ }
42
+ declare const ServiceResolverError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
43
+ readonly _tag: "ServiceResolverError";
44
+ } & Readonly<A>;
45
+ export declare class ServiceResolverError extends ServiceResolverError_base<{
46
+ readonly serviceName: string;
47
+ readonly strategies: readonly string[];
48
+ readonly message: string;
49
+ }> {
50
+ }
51
+ export type MiddlewareError = BrowserError | SelectorError | WizardStepError | CouponError | ServiceResolverError;
52
+ /**
53
+ * Convert Effect middleware errors to fp-ts SchedulingError
54
+ * for compatibility with the existing booking pipeline.
55
+ */
56
+ export declare const toSchedulingError: (error: MiddlewareError) => SchedulingError;
57
+ export {};
58
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/middleware/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAU,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;;;;AAMhE,qBAAa,YAAa,SAAQ,kBAAiC;IAClE,QAAQ,CAAC,MAAM,EACZ,oBAAoB,GACpB,eAAe,GACf,aAAa,GACb,mBAAmB,GACnB,mBAAmB,CAAC;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;CAAG;;;;AAEL,qBAAa,aAAc,SAAQ,mBAAkC;IACpE,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB,CAAC;CAAG;;;;AAEL,qBAAa,eAAgB,SAAQ,qBAAoC;IACxE,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,WAAW,GAAG,gBAAgB,GAAG,QAAQ,GAAG,SAAS,GAAG,mBAAmB,GAAG,YAAY,GAAG,kBAAkB,CAAC;IAC5I,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;CAAG;;;;AAEL,qBAAa,WAAY,SAAQ,iBAAgC;IAChE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB,CAAC;CAAG;;;;AAEL,qBAAa,oBAAqB,SAAQ,0BAAyC;IAClF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB,CAAC;CAAG;AAEL,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,aAAa,GAAG,eAAe,GAAG,WAAW,GAAG,oBAAoB,CAAC;AAMlH;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,eAAe,KAAG,eAoB1D,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Middleware Error Types
3
+ *
4
+ * Effect TS error types for the Acuity wizard middleware.
5
+ * Bridges to fp-ts SchedulingError at the adapter boundary.
6
+ */
7
+ import { Data } from 'effect';
8
+ import { Errors } from '../core/types.js';
9
+ // =============================================================================
10
+ // ERROR CLASSES
11
+ // =============================================================================
12
+ export class BrowserError extends Data.TaggedError('BrowserError') {
13
+ }
14
+ export class SelectorError extends Data.TaggedError('SelectorError') {
15
+ }
16
+ export class WizardStepError extends Data.TaggedError('WizardStepError') {
17
+ }
18
+ export class CouponError extends Data.TaggedError('CouponError') {
19
+ }
20
+ export class ServiceResolverError extends Data.TaggedError('ServiceResolverError') {
21
+ }
22
+ // =============================================================================
23
+ // BRIDGE: Effect errors -> fp-ts SchedulingError
24
+ // =============================================================================
25
+ /**
26
+ * Convert Effect middleware errors to fp-ts SchedulingError
27
+ * for compatibility with the existing booking pipeline.
28
+ */
29
+ export const toSchedulingError = (error) => {
30
+ switch (error._tag) {
31
+ case 'BrowserError':
32
+ return Errors.infrastructure(error.reason === 'PLAYWRIGHT_MISSING' ? 'UNKNOWN' : 'NETWORK', `Browser error: ${error.reason}`, error.cause instanceof Error ? error.cause : undefined);
33
+ case 'SelectorError':
34
+ return Errors.acuity('SCRAPE_FAILED', error.message);
35
+ case 'WizardStepError':
36
+ return Errors.acuity('SCRAPE_FAILED', `Wizard step '${error.step}' failed: ${error.message}`);
37
+ case 'CouponError':
38
+ return Errors.acuity('BOOKING_FAILED', `Coupon error: ${error.message}`);
39
+ case 'ServiceResolverError':
40
+ return Errors.acuity('SCRAPE_FAILED', `Service resolution failed: ${error.message}`);
41
+ }
42
+ };
43
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/middleware/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAwB,MAAM,kBAAkB,CAAC;AAEhE,gFAAgF;AAChF,gBAAgB;AAChB,gFAAgF;AAEhF,MAAM,OAAO,YAAa,SAAQ,IAAI,CAAC,WAAW,CAAC,cAAc,CAQ/D;CAAG;AAEL,MAAM,OAAO,aAAc,SAAQ,IAAI,CAAC,WAAW,CAAC,eAAe,CAGjE;CAAG;AAEL,MAAM,OAAO,eAAgB,SAAQ,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAKrE;CAAG;AAEL,MAAM,OAAO,WAAY,SAAQ,IAAI,CAAC,WAAW,CAAC,aAAa,CAG7D;CAAG;AAEL,MAAM,OAAO,oBAAqB,SAAQ,IAAI,CAAC,WAAW,CAAC,sBAAsB,CAI/E;CAAG;AAIL,gFAAgF;AAChF,iDAAiD;AACjD,gFAAgF;AAEhF;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAsB,EAAmB,EAAE;IAC5E,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,cAAc;YAClB,OAAO,MAAM,CAAC,cAAc,CAC3B,KAAK,CAAC,MAAM,KAAK,oBAAoB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EAC7D,kBAAkB,KAAK,CAAC,MAAM,EAAE,EAChC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CACtD,CAAC;QACH,KAAK,eAAe;YACnB,OAAO,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QACtD,KAAK,iBAAiB;YACrB,OAAO,MAAM,CAAC,MAAM,CACnB,eAAe,EACf,gBAAgB,KAAK,CAAC,IAAI,aAAa,KAAK,CAAC,OAAO,EAAE,CACtD,CAAC;QACH,KAAK,aAAa;YACjB,OAAO,MAAM,CAAC,MAAM,CAAC,gBAAgB,EAAE,iBAAiB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC1E,KAAK,sBAAsB;YAC1B,OAAO,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,8BAA8B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IACvF,CAAC;AACF,CAAC,CAAC"}
@@ -24,57 +24,10 @@
24
24
  * const result = await kit.completeBooking(request, 'venmo')();
25
25
  * ```
26
26
  */
27
-
28
- // Adapter factories
29
27
  export { createWizardAdapter, type WizardAdapterConfig } from './acuity-wizard.js';
30
28
  export { createRemoteWizardAdapter, type RemoteAdapterConfig } from './remote-adapter.js';
31
-
32
- // Browser service (for custom Layer composition)
33
- export {
34
- BrowserService,
35
- BrowserServiceLive,
36
- BrowserServiceTest,
37
- defaultBrowserConfig,
38
- type BrowserConfig,
39
- type BrowserServiceShape,
40
- } from './browser-service.js';
41
-
42
- // Error types and bridge
43
- export {
44
- BrowserError,
45
- SelectorError,
46
- WizardStepError,
47
- CouponError,
48
- toSchedulingError,
49
- type MiddlewareError,
50
- } from './errors.js';
51
-
52
- // Selector registry
53
- export {
54
- Selectors,
55
- resolveSelector,
56
- resolve,
57
- probeSelector,
58
- probe,
59
- healthCheck,
60
- type SelectorKey,
61
- type ResolvedSelector,
62
- } from './selectors.js';
63
-
64
- // Individual wizard steps (for advanced composition)
65
- export {
66
- navigateToBooking,
67
- fillFormFields,
68
- bypassPayment,
69
- generateCouponCode,
70
- submitBooking,
71
- extractConfirmation,
72
- toBooking,
73
- type NavigateParams,
74
- type NavigateResult,
75
- type FillFormParams,
76
- type FillFormResult,
77
- type BypassPaymentResult,
78
- type SubmitResult,
79
- type ConfirmationData,
80
- } from './steps/index.js';
29
+ export { BrowserService, BrowserServiceLive, BrowserServiceTest, defaultBrowserConfig, type BrowserConfig, type BrowserServiceShape, } from './browser-service.js';
30
+ export { BrowserError, SelectorError, WizardStepError, CouponError, toSchedulingError, type MiddlewareError, } from './errors.js';
31
+ export { Selectors, resolveSelector, resolve, probeSelector, probe, healthCheck, type SelectorKey, type ResolvedSelector, } from './selectors.js';
32
+ export { navigateToBooking, fillFormFields, bypassPayment, generateCouponCode, submitBooking, extractConfirmation, toBooking, type NavigateParams, type NavigateResult, type FillFormParams, type FillFormResult, type BypassPaymentResult, type SubmitResult, type ConfirmationData, } from './steps/index.js';
33
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,EAAE,mBAAmB,EAAE,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACnF,OAAO,EAAE,yBAAyB,EAAE,KAAK,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAG1F,OAAO,EACN,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,KAAK,aAAa,EAClB,KAAK,mBAAmB,GACxB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACN,YAAY,EACZ,aAAa,EACb,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,KAAK,eAAe,GACpB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACN,SAAS,EACT,eAAe,EACf,OAAO,EACP,aAAa,EACb,KAAK,EACL,WAAW,EACX,KAAK,WAAW,EAChB,KAAK,gBAAgB,GACrB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACN,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,SAAS,EACT,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,gBAAgB,GACrB,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Middleware Module - Server-only Acuity wizard automation
3
+ *
4
+ * This module provides the Effect TS-based browser middleware for
5
+ * puppeteering the Acuity scheduling wizard. It is a SEPARATE subpath
6
+ * export (`@tummycrypt/scheduling-kit/middleware`) and should NOT be
7
+ * imported in client-side code (it depends on Playwright).
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { createWizardAdapter } from '@tummycrypt/scheduling-kit/middleware';
12
+ * import { createSchedulingKit } from '@tummycrypt/scheduling-kit';
13
+ * import { createVenmoAdapter } from '@tummycrypt/scheduling-kit/payments';
14
+ *
15
+ * const scheduler = createWizardAdapter({
16
+ * baseUrl: process.env.ACUITY_BASE_URL,
17
+ * couponCode: process.env.ACUITY_BYPASS_COUPON,
18
+ * });
19
+ *
20
+ * const venmo = createVenmoAdapter({ ... });
21
+ * const kit = createSchedulingKit(scheduler, [venmo]);
22
+ *
23
+ * // Full booking with Venmo payment
24
+ * const result = await kit.completeBooking(request, 'venmo')();
25
+ * ```
26
+ */
27
+ // Adapter factories
28
+ export { createWizardAdapter } from './acuity-wizard.js';
29
+ export { createRemoteWizardAdapter } from './remote-adapter.js';
30
+ // Browser service (for custom Layer composition)
31
+ export { BrowserService, BrowserServiceLive, BrowserServiceTest, defaultBrowserConfig, } from './browser-service.js';
32
+ // Error types and bridge
33
+ export { BrowserError, SelectorError, WizardStepError, CouponError, toSchedulingError, } from './errors.js';
34
+ // Selector registry
35
+ export { Selectors, resolveSelector, resolve, probeSelector, probe, healthCheck, } from './selectors.js';
36
+ // Individual wizard steps (for advanced composition)
37
+ export { navigateToBooking, fillFormFields, bypassPayment, generateCouponCode, submitBooking, extractConfirmation, toBooking, } from './steps/index.js';
38
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,oBAAoB;AACpB,OAAO,EAAE,mBAAmB,EAA4B,MAAM,oBAAoB,CAAC;AACnF,OAAO,EAAE,yBAAyB,EAA4B,MAAM,qBAAqB,CAAC;AAE1F,iDAAiD;AACjD,OAAO,EACN,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,GAGpB,MAAM,sBAAsB,CAAC;AAE9B,yBAAyB;AACzB,OAAO,EACN,YAAY,EACZ,aAAa,EACb,eAAe,EACf,WAAW,EACX,iBAAiB,GAEjB,MAAM,aAAa,CAAC;AAErB,oBAAoB;AACpB,OAAO,EACN,SAAS,EACT,eAAe,EACf,OAAO,EACP,aAAa,EACb,KAAK,EACL,WAAW,GAGX,MAAM,gBAAgB,CAAC;AAExB,qDAAqD;AACrD,OAAO,EACN,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,SAAS,GAQT,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Structured NDJSON Logger
3
+ *
4
+ * Provides two logging mechanisms:
5
+ * 1. Effect Logger (for code inside Effect.gen) — uses Effect's Logger API
6
+ * 2. ndjsonLog() standalone helper (for plain async handlers outside Effect)
7
+ *
8
+ * Both emit JSON lines to stdout/stderr, compatible with Modal's log capture.
9
+ */
10
+ import { Layer } from 'effect';
11
+ /**
12
+ * Effect Layer that replaces the default logger with NDJSON output.
13
+ * Add to your layer composition: `Layer.merge(BrowserServiceLive(...), LoggerLive)`
14
+ */
15
+ export declare const LoggerLive: Layer.Layer<never>;
16
+ type LogLevel = 'DEBUG' | 'INFO' | 'WARN' | 'ERROR';
17
+ /**
18
+ * Write a structured NDJSON log entry.
19
+ * Use this in plain async handlers that are NOT inside Effect programs.
20
+ *
21
+ * @example
22
+ * ndjsonLog('INFO', 'Request received', { endpoint: '/services', serviceId: '123' });
23
+ */
24
+ export declare const ndjsonLog: (level: LogLevel, msg: string, data?: Record<string, unknown>) => void;
25
+ export {};
26
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/middleware/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAU,KAAK,EAAW,MAAM,QAAQ,CAAC;AAiChD;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,CAAoD,CAAC;AAM/F,KAAK,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEpD;;;;;;GAMG;AACH,eAAO,MAAM,SAAS,GACrB,OAAO,QAAQ,EACf,KAAK,MAAM,EACX,OAAO,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,IAeF,CAAC"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Structured NDJSON Logger
3
+ *
4
+ * Provides two logging mechanisms:
5
+ * 1. Effect Logger (for code inside Effect.gen) — uses Effect's Logger API
6
+ * 2. ndjsonLog() standalone helper (for plain async handlers outside Effect)
7
+ *
8
+ * Both emit JSON lines to stdout/stderr, compatible with Modal's log capture.
9
+ */
10
+ import { Logger, HashMap } from 'effect';
11
+ // =============================================================================
12
+ // EFFECT LOGGER (for inside Effect programs)
13
+ // =============================================================================
14
+ /**
15
+ * JSON-line logger that writes structured entries to stdout/stderr.
16
+ * Integrates with Effect.logInfo, Effect.logWarning, Effect.logError, etc.
17
+ */
18
+ const JsonLogger = Logger.make(({ logLevel, message, annotations, date }) => {
19
+ const entry = {
20
+ ts: date.toISOString(),
21
+ level: logLevel.label.toUpperCase(),
22
+ msg: typeof message === 'string' ? message : JSON.stringify(message),
23
+ };
24
+ // Merge annotations as top-level fields
25
+ if (!HashMap.isEmpty(annotations)) {
26
+ for (const [key, value] of HashMap.toEntries(annotations)) {
27
+ entry[key] = value;
28
+ }
29
+ }
30
+ const line = JSON.stringify(entry) + '\n';
31
+ if (logLevel.ordinal >= 40000) { // Error, Fatal
32
+ process.stderr.write(line);
33
+ }
34
+ else {
35
+ process.stdout.write(line);
36
+ }
37
+ });
38
+ /**
39
+ * Effect Layer that replaces the default logger with NDJSON output.
40
+ * Add to your layer composition: `Layer.merge(BrowserServiceLive(...), LoggerLive)`
41
+ */
42
+ export const LoggerLive = Logger.replace(Logger.defaultLogger, JsonLogger);
43
+ /**
44
+ * Write a structured NDJSON log entry.
45
+ * Use this in plain async handlers that are NOT inside Effect programs.
46
+ *
47
+ * @example
48
+ * ndjsonLog('INFO', 'Request received', { endpoint: '/services', serviceId: '123' });
49
+ */
50
+ export const ndjsonLog = (level, msg, data) => {
51
+ const entry = {
52
+ ts: new Date().toISOString(),
53
+ level,
54
+ msg,
55
+ ...data,
56
+ };
57
+ const line = JSON.stringify(entry) + '\n';
58
+ if (level === 'ERROR') {
59
+ process.stderr.write(line);
60
+ }
61
+ else {
62
+ process.stdout.write(line);
63
+ }
64
+ };
65
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/middleware/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,MAAM,EAAS,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEhD,gFAAgF;AAChF,6CAA6C;AAC7C,gFAAgF;AAEhF;;;GAGG;AACH,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,EAAE;IAC3E,MAAM,KAAK,GAA4B;QACtC,EAAE,EAAE,IAAI,CAAC,WAAW,EAAE;QACtB,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,WAAW,EAAE;QACnC,GAAG,EAAE,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;KACpE,CAAC;IAEF,wCAAwC;IACxC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QACnC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC;YAC3D,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACpB,CAAC;IACF,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;IAE1C,IAAI,QAAQ,CAAC,OAAO,IAAI,KAAK,EAAE,CAAC,CAAC,eAAe;QAC/C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;SAAM,CAAC;QACP,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;AACF,CAAC,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAuB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;AAQ/F;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CACxB,KAAe,EACf,GAAW,EACX,IAA8B,EACvB,EAAE;IACT,MAAM,KAAK,GAA4B;QACtC,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QAC5B,KAAK;QACL,GAAG;QACH,GAAG,IAAI;KACP,CAAC;IAEF,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;IAE1C,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;QACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;SAAM,CAAC;QACP,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;AACF,CAAC,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Remote Wizard Adapter
3
+ *
4
+ * SchedulingAdapter implementation backed by HTTP calls to a remote
5
+ * middleware server running Playwright + Chromium (e.g., Modal Labs,
6
+ * Fly.io, or any Docker host).
7
+ *
8
+ * This adapter is the client-side counterpart to `middleware/server.ts`.
9
+ * It serializes requests, sends them over HTTP, and deserializes
10
+ * responses back into fp-ts TaskEither types.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const adapter = createRemoteWizardAdapter({
15
+ * baseUrl: process.env.MODAL_MIDDLEWARE_URL,
16
+ * authToken: process.env.MODAL_AUTH_TOKEN,
17
+ * });
18
+ * const kit = createSchedulingKit(adapter, [venmoAdapter]);
19
+ * ```
20
+ */
21
+ import type { SchedulingAdapter } from '../adapters/types.js';
22
+ import type { Service } from '../core/types.js';
23
+ export interface RemoteAdapterConfig {
24
+ /** Base URL of the middleware server (e.g., https://scheduling-middleware--org.modal.run) */
25
+ readonly baseUrl: string;
26
+ /** Auth token for the middleware server */
27
+ readonly authToken?: string;
28
+ /** Request timeout in ms (default: 60000 - wizard flow can take 30s+) */
29
+ readonly timeout?: number;
30
+ /** Coupon code for payment bypass */
31
+ readonly couponCode?: string;
32
+ /**
33
+ * Static service catalog. When provided, getServices()/getService() return
34
+ * from this list without hitting the remote server. Avoids dependency on
35
+ * the middleware's DOM scraper for service listing.
36
+ */
37
+ readonly services?: readonly Service[];
38
+ }
39
+ /**
40
+ * Create a SchedulingAdapter that proxies all operations to a remote
41
+ * middleware server via HTTP. The remote server runs Playwright + Chromium
42
+ * and executes the actual wizard automation.
43
+ */
44
+ export declare const createRemoteWizardAdapter: (config: RemoteAdapterConfig) => SchedulingAdapter;
45
+ //# sourceMappingURL=remote-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-adapter.d.ts","sourceRoot":"","sources":["../../src/middleware/remote-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,KAAK,EAGX,OAAO,EAQP,MAAM,kBAAkB,CAAC;AAO1B,MAAM,WAAW,mBAAmB;IACnC,6FAA6F;IAC7F,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,2CAA2C;IAC3C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,yEAAyE;IACzE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,qCAAqC;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CACvC;AAgGD;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,GAAI,QAAQ,mBAAmB,KAAG,iBAwHtE,CAAC"}
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Remote Wizard Adapter
3
+ *
4
+ * SchedulingAdapter implementation backed by HTTP calls to a remote
5
+ * middleware server running Playwright + Chromium (e.g., Modal Labs,
6
+ * Fly.io, or any Docker host).
7
+ *
8
+ * This adapter is the client-side counterpart to `middleware/server.ts`.
9
+ * It serializes requests, sends them over HTTP, and deserializes
10
+ * responses back into fp-ts TaskEither types.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const adapter = createRemoteWizardAdapter({
15
+ * baseUrl: process.env.MODAL_MIDDLEWARE_URL,
16
+ * authToken: process.env.MODAL_AUTH_TOKEN,
17
+ * });
18
+ * const kit = createSchedulingKit(adapter, [venmoAdapter]);
19
+ * ```
20
+ */
21
+ import { Effect } from 'effect';
22
+ import { Errors } from '../core/types.js';
23
+ const makeRequest = (config, path, method, body) => Effect.tryPromise({
24
+ try: async () => {
25
+ const url = `${config.baseUrl}${path}`;
26
+ const headers = {
27
+ 'Content-Type': 'application/json',
28
+ };
29
+ if (config.authToken) {
30
+ headers['Authorization'] = `Bearer ${config.authToken}`;
31
+ }
32
+ const response = await fetch(url, {
33
+ method,
34
+ headers,
35
+ body: body ? JSON.stringify(body) : undefined,
36
+ signal: AbortSignal.timeout(config.timeout ?? 60000),
37
+ });
38
+ if (!response.ok) {
39
+ const errorBody = await response.json().catch(() => ({}));
40
+ throw Object.assign(new Error(errorBody.error?.message ?? `HTTP ${response.status}`), {
41
+ tag: errorBody.error?.tag ?? 'InfrastructureError',
42
+ code: errorBody.error?.code ?? 'NETWORK',
43
+ });
44
+ }
45
+ const json = (await response.json());
46
+ if (!json.success && json.error) {
47
+ throw Object.assign(new Error(json.error.message), {
48
+ tag: json.error.tag,
49
+ code: json.error.code,
50
+ });
51
+ }
52
+ return json.data;
53
+ },
54
+ catch: (e) => {
55
+ if (e instanceof Error && 'tag' in e) {
56
+ const tagged = e;
57
+ return mapRemoteError(tagged.tag, tagged.code, tagged.message);
58
+ }
59
+ if (e instanceof DOMException && e.name === 'TimeoutError') {
60
+ return Errors.infrastructure('TIMEOUT', 'Middleware server request timed out');
61
+ }
62
+ return Errors.infrastructure('NETWORK', `Middleware server error: ${e instanceof Error ? e.message : String(e)}`);
63
+ },
64
+ });
65
+ const mapRemoteError = (tag, code, message) => {
66
+ switch (tag) {
67
+ case 'AcuityError':
68
+ return Errors.acuity(code, message);
69
+ case 'PaymentError':
70
+ return Errors.payment(code, message, 'remote');
71
+ case 'ValidationError':
72
+ return Errors.validation(code, message);
73
+ case 'ReservationError':
74
+ return Errors.reservation(code, message);
75
+ case 'InfrastructureError':
76
+ default:
77
+ return Errors.infrastructure(code ?? 'UNKNOWN', message);
78
+ }
79
+ };
80
+ // =============================================================================
81
+ // ADAPTER FACTORY
82
+ // =============================================================================
83
+ /**
84
+ * Create a SchedulingAdapter that proxies all operations to a remote
85
+ * middleware server via HTTP. The remote server runs Playwright + Chromium
86
+ * and executes the actual wizard automation.
87
+ */
88
+ export const createRemoteWizardAdapter = (config) => ({
89
+ name: 'acuity-wizard-remote',
90
+ // ---------------------------------------------------------------------------
91
+ // Read operations - proxied to remote scraper
92
+ // ---------------------------------------------------------------------------
93
+ getServices: () => {
94
+ if (config.services) {
95
+ return Effect.succeed([...config.services]);
96
+ }
97
+ return makeRequest(config, '/services', 'GET');
98
+ },
99
+ getService: (serviceId) => {
100
+ if (config.services) {
101
+ const found = config.services.find((s) => s.id === serviceId);
102
+ return found
103
+ ? Effect.succeed(found)
104
+ : Effect.fail(Errors.acuity('NOT_FOUND', `Service ${serviceId} not found`));
105
+ }
106
+ return makeRequest(config, `/services/${encodeURIComponent(serviceId)}`, 'GET');
107
+ },
108
+ getProviders: () => Effect.succeed([{
109
+ id: '1',
110
+ name: 'Default Provider',
111
+ email: 'provider@example.com',
112
+ description: 'Primary provider',
113
+ timezone: 'America/New_York',
114
+ }]),
115
+ getProvider: () => Effect.succeed({
116
+ id: '1',
117
+ name: 'Default Provider',
118
+ email: 'provider@example.com',
119
+ description: 'Primary provider',
120
+ timezone: 'America/New_York',
121
+ }),
122
+ getProvidersForService: () => Effect.succeed([{
123
+ id: '1',
124
+ name: 'Default Provider',
125
+ email: 'provider@example.com',
126
+ description: 'Primary provider',
127
+ timezone: 'America/New_York',
128
+ }]),
129
+ getAvailableDates: (params) => {
130
+ // Resolve service name for wizard navigation (Acuity navigates by name, not ID)
131
+ const serviceName = config.services?.find((s) => s.id === params.serviceId)?.name;
132
+ return makeRequest(config, '/availability/dates', 'POST', {
133
+ ...params,
134
+ serviceName: serviceName ?? params.serviceId,
135
+ });
136
+ },
137
+ getAvailableSlots: (params) => {
138
+ const serviceName = config.services?.find((s) => s.id === params.serviceId)?.name;
139
+ return makeRequest(config, '/availability/slots', 'POST', {
140
+ ...params,
141
+ serviceName: serviceName ?? params.serviceId,
142
+ });
143
+ },
144
+ checkSlotAvailability: (params) => {
145
+ const serviceName = config.services?.find((s) => s.id === params.serviceId)?.name;
146
+ return makeRequest(config, '/availability/check', 'POST', {
147
+ ...params,
148
+ serviceName: serviceName ?? params.serviceId,
149
+ });
150
+ },
151
+ // ---------------------------------------------------------------------------
152
+ // Reservation - not supported (pipeline has graceful fallback)
153
+ // ---------------------------------------------------------------------------
154
+ createReservation: () => Effect.fail(Errors.reservation('BLOCK_FAILED', 'Reservations not supported by remote wizard adapter')),
155
+ releaseReservation: () => Effect.succeed(undefined),
156
+ // ---------------------------------------------------------------------------
157
+ // Write operations - proxied to remote wizard
158
+ // ---------------------------------------------------------------------------
159
+ createBooking: (request) => makeRequest(config, '/booking/create', 'POST', {
160
+ request,
161
+ couponCode: config.couponCode,
162
+ }),
163
+ createBookingWithPaymentRef: (request, paymentRef, paymentProcessor) => makeRequest(config, '/booking/create-with-payment', 'POST', {
164
+ request,
165
+ paymentRef,
166
+ paymentProcessor,
167
+ couponCode: config.couponCode,
168
+ }),
169
+ getBooking: () => Effect.fail(Errors.acuity('NOT_IMPLEMENTED', 'Get booking not yet supported via wizard')),
170
+ cancelBooking: () => Effect.fail(Errors.acuity('NOT_IMPLEMENTED', 'Cancel not yet supported via wizard')),
171
+ rescheduleBooking: () => Effect.fail(Errors.acuity('NOT_IMPLEMENTED', 'Reschedule not yet supported via wizard')),
172
+ // ---------------------------------------------------------------------------
173
+ // Client - pass-through
174
+ // ---------------------------------------------------------------------------
175
+ findOrCreateClient: (client) => Effect.succeed({ id: `local-${client.email}`, isNew: true }),
176
+ getClientByEmail: () => Effect.succeed(null),
177
+ });
178
+ //# sourceMappingURL=remote-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-adapter.js","sourceRoot":"","sources":["../../src/middleware/remote-adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Selector Health Check
3
+ *
4
+ * Tiered probing of Acuity page selectors with degradation detection.
5
+ * "Degraded" means the primary selector (index 0) failed but a fallback
6
+ * (index > 0) still works — an early warning that Acuity changed their DOM.
7
+ *
8
+ * Tiers:
9
+ * depth=0: HTTP-only BUSINESS object check (~200ms, no browser)
10
+ * depth=1: Service page selectors (~3-5s, browser required)
11
+ * depth=2: + Calendar page selectors (~8-15s, clicks through wizard)
12
+ */
13
+ import { Effect, Scope } from 'effect';
14
+ import { BrowserService } from './browser-service.js';
15
+ import { type SelectorKey } from './selectors.js';
16
+ export interface SelectorProbeResult {
17
+ readonly key: SelectorKey;
18
+ readonly status: 'passed' | 'degraded' | 'failed';
19
+ /** Which selector matched (null if failed) */
20
+ readonly matchedSelector: string | null;
21
+ /** Index in the candidates array (0 = primary, >0 = degraded) */
22
+ readonly matchedIndex: number | null;
23
+ /** Time to probe in ms */
24
+ readonly probeMs: number;
25
+ }
26
+ export interface SelectorHealthReport {
27
+ readonly status: 'healthy' | 'degraded' | 'unhealthy';
28
+ readonly selectors: SelectorProbeResult[];
29
+ readonly passed: number;
30
+ readonly degraded: number;
31
+ readonly failed: number;
32
+ readonly totalMs: number;
33
+ readonly pagesProbed: readonly string[];
34
+ readonly businessObjectAvailable: boolean;
35
+ readonly timestamp: string;
36
+ }
37
+ /**
38
+ * Run a selector health check at the specified depth.
39
+ *
40
+ * @param baseUrl - Acuity scheduling URL
41
+ * @param depth - 0 = HTTP-only, 1 = service page, 2 = service + calendar
42
+ */
43
+ export declare const selectorHealthCheck: (baseUrl: string, depth?: 0 | 1 | 2) => Effect.Effect<SelectorHealthReport, never, BrowserService | Scope.Scope>;
44
+ //# sourceMappingURL=selector-health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selector-health.d.ts","sourceRoot":"","sources":["../../src/middleware/selector-health.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAEvC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAa,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAO7D,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,UAAU,GAAG,QAAQ,CAAC;IAClD,8CAA8C;IAC9C,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,iEAAiE;IACjE,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,0BAA0B;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,CAAC;IACtD,QAAQ,CAAC,SAAS,EAAE,mBAAmB,EAAE,CAAC;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,uBAAuB,EAAE,OAAO,CAAC;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B;AA8FD;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAC/B,SAAS,MAAM,EACf,QAAO,CAAC,GAAG,CAAC,GAAG,CAAK,KAClB,MAAM,CAAC,MAAM,CAAC,oBAAoB,EAAE,KAAK,EAAE,cAAc,GAAG,KAAK,CAAC,KAAK,CA8DvE,CAAC"}