@foxscheduling/sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -0
- package/dist/auth/apiKey.d.ts +10 -0
- package/dist/auth/apiKey.d.ts.map +1 -0
- package/dist/auth/apiKey.js +17 -0
- package/dist/auth/oauth.d.ts +29 -0
- package/dist/auth/oauth.d.ts.map +1 -0
- package/dist/auth/oauth.js +110 -0
- package/dist/auth/pkce.d.ts +4 -0
- package/dist/auth/pkce.d.ts.map +1 -0
- package/dist/auth/pkce.js +10 -0
- package/dist/auth/tokenManager.d.ts +24 -0
- package/dist/auth/tokenManager.d.ts.map +1 -0
- package/dist/auth/tokenManager.js +50 -0
- package/dist/auth/tokenStore.d.ts +21 -0
- package/dist/auth/tokenStore.d.ts.map +1 -0
- package/dist/auth/tokenStore.js +49 -0
- package/dist/cjs/auth/apiKey.cjs +21 -0
- package/dist/cjs/auth/apiKey.d.ts +10 -0
- package/dist/cjs/auth/apiKey.d.ts.map +1 -0
- package/dist/cjs/auth/oauth.cjs +114 -0
- package/dist/cjs/auth/oauth.d.ts +29 -0
- package/dist/cjs/auth/oauth.d.ts.map +1 -0
- package/dist/cjs/auth/pkce.cjs +15 -0
- package/dist/cjs/auth/pkce.d.ts +4 -0
- package/dist/cjs/auth/pkce.d.ts.map +1 -0
- package/dist/cjs/auth/tokenManager.cjs +55 -0
- package/dist/cjs/auth/tokenManager.d.ts +24 -0
- package/dist/cjs/auth/tokenManager.d.ts.map +1 -0
- package/dist/cjs/auth/tokenStore.cjs +87 -0
- package/dist/cjs/auth/tokenStore.d.ts +21 -0
- package/dist/cjs/auth/tokenStore.d.ts.map +1 -0
- package/dist/cjs/client.cjs +48 -0
- package/dist/cjs/client.d.ts +16 -0
- package/dist/cjs/client.d.ts.map +1 -0
- package/dist/cjs/errors.cjs +19 -0
- package/dist/cjs/errors.d.ts +9 -0
- package/dist/cjs/errors.d.ts.map +1 -0
- package/dist/cjs/http/client.cjs +62 -0
- package/dist/cjs/http/client.d.ts +13 -0
- package/dist/cjs/http/client.d.ts.map +1 -0
- package/dist/cjs/index.cjs +19 -0
- package/dist/cjs/index.d.ts +7 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/resources/index.cjs +120 -0
- package/dist/cjs/resources/index.d.ts +71 -0
- package/dist/cjs/resources/index.d.ts.map +1 -0
- package/dist/cjs/types.cjs +4 -0
- package/dist/cjs/types.d.ts +31 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/webhooks/verify.cjs +16 -0
- package/dist/cjs/webhooks/verify.d.ts +7 -0
- package/dist/cjs/webhooks/verify.d.ts.map +1 -0
- package/dist/client.d.ts +16 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +44 -0
- package/dist/errors.d.ts +9 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +14 -0
- package/dist/http/client.d.ts +13 -0
- package/dist/http/client.d.ts.map +1 -0
- package/dist/http/client.js +58 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/resources/index.d.ts +71 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +110 -0
- package/dist/types.d.ts +31 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/webhooks/verify.d.ts +7 -0
- package/dist/webhooks/verify.d.ts.map +1 -0
- package/dist/webhooks/verify.js +13 -0
- package/package.json +39 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.verifyFoxWebhookSignature = verifyFoxWebhookSignature;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
function verifyFoxWebhookSignature(params) {
|
|
6
|
+
const payload = `${params.timestamp}.${params.rawBody}`;
|
|
7
|
+
const expected = (0, node_crypto_1.createHmac)("sha256", params.secret)
|
|
8
|
+
.update(payload)
|
|
9
|
+
.digest("hex");
|
|
10
|
+
try {
|
|
11
|
+
return (0, node_crypto_1.timingSafeEqual)(Buffer.from(expected, "hex"), Buffer.from(params.signatureHex, "hex"));
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../../src/webhooks/verify.ts"],"names":[],"mappings":"AAEA,wBAAgB,yBAAyB,CAAC,MAAM,EAAE;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAaV"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { OAuthClient } from "./auth/oauth.js";
|
|
2
|
+
import { AvailabilityResource, BookingsResource, BusinessResource, CustomersResource, ServicesResource, StaffResource, WebhooksResource } from "./resources/index.js";
|
|
3
|
+
import { type FoxSchedulingConfig } from "./types.js";
|
|
4
|
+
export declare class FoxScheduling {
|
|
5
|
+
readonly oauth?: OAuthClient;
|
|
6
|
+
readonly business: BusinessResource;
|
|
7
|
+
readonly services: ServicesResource;
|
|
8
|
+
readonly staff: StaffResource;
|
|
9
|
+
readonly availability: AvailabilityResource;
|
|
10
|
+
readonly bookings: BookingsResource;
|
|
11
|
+
readonly customers: CustomersResource;
|
|
12
|
+
readonly webhooks: WebhooksResource;
|
|
13
|
+
private readonly http;
|
|
14
|
+
constructor(config: FoxSchedulingConfig);
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,YAAY,CAAC;AAEpB,qBAAa,aAAa;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAC;IAC5C,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IAEpC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;gBAEtB,MAAM,EAAE,mBAAmB;CA6BxC"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ApiKeyAuthProvider } from "./auth/apiKey.js";
|
|
2
|
+
import { OAuthClient } from "./auth/oauth.js";
|
|
3
|
+
import { HttpClient } from "./http/client.js";
|
|
4
|
+
import { AvailabilityResource, BookingsResource, BusinessResource, CustomersResource, ServicesResource, StaffResource, WebhooksResource, } from "./resources/index.js";
|
|
5
|
+
import { DEFAULT_BASE_URL, } from "./types.js";
|
|
6
|
+
export class FoxScheduling {
|
|
7
|
+
oauth;
|
|
8
|
+
business;
|
|
9
|
+
services;
|
|
10
|
+
staff;
|
|
11
|
+
availability;
|
|
12
|
+
bookings;
|
|
13
|
+
customers;
|
|
14
|
+
webhooks;
|
|
15
|
+
http;
|
|
16
|
+
constructor(config) {
|
|
17
|
+
const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
|
|
18
|
+
const fetchImpl = config.fetch ?? fetch;
|
|
19
|
+
let auth;
|
|
20
|
+
if (config.auth.type === "apiKey") {
|
|
21
|
+
auth = new ApiKeyAuthProvider(config.auth.apiKey);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
const oauth = new OAuthClient({
|
|
25
|
+
baseUrl,
|
|
26
|
+
clientId: config.auth.clientId,
|
|
27
|
+
clientSecret: config.auth.clientSecret,
|
|
28
|
+
redirectUri: config.auth.redirectUri,
|
|
29
|
+
tokenStore: config.auth.tokenStore,
|
|
30
|
+
fetchImpl,
|
|
31
|
+
});
|
|
32
|
+
this.oauth = oauth;
|
|
33
|
+
auth = oauth;
|
|
34
|
+
}
|
|
35
|
+
this.http = new HttpClient(baseUrl, auth, fetchImpl);
|
|
36
|
+
this.business = new BusinessResource(this.http);
|
|
37
|
+
this.services = new ServicesResource(this.http);
|
|
38
|
+
this.staff = new StaffResource(this.http);
|
|
39
|
+
this.availability = new AvailabilityResource(this.http);
|
|
40
|
+
this.bookings = new BookingsResource(this.http);
|
|
41
|
+
this.customers = new CustomersResource(this.http);
|
|
42
|
+
this.webhooks = new WebhooksResource(this.http);
|
|
43
|
+
}
|
|
44
|
+
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ErrorCodes } from "@foxscheduling/shared";
|
|
2
|
+
export declare class FoxSchedulingError extends Error {
|
|
3
|
+
readonly errorCode: string;
|
|
4
|
+
constructor(errorCode: string, message?: string);
|
|
5
|
+
static fromResponse(errorCode: string): FoxSchedulingError;
|
|
6
|
+
}
|
|
7
|
+
export declare function isFoxSchedulingError(err: unknown): err is FoxSchedulingError;
|
|
8
|
+
export type { ErrorCodes };
|
|
9
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;IAM/C,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB;CAG3D;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,kBAAkB,CAE5E;AAED,YAAY,EAAE,UAAU,EAAE,CAAC"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export class FoxSchedulingError extends Error {
|
|
2
|
+
errorCode;
|
|
3
|
+
constructor(errorCode, message) {
|
|
4
|
+
super(message ?? errorCode);
|
|
5
|
+
this.name = "FoxSchedulingError";
|
|
6
|
+
this.errorCode = errorCode;
|
|
7
|
+
}
|
|
8
|
+
static fromResponse(errorCode) {
|
|
9
|
+
return new FoxSchedulingError(errorCode);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function isFoxSchedulingError(err) {
|
|
13
|
+
return err instanceof FoxSchedulingError;
|
|
14
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AuthProvider } from "../auth/apiKey.js";
|
|
2
|
+
export declare class HttpClient {
|
|
3
|
+
private readonly baseUrl;
|
|
4
|
+
private readonly auth;
|
|
5
|
+
private readonly fetchImpl;
|
|
6
|
+
constructor(baseUrl: string, auth: AuthProvider, fetchImpl: typeof fetch);
|
|
7
|
+
request<T>(path: string, options?: RequestInit, retried?: boolean): Promise<T>;
|
|
8
|
+
get<T>(path: string, query?: Record<string, string | undefined>): Promise<T>;
|
|
9
|
+
post<T>(path: string, body?: unknown, query?: Record<string, string>): Promise<T>;
|
|
10
|
+
patch<T>(path: string, body?: unknown): Promise<T>;
|
|
11
|
+
delete<T>(path: string): Promise<T>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/http/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAQtD,qBAAa,UAAU;IAEnB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAFT,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,YAAY,EAClB,SAAS,EAAE,OAAO,KAAK;IAGpC,OAAO,CAAC,CAAC,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,WAAgB,EACzB,OAAO,UAAQ,GACd,OAAO,CAAC,CAAC,CAAC;IA8Bb,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAS5E,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAQjF,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAOlD,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;CAGpC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { FoxSchedulingError } from "../errors.js";
|
|
2
|
+
export class HttpClient {
|
|
3
|
+
baseUrl;
|
|
4
|
+
auth;
|
|
5
|
+
fetchImpl;
|
|
6
|
+
constructor(baseUrl, auth, fetchImpl) {
|
|
7
|
+
this.baseUrl = baseUrl;
|
|
8
|
+
this.auth = auth;
|
|
9
|
+
this.fetchImpl = fetchImpl;
|
|
10
|
+
}
|
|
11
|
+
async request(path, options = {}, retried = false) {
|
|
12
|
+
const authHeader = await this.auth.getAuthorizationHeader();
|
|
13
|
+
const headers = new Headers(options.headers);
|
|
14
|
+
headers.set("Authorization", authHeader);
|
|
15
|
+
if (options.body && !headers.has("Content-Type")) {
|
|
16
|
+
headers.set("Content-Type", "application/json");
|
|
17
|
+
}
|
|
18
|
+
const res = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
19
|
+
...options,
|
|
20
|
+
headers,
|
|
21
|
+
});
|
|
22
|
+
const json = (await res.json());
|
|
23
|
+
if (json.statusMessage === "ERROR" || json.errorCode) {
|
|
24
|
+
throw FoxSchedulingError.fromResponse(json.errorCode ?? "UNKNOWN_ERROR");
|
|
25
|
+
}
|
|
26
|
+
if (res.status === 401 && !retried && this.auth.onUnauthorized) {
|
|
27
|
+
const refreshed = await this.auth.onUnauthorized();
|
|
28
|
+
if (refreshed)
|
|
29
|
+
return this.request(path, options, true);
|
|
30
|
+
}
|
|
31
|
+
if (!res.ok) {
|
|
32
|
+
throw FoxSchedulingError.fromResponse(json.errorCode ?? "HTTP_ERROR");
|
|
33
|
+
}
|
|
34
|
+
return json.data;
|
|
35
|
+
}
|
|
36
|
+
get(path, query) {
|
|
37
|
+
const qs = query
|
|
38
|
+
? `?${new URLSearchParams(Object.entries(query).filter(([, v]) => v != null)).toString()}`
|
|
39
|
+
: "";
|
|
40
|
+
return this.request(`${path}${qs}`, { method: "GET" });
|
|
41
|
+
}
|
|
42
|
+
post(path, body, query) {
|
|
43
|
+
const qs = query ? `?${new URLSearchParams(query).toString()}` : "";
|
|
44
|
+
return this.request(`${path}${qs}`, {
|
|
45
|
+
method: "POST",
|
|
46
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
patch(path, body) {
|
|
50
|
+
return this.request(path, {
|
|
51
|
+
method: "PATCH",
|
|
52
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
delete(path) {
|
|
56
|
+
return this.request(path, { method: "DELETE" });
|
|
57
|
+
}
|
|
58
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { FoxScheduling } from "./client.js";
|
|
2
|
+
export { FoxSchedulingError, isFoxSchedulingError } from "./errors.js";
|
|
3
|
+
export { MemoryTokenStore, FileTokenStore, type TokenStore, } from "./auth/tokenStore.js";
|
|
4
|
+
export { generateCodeVerifier, generateCodeChallengeS256, generateState, } from "./auth/pkce.js";
|
|
5
|
+
export { verifyFoxWebhookSignature } from "./webhooks/verify.js";
|
|
6
|
+
export { DEFAULT_BASE_URL, type FoxSchedulingConfig, type FoxSchedulingAuth, type FoxSchedulingApiKeyAuth, type FoxSchedulingOAuthAuth, type TokenSet, type AuthorizationUrlResult, } from "./types.js";
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,KAAK,UAAU,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,oBAAoB,EACpB,yBAAyB,EACzB,aAAa,GACd,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EACL,gBAAgB,EAChB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,QAAQ,EACb,KAAK,sBAAsB,GAC5B,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { FoxScheduling } from "./client.js";
|
|
2
|
+
export { FoxSchedulingError, isFoxSchedulingError } from "./errors.js";
|
|
3
|
+
export { MemoryTokenStore, FileTokenStore, } from "./auth/tokenStore.js";
|
|
4
|
+
export { generateCodeVerifier, generateCodeChallengeS256, generateState, } from "./auth/pkce.js";
|
|
5
|
+
export { verifyFoxWebhookSignature } from "./webhooks/verify.js";
|
|
6
|
+
export { DEFAULT_BASE_URL, } from "./types.js";
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { BusinessProfileDto, PartnerBookingDto, PartnerCustomerDto, PartnerServiceDto, PartnerStaffDto, PartnerWebhookEvent } from "@foxscheduling/shared";
|
|
2
|
+
import type { HttpClient } from "../http/client.js";
|
|
3
|
+
export declare class BusinessResource {
|
|
4
|
+
private readonly http;
|
|
5
|
+
constructor(http: HttpClient);
|
|
6
|
+
get(): Promise<BusinessProfileDto>;
|
|
7
|
+
}
|
|
8
|
+
export declare class ServicesResource {
|
|
9
|
+
private readonly http;
|
|
10
|
+
constructor(http: HttpClient);
|
|
11
|
+
list(): Promise<PartnerServiceDto[]>;
|
|
12
|
+
get(id: string): Promise<PartnerServiceDto>;
|
|
13
|
+
}
|
|
14
|
+
export declare class StaffResource {
|
|
15
|
+
private readonly http;
|
|
16
|
+
constructor(http: HttpClient);
|
|
17
|
+
list(): Promise<PartnerStaffDto[]>;
|
|
18
|
+
get(id: string): Promise<PartnerStaffDto>;
|
|
19
|
+
}
|
|
20
|
+
export declare class AvailabilityResource {
|
|
21
|
+
private readonly http;
|
|
22
|
+
constructor(http: HttpClient);
|
|
23
|
+
list(): Promise<unknown[]>;
|
|
24
|
+
get(id: string): Promise<unknown>;
|
|
25
|
+
create(body: unknown): Promise<unknown>;
|
|
26
|
+
update(id: string, body: unknown): Promise<unknown>;
|
|
27
|
+
delete(id: string): Promise<unknown>;
|
|
28
|
+
}
|
|
29
|
+
export declare class BookingsResource {
|
|
30
|
+
private readonly http;
|
|
31
|
+
constructor(http: HttpClient);
|
|
32
|
+
list(query?: Record<string, string>): Promise<PartnerBookingDto[]>;
|
|
33
|
+
get(id: string, serviceId: string): Promise<PartnerBookingDto>;
|
|
34
|
+
create(body: unknown): Promise<unknown>;
|
|
35
|
+
cancel(id: string, serviceId: string): Promise<unknown>;
|
|
36
|
+
}
|
|
37
|
+
export declare class CustomersResource {
|
|
38
|
+
private readonly http;
|
|
39
|
+
constructor(http: HttpClient);
|
|
40
|
+
list(): Promise<PartnerCustomerDto[]>;
|
|
41
|
+
get(id: string): Promise<PartnerCustomerDto>;
|
|
42
|
+
create(body: {
|
|
43
|
+
name: string;
|
|
44
|
+
email: string;
|
|
45
|
+
}): Promise<PartnerCustomerDto>;
|
|
46
|
+
update(id: string, body: unknown): Promise<PartnerCustomerDto>;
|
|
47
|
+
}
|
|
48
|
+
export interface WebhookSubscriptionPublic {
|
|
49
|
+
id: string;
|
|
50
|
+
url: string;
|
|
51
|
+
events: PartnerWebhookEvent[];
|
|
52
|
+
creationDate?: string;
|
|
53
|
+
}
|
|
54
|
+
export declare class WebhooksResource {
|
|
55
|
+
private readonly http;
|
|
56
|
+
constructor(http: HttpClient);
|
|
57
|
+
list(): Promise<WebhookSubscriptionPublic[]>;
|
|
58
|
+
create(body: {
|
|
59
|
+
url: string;
|
|
60
|
+
events: PartnerWebhookEvent[];
|
|
61
|
+
}): Promise<{
|
|
62
|
+
subscription: WebhookSubscriptionPublic;
|
|
63
|
+
secret: string;
|
|
64
|
+
}>;
|
|
65
|
+
update(id: string, body: Partial<{
|
|
66
|
+
url: string;
|
|
67
|
+
events: PartnerWebhookEvent[];
|
|
68
|
+
}>): Promise<WebhookSubscriptionPublic>;
|
|
69
|
+
delete(id: string): Promise<unknown>;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
export class BusinessResource {
|
|
2
|
+
http;
|
|
3
|
+
constructor(http) {
|
|
4
|
+
this.http = http;
|
|
5
|
+
}
|
|
6
|
+
get() {
|
|
7
|
+
return this.http.get("/partner/business");
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export class ServicesResource {
|
|
11
|
+
http;
|
|
12
|
+
constructor(http) {
|
|
13
|
+
this.http = http;
|
|
14
|
+
}
|
|
15
|
+
list() {
|
|
16
|
+
return this.http.get("/partner/services");
|
|
17
|
+
}
|
|
18
|
+
get(id) {
|
|
19
|
+
return this.http.get(`/partner/services/${id}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export class StaffResource {
|
|
23
|
+
http;
|
|
24
|
+
constructor(http) {
|
|
25
|
+
this.http = http;
|
|
26
|
+
}
|
|
27
|
+
list() {
|
|
28
|
+
return this.http.get("/partner/staff");
|
|
29
|
+
}
|
|
30
|
+
get(id) {
|
|
31
|
+
return this.http.get(`/partner/staff/${id}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export class AvailabilityResource {
|
|
35
|
+
http;
|
|
36
|
+
constructor(http) {
|
|
37
|
+
this.http = http;
|
|
38
|
+
}
|
|
39
|
+
list() {
|
|
40
|
+
return this.http.get("/partner/availability");
|
|
41
|
+
}
|
|
42
|
+
get(id) {
|
|
43
|
+
return this.http.get(`/partner/availability/${id}`);
|
|
44
|
+
}
|
|
45
|
+
create(body) {
|
|
46
|
+
return this.http.post("/partner/availability", body);
|
|
47
|
+
}
|
|
48
|
+
update(id, body) {
|
|
49
|
+
return this.http.patch(`/partner/availability/${id}`, body);
|
|
50
|
+
}
|
|
51
|
+
delete(id) {
|
|
52
|
+
return this.http.delete(`/partner/availability/${id}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export class BookingsResource {
|
|
56
|
+
http;
|
|
57
|
+
constructor(http) {
|
|
58
|
+
this.http = http;
|
|
59
|
+
}
|
|
60
|
+
list(query) {
|
|
61
|
+
return this.http.get("/partner/bookings", query);
|
|
62
|
+
}
|
|
63
|
+
get(id, serviceId) {
|
|
64
|
+
return this.http.get(`/partner/bookings/${id}`, { serviceId });
|
|
65
|
+
}
|
|
66
|
+
create(body) {
|
|
67
|
+
return this.http.post("/partner/bookings", body);
|
|
68
|
+
}
|
|
69
|
+
cancel(id, serviceId) {
|
|
70
|
+
return this.http.post(`/partner/bookings/${id}/cancel`, undefined, {
|
|
71
|
+
serviceId,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export class CustomersResource {
|
|
76
|
+
http;
|
|
77
|
+
constructor(http) {
|
|
78
|
+
this.http = http;
|
|
79
|
+
}
|
|
80
|
+
list() {
|
|
81
|
+
return this.http.get("/partner/customers");
|
|
82
|
+
}
|
|
83
|
+
get(id) {
|
|
84
|
+
return this.http.get(`/partner/customers/${id}`);
|
|
85
|
+
}
|
|
86
|
+
create(body) {
|
|
87
|
+
return this.http.post("/partner/customers", body);
|
|
88
|
+
}
|
|
89
|
+
update(id, body) {
|
|
90
|
+
return this.http.patch(`/partner/customers/${id}`, body);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export class WebhooksResource {
|
|
94
|
+
http;
|
|
95
|
+
constructor(http) {
|
|
96
|
+
this.http = http;
|
|
97
|
+
}
|
|
98
|
+
list() {
|
|
99
|
+
return this.http.get("/partner/webhooks");
|
|
100
|
+
}
|
|
101
|
+
create(body) {
|
|
102
|
+
return this.http.post("/partner/webhooks", body);
|
|
103
|
+
}
|
|
104
|
+
update(id, body) {
|
|
105
|
+
return this.http.patch(`/partner/webhooks/${id}`, body);
|
|
106
|
+
}
|
|
107
|
+
delete(id) {
|
|
108
|
+
return this.http.delete(`/partner/webhooks/${id}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export declare const DEFAULT_BASE_URL = "https://foxscheduling.com/api/v1";
|
|
2
|
+
export interface TokenSet {
|
|
3
|
+
accessToken: string;
|
|
4
|
+
refreshToken: string;
|
|
5
|
+
expiresAt: number;
|
|
6
|
+
scope: string;
|
|
7
|
+
tokenType: string;
|
|
8
|
+
}
|
|
9
|
+
export interface FoxSchedulingApiKeyAuth {
|
|
10
|
+
type: "apiKey";
|
|
11
|
+
apiKey: string;
|
|
12
|
+
}
|
|
13
|
+
export interface FoxSchedulingOAuthAuth {
|
|
14
|
+
type: "oauth";
|
|
15
|
+
clientId: string;
|
|
16
|
+
clientSecret?: string;
|
|
17
|
+
redirectUri: string;
|
|
18
|
+
tokenStore: import("./auth/tokenStore.js").TokenStore;
|
|
19
|
+
}
|
|
20
|
+
export type FoxSchedulingAuth = FoxSchedulingApiKeyAuth | FoxSchedulingOAuthAuth;
|
|
21
|
+
export interface FoxSchedulingConfig {
|
|
22
|
+
auth: FoxSchedulingAuth;
|
|
23
|
+
baseUrl?: string;
|
|
24
|
+
fetch?: typeof fetch;
|
|
25
|
+
}
|
|
26
|
+
export interface AuthorizationUrlResult {
|
|
27
|
+
url: string;
|
|
28
|
+
codeVerifier: string;
|
|
29
|
+
state: string;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,qCAAqC,CAAC;AAEnE,MAAM,WAAW,QAAQ;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,OAAO,sBAAsB,EAAE,UAAU,CAAC;CACvD;AAED,MAAM,MAAM,iBAAiB,GAAG,uBAAuB,GAAG,sBAAsB,CAAC;AAEjF,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,iBAAiB,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const DEFAULT_BASE_URL = "https://foxscheduling.com/api/v1";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/webhooks/verify.ts"],"names":[],"mappings":"AAEA,wBAAgB,yBAAyB,CAAC,MAAM,EAAE;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAaV"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
2
|
+
export function verifyFoxWebhookSignature(params) {
|
|
3
|
+
const payload = `${params.timestamp}.${params.rawBody}`;
|
|
4
|
+
const expected = createHmac("sha256", params.secret)
|
|
5
|
+
.update(payload)
|
|
6
|
+
.digest("hex");
|
|
7
|
+
try {
|
|
8
|
+
return timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(params.signatureHex, "hex"));
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@foxscheduling/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official Fox Scheduling Partner API SDK",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/cjs/index.cjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"require": "./dist/cjs/index.cjs",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": ["dist", "README.md"],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc && tsc -p tsconfig.cjs.json && node scripts/rename-cjs.mjs",
|
|
19
|
+
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
|
|
20
|
+
"prepare": "npm run build"
|
|
21
|
+
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"@foxscheduling/shared": "^0.1.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@foxscheduling/shared": "file:../shared-library",
|
|
33
|
+
"@types/jest": "^30",
|
|
34
|
+
"@types/node": "^24.10.1",
|
|
35
|
+
"jest": "^30",
|
|
36
|
+
"ts-jest": "^29",
|
|
37
|
+
"typescript": "~5.9.3"
|
|
38
|
+
}
|
|
39
|
+
}
|