@evinvest/sites-contract 0.1.3 → 0.1.5
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 +6 -4
- package/dist/booking-config.d.ts +1 -1
- package/dist/booking-config.js +1 -1
- package/dist/booking.d.ts +1 -1
- package/dist/booking.js +4 -1
- package/dist/experiments.js +4 -4
- package/dist/generated/booking-codes.d.ts +2 -0
- package/dist/generated/booking-codes.js +2 -0
- package/dist/generated/booking-limits.d.ts +6 -0
- package/dist/generated/booking-limits.js +7 -0
- package/dist/generated/booking-providers.d.ts +1 -0
- package/dist/generated/booking-providers.js +2 -0
- package/dist/generated/booking-statuses.d.ts +2 -0
- package/dist/generated/booking-statuses.js +2 -0
- package/dist/generated/day-parts.d.ts +2 -0
- package/dist/generated/day-parts.js +2 -0
- package/dist/generated/days.d.ts +1 -0
- package/dist/generated/days.js +2 -0
- package/dist/generated/index.d.ts +24 -0
- package/dist/generated/index.js +25 -0
- package/dist/generated/input-kinds.d.ts +2 -0
- package/dist/generated/input-kinds.js +2 -0
- package/dist/generated/lead-channels.d.ts +2 -0
- package/dist/generated/lead-channels.js +2 -0
- package/dist/generated/lead-flows.d.ts +2 -0
- package/dist/generated/lead-flows.js +2 -0
- package/dist/generated/lead-limits.d.ts +5 -0
- package/dist/generated/lead-limits.js +6 -0
- package/dist/generated/lead-suspects.d.ts +2 -0
- package/dist/generated/lead-suspects.js +2 -0
- package/dist/generated/messengers.d.ts +1 -0
- package/dist/generated/messengers.js +2 -0
- package/dist/generated/page-providers.d.ts +1 -0
- package/dist/generated/page-providers.js +2 -0
- package/dist/generated/place-codes.d.ts +2 -0
- package/dist/generated/place-codes.js +2 -0
- package/dist/generated/place-fields.d.ts +2 -0
- package/dist/generated/place-fields.js +2 -0
- package/dist/generated/place-limits.d.ts +11 -0
- package/dist/generated/{place.js → place-limits.js} +0 -3
- package/dist/generated/pricing-codes.d.ts +2 -0
- package/dist/generated/pricing-codes.js +2 -0
- package/dist/generated/pricing-currency.d.ts +1 -0
- package/dist/generated/pricing-currency.js +2 -0
- package/dist/generated/pricing-format.d.ts +1 -0
- package/dist/generated/pricing-format.js +2 -0
- package/dist/generated/{pricing.d.ts → pricing-limits.d.ts} +0 -4
- package/dist/generated/{pricing.js → pricing-limits.js} +0 -3
- package/dist/generated/site-channels.d.ts +2 -0
- package/dist/generated/site-channels.js +2 -0
- package/dist/index.d.ts +3 -8
- package/dist/index.js +3 -7
- package/dist/ingest.d.ts +3 -1
- package/dist/message-ref.d.ts +7 -0
- package/dist/message-ref.js +22 -0
- package/dist/place.d.ts +2 -1
- package/dist/place.js +3 -1
- package/dist/price.d.ts +1 -1
- package/dist/pricing.d.ts +1 -1
- package/dist/pricing.js +4 -1
- package/package.json +4 -1
- package/dist/generated/booking.d.ts +0 -12
- package/dist/generated/booking.js +0 -11
- package/dist/generated/codes.d.ts +0 -6
- package/dist/generated/codes.js +0 -4
- package/dist/generated/lead.d.ts +0 -13
- package/dist/generated/lead.js +0 -10
- package/dist/generated/place.d.ts +0 -15
- /package/dist/generated/{experiments.d.ts → experiment-limits.d.ts} +0 -0
- /package/dist/generated/{experiments.js → experiment-limits.js} +0 -0
package/README.md
CHANGED
|
@@ -3,20 +3,22 @@
|
|
|
3
3
|
The Service-Arb sites ↔ panel contract, in TS: what a landing reads from the panel and sends
|
|
4
4
|
to it. Its source is the panel — `crates/panel_core` and `contracts/proto/sa/v1` in
|
|
5
5
|
[EV-Service-Arb/sites_panel](https://github.com/EV-Service-Arb/sites_panel) — and this is its
|
|
6
|
-
only TS form.
|
|
6
|
+
only TS form. Its one dependency is `@evinvest/experiments` (zero-dep), no Node imports: it is bundled into landing pages and
|
|
7
7
|
the panel's front end.
|
|
8
8
|
|
|
9
9
|
```text
|
|
10
|
-
src/generated
|
|
10
|
+
src/generated/*.ts panel_core's shapes, vocabularies and limits (`nix run .#gen`), a
|
|
11
|
+
module per constant
|
|
11
12
|
src/generated/wire.ts the protos as protojson: the envelope, every type's properties
|
|
12
13
|
src/*.ts the one TS implementation of what both sides run, held to
|
|
13
14
|
contracts/vectors with panel_core:
|
|
14
15
|
price priceOf: what a page runs pricing checkPricingModel
|
|
15
16
|
booking bookingRequested, isLeadRef booking-config checkBookingConfig, checkBookingUrl
|
|
16
17
|
place checkPlaceLive: a place's live settings, field by field
|
|
17
|
-
phone normalizePhone, phoneProblem
|
|
18
|
+
phone normalizePhone, phoneProblem message-ref messageRefOf: a ref as typed
|
|
18
19
|
ingest siteEvent, ingestBody, uuidV7, isOpaqueId: the only way a site builds an event
|
|
19
|
-
experiments parseLiveExperiments, declarationProblem
|
|
20
|
+
experiments parseLiveExperiments, declarationProblem; validWeights, validHoldout are
|
|
21
|
+
@evinvest/experiments' (what applyOverrides takes), re-exported
|
|
20
22
|
```
|
|
21
23
|
|
|
22
24
|
A page bundles what it runs and not the panel's checks: they sit in modules of their own.
|
package/dist/booking-config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BookingCode } from "./generated/codes.js";
|
|
1
|
+
import type { BookingCode } from "./generated/booking-codes.js";
|
|
2
2
|
import type { BookingConfig, PageProvider } from "./generated/types.js";
|
|
3
3
|
/** One thing wrong with a place's `booking`: where below it (`""`, `default`, `providers.cal_com.url`) and why. */
|
|
4
4
|
export interface BookingProblem {
|
package/dist/booking-config.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isBookingProvider, isPageProvider } from "./booking.js";
|
|
2
|
-
import { BOOKING_LIMITS as LIMIT } from "./generated/booking.js";
|
|
2
|
+
import { BOOKING_LIMITS as LIMIT } from "./generated/booking-limits.js";
|
|
3
3
|
import { at, isObject } from "./text.js";
|
|
4
4
|
const CAL_SEGMENT = /* @__PURE__ */ new RegExp(LIMIT.calComSegment);
|
|
5
5
|
const LABEL = /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?$/;
|
package/dist/booking.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type DayPart } from "./generated/
|
|
1
|
+
import { type DayPart } from "./generated/day-parts.js";
|
|
2
2
|
import type { BookingProvider, PageProvider } from "./generated/types.js";
|
|
3
3
|
import type { BookingRequestedV1 } from "./generated/wire.js";
|
|
4
4
|
export declare const isBookingProvider: (v: unknown) => v is BookingProvider;
|
package/dist/booking.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import { BOOKING_LIMITS as LIMIT
|
|
1
|
+
import { BOOKING_LIMITS as LIMIT } from "./generated/booking-limits.js";
|
|
2
|
+
import { BOOKING_PROVIDERS } from "./generated/booking-providers.js";
|
|
3
|
+
import { DAY_PARTS } from "./generated/day-parts.js";
|
|
4
|
+
import { PAGE_PROVIDERS } from "./generated/page-providers.js";
|
|
2
5
|
import { isDate, isObject } from "./text.js";
|
|
3
6
|
export const isBookingProvider = (v) => BOOKING_PROVIDERS.some(p => p === v);
|
|
4
7
|
export const isPageProvider = (v) => PAGE_PROVIDERS.some(p => p === v);
|
package/dist/experiments.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { validHoldout, validWeights } from "@evinvest/experiments";
|
|
2
|
+
import { EXPERIMENT_LIMITS } from "./generated/experiment-limits.js";
|
|
2
3
|
import { charCount, isObject, trim } from "./text.js";
|
|
3
4
|
/**
|
|
4
5
|
* The panel's answer to `GET …/brands/{brand}/experiments`, or `null` when it is not one: an
|
|
@@ -45,10 +46,9 @@ export function declarationProblem(d) {
|
|
|
45
46
|
return "variant";
|
|
46
47
|
if (new Set(d.variants).size !== d.variants.length)
|
|
47
48
|
return "duplicate_variant";
|
|
48
|
-
|
|
49
|
-
if (!weightsOk)
|
|
49
|
+
if (validWeights(d.weights, d.variants.length) === undefined)
|
|
50
50
|
return "weights";
|
|
51
|
-
if (d.holdout !== undefined &&
|
|
51
|
+
if (d.holdout !== undefined && validHoldout(d.holdout) === undefined)
|
|
52
52
|
return "holdout";
|
|
53
53
|
if (d.summary !== undefined && charCount(trim(d.summary)) > EXPERIMENT_LIMITS.maxSummary)
|
|
54
54
|
return "summary";
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const BOOKING_CODES: readonly ["shape", "unknown_key", "required", "provider_unknown", "provider_shape", "provider_extra", "manual", "url_type", "default_unknown", "default_unset", "format", "scheme", "fragment", "backslash", "userinfo", "ip", "port", "host", "google", "cal_host", "cal_path"];
|
|
2
|
+
export type BookingCode = (typeof BOOKING_CODES)[number];
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// AUTO-GENERATED by `nix run .#gen` — do not edit.
|
|
2
|
+
export const BOOKING_CODES = ["shape", "unknown_key", "required", "provider_unknown", "provider_shape", "provider_extra", "manual", "url_type", "default_unknown", "default_unset", "format", "scheme", "fragment", "backslash", "userinfo", "ip", "port", "host", "google", "cal_host", "cal_path"];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const BOOKING_PROVIDERS: readonly ["manual", "link", "google_calendar", "cal_com"];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const DAYS: readonly ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export * from "./booking-codes.js";
|
|
2
|
+
export * from "./booking-limits.js";
|
|
3
|
+
export * from "./booking-providers.js";
|
|
4
|
+
export * from "./booking-statuses.js";
|
|
5
|
+
export * from "./day-parts.js";
|
|
6
|
+
export * from "./days.js";
|
|
7
|
+
export * from "./experiment-limits.js";
|
|
8
|
+
export * from "./input-kinds.js";
|
|
9
|
+
export * from "./lead-channels.js";
|
|
10
|
+
export * from "./lead-flows.js";
|
|
11
|
+
export * from "./lead-limits.js";
|
|
12
|
+
export * from "./lead-suspects.js";
|
|
13
|
+
export * from "./messengers.js";
|
|
14
|
+
export * from "./page-providers.js";
|
|
15
|
+
export * from "./place-codes.js";
|
|
16
|
+
export * from "./place-fields.js";
|
|
17
|
+
export * from "./place-limits.js";
|
|
18
|
+
export * from "./pricing-codes.js";
|
|
19
|
+
export * from "./pricing-currency.js";
|
|
20
|
+
export * from "./pricing-format.js";
|
|
21
|
+
export * from "./pricing-limits.js";
|
|
22
|
+
export * from "./site-channels.js";
|
|
23
|
+
export * from "./types.js";
|
|
24
|
+
export * from "./wire.js";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// AUTO-GENERATED by `nix run .#gen` — do not edit.
|
|
2
|
+
export * from "./booking-codes.js";
|
|
3
|
+
export * from "./booking-limits.js";
|
|
4
|
+
export * from "./booking-providers.js";
|
|
5
|
+
export * from "./booking-statuses.js";
|
|
6
|
+
export * from "./day-parts.js";
|
|
7
|
+
export * from "./days.js";
|
|
8
|
+
export * from "./experiment-limits.js";
|
|
9
|
+
export * from "./input-kinds.js";
|
|
10
|
+
export * from "./lead-channels.js";
|
|
11
|
+
export * from "./lead-flows.js";
|
|
12
|
+
export * from "./lead-limits.js";
|
|
13
|
+
export * from "./lead-suspects.js";
|
|
14
|
+
export * from "./messengers.js";
|
|
15
|
+
export * from "./page-providers.js";
|
|
16
|
+
export * from "./place-codes.js";
|
|
17
|
+
export * from "./place-fields.js";
|
|
18
|
+
export * from "./place-limits.js";
|
|
19
|
+
export * from "./pricing-codes.js";
|
|
20
|
+
export * from "./pricing-currency.js";
|
|
21
|
+
export * from "./pricing-format.js";
|
|
22
|
+
export * from "./pricing-limits.js";
|
|
23
|
+
export * from "./site-channels.js";
|
|
24
|
+
export * from "./types.js";
|
|
25
|
+
export * from "./wire.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const MESSENGERS: readonly ["whatsapp", "telegram"];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const PAGE_PROVIDERS: readonly ["link", "google_calendar", "cal_com"];
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const PLACE_CODES: readonly ["object", "unknown_field", "required", "type", "blank", "too_long", "control", "e164", "telegram_bot", "messenger_unknown", "boolean", "shape", "empty", "too_many", "day", "duplicate", "time", "closes_before_opens", "postal_code", "coordinate", "https_url", "review_url", "locale", "rating_value", "rating_count", "instant"];
|
|
2
|
+
export type PlaceCode = (typeof PLACE_CODES)[number];
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// AUTO-GENERATED by `nix run .#gen` — do not edit.
|
|
2
|
+
export const PLACE_CODES = ["object", "unknown_field", "required", "type", "blank", "too_long", "control", "e164", "telegram_bot", "messenger_unknown", "boolean", "shape", "empty", "too_many", "day", "duplicate", "time", "closes_before_opens", "postal_code", "coordinate", "https_url", "review_url", "locale", "rating_value", "rating_count", "instant"];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const PLACE_LIMITS: {
|
|
2
|
+
readonly e164: "^\\+[1-9][0-9]{6,14}$";
|
|
3
|
+
readonly maxArea: 200;
|
|
4
|
+
readonly maxHours: 14;
|
|
5
|
+
readonly maxLocales: 8;
|
|
6
|
+
readonly maxText: 200;
|
|
7
|
+
readonly maxUrl: 2048;
|
|
8
|
+
readonly reviewHosts: readonly ["g.page", "search.google.com"];
|
|
9
|
+
readonly telegramBot: "^[A-Za-z][A-Za-z0-9_]{1,28}[Bb][Oo][Tt]$";
|
|
10
|
+
readonly time: "^([01][0-9]|2[0-3]):[0-5][0-9]$";
|
|
11
|
+
};
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
// AUTO-GENERATED by `nix run .#gen` — do not edit.
|
|
2
|
-
export const DAYS = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
|
|
3
|
-
export const MESSENGERS = ["whatsapp", "telegram"];
|
|
4
|
-
export const PLACE_FIELDS = ["phone", "whatsapp", "telegram", "messengers", "hours", "serviceArea", "address", "geo", "storefrontPhoto", "landmark", "rating", "booking", "reviewUrl"];
|
|
5
2
|
export const PLACE_LIMITS = {
|
|
6
3
|
"e164": "^\\+[1-9][0-9]{6,14}$",
|
|
7
4
|
"maxArea": 200,
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const PRICING_CODES: readonly ["object", "missing", "unknownField", "format", "currency", "date", "int", "slug", "labels", "locale", "label", "list", "duplicate", "kind", "needKind", "noInput", "dearest", "labelMissing"];
|
|
2
|
+
export type PricingCode = (typeof PRICING_CODES)[number];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const PRICING_CURRENCY = "EUR";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const PRICING_FORMAT = 1;
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
export declare const PRICING_FORMAT = 1;
|
|
2
|
-
export declare const PRICING_CURRENCY = "EUR";
|
|
3
1
|
export declare const PRICING_LIMITS: {
|
|
4
2
|
readonly locale: "^[a-z]{2}(-[A-Z]{2})?$";
|
|
5
3
|
readonly maxDiscountBp: 10000;
|
|
@@ -12,5 +10,3 @@ export declare const PRICING_LIMITS: {
|
|
|
12
10
|
readonly maxPriceCents: 100000000;
|
|
13
11
|
readonly slug: "^[a-z0-9_-]{1,40}$";
|
|
14
12
|
};
|
|
15
|
-
export declare const INPUT_KINDS: readonly ["add", "multiply", "discount"];
|
|
16
|
-
export type PricingInputKind = (typeof INPUT_KINDS)[number];
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
// AUTO-GENERATED by `nix run .#gen` — do not edit.
|
|
2
|
-
export const PRICING_FORMAT = 1;
|
|
3
|
-
export const PRICING_CURRENCY = "EUR";
|
|
4
2
|
export const PRICING_LIMITS = {
|
|
5
3
|
"locale": "^[a-z]{2}(-[A-Z]{2})?$",
|
|
6
4
|
"maxDiscountBp": 10000,
|
|
@@ -13,4 +11,3 @@ export const PRICING_LIMITS = {
|
|
|
13
11
|
"maxPriceCents": 100000000,
|
|
14
12
|
"slug": "^[a-z0-9_-]{1,40}$",
|
|
15
13
|
};
|
|
16
|
-
export const INPUT_KINDS = ["add", "multiply", "discount"];
|
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
export * from "./generated/
|
|
2
|
-
export * from "./generated/codes.js";
|
|
3
|
-
export * from "./generated/experiments.js";
|
|
4
|
-
export * from "./generated/lead.js";
|
|
5
|
-
export * from "./generated/place.js";
|
|
6
|
-
export * from "./generated/pricing.js";
|
|
7
|
-
export type * from "./generated/types.js";
|
|
8
|
-
export * from "./generated/wire.js";
|
|
1
|
+
export * from "./generated/index.js";
|
|
9
2
|
export { bookingRequested, isBookingProvider, isLeadRef, isPageProvider, preferredDateInWindow, type BookingRequested } from "./booking.js";
|
|
10
3
|
export { checkBookingConfig, checkBookingUrl, type BookingProblem } from "./booking-config.js";
|
|
11
4
|
export { declarationProblem, parseLiveExperiments, type DeclarationProblem } from "./experiments.js";
|
|
5
|
+
export { validHoldout, validWeights } from "@evinvest/experiments";
|
|
12
6
|
export { ingestBody, isOpaqueId, siteEvent, uuidV7, type LeadCreated, type SiteEvent, type SiteEventHead, type SiteProperties } from "./ingest.js";
|
|
7
|
+
export { messageRefOf } from "./message-ref.js";
|
|
13
8
|
export { normalizePhone, phoneProblem } from "./phone.js";
|
|
14
9
|
export { checkPlaceLive, isInstant, type PlaceProblem } from "./place.js";
|
|
15
10
|
export { mulBp, priceOf, roundTo, type Price, type PriceLine, type PricingInputs, type PricingLabels } from "./price.js";
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
export * from "./generated/
|
|
2
|
-
export * from "./generated/codes.js";
|
|
3
|
-
export * from "./generated/experiments.js";
|
|
4
|
-
export * from "./generated/lead.js";
|
|
5
|
-
export * from "./generated/place.js";
|
|
6
|
-
export * from "./generated/pricing.js";
|
|
7
|
-
export * from "./generated/wire.js";
|
|
1
|
+
export * from "./generated/index.js";
|
|
8
2
|
export { bookingRequested, isBookingProvider, isLeadRef, isPageProvider, preferredDateInWindow } from "./booking.js";
|
|
9
3
|
export { checkBookingConfig, checkBookingUrl } from "./booking-config.js";
|
|
10
4
|
export { declarationProblem, parseLiveExperiments } from "./experiments.js";
|
|
5
|
+
export { validHoldout, validWeights } from "@evinvest/experiments";
|
|
11
6
|
export { ingestBody, isOpaqueId, siteEvent, uuidV7 } from "./ingest.js";
|
|
7
|
+
export { messageRefOf } from "./message-ref.js";
|
|
12
8
|
export { normalizePhone, phoneProblem } from "./phone.js";
|
|
13
9
|
export { checkPlaceLive, isInstant } from "./place.js";
|
|
14
10
|
export { mulBp, priceOf, roundTo } from "./price.js";
|
package/dist/ingest.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { BookingRequested } from "./booking.js";
|
|
2
|
-
import type { LeadFlow
|
|
2
|
+
import type { LeadFlow } from "./generated/lead-flows.js";
|
|
3
|
+
import type { LeadSuspect } from "./generated/lead-suspects.js";
|
|
4
|
+
import type { SiteChannel } from "./generated/site-channels.js";
|
|
3
5
|
import { type Event, type ExperimentsDeclaredV1, type IngestRequest, type LeadCreatedV1, type Registered, type SiteEventKey, type Subject } from "./generated/wire.js";
|
|
4
6
|
/** `lead.created@1`'s properties, their vocabularies as the panel checks them. */
|
|
5
7
|
export type LeadCreated = LeadCreatedV1 & {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A ref as an operator types or pastes it ("aq-7k3f ", "Réf. AQ-7K3F", "ref aq 7k3f", "AQ 7K3F")
|
|
3
|
+
* in the form the landing made it, `AQ-7K3F`, or `null` when it cannot be one
|
|
4
|
+
* (`contracts/vectors/message-ref.json`). In the code Crockford's look-alikes are read as it
|
|
5
|
+
* reads them: O is 0, I and L are 1.
|
|
6
|
+
*/
|
|
7
|
+
export declare function messageRefOf(raw: string | null): string | null;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { LEAD_LIMITS } from "./generated/lead-limits.js";
|
|
2
|
+
const MESSAGE_REF = /* @__PURE__ */ new RegExp(LEAD_LIMITS.messageRef);
|
|
3
|
+
/** A label pasted with the ref ("Réf. ", "ref ", "Ref: "): the prefilled WhatsApp line ends "Réf. AQ-7K3F". */
|
|
4
|
+
const REF_LABEL = /^R[EÉ]F(?:[EÉ]RENCE)?(?:[.:#]\s*|\s+)/;
|
|
5
|
+
/** The prefix and the code, apart: a dash, spaces, or both between them. */
|
|
6
|
+
const REF_PARTS = /^([A-Z]{2,4})[\s-]*([0-9A-Z]{4,8})$/;
|
|
7
|
+
/**
|
|
8
|
+
* A ref as an operator types or pastes it ("aq-7k3f ", "Réf. AQ-7K3F", "ref aq 7k3f", "AQ 7K3F")
|
|
9
|
+
* in the form the landing made it, `AQ-7K3F`, or `null` when it cannot be one
|
|
10
|
+
* (`contracts/vectors/message-ref.json`). In the code Crockford's look-alikes are read as it
|
|
11
|
+
* reads them: O is 0, I and L are 1.
|
|
12
|
+
*/
|
|
13
|
+
export function messageRefOf(raw) {
|
|
14
|
+
const text = (raw ?? "").trim().toUpperCase().replace(REF_LABEL, "").trim();
|
|
15
|
+
const parts = REF_PARTS.exec(text);
|
|
16
|
+
const prefix = parts?.[1];
|
|
17
|
+
const code = parts?.[2];
|
|
18
|
+
if (prefix === undefined || code === undefined)
|
|
19
|
+
return null;
|
|
20
|
+
const ref = `${prefix}-${code.replace(/O/g, "0").replace(/[IL]/g, "1")}`;
|
|
21
|
+
return MESSAGE_REF.test(ref) ? ref : null;
|
|
22
|
+
}
|
package/dist/place.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { BookingCode
|
|
1
|
+
import type { BookingCode } from "./generated/booking-codes.js";
|
|
2
|
+
import type { PlaceCode } from "./generated/place-codes.js";
|
|
2
3
|
import type { PlaceLive } from "./generated/types.js";
|
|
3
4
|
/** One thing wrong with a place's settings: its path (`phone`, `hours[0].opens`, `booking.providers.cal_com.url`) and why. */
|
|
4
5
|
export interface PlaceProblem {
|
package/dist/place.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { checkBookingConfig } from "./booking-config.js";
|
|
2
|
-
import { DAYS
|
|
2
|
+
import { DAYS } from "./generated/days.js";
|
|
3
|
+
import { MESSENGERS } from "./generated/messengers.js";
|
|
4
|
+
import { PLACE_LIMITS as LIMIT } from "./generated/place-limits.js";
|
|
3
5
|
import { at, charCount, hasControl, hasWhitespace, isDate, isObject, trim } from "./text.js";
|
|
4
6
|
const E164 = /* @__PURE__ */ new RegExp(LIMIT.e164);
|
|
5
7
|
const TELEGRAM_BOT = /* @__PURE__ */ new RegExp(LIMIT.telegramBot);
|
package/dist/price.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PricingInputKind } from "./generated/
|
|
1
|
+
import type { PricingInputKind } from "./generated/input-kinds.js";
|
|
2
2
|
import type { PricingInput, PricingModel } from "./generated/types.js";
|
|
3
3
|
/** The answers to an estimate's inputs: input id → option id. */
|
|
4
4
|
export type PricingInputs = Readonly<Record<string, string>>;
|
package/dist/pricing.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PricingCode } from "./generated/codes.js";
|
|
1
|
+
import type { PricingCode } from "./generated/pricing-codes.js";
|
|
2
2
|
import type { PricingModel } from "./generated/types.js";
|
|
3
3
|
/**
|
|
4
4
|
* One thing wrong with a model: its path from the model's root (`inputs[0].options[2].addCents`,
|
package/dist/pricing.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import { INPUT_KINDS
|
|
1
|
+
import { INPUT_KINDS } from "./generated/input-kinds.js";
|
|
2
|
+
import { PRICING_CURRENCY } from "./generated/pricing-currency.js";
|
|
3
|
+
import { PRICING_FORMAT } from "./generated/pricing-format.js";
|
|
4
|
+
import { PRICING_LIMITS as LIMIT } from "./generated/pricing-limits.js";
|
|
2
5
|
import { effects, mulBp } from "./price.js";
|
|
3
6
|
import { at, isDate, isObject, trim } from "./text.js";
|
|
4
7
|
const SLUG = /* @__PURE__ */ new RegExp(LIMIT.slug);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evinvest/sites-contract",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "The Service-Arb sites ↔ panel contract in TS: the shapes and vocabularies generated from the panel's Rust and protos, and the one TS implementation of what both sides run — pricing, booking and place checks, phone numbers, the ingest events a site sends.",
|
|
5
5
|
"license": "BlueOak-1.0.0",
|
|
6
6
|
"publishConfig": {
|
|
@@ -35,6 +35,9 @@
|
|
|
35
35
|
"typecheck": "tsc --noEmit",
|
|
36
36
|
"prepare": "npm run build"
|
|
37
37
|
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@evinvest/experiments": "^0.6.1"
|
|
40
|
+
},
|
|
38
41
|
"devDependencies": {
|
|
39
42
|
"@types/node": "^22.10.0",
|
|
40
43
|
"typescript": "^5.9.3",
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export declare const BOOKING_PROVIDERS: readonly ["manual", "link", "google_calendar", "cal_com"];
|
|
2
|
-
export declare const PAGE_PROVIDERS: readonly ["link", "google_calendar", "cal_com"];
|
|
3
|
-
export declare const BOOKING_LIMITS: {
|
|
4
|
-
readonly calComHosts: readonly ["cal.evinvest.ltd", "cal.com"];
|
|
5
|
-
readonly calComSegment: "^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$";
|
|
6
|
-
readonly leadRef: "^lead-[1-9][0-9]{0,18}-[0-9a-f]{8}$";
|
|
7
|
-
readonly maxUrl: 2048;
|
|
8
|
-
};
|
|
9
|
-
export declare const BOOKING_STATUSES: readonly ["none", "requested", "booked", "canceled", "done", "no_show"];
|
|
10
|
-
export type BookingStatus = (typeof BOOKING_STATUSES)[number];
|
|
11
|
-
export declare const DAY_PARTS: readonly ["morning", "afternoon", "evening"];
|
|
12
|
-
export type DayPart = (typeof DAY_PARTS)[number];
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
// AUTO-GENERATED by `nix run .#gen` — do not edit.
|
|
2
|
-
export const BOOKING_PROVIDERS = ["manual", "link", "google_calendar", "cal_com"];
|
|
3
|
-
export const PAGE_PROVIDERS = ["link", "google_calendar", "cal_com"];
|
|
4
|
-
export const BOOKING_LIMITS = {
|
|
5
|
-
"calComHosts": ["cal.evinvest.ltd", "cal.com"],
|
|
6
|
-
"calComSegment": "^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$",
|
|
7
|
-
"leadRef": "^lead-[1-9][0-9]{0,18}-[0-9a-f]{8}$",
|
|
8
|
-
"maxUrl": 2048,
|
|
9
|
-
};
|
|
10
|
-
export const BOOKING_STATUSES = ["none", "requested", "booked", "canceled", "done", "no_show"];
|
|
11
|
-
export const DAY_PARTS = ["morning", "afternoon", "evening"];
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export declare const PRICING_CODES: readonly ["object", "missing", "unknownField", "format", "currency", "date", "int", "slug", "labels", "locale", "label", "list", "duplicate", "kind", "needKind", "noInput", "dearest", "labelMissing"];
|
|
2
|
-
export type PricingCode = (typeof PRICING_CODES)[number];
|
|
3
|
-
export declare const BOOKING_CODES: readonly ["shape", "unknown_key", "required", "provider_unknown", "provider_shape", "provider_extra", "manual", "url_type", "default_unknown", "default_unset", "format", "scheme", "fragment", "backslash", "userinfo", "ip", "port", "host", "google", "cal_host", "cal_path"];
|
|
4
|
-
export type BookingCode = (typeof BOOKING_CODES)[number];
|
|
5
|
-
export declare const PLACE_CODES: readonly ["object", "unknown_field", "required", "type", "blank", "too_long", "control", "e164", "telegram_bot", "messenger_unknown", "boolean", "shape", "empty", "too_many", "day", "duplicate", "time", "closes_before_opens", "postal_code", "coordinate", "https_url", "review_url", "locale", "rating_value", "rating_count", "instant"];
|
|
6
|
-
export type PlaceCode = (typeof PLACE_CODES)[number];
|
package/dist/generated/codes.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
// AUTO-GENERATED by `nix run .#gen` — do not edit.
|
|
2
|
-
export const PRICING_CODES = ["object", "missing", "unknownField", "format", "currency", "date", "int", "slug", "labels", "locale", "label", "list", "duplicate", "kind", "needKind", "noInput", "dearest", "labelMissing"];
|
|
3
|
-
export const BOOKING_CODES = ["shape", "unknown_key", "required", "provider_unknown", "provider_shape", "provider_extra", "manual", "url_type", "default_unknown", "default_unset", "format", "scheme", "fragment", "backslash", "userinfo", "ip", "port", "host", "google", "cal_host", "cal_path"];
|
|
4
|
-
export const PLACE_CODES = ["object", "unknown_field", "required", "type", "blank", "too_long", "control", "e164", "telegram_bot", "messenger_unknown", "boolean", "shape", "empty", "too_many", "day", "duplicate", "time", "closes_before_opens", "postal_code", "coordinate", "https_url", "review_url", "locale", "rating_value", "rating_count", "instant"];
|
package/dist/generated/lead.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export declare const LEAD_LIMITS: {
|
|
2
|
-
readonly analyticsId: "^[A-Za-z0-9._:-]{1,128}$";
|
|
3
|
-
readonly maxEstimateInputs: 12;
|
|
4
|
-
readonly messageRef: "^[A-Z]{2,4}-[0-9A-HJKMNP-TV-Z]{4,8}$";
|
|
5
|
-
};
|
|
6
|
-
export declare const LEAD_CHANNELS: readonly ["form", "phone_inbound", "callback", "whatsapp", "telegram"];
|
|
7
|
-
export type LeadChannel = (typeof LEAD_CHANNELS)[number];
|
|
8
|
-
export declare const SITE_CHANNELS: readonly ["form", "callback", "whatsapp", "telegram"];
|
|
9
|
-
export type SiteChannel = (typeof SITE_CHANNELS)[number];
|
|
10
|
-
export declare const LEAD_SUSPECTS: readonly ["rate_limited", "too_fast"];
|
|
11
|
-
export type LeadSuspect = (typeof LEAD_SUSPECTS)[number];
|
|
12
|
-
export declare const LEAD_FLOWS: readonly ["quote", "estimate", "fixed"];
|
|
13
|
-
export type LeadFlow = (typeof LEAD_FLOWS)[number];
|
package/dist/generated/lead.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
// AUTO-GENERATED by `nix run .#gen` — do not edit.
|
|
2
|
-
export const LEAD_LIMITS = {
|
|
3
|
-
"analyticsId": "^[A-Za-z0-9._:-]{1,128}$",
|
|
4
|
-
"maxEstimateInputs": 12,
|
|
5
|
-
"messageRef": "^[A-Z]{2,4}-[0-9A-HJKMNP-TV-Z]{4,8}$",
|
|
6
|
-
};
|
|
7
|
-
export const LEAD_CHANNELS = ["form", "phone_inbound", "callback", "whatsapp", "telegram"];
|
|
8
|
-
export const SITE_CHANNELS = ["form", "callback", "whatsapp", "telegram"];
|
|
9
|
-
export const LEAD_SUSPECTS = ["rate_limited", "too_fast"];
|
|
10
|
-
export const LEAD_FLOWS = ["quote", "estimate", "fixed"];
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export declare const DAYS: readonly ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
|
|
2
|
-
export declare const MESSENGERS: readonly ["whatsapp", "telegram"];
|
|
3
|
-
export declare const PLACE_FIELDS: readonly ["phone", "whatsapp", "telegram", "messengers", "hours", "serviceArea", "address", "geo", "storefrontPhoto", "landmark", "rating", "booking", "reviewUrl"];
|
|
4
|
-
export type PlaceField = (typeof PLACE_FIELDS)[number];
|
|
5
|
-
export declare const PLACE_LIMITS: {
|
|
6
|
-
readonly e164: "^\\+[1-9][0-9]{6,14}$";
|
|
7
|
-
readonly maxArea: 200;
|
|
8
|
-
readonly maxHours: 14;
|
|
9
|
-
readonly maxLocales: 8;
|
|
10
|
-
readonly maxText: 200;
|
|
11
|
-
readonly maxUrl: 2048;
|
|
12
|
-
readonly reviewHosts: readonly ["g.page", "search.google.com"];
|
|
13
|
-
readonly telegramBot: "^[A-Za-z][A-Za-z0-9_]{1,28}[Bb][Oo][Tt]$";
|
|
14
|
-
readonly time: "^([01][0-9]|2[0-3]):[0-5][0-9]$";
|
|
15
|
-
};
|
|
File without changes
|
|
File without changes
|