@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 +73 -2
- package/agent-meta/manifest.json +16 -0
- package/agent-meta/skills/common-inquiry/SKILL.md +138 -0
- package/build/config/types.d.ts +24 -0
- package/build/config/types.d.ts.map +1 -0
- package/build/config/types.js +2 -0
- package/build/config/types.js.map +1 -0
- package/build/config.d.ts +4 -0
- package/build/config.d.ts.map +1 -0
- package/build/config.js +118 -0
- package/build/config.js.map +1 -0
- package/build/consts.d.ts +62 -0
- package/build/consts.d.ts.map +1 -0
- package/build/consts.js +74 -0
- package/build/consts.js.map +1 -0
- package/build/consts.local.d.ts +3 -0
- package/build/consts.local.d.ts.map +1 -0
- package/build/consts.local.js +3 -0
- package/build/consts.local.js.map +1 -0
- package/build/index.d.ts +6 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +4 -0
- package/build/index.js.map +1 -0
- package/build/schemas.d.ts +18 -0
- package/build/schemas.d.ts.map +1 -0
- package/build/schemas.js +115 -0
- package/build/schemas.js.map +1 -0
- package/build/types.d.ts +180 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/package.json +46 -4
package/README.md
CHANGED
|
@@ -1,3 +1,74 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @owlmeans/common-inquiry
|
|
2
2
|
|
|
3
|
-
|
|
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 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":""}
|
|
@@ -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"}
|
package/build/config.js
ADDED
|
@@ -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"}
|
package/build/consts.js
ADDED
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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"}
|
package/build/index.d.ts
ADDED
|
@@ -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 @@
|
|
|
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"}
|
package/build/schemas.js
ADDED
|
@@ -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":"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"}
|
package/build/types.d.ts
ADDED
|
@@ -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 @@
|
|
|
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.
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
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
|
+
}
|