@owlmeans/common-inquiry 0.0.0-stage → 0.1.18-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,74 @@
1
- # Temporary Holding Version
1
+ # @owlmeans/common-inquiry
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The runtime-free contract of the OwlMeans customer inquiry widget: a visitor opens a dialog from a
4
+ host page, picks an intent (a tab), leaves contact details, a message and up to five attachments,
5
+ and a CRM service mails it on. Three parties share this package — the browser SDK
6
+ (`@owlmeans/web-inquiry`), the widget bundle that renders the dialog, and the CRM API that accepts
7
+ the submission — so the names, limits and shapes they agree on live in one place.
8
+
9
+ No React, no DOM, no runtime dependencies: constants, types, JSON schemas and one pure helper.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ bun add @owlmeans/common-inquiry@^0.1.18-rc.1
15
+ ```
16
+
17
+ `ajv` is an optional peer: the schemas are typed with its `JSONSchemaType`, and a server that
18
+ compiles them brings its own.
19
+
20
+ ## Concepts
21
+
22
+ - **Widget config** (`InquiryWidgetConfig`): an id, one or more tabs (`alias`, localized `title`
23
+ and `description`), an optional `defaultTab`, the terms and privacy links the inquirer consents
24
+ to, and an optional language. A config with ONE tab renders without a tab strip.
25
+ - **Runtime** (`InquiryRuntime`): what the widget bundle `inquiry.js` installs at
26
+ `window.__owlmeansInquiry` — `version`, `configure`, `open`, `button`, `unmount`. Hosts reach it
27
+ through `@owlmeans/web-inquiry`, which checks `version` against `INQUIRY_RUNTIME_VERSION`.
28
+ - **Submission** (`InquirySubmission`): one multipart POST to `<crm>/api/inquiry` — text fields,
29
+ `files` as a JSON string of `InquiryFileMeta[]`, and the bytes in `file0` … `file4`.
30
+ - **Limits**: 5 000 000 bytes per file, 20 000 000 in total, five files; PNG, JPEG, GIF, WEBP,
31
+ PDF, CSV and plain text only (never SVG).
32
+
33
+ ## Usage
34
+
35
+ ```ts
36
+ import { inquiryConfigHelper, type InquiryWidgetConfig } from '@owlmeans/common-inquiry'
37
+
38
+ const config: InquiryWidgetConfig = {
39
+ id: 'owlmeans-quote',
40
+ tabs: [{ alias: 'quote', title: { en: 'Get a quote', pl: 'Poproś o wycenę' } }],
41
+ legal: { terms: 'https://owlmeans.com/legal/terms', privacy: 'https://owlmeans.com/legal/privacy' },
42
+ }
43
+
44
+ inquiryConfigHelper.validate(config) // [] — or English sentences, one per problem
45
+ inquiryConfigHelper.tabOf(config, 'quote') // the tab, else the default, else the first
46
+ inquiryConfigHelper.text(config.tabs[0].title, 'pl-PL') // 'Poproś o wycenę'
47
+ inquiryConfigHelper.normalizeLanguage('uk-UA') // 'uk' — or 'en' when unsupported
48
+ ```
49
+
50
+ A CRM route validates the multipart body with `InquirySubmissionSchema` (ajv with
51
+ `removeAdditional` and `coerceTypes`), then parses `files` and validates it with
52
+ `InquiryFileMetaListSchema`. The file fields are declared as open objects on purpose: any stricter
53
+ keyword makes ajv walk the Buffer's bytes.
54
+
55
+ ## Related
56
+
57
+ - [`@owlmeans/web-inquiry`](../web-inquiry): the browser SDK that loads the widget and reports opens
58
+ - [`@owlmeans/web-log`](../web-log): the consent-gated tag-manager plugin the open event reaches
59
+
60
+ <!-- owlmeans:agent-guidance:start -->
61
+ ## Agent guidance
62
+
63
+ This package ships embedded agent skills under `agent-meta/`. After installing your
64
+ `@owlmeans/*` packages, run the OwlMeans agent-skills installer to place them into
65
+ your project's skill store (`.agents/skills/`):
66
+
67
+ ```sh
68
+ npx @owlmeans/agent-skills@^0.1.18-rc.53
69
+ ```
70
+
71
+ The embedded files are version-matched to this package release. Do not edit them
72
+ directly — they are regenerated on each publish. To contribute guidance edits,
73
+ open a PR against the source monorepo.
74
+ <!-- owlmeans:agent-guidance:end -->
@@ -0,0 +1,16 @@
1
+ {
2
+ "schemaVersion": 2,
3
+ "package": "@owlmeans/common-inquiry",
4
+ "version": "0.1.18-rc.1",
5
+ "generatedAt": "2026-10-09T11:30:42.759Z",
6
+ "canonicalRepo": "https://github.com/owlmeans/common",
7
+ "entries": [
8
+ {
9
+ "kind": "skill",
10
+ "name": "common-inquiry",
11
+ "category": "package-specific",
12
+ "file": "skills/common-inquiry/SKILL.md",
13
+ "canonicalPath": ".agents/skills/common-inquiry/SKILL.md"
14
+ }
15
+ ]
16
+ }
@@ -0,0 +1,138 @@
1
+ ---
2
+ name: common-inquiry
3
+ description: How to use @owlmeans/common-inquiry — the runtime-free contract of the OwlMeans customer inquiry widget (a contact dialog a host page opens, mailed on by a CRM service). Covers the widget config and its tabs, the window runtime contract (INQUIRY_GLOBAL, INQUIRY_RUNTIME_VERSION, configure/open/button/unmount, one onOpen per open), the multipart submission and its file fields, the size/type/text limits, the JSON schemas and inquiryConfigHelper (text, validate, tabOf, normalizeLanguage). Auto-invoked when building the widget bundle, a CRM inquiry route, or a host's widget config, or when importing any INQUIRY_* constant, Inquiry* type or schema. Not the agent's ask-a-person inquiry (that is the `inquiry` skill).
4
+ user-invocable: false
5
+ ---
6
+ <!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
7
+
8
+ # @owlmeans/common-inquiry
9
+
10
+ **Layer:** Cross-cutting domain (no `@owlmeans/*` dependencies; optional `ajv` peer for schema types)
11
+ **Install:** `"@owlmeans/common-inquiry": "^0.1.18-rc.1"` in `dependencies`
12
+
13
+ The one place the three parties of the inquiry widget agree: the browser SDK
14
+ (`@owlmeans/web-inquiry`), the widget bundle that renders the dialog, and the CRM API that accepts
15
+ the submission. Constants, types, JSON schemas and one pure helper — no React, no DOM, nothing that
16
+ runs on import.
17
+
18
+ ## Addresses
19
+
20
+ A CRM is addressed by its base URL (`https://<web host>/crm`, no trailing slash):
21
+
22
+ | Constant | Value | Full address |
23
+ |---|---|---|
24
+ | `INQUIRY_SCRIPT` | `inquiry.js` | `<crm>/inquiry.js?v=<INQUIRY_RUNTIME_VERSION>` — the widget bundle |
25
+ | `INQUIRY_API_SEGMENT` | `api` | `<crm>/api` — the CRM API |
26
+ | `INQUIRY_CONFIG_PATH` | `/assets/config.json` | `<crm>/api/assets/config.json` — the advertised config (reCAPTCHA site key) |
27
+ | `INQUIRY_SUBMIT_PATH` | `/inquiry` | `POST <crm>/api/inquiry` — multipart |
28
+ | `INQUIRY_RECAPTCHA_ACTION` | `inquiry` | the reCAPTCHA v3 action the widget executes and the CRM requires |
29
+ | `INQUIRY_OPEN_EVENT` | `inquiry_dialog_open` | the analytics event of an open |
30
+
31
+ ## The widget config
32
+
33
+ ```ts
34
+ const config: InquiryWidgetConfig = {
35
+ id: 'viable', // INQUIRY_ALIAS_PATTERN: ^[a-z0-9][a-z0-9-]{0,31}$
36
+ tabs: [
37
+ { alias: 'report-issue', title: { en: 'Report an issue', pl: 'Zgłoś problem' } },
38
+ { alias: 'ask-question', title: 'Ask a question', description: 'We answer within a day.' },
39
+ ],
40
+ defaultTab: 'report-issue', // optional; default: the first tab
41
+ legal: { terms: 'https://…/terms', privacy: '/legal/privacy' },
42
+ language: 'pl', // optional; default: the runtime's, then the document's
43
+ }
44
+ ```
45
+
46
+ - **One tab renders without a tab strip** — the dialog is that single intent. A site that opens a
47
+ dialog per intent (a "Get a quote" button, a "Book a session" button) gives each its own one-tab
48
+ config with its own `id`.
49
+ - `LocalizedText` is a string or a `{ language: string }` map; `inquiryConfigHelper.text` reads it
50
+ with the fallback chain exact tag → primary subtag → `en` → first entry.
51
+ - Legal links are absolute http(s) URLs or root-relative paths; a widget resolves a relative one
52
+ against the host page and submits the absolute form (`terms`, `privacy`).
53
+ - Caps: 1–`INQUIRY_MAX_TABS` (12) tabs, title ≤ `INQUIRY_TITLE_MAX` (120), description ≤
54
+ `INQUIRY_DESCRIPTION_MAX` (600) per language.
55
+
56
+ `inquiryConfigHelper.validate(config)` returns every problem as an English sentence (`[]` when
57
+ usable): the id and aliases against the pattern, alias uniqueness, non-empty titles, `defaultTab`
58
+ naming a tab, the legal links. `InquiryWidgetConfigSchema` checks the structure only — uniqueness
59
+ and `defaultTab` membership are the helper's.
60
+
61
+ ## The runtime contract
62
+
63
+ The bundle installs an `InquiryRuntime` at `window[INQUIRY_GLOBAL]` (`window.__owlmeansInquiry`):
64
+
65
+ | Member | Contract |
66
+ |---|---|
67
+ | `version` | `INQUIRY_RUNTIME_VERSION`; a client refuses another. Bump it only for an incompatible change |
68
+ | `configure(options)` | page-wide `{ url, language?, onOpen? }`, last call wins; `language` may be a function read at every open |
69
+ | `open(config, opts?)` | mount the widget's dialog on first use, open it on `opts.tab` or the default tab; apply `opts.email` when supplied |
70
+ | `button(config, opts?)` | mount a floating button (`position`, `offset`, `label`, `source` — default `fab`, `email`); returns an `InquiryHandle` (`open`, `update`, `unmount`); a second call for the same id updates it |
71
+ | `unmount(id?)` | remove one widget, or all |
72
+
73
+ **`onOpen` is called exactly once per dialog open**, whatever opened it — `open`, a handle's
74
+ `open`, the floating button — with `{ widget, tab, source }`. Opening a dialog that is already open
75
+ does not call it again. The SDK reports analytics from this callback only, so a runtime that also
76
+ reported from elsewhere would double-count.
77
+
78
+ `InquiryEmailOptions.email` is an optional `InquiryEmailPreset`: a string or a lazy function
79
+ returning `InquiryEmailValue` (`string | null | undefined`), synchronously or in a Promise. The
80
+ runtime resolves it on each closed-to-open transition and replaces any manually edited address;
81
+ calling `open` on an already open dialog does not resolve it again. A null/undefined result or a
82
+ provider failure clears the address for manual entry. Omitting the option preserves the manual
83
+ draft. A button's provider also applies to its floating trigger and handle's `open`; an explicit
84
+ open option overrides it.
85
+
86
+ While a Promise is pending, the address is empty, its field and Send are disabled, and a spinner
87
+ beside the field announces loading. Other fields remain editable. Closing, reopening or unmounting
88
+ invalidates earlier pending results. A synchronous result needs no spinner. The host owns caching;
89
+ the runtime does not fetch identity or persist addresses. These optional options keep runtime
90
+ version 1 compatible with clients that omit them.
91
+
92
+ ## The submission
93
+
94
+ One multipart POST. A multipart parser with `attachFieldsToBody: 'keyValues'` hands every text
95
+ field over as a string and every file as a Buffer:
96
+
97
+ | Field | Rule |
98
+ |---|---|
99
+ | `widget`, `tab` | alias pattern; required |
100
+ | `email` | ≤ `INQUIRY_EMAIL_MAX` (254), `format: email`; required |
101
+ | `subject` | 1–`INQUIRY_SUBJECT_MAX` (150); required |
102
+ | `contactMethod` | `InquiryContactMethod`: `email`, `phone`, `messenger`, `video`; required |
103
+ | `contactDetail` | ≤ `INQUIRY_DETAIL_MAX` (100); the number, handle or time the method needs |
104
+ | `body` | 1–`INQUIRY_BODY_MAX` (5000); required |
105
+ | `consent` | `true` or `'true'` only; required |
106
+ | `files` | JSON string of `InquiryFileMeta[]` (`'[]'` without attachments); required |
107
+ | `tabTitle`, `language`, `page`, `terms`, `privacy` | optional context for the mail |
108
+ | `file0` … `file4` | the bytes, in the fields `files` names |
109
+
110
+ `InquirySubmissionSchema` is written for ajv with `removeAdditional` + `coerceTypes`. The file
111
+ fields are declared as `{ type: 'object', additionalProperties: true }` and nothing else: any
112
+ `properties`, `additionalProperties: false` or size keyword makes ajv walk the Buffer (or strip its
113
+ bytes). The handler parses `files` and validates it with `InquiryFileMetaListSchema` (known field,
114
+ allowed type, size ≤ the per-file cap, at most five), then checks that each named field is present.
115
+
116
+ ## Limits
117
+
118
+ | Constant | Value |
119
+ |---|---|
120
+ | `INQUIRY_MAX_FILE_BYTES` | 5 000 000 (decimal) |
121
+ | `INQUIRY_MAX_TOTAL_BYTES` | 20 000 000 |
122
+ | `INQUIRY_MAX_FILES` | 5 (`INQUIRY_FILE_FIELDS` = `file0` … `file4`) |
123
+ | `INQUIRY_ALLOWED_TYPES` | `image/png`, `image/jpeg`, `image/gif`, `image/webp`, `application/pdf`, `text/csv`, `text/plain` — never SVG |
124
+ | `INQUIRY_TYPE_EXTENSIONS` | per type, lower case, first canonical (`jpg`/`jpeg`, `txt`/`log`) |
125
+
126
+ Declared types are claims: the CRM re-detects the type from the bytes and refuses a mismatch, so a
127
+ widget's client-side check is a convenience, never the gate.
128
+
129
+ ## Languages
130
+
131
+ `INQUIRY_LANGUAGES` (`en pl ru be uk es de fr`) is what the widget ships strings for;
132
+ `inquiryConfigHelper.normalizeLanguage(tag)` maps any tag to its primary subtag when supported,
133
+ else `en`.
134
+
135
+ ## Related
136
+
137
+ - `web-inquiry` — the browser SDK over this contract (load, open, bind, button, analytics)
138
+ - `web-log` — `gtmAnalyticsPlugin`, which carries the open event to a tag manager
@@ -0,0 +1,24 @@
1
+ import type { InquiryTab, InquiryWidgetConfig, LocalizedText } from '../types.js';
2
+ /** Reading and checking an `InquiryWidgetConfig` — the same rules in the widget, the SDK and a server. */
3
+ export interface InquiryConfigHelper {
4
+ /**
5
+ * The text of `value` in `language`: the exact tag, then its primary subtag (`pt-BR` → `pt`),
6
+ * then `fallback`, then the first entry; `''` for `undefined`.
7
+ */
8
+ text: (value: LocalizedText | undefined, language: string, fallback?: string) => string;
9
+ /**
10
+ * Everything wrong with a config, as English sentences; `[]` when it is usable. Checks the id
11
+ * and every alias against `INQUIRY_ALIAS_PATTERN`, at least one and at most `INQUIRY_MAX_TABS`
12
+ * tabs, unique aliases, non-empty titles within their caps, `defaultTab` naming a tab, and legal
13
+ * links that are absolute http(s) URLs or root-relative paths.
14
+ */
15
+ validate: (config: InquiryWidgetConfig) => string[];
16
+ /** The tab `alias` names, else `defaultTab`'s, else the first; `undefined` only without tabs. */
17
+ tabOf: (config: InquiryWidgetConfig, alias?: string) => InquiryTab | undefined;
18
+ /**
19
+ * The supported language closest to `language` — its primary subtag, lower case — or `fallback`
20
+ * (`INQUIRY_FALLBACK_LANGUAGE`) when that is not among `supported` (`INQUIRY_LANGUAGES`).
21
+ */
22
+ normalizeLanguage: (language: string | undefined | null, supported?: readonly string[], fallback?: string) => string;
23
+ }
24
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEjF,0GAA0G;AAC1G,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,IAAI,EAAE,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;IACvF;;;;;OAKG;IACH,QAAQ,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,MAAM,EAAE,CAAA;IACnD,iGAAiG;IACjG,KAAK,EAAE,CAAC,MAAM,EAAE,mBAAmB,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,UAAU,GAAG,SAAS,CAAA;IAC9E;;;OAGG;IACH,iBAAiB,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,EAAE,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;CACrH"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ import type { InquiryConfigHelper } from './config/types.js';
2
+ export declare const createInquiryConfigHelper: () => InquiryConfigHelper;
3
+ export declare const inquiryConfigHelper: InquiryConfigHelper;
4
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAG5D,eAAO,MAAM,yBAAyB,QAAO,mBAiI5C,CAAA;AAED,eAAO,MAAM,mBAAmB,qBAA8B,CAAA"}
@@ -0,0 +1,118 @@
1
+ import { INQUIRY_ALIAS_PATTERN, INQUIRY_DESCRIPTION_MAX, INQUIRY_FALLBACK_LANGUAGE, INQUIRY_LANGUAGES, INQUIRY_MAX_TABS, INQUIRY_TITLE_MAX, INQUIRY_URL_MAX, } from './consts.js';
2
+ import { INQUIRY_LINK_PATTERN } from './consts.local.js';
3
+ export const createInquiryConfigHelper = () => {
4
+ const alias = new RegExp(INQUIRY_ALIAS_PATTERN);
5
+ const link = new RegExp(INQUIRY_LINK_PATTERN);
6
+ /** `pt-BR` / `pt_br` → `pt`. */
7
+ const primaryOf = (language) => language.trim().toLowerCase().split(/[-_]/)[0] ?? '';
8
+ const text = (value, language, fallback = INQUIRY_FALLBACK_LANGUAGE) => {
9
+ if (value == null) {
10
+ return '';
11
+ }
12
+ if (typeof value === 'string') {
13
+ return value;
14
+ }
15
+ const exact = value[language];
16
+ if (exact != null) {
17
+ return exact;
18
+ }
19
+ const primary = primaryOf(language);
20
+ const byPrimary = Object.entries(value).find(([key]) => primaryOf(key) === primary)?.[1];
21
+ if (byPrimary != null) {
22
+ return byPrimary;
23
+ }
24
+ return value[fallback] ?? Object.values(value)[0] ?? '';
25
+ };
26
+ /** The non-empty values a localized text holds, or `null` for a malformed one. */
27
+ const valuesOf = (value) => {
28
+ if (typeof value === 'string') {
29
+ return [value];
30
+ }
31
+ if (value == null || typeof value !== 'object' || Array.isArray(value)) {
32
+ return null;
33
+ }
34
+ const values = Object.values(value);
35
+ return values.every(entry => typeof entry === 'string') ? values : null;
36
+ };
37
+ const checkText = (errors, label, value, max, required) => {
38
+ if (value == null) {
39
+ if (required) {
40
+ errors.push(`${label} is missing`);
41
+ }
42
+ return;
43
+ }
44
+ const values = valuesOf(value);
45
+ if (values == null || values.length === 0 || values.some(entry => entry.trim() === '')) {
46
+ errors.push(`${label} must be a non-empty string or a map of language to non-empty string`);
47
+ return;
48
+ }
49
+ if (values.some(entry => entry.length > max)) {
50
+ errors.push(`${label} is longer than ${max} characters`);
51
+ }
52
+ };
53
+ const checkLink = (errors, label, value) => {
54
+ if (typeof value !== 'string' || value.length > INQUIRY_URL_MAX || !link.test(value)) {
55
+ errors.push(`${label} must be an http(s) URL or a root-relative path`);
56
+ }
57
+ };
58
+ const validate = config => {
59
+ const errors = [];
60
+ if (config == null || typeof config !== 'object') {
61
+ return ['config must be an object'];
62
+ }
63
+ if (typeof config.id !== 'string' || !alias.test(config.id)) {
64
+ errors.push(`id must match ${INQUIRY_ALIAS_PATTERN}`);
65
+ }
66
+ const tabs = config.tabs;
67
+ if (!Array.isArray(tabs) || tabs.length === 0) {
68
+ errors.push('tabs must hold at least one tab');
69
+ }
70
+ else {
71
+ if (tabs.length > INQUIRY_MAX_TABS) {
72
+ errors.push(`tabs must hold at most ${INQUIRY_MAX_TABS} tabs`);
73
+ }
74
+ const seen = new Set();
75
+ tabs.forEach((tab, index) => {
76
+ if (tab == null || typeof tab !== 'object') {
77
+ errors.push(`tabs[${index}] must be an object`);
78
+ return;
79
+ }
80
+ if (typeof tab.alias !== 'string' || !alias.test(tab.alias)) {
81
+ errors.push(`tabs[${index}].alias must match ${INQUIRY_ALIAS_PATTERN}`);
82
+ }
83
+ else if (seen.has(tab.alias)) {
84
+ errors.push(`tabs[${index}].alias "${tab.alias}" is not unique`);
85
+ }
86
+ else {
87
+ seen.add(tab.alias);
88
+ }
89
+ checkText(errors, `tabs[${index}].title`, tab.title, INQUIRY_TITLE_MAX, true);
90
+ checkText(errors, `tabs[${index}].description`, tab.description, INQUIRY_DESCRIPTION_MAX, false);
91
+ });
92
+ if (config.defaultTab != null && !seen.has(config.defaultTab)) {
93
+ errors.push(`defaultTab "${String(config.defaultTab)}" names no tab`);
94
+ }
95
+ }
96
+ if (config.legal == null || typeof config.legal !== 'object') {
97
+ errors.push('legal must hold the terms and privacy links');
98
+ }
99
+ else {
100
+ checkLink(errors, 'legal.terms', config.legal.terms);
101
+ checkLink(errors, 'legal.privacy', config.legal.privacy);
102
+ }
103
+ return errors;
104
+ };
105
+ const tabOf = (config, wanted) => (wanted != null ? config.tabs.find(tab => tab.alias === wanted) : undefined)
106
+ ?? (config.defaultTab != null ? config.tabs.find(tab => tab.alias === config.defaultTab) : undefined)
107
+ ?? config.tabs[0];
108
+ const normalizeLanguage = (language, supported = INQUIRY_LANGUAGES, fallback = INQUIRY_FALLBACK_LANGUAGE) => {
109
+ if (language == null || language.trim() === '') {
110
+ return fallback;
111
+ }
112
+ const primary = primaryOf(language);
113
+ return supported.includes(primary) ? primary : fallback;
114
+ };
115
+ return { text, validate, tabOf, normalizeLanguage };
116
+ };
117
+ export const inquiryConfigHelper = createInquiryConfigHelper();
118
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ import type { InquiryFileField, InquiryFileType } from './types.js';
2
+ /** The widget bundle, served at `<crm url>/inquiry.js`. */
3
+ export declare const INQUIRY_SCRIPT = "inquiry.js";
4
+ /** The CRM API sits under `<crm url>/api`. */
5
+ export declare const INQUIRY_API_SEGMENT = "api";
6
+ /** POST, multipart — relative to the API (`<crm url>/api/inquiry`). */
7
+ export declare const INQUIRY_SUBMIT_PATH = "/inquiry";
8
+ /** GET — the advertised config (reCAPTCHA site key), relative to the API (`<crm url>/api/assets/config.json`). */
9
+ export declare const INQUIRY_CONFIG_PATH = "/assets/config.json";
10
+ /** The `window` property the bundle installs its `InquiryRuntime` at. */
11
+ export declare const INQUIRY_GLOBAL = "__owlmeansInquiry";
12
+ /**
13
+ * The runtime contract version. The bundle reports it as `InquiryRuntime.version`, a client
14
+ * requests the bundle with `?v=<version>` and refuses a runtime of another version. Bump it only
15
+ * for an incompatible change of `InquiryRuntime`.
16
+ */
17
+ export declare const INQUIRY_RUNTIME_VERSION = 1;
18
+ /** The analytics event of a dialog open (`@owlmeans/log` `analytics` option → tag manager). */
19
+ export declare const INQUIRY_OPEN_EVENT = "inquiry_dialog_open";
20
+ /** The reCAPTCHA v3 action the widget executes and the CRM requires. */
21
+ export declare const INQUIRY_RECAPTCHA_ACTION = "inquiry";
22
+ /** One attachment at most, in bytes (decimal). */
23
+ export declare const INQUIRY_MAX_FILE_BYTES = 5000000;
24
+ /** All attachments of one inquiry together, in bytes (decimal). */
25
+ export declare const INQUIRY_MAX_TOTAL_BYTES = 20000000;
26
+ export declare const INQUIRY_MAX_FILES = 5;
27
+ /** The multipart fields attachments travel in, in order. */
28
+ export declare const INQUIRY_FILE_FIELDS: readonly InquiryFileField[];
29
+ /** Accepted attachment types. SVG is not one of them: it can carry script. */
30
+ export declare const INQUIRY_ALLOWED_TYPES: readonly InquiryFileType[];
31
+ /** The file extensions of each accepted type, lower case without the dot; the first is canonical. */
32
+ export declare const INQUIRY_TYPE_EXTENSIONS: Readonly<Record<InquiryFileType, readonly string[]>>;
33
+ export declare const INQUIRY_EMAIL_MAX = 254;
34
+ export declare const INQUIRY_SUBJECT_MAX = 150;
35
+ export declare const INQUIRY_DETAIL_MAX = 100;
36
+ export declare const INQUIRY_BODY_MAX = 5000;
37
+ /** A tab title, per language. */
38
+ export declare const INQUIRY_TITLE_MAX = 120;
39
+ /** A tab description, per language. */
40
+ export declare const INQUIRY_DESCRIPTION_MAX = 600;
41
+ /** A reported file name. */
42
+ export declare const INQUIRY_FILE_NAME_MAX = 255;
43
+ /** A page or legal URL. */
44
+ export declare const INQUIRY_URL_MAX = 2048;
45
+ /** Tabs of one widget. */
46
+ export declare const INQUIRY_MAX_TABS = 12;
47
+ /** How the inquirer prefers to be contacted; every method but `email` asks for a detail line. */
48
+ export declare enum InquiryContactMethod {
49
+ Email = "email",
50
+ Phone = "phone",
51
+ Messenger = "messenger",
52
+ Video = "video"
53
+ }
54
+ /** A widget id and a tab alias: lower-case, digits and dashes, at most 32 characters. */
55
+ export declare const INQUIRY_ALIAS_PATTERN = "^[a-z0-9][a-z0-9-]{0,31}$";
56
+ /** A language tag as the widget and the submission carry it (`en`, `pt-BR`, `en_US`). */
57
+ export declare const INQUIRY_LANGUAGE_PATTERN = "^[A-Za-z]{2,3}([-_][A-Za-z0-9]{2,8}){0,3}$";
58
+ /** The languages the widget ships strings for. */
59
+ export declare const INQUIRY_LANGUAGES: readonly string[];
60
+ /** The language every lookup falls back to. */
61
+ export declare const INQUIRY_FALLBACK_LANGUAGE = "en";
62
+ //# sourceMappingURL=consts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEnE,2DAA2D;AAC3D,eAAO,MAAM,cAAc,eAAe,CAAA;AAE1C,8CAA8C;AAC9C,eAAO,MAAM,mBAAmB,QAAQ,CAAA;AAExC,uEAAuE;AACvE,eAAO,MAAM,mBAAmB,aAAa,CAAA;AAE7C,kHAAkH;AAClH,eAAO,MAAM,mBAAmB,wBAAwB,CAAA;AAExD,yEAAyE;AACzE,eAAO,MAAM,cAAc,sBAAsB,CAAA;AAEjD;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,IAAI,CAAA;AAExC,+FAA+F;AAC/F,eAAO,MAAM,kBAAkB,wBAAwB,CAAA;AAEvD,wEAAwE;AACxE,eAAO,MAAM,wBAAwB,YAAY,CAAA;AAEjD,kDAAkD;AAClD,eAAO,MAAM,sBAAsB,UAAY,CAAA;AAE/C,mEAAmE;AACnE,eAAO,MAAM,uBAAuB,WAAa,CAAA;AAEjD,eAAO,MAAM,iBAAiB,IAAI,CAAA;AAElC,4DAA4D;AAC5D,eAAO,MAAM,mBAAmB,EAAE,SAAS,gBAAgB,EAEzD,CAAA;AAEF,8EAA8E;AAC9E,eAAO,MAAM,qBAAqB,EAAE,SAAS,eAAe,EAE1D,CAAA;AAEF,qGAAqG;AACrG,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC,CAQvF,CAAA;AAEF,eAAO,MAAM,iBAAiB,MAAM,CAAA;AACpC,eAAO,MAAM,mBAAmB,MAAM,CAAA;AACtC,eAAO,MAAM,kBAAkB,MAAM,CAAA;AACrC,eAAO,MAAM,gBAAgB,OAAO,CAAA;AACpC,iCAAiC;AACjC,eAAO,MAAM,iBAAiB,MAAM,CAAA;AACpC,uCAAuC;AACvC,eAAO,MAAM,uBAAuB,MAAM,CAAA;AAC1C,4BAA4B;AAC5B,eAAO,MAAM,qBAAqB,MAAM,CAAA;AACxC,2BAA2B;AAC3B,eAAO,MAAM,eAAe,OAAO,CAAA;AACnC,0BAA0B;AAC1B,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAElC,iGAAiG;AACjG,oBAAY,oBAAoB;IAC9B,KAAK,UAAU;IACf,KAAK,UAAU;IACf,SAAS,cAAc;IACvB,KAAK,UAAU;CAChB;AAED,yFAAyF;AACzF,eAAO,MAAM,qBAAqB,8BAA8B,CAAA;AAEhE,yFAAyF;AACzF,eAAO,MAAM,wBAAwB,+CAA+C,CAAA;AAEpF,kDAAkD;AAClD,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAAoE,CAAA;AAEnH,+CAA+C;AAC/C,eAAO,MAAM,yBAAyB,OAAO,CAAA"}
@@ -0,0 +1,74 @@
1
+ /** The widget bundle, served at `<crm url>/inquiry.js`. */
2
+ export const INQUIRY_SCRIPT = 'inquiry.js';
3
+ /** The CRM API sits under `<crm url>/api`. */
4
+ export const INQUIRY_API_SEGMENT = 'api';
5
+ /** POST, multipart — relative to the API (`<crm url>/api/inquiry`). */
6
+ export const INQUIRY_SUBMIT_PATH = '/inquiry';
7
+ /** GET — the advertised config (reCAPTCHA site key), relative to the API (`<crm url>/api/assets/config.json`). */
8
+ export const INQUIRY_CONFIG_PATH = '/assets/config.json';
9
+ /** The `window` property the bundle installs its `InquiryRuntime` at. */
10
+ export const INQUIRY_GLOBAL = '__owlmeansInquiry';
11
+ /**
12
+ * The runtime contract version. The bundle reports it as `InquiryRuntime.version`, a client
13
+ * requests the bundle with `?v=<version>` and refuses a runtime of another version. Bump it only
14
+ * for an incompatible change of `InquiryRuntime`.
15
+ */
16
+ export const INQUIRY_RUNTIME_VERSION = 1;
17
+ /** The analytics event of a dialog open (`@owlmeans/log` `analytics` option → tag manager). */
18
+ export const INQUIRY_OPEN_EVENT = 'inquiry_dialog_open';
19
+ /** The reCAPTCHA v3 action the widget executes and the CRM requires. */
20
+ export const INQUIRY_RECAPTCHA_ACTION = 'inquiry';
21
+ /** One attachment at most, in bytes (decimal). */
22
+ export const INQUIRY_MAX_FILE_BYTES = 5_000_000;
23
+ /** All attachments of one inquiry together, in bytes (decimal). */
24
+ export const INQUIRY_MAX_TOTAL_BYTES = 20_000_000;
25
+ export const INQUIRY_MAX_FILES = 5;
26
+ /** The multipart fields attachments travel in, in order. */
27
+ export const INQUIRY_FILE_FIELDS = Object.freeze([
28
+ 'file0', 'file1', 'file2', 'file3', 'file4',
29
+ ]);
30
+ /** Accepted attachment types. SVG is not one of them: it can carry script. */
31
+ export const INQUIRY_ALLOWED_TYPES = Object.freeze([
32
+ 'image/png', 'image/jpeg', 'image/gif', 'image/webp', 'application/pdf', 'text/csv', 'text/plain',
33
+ ]);
34
+ /** The file extensions of each accepted type, lower case without the dot; the first is canonical. */
35
+ export const INQUIRY_TYPE_EXTENSIONS = Object.freeze({
36
+ 'image/png': Object.freeze(['png']),
37
+ 'image/jpeg': Object.freeze(['jpg', 'jpeg']),
38
+ 'image/gif': Object.freeze(['gif']),
39
+ 'image/webp': Object.freeze(['webp']),
40
+ 'application/pdf': Object.freeze(['pdf']),
41
+ 'text/csv': Object.freeze(['csv']),
42
+ 'text/plain': Object.freeze(['txt', 'log']),
43
+ });
44
+ export const INQUIRY_EMAIL_MAX = 254;
45
+ export const INQUIRY_SUBJECT_MAX = 150;
46
+ export const INQUIRY_DETAIL_MAX = 100;
47
+ export const INQUIRY_BODY_MAX = 5000;
48
+ /** A tab title, per language. */
49
+ export const INQUIRY_TITLE_MAX = 120;
50
+ /** A tab description, per language. */
51
+ export const INQUIRY_DESCRIPTION_MAX = 600;
52
+ /** A reported file name. */
53
+ export const INQUIRY_FILE_NAME_MAX = 255;
54
+ /** A page or legal URL. */
55
+ export const INQUIRY_URL_MAX = 2048;
56
+ /** Tabs of one widget. */
57
+ export const INQUIRY_MAX_TABS = 12;
58
+ /** How the inquirer prefers to be contacted; every method but `email` asks for a detail line. */
59
+ export var InquiryContactMethod;
60
+ (function (InquiryContactMethod) {
61
+ InquiryContactMethod["Email"] = "email";
62
+ InquiryContactMethod["Phone"] = "phone";
63
+ InquiryContactMethod["Messenger"] = "messenger";
64
+ InquiryContactMethod["Video"] = "video";
65
+ })(InquiryContactMethod || (InquiryContactMethod = {}));
66
+ /** A widget id and a tab alias: lower-case, digits and dashes, at most 32 characters. */
67
+ export const INQUIRY_ALIAS_PATTERN = '^[a-z0-9][a-z0-9-]{0,31}$';
68
+ /** A language tag as the widget and the submission carry it (`en`, `pt-BR`, `en_US`). */
69
+ export const INQUIRY_LANGUAGE_PATTERN = '^[A-Za-z]{2,3}([-_][A-Za-z0-9]{2,8}){0,3}$';
70
+ /** The languages the widget ships strings for. */
71
+ export const INQUIRY_LANGUAGES = Object.freeze(['en', 'pl', 'ru', 'be', 'uk', 'es', 'de', 'fr']);
72
+ /** The language every lookup falls back to. */
73
+ export const INQUIRY_FALLBACK_LANGUAGE = 'en';
74
+ //# sourceMappingURL=consts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ /** A legal link: an absolute http(s) URL, or a root-relative path (never protocol-relative). */
2
+ export declare const INQUIRY_LINK_PATTERN = "^(https?://[^\\s]+|/(?!/)[^\\s]*)$";
3
+ //# sourceMappingURL=consts.local.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consts.local.d.ts","sourceRoot":"","sources":["../src/consts.local.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,eAAO,MAAM,oBAAoB,uCAAuC,CAAA"}
@@ -0,0 +1,3 @@
1
+ /** A legal link: an absolute http(s) URL, or a root-relative path (never protocol-relative). */
2
+ export const INQUIRY_LINK_PATTERN = '^(https?://[^\\s]+|/(?!/)[^\\s]*)$';
3
+ //# sourceMappingURL=consts.local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consts.local.js","sourceRoot":"","sources":["../src/consts.local.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,MAAM,CAAC,MAAM,oBAAoB,GAAG,oCAAoC,CAAA"}
@@ -0,0 +1,6 @@
1
+ export type * from './types.js';
2
+ export type * from './config/types.js';
3
+ export * from './consts.js';
4
+ export * from './schemas.js';
5
+ export * from './config.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,YAAY,CAAA;AAC/B,mBAAmB,mBAAmB,CAAA;AACtC,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA"}
package/build/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export * from './consts.js';
2
+ export * from './schemas.js';
3
+ export * from './config.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA"}
@@ -0,0 +1,18 @@
1
+ import type { JSONSchemaType } from 'ajv';
2
+ import type { InquiryFileMeta, InquiryReceipt, InquirySubmission, InquiryWidgetConfig } from './types.js';
3
+ /**
4
+ * A widget config. Structure only: alias uniqueness and `defaultTab` membership are checked by
5
+ * `inquiryConfigHelper.validate`, which a JSON schema cannot express.
6
+ */
7
+ export declare const InquiryWidgetConfigSchema: JSONSchemaType<InquiryWidgetConfig>;
8
+ export declare const InquiryFileMetaSchema: JSONSchemaType<InquiryFileMeta>;
9
+ /** The parsed `files` field of a submission. Field uniqueness is the handler's to check. */
10
+ export declare const InquiryFileMetaListSchema: JSONSchemaType<InquiryFileMeta[]>;
11
+ /**
12
+ * The multipart body of `POST <crm url>/api/inquiry`, for a route validated with
13
+ * `removeAdditional` + `coerceTypes`. `files` stays a JSON string here; validate its parsed value
14
+ * with `InquiryFileMetaListSchema`.
15
+ */
16
+ export declare const InquirySubmissionSchema: JSONSchemaType<InquirySubmission>;
17
+ export declare const InquiryReceiptSchema: JSONSchemaType<InquiryReceipt>;
18
+ //# sourceMappingURL=schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAA;AAOzC,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,iBAAiB,EAAc,mBAAmB,EAAE,MAAM,YAAY,CAAA;AA4BrH;;;GAGG;AACH,eAAO,MAAM,yBAAyB,EAAE,cAAc,CAAC,mBAAmB,CAmBzE,CAAA;AAED,eAAO,MAAM,qBAAqB,EAAE,cAAc,CAAC,eAAe,CAUjE,CAAA;AAED,4FAA4F;AAC5F,eAAO,MAAM,yBAAyB,EAAE,cAAc,CAAC,eAAe,EAAE,CAKvE,CAAA;AASD;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,EAAE,cAAc,CAAC,iBAAiB,CAyBrE,CAAA;AAED,eAAO,MAAM,oBAAoB,EAAE,cAAc,CAAC,cAAc,CAQ/D,CAAA"}
@@ -0,0 +1,115 @@
1
+ import { INQUIRY_ALIAS_PATTERN, INQUIRY_ALLOWED_TYPES, INQUIRY_BODY_MAX, INQUIRY_DESCRIPTION_MAX, INQUIRY_DETAIL_MAX, INQUIRY_EMAIL_MAX, INQUIRY_FILE_FIELDS, INQUIRY_FILE_NAME_MAX, INQUIRY_LANGUAGE_PATTERN, INQUIRY_MAX_FILE_BYTES, INQUIRY_MAX_FILES, INQUIRY_MAX_TABS, INQUIRY_SUBJECT_MAX, INQUIRY_TITLE_MAX, INQUIRY_URL_MAX, InquiryContactMethod, } from './consts.js';
2
+ import { INQUIRY_LINK_PATTERN } from './consts.local.js';
3
+ /** `LocalizedText`: a string, or a non-empty map of language tag → string. */
4
+ const localizedText = (maxLength) => ({
5
+ anyOf: [
6
+ { type: 'string', minLength: 1, maxLength },
7
+ {
8
+ type: 'object',
9
+ minProperties: 1,
10
+ maxProperties: 32,
11
+ propertyNames: { pattern: INQUIRY_LANGUAGE_PATTERN },
12
+ additionalProperties: { type: 'string', minLength: 1, maxLength },
13
+ required: [],
14
+ },
15
+ ],
16
+ });
17
+ const InquiryTabSchema = {
18
+ type: 'object',
19
+ properties: {
20
+ alias: { type: 'string', pattern: INQUIRY_ALIAS_PATTERN },
21
+ title: localizedText(INQUIRY_TITLE_MAX),
22
+ description: localizedText(INQUIRY_DESCRIPTION_MAX),
23
+ },
24
+ required: ['alias', 'title'],
25
+ additionalProperties: false,
26
+ };
27
+ /**
28
+ * A widget config. Structure only: alias uniqueness and `defaultTab` membership are checked by
29
+ * `inquiryConfigHelper.validate`, which a JSON schema cannot express.
30
+ */
31
+ export const InquiryWidgetConfigSchema = {
32
+ type: 'object',
33
+ properties: {
34
+ id: { type: 'string', pattern: INQUIRY_ALIAS_PATTERN },
35
+ tabs: { type: 'array', minItems: 1, maxItems: INQUIRY_MAX_TABS, items: InquiryTabSchema },
36
+ defaultTab: { type: 'string', pattern: INQUIRY_ALIAS_PATTERN, nullable: true },
37
+ legal: {
38
+ type: 'object',
39
+ properties: {
40
+ terms: { type: 'string', maxLength: INQUIRY_URL_MAX, pattern: INQUIRY_LINK_PATTERN },
41
+ privacy: { type: 'string', maxLength: INQUIRY_URL_MAX, pattern: INQUIRY_LINK_PATTERN },
42
+ },
43
+ required: ['terms', 'privacy'],
44
+ additionalProperties: false,
45
+ },
46
+ language: { type: 'string', pattern: INQUIRY_LANGUAGE_PATTERN, nullable: true },
47
+ },
48
+ required: ['id', 'tabs', 'legal'],
49
+ additionalProperties: false,
50
+ };
51
+ export const InquiryFileMetaSchema = {
52
+ type: 'object',
53
+ properties: {
54
+ field: { type: 'string', enum: [...INQUIRY_FILE_FIELDS] },
55
+ name: { type: 'string', minLength: 1, maxLength: INQUIRY_FILE_NAME_MAX },
56
+ type: { type: 'string', enum: [...INQUIRY_ALLOWED_TYPES] },
57
+ size: { type: 'integer', minimum: 1, maximum: INQUIRY_MAX_FILE_BYTES },
58
+ },
59
+ required: ['field', 'name', 'type', 'size'],
60
+ additionalProperties: false,
61
+ };
62
+ /** The parsed `files` field of a submission. Field uniqueness is the handler's to check. */
63
+ export const InquiryFileMetaListSchema = {
64
+ type: 'array',
65
+ minItems: 0,
66
+ maxItems: INQUIRY_MAX_FILES,
67
+ items: InquiryFileMetaSchema,
68
+ };
69
+ /**
70
+ * A file field: the multipart parser (`attachFieldsToBody: 'keyValues'`) hands it over as a
71
+ * Buffer. It is declared ONLY as an open object — `properties`, `additionalProperties: false` or
72
+ * any size keyword would make ajv walk (or, with `removeAdditional`, strip) the bytes.
73
+ */
74
+ const fileField = { type: 'object', additionalProperties: true };
75
+ /**
76
+ * The multipart body of `POST <crm url>/api/inquiry`, for a route validated with
77
+ * `removeAdditional` + `coerceTypes`. `files` stays a JSON string here; validate its parsed value
78
+ * with `InquiryFileMetaListSchema`.
79
+ */
80
+ export const InquirySubmissionSchema = {
81
+ type: 'object',
82
+ properties: {
83
+ widget: { type: 'string', pattern: INQUIRY_ALIAS_PATTERN },
84
+ tab: { type: 'string', pattern: INQUIRY_ALIAS_PATTERN },
85
+ tabTitle: { type: 'string', maxLength: INQUIRY_TITLE_MAX, nullable: true },
86
+ email: { type: 'string', minLength: 3, maxLength: INQUIRY_EMAIL_MAX, format: 'email' },
87
+ subject: { type: 'string', minLength: 1, maxLength: INQUIRY_SUBJECT_MAX },
88
+ contactMethod: { type: 'string', enum: Object.values(InquiryContactMethod) },
89
+ contactDetail: { type: 'string', maxLength: INQUIRY_DETAIL_MAX, nullable: true },
90
+ body: { type: 'string', minLength: 1, maxLength: INQUIRY_BODY_MAX },
91
+ language: { type: 'string', pattern: INQUIRY_LANGUAGE_PATTERN, nullable: true },
92
+ page: { type: 'string', maxLength: INQUIRY_URL_MAX, nullable: true },
93
+ terms: { type: 'string', maxLength: INQUIRY_URL_MAX, nullable: true },
94
+ privacy: { type: 'string', maxLength: INQUIRY_URL_MAX, nullable: true },
95
+ consent: { type: ['boolean', 'string'], enum: [true, 'true'] },
96
+ files: { type: 'string', minLength: 2, maxLength: 4096 },
97
+ file0: fileField,
98
+ file1: fileField,
99
+ file2: fileField,
100
+ file3: fileField,
101
+ file4: fileField,
102
+ },
103
+ required: ['widget', 'tab', 'email', 'subject', 'contactMethod', 'body', 'consent', 'files'],
104
+ additionalProperties: false,
105
+ };
106
+ export const InquiryReceiptSchema = {
107
+ type: 'object',
108
+ properties: {
109
+ id: { type: 'string', minLength: 1 },
110
+ queued: { type: 'boolean' },
111
+ },
112
+ required: ['id', 'queued'],
113
+ additionalProperties: false,
114
+ };
115
+ //# sourceMappingURL=schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AACA,OAAO,EACL,qBAAqB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,kBAAkB,EAC3G,iBAAiB,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,sBAAsB,EAC/G,iBAAiB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,eAAe,EAAE,oBAAoB,GACnH,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAGxD,8EAA8E;AAC9E,MAAM,aAAa,GAAG,CAAC,SAAiB,EAAE,EAAE,CAAC,CAAC;IAC5C,KAAK,EAAE;QACL,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE;QAC3C;YACE,IAAI,EAAE,QAAQ;YACd,aAAa,EAAE,CAAC;YAChB,aAAa,EAAE,EAAE;YACjB,aAAa,EAAE,EAAE,OAAO,EAAE,wBAAwB,EAAE;YACpD,oBAAoB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE;YACjE,QAAQ,EAAE,EAAE;SACb;KACF;CACF,CAAC,CAAA;AAEF,MAAM,gBAAgB,GAA+B;IACnD,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,EAAE;QACzD,KAAK,EAAE,aAAa,CAAC,iBAAiB,CAAC;QACvC,WAAW,EAAE,aAAa,CAAC,uBAAuB,CAAC;KACR;IAC7C,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC;IAC5B,oBAAoB,EAAE,KAAK;CAC5B,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAwC;IAC5E,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,EAAE;QACtD,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,gBAAgB,EAAE,KAAK,EAAE,gBAAgB,EAAE;QACzF,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,EAAE,QAAQ,EAAE,IAAI,EAAE;QAC9E,KAAK,EAAE;YACL,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,OAAO,EAAE,oBAAoB,EAAE;gBACpF,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,OAAO,EAAE,oBAAoB,EAAE;aACvF;YACD,QAAQ,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC;YAC9B,oBAAoB,EAAE,KAAK;SAC5B;QACD,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,wBAAwB,EAAE,QAAQ,EAAE,IAAI,EAAE;KAChF;IACD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC;IACjC,oBAAoB,EAAE,KAAK;CAC5B,CAAA;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAoC;IACpE,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,GAAG,mBAAmB,CAAC,EAAE;QACzD,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,qBAAqB,EAAE;QACxE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,GAAG,qBAAqB,CAAC,EAAE;QAC1D,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,sBAAsB,EAAE;KACvE;IACD,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAC3C,oBAAoB,EAAE,KAAK;CAC5B,CAAA;AAED,4FAA4F;AAC5F,MAAM,CAAC,MAAM,yBAAyB,GAAsC;IAC1E,IAAI,EAAE,OAAO;IACb,QAAQ,EAAE,CAAC;IACX,QAAQ,EAAE,iBAAiB;IAC3B,KAAK,EAAE,qBAAqB;CAC7B,CAAA;AAED;;;;GAIG;AACH,MAAM,SAAS,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,oBAAoB,EAAE,IAAI,EAAE,CAAA;AAEhE;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAsC;IACxE,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,EAAE;QAC1D,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,EAAE;QACvD,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,iBAAiB,EAAE,QAAQ,EAAE,IAAI,EAAE;QAC1E,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,EAAE,OAAO,EAAE;QACtF,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,mBAAmB,EAAE;QACzE,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,oBAAoB,CAAC,EAAE;QAC5E,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,kBAAkB,EAAE,QAAQ,EAAE,IAAI,EAAE;QAChF,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,gBAAgB,EAAE;QACnE,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,wBAAwB,EAAE,QAAQ,EAAE,IAAI,EAAE;QAC/E,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,QAAQ,EAAE,IAAI,EAAE;QACpE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,QAAQ,EAAE,IAAI,EAAE;QACrE,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,QAAQ,EAAE,IAAI,EAAE;QACvE,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE;QAC9D,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE;QACxD,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,SAAS;KACkC;IACpD,QAAQ,EAAE,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC;IAC5F,oBAAoB,EAAE,KAAK;CAC5B,CAAA;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAmC;IAClE,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE;QACpC,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;KAC5B;IACD,QAAQ,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC;IAC1B,oBAAoB,EAAE,KAAK;CAC5B,CAAA"}
@@ -0,0 +1,180 @@
1
+ import type { InquiryContactMethod } from './consts.js';
2
+ /**
3
+ * A text the widget shows: one string for every language, or one string per language keyed by
4
+ * its tag (`{ en: 'Report an issue', pl: 'Zgłoś problem' }`). A missing language falls back to the
5
+ * primary subtag, then English, then the first entry (`inquiryConfigHelper.text`).
6
+ */
7
+ export type LocalizedText = string | Record<string, string>;
8
+ /** One of the attachment types the CRM accepts — the detected type, never only the declared one. */
9
+ export type InquiryFileType = 'image/png' | 'image/jpeg' | 'image/gif' | 'image/webp' | 'application/pdf' | 'text/csv' | 'text/plain';
10
+ /** The multipart field an attachment travels in. */
11
+ export type InquiryFileField = 'file0' | 'file1' | 'file2' | 'file3' | 'file4';
12
+ /** Where the floating button sits. */
13
+ export type InquiryButtonPosition = 'bottom-right' | 'bottom-left';
14
+ /** One intent of a widget — a tab of the dialog. */
15
+ export interface InquiryTab {
16
+ /** Stable machine name (`INQUIRY_ALIAS_PATTERN`); it prefixes the mail subject. */
17
+ alias: string;
18
+ title: LocalizedText;
19
+ /** One or two sentences under the tab strip. */
20
+ description?: LocalizedText;
21
+ }
22
+ /** The documents the inquirer consents to before sending. */
23
+ export interface InquiryLegalLinks {
24
+ /** An absolute http(s) URL, or a root-relative path resolved against the host page. */
25
+ terms: string;
26
+ /** An absolute http(s) URL, or a root-relative path resolved against the host page. */
27
+ privacy: string;
28
+ }
29
+ /**
30
+ * What a host page asks the widget to show.
31
+ *
32
+ * A config with ONE tab renders without a tab strip — the dialog is then that single intent, its
33
+ * title the dialog's title. Two or more tabs render a tab strip, `defaultTab` (or the first)
34
+ * selected.
35
+ */
36
+ export interface InquiryWidgetConfig {
37
+ /** The widget's id (`INQUIRY_ALIAS_PATTERN`): one mounted dialog per id, reported in analytics and mail. */
38
+ id: string;
39
+ tabs: InquiryTab[];
40
+ /** The alias of the tab selected when no other is asked for. Default: the first tab. */
41
+ defaultTab?: string;
42
+ legal: InquiryLegalLinks;
43
+ /** The interface language; default: the runtime's configured language, then the document's. */
44
+ language?: string;
45
+ }
46
+ /** A preset reply address, resolved when the dialog opens. A missing result clears the email. */
47
+ export type InquiryEmailValue = string | null | undefined;
48
+ /** A reply address or a lazy provider; a pending provider shows the widget's email spinner. */
49
+ export type InquiryEmailPreset = string | (() => InquiryEmailValue | Promise<InquiryEmailValue>);
50
+ export interface InquiryEmailOptions {
51
+ /** Applied on every dialog open, replacing any previously edited email. Omit to keep manual entry. */
52
+ email?: InquiryEmailPreset;
53
+ }
54
+ export interface InquiryOpenOptions extends InquiryEmailOptions {
55
+ /** The alias of the tab to select; an unknown alias selects the default tab. */
56
+ tab?: string;
57
+ /** Which trigger opened the dialog (`fab`, `menu`, `pricing-card` …), reported in analytics. */
58
+ source?: string;
59
+ }
60
+ export interface InquiryButtonOptions extends InquiryEmailOptions {
61
+ /** Default: `bottom-right`. */
62
+ position?: InquiryButtonPosition;
63
+ /** Distance from the viewport edges in CSS pixels. */
64
+ offset?: number;
65
+ /** The button's accessible label (and tooltip); default: the widget's own "Contact us". */
66
+ label?: LocalizedText;
67
+ /** Reported as the source of every open the button makes. Default: `fab`. */
68
+ source?: string;
69
+ }
70
+ /** One dialog open, as analytics and `onOpen` callbacks receive it. */
71
+ export interface InquiryOpenEvent {
72
+ /** `InquiryWidgetConfig.id`. */
73
+ widget: string;
74
+ /** The alias of the tab the dialog opened on. */
75
+ tab: string;
76
+ source?: string;
77
+ }
78
+ /** One attachment, described in the submission's `files` field (a JSON string of these). */
79
+ export interface InquiryFileMeta {
80
+ /** The multipart field carrying the bytes. */
81
+ field: InquiryFileField;
82
+ /** The file name as the inquirer's device reported it. */
83
+ name: string;
84
+ /** The declared type; the CRM re-detects it from the bytes and refuses a mismatch. */
85
+ type: InquiryFileType;
86
+ /** Size in bytes. */
87
+ size: number;
88
+ }
89
+ /**
90
+ * The multipart text fields of one inquiry.
91
+ *
92
+ * The multipart parser hands every text field over as a string, so `consent` arrives as `'true'`
93
+ * and `files` is a JSON string of `InquiryFileMeta[]` the handler parses and validates
94
+ * (`InquiryFileMetaListSchema`). Every field `files` names must be present.
95
+ */
96
+ export interface InquirySubmissionFields {
97
+ /** `InquiryWidgetConfig.id`. */
98
+ widget: string;
99
+ /** The tab's alias. */
100
+ tab: string;
101
+ /** The tab's title as the inquirer saw it. */
102
+ tabTitle?: string;
103
+ /** The reply address. */
104
+ email: string;
105
+ subject: string;
106
+ contactMethod: InquiryContactMethod;
107
+ /** A phone number, a messenger handle or a preferred call time — whatever the method needs. */
108
+ contactDetail?: string;
109
+ body: string;
110
+ /** The interface language the inquirer used. */
111
+ language?: string;
112
+ /** The page the dialog was opened on. */
113
+ page?: string;
114
+ /** The terms the inquirer consented to, absolute. */
115
+ terms?: string;
116
+ /** The privacy notice the inquirer consented to, absolute. */
117
+ privacy?: string;
118
+ /** The consent checkbox: only `true` is accepted. */
119
+ consent: true | 'true';
120
+ /** JSON of `InquiryFileMeta[]`; `'[]'` without attachments. */
121
+ files: string;
122
+ }
123
+ /** The whole multipart body as the server receives it: the text fields plus the file buffers. */
124
+ export interface InquirySubmission extends InquirySubmissionFields {
125
+ file0?: Uint8Array;
126
+ file1?: Uint8Array;
127
+ file2?: Uint8Array;
128
+ file3?: Uint8Array;
129
+ file4?: Uint8Array;
130
+ }
131
+ /** What the CRM answers to an accepted inquiry. */
132
+ export interface InquiryReceipt {
133
+ id: string;
134
+ /** Whether the mail was queued (always, once accepted). */
135
+ queued: boolean;
136
+ }
137
+ /** What a host (through `@owlmeans/web-inquiry`) tells the runtime once it is loaded. */
138
+ export interface InquiryRuntimeOptions {
139
+ /** The CRM base URL the bundle was loaded from, without a trailing slash (`https://<web>/crm`). */
140
+ url: string;
141
+ /** The interface language, or a function read at every open (so a language switch is honoured). */
142
+ language?: string | (() => string);
143
+ /**
144
+ * Called exactly once per dialog open, whatever opened it — `open`, a handle's `open` or the
145
+ * floating button. An `open` of a dialog that is already open does not call it again.
146
+ */
147
+ onOpen?: (event: InquiryOpenEvent) => void;
148
+ }
149
+ /** A mounted floating button. */
150
+ export interface InquiryHandle {
151
+ /** Open the button's dialog as if it were clicked (its `source` unless `opts` names another). */
152
+ open: (opts?: InquiryOpenOptions) => void;
153
+ /** Replace the widget's config (texts, tabs, language) in place. */
154
+ update: (config: InquiryWidgetConfig) => void;
155
+ /** Remove the button and its dialog. */
156
+ unmount: () => void;
157
+ }
158
+ /**
159
+ * The contract the widget bundle (`INQUIRY_SCRIPT`) installs at `window[INQUIRY_GLOBAL]`.
160
+ *
161
+ * A host never loads the bundle by hand: `@owlmeans/web-inquiry` injects it once, checks `version`
162
+ * against `INQUIRY_RUNTIME_VERSION` and calls `configure` before anything else.
163
+ */
164
+ export interface InquiryRuntime {
165
+ /** `INQUIRY_RUNTIME_VERSION` of the bundle; a client refuses a runtime of another version. */
166
+ version: number;
167
+ /** Set (or replace) the page-wide options; the last call wins. */
168
+ configure: (options: InquiryRuntimeOptions) => void;
169
+ /** Open the widget's dialog (mounting it on first use) on `opts.tab` or the default tab. */
170
+ open: (config: InquiryWidgetConfig, opts?: InquiryOpenOptions) => void;
171
+ /** Mount the widget's floating button; a second call for the same `config.id` updates it. */
172
+ button: (config: InquiryWidgetConfig, opts?: InquiryButtonOptions) => InquiryHandle;
173
+ /** Remove one widget (button and dialog) by its id, or every widget. */
174
+ unmount: (id?: string) => void;
175
+ }
176
+ /** The `window` slot the runtime lives in. */
177
+ export interface InquiryWindow {
178
+ __owlmeansInquiry?: InquiryRuntime;
179
+ }
180
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/build/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,48 @@
1
1
  {
2
2
  "name": "@owlmeans/common-inquiry",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.18-rc.1",
4
+ "license": "MIT",
5
+ "description": "Runtime-free contract of the OwlMeans customer inquiry widget — the window runtime, the widget config, the multipart submission and its limits, schemas and the config helper.",
6
+ "type": "module",
7
+ "scripts": {
8
+ "build": "tsc -b",
9
+ "dev": "sleep 2 && nodemon -e ts,json --watch src --exec \"tsc -p ./tsconfig.json\"",
10
+ "watch": "tsc -b -w --preserveWatchOutput --pretty",
11
+ "test": "bun test ./tests"
12
+ },
13
+ "main": "build/index.js",
14
+ "module": "build/index.js",
15
+ "types": "build/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "import": "./build/index.js",
19
+ "require": "./build/index.js",
20
+ "default": "./build/index.js",
21
+ "module": "./build/index.js",
22
+ "types": "./build/index.d.ts"
23
+ }
24
+ },
25
+ "files": [
26
+ "build",
27
+ "agent-meta"
28
+ ],
29
+ "peerDependencies": {
30
+ "ajv": "*"
31
+ },
32
+ "peerDependenciesMeta": {
33
+ "ajv": {
34
+ "optional": true
35
+ }
36
+ },
37
+ "devDependencies": {
38
+ "@owlmeans/dep-config": "workspace:*",
39
+ "@types/bun": "^1.4.2",
40
+ "ajv": "^8.20.0",
41
+ "ajv-formats": "^3.0.1",
42
+ "nodemon": "^3.1.14",
43
+ "typescript": "^7.0.2"
44
+ },
45
+ "publishConfig": {
46
+ "access": "public"
47
+ }
48
+ }