PageSourceSearch

https://www.text-art.de/wp-content/plugins/bookingpress-appointmen…/js/booking-form-vue3/api/client.js?v=3

js text-art.de collected 2026-10-05 11:44:10 UTC 4,330 bytes, 132 lines download raw bytes

1/**
2 * api/client.js — thin fetch wrapper for the /form-v3/* REST endpoints.
3 *
4 * Auto-attaches the three auth tokens (per plan §4.1):
5 *   - `X-WP-Nonce` HTTP header  (verifies against `wp_rest`)
6 *   - `bp_v3_nonce` body field  (verifies against `bookingpress_form_v3_nonce`)
7 *   - `bp_v3_instance_token` + `instanceId` body fields  (per-instance anti-replay)
8 *
9 * One client per Vue 3 form instance. Caller passes the instance-bound
10 * `state.rest` + `state.nonces` snapshot to `createApiClient()` at mount time.
11 */
12
13/**
14 * @typedef {Object} ApiConfig
15 * @property {string} restRoot       Absolute URL to the `/form-v3/` namespace.
16 * @property {string} instanceId     12-char per-render id.
17 * @property {string} wpRestNonce    Nonce against `wp_rest` action.
18 * @property {string} formNonce      Nonce against `bookingpress_form_v3_nonce` action.
19 * @property {string} instanceToken  Per-render opaque token.
20 */
21
22/**
23 * @param {ApiConfig} cfg
24 * @returns {object} API methods.
25 */
26export function createApiClient(cfg) {
27  const root = String(cfg.restRoot || '').replace(/\/+$/, '');
28	
29	async function refreshWpNonce() {
30    try {
31		const refreshPayload = {
32      		instanceId: String(cfg.instanceId || ''),
33    	};
34		
35      const res = await fetch(`${root}/refresh-nonce`, {
36        method: 'POST',
37        credentials: 'same-origin',
38        cache: 'no-store',
39        headers: { 'Content-Type': 'application/json' },
40        body: JSON.stringify(refreshPayload),
41      });
42      const json = await res.json();
43      if (json && json.ok && json.data && json.data.wp_rest_nonce ) {
44        	cfg.wpRestNonce   = json.data.wp_rest_nonce;
45		  cfg.formNonce     = json.data.form_nonce;
46		  //cfg.instanceId    = json.data.instanceId;
47		  cfg.instanceToken = json.data.instanceToken;
48
49		  
50        return true;
51      }
52    } catch (_err) { /* fall through */ }
53    return false;
54  }
55	
56  async function post(route, body, _retried) {
57    const payload = {
58      ...(body || {}),
59      bp_v3_nonce: cfg.formNonce,
60      bp_v3_instance_token: cfg.instanceToken,
61      instanceId: cfg.instanceId,
62    };
63    if( 'submit' == route ){
64      if( "undefined" != typeof BookingPressFormV3 ){
65        var formState = BookingPressFormV3.instances[ cfg.instanceId ].state;
66        if( "undefined" != typeof formState.config.current_locale && formState.config.current_locale ){
67          payload.locale = formState.config.current_locale;
68        }
69      }
70    }
71    const res = await fetch(`${root}/${route}`, {
72      method: 'POST',
73      credentials: 'same-origin',
74      headers: {
75        'Content-Type': 'application/json',
76        'X-WP-Nonce': cfg.wpRestNonce,
77      },
78      body: JSON.stringify(payload),
79    });
80    let json = null;
81    try {
82      json = await res.json();
83    } catch (_err) {
84      json = { ok: false, error: { code: 'bp_v3_invalid_json', message: 'Server returned non-JSON.' } };
85    }
86	  
87	 const failureCode = (json && (json.code || (json.error && json.error.code))) || '';
88	 const isStaleAuth = (
89	   failureCode === 'rest_cookie_invalid_nonce'
90	   || failureCode === 'bp_v3_rest_invalid_nonce'
91	   || failureCode === 'bp_v3_invalid_form_nonce'
92	   || failureCode === 'bp_v3_invalid_instance'
93	 );
94
95	 if (!res.ok && isStaleAuth && !_retried) {
96      const refreshed = await refreshWpNonce();
97      if (refreshed) return post(route, body, true);
98    }
99	  
100    return { status: res.status, ok: !!(json && json.ok), data: json && json.data, error: json && json.error, errors: json && json.errors, raw: json };
101  }
102
103  return {
104    state(extra) {
105      return post('state', extra || {});
106    },
107    timeslots(body) {
108      return post('timeslots', body || {});
109    },
110    monthDetails(body) {
111      return post('month-details', body || {});
112    },
113    submit(appointmentData) {
114      return post('submit', appointmentData || {});
115    },
116    captcha() {
117      return post('captcha', {});
118    },
119    validateUsername(username) {
120      return post('validate-username', { username: String(username || '') });
121    },
122    paypalValidate(body) {
123      return post('payment/paypal-validate', body || {});
124    },
125    paypalConfirm(body) {
126      return post('payment/paypal-confirm', body || {});
127    },
128    paypalRedirectPrepare(body) {
129      return post('payment/paypal-redirect-prepare', body || {});
130    },
131  };
132}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.