@owlmeans/web-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 +84 -2
- package/agent-meta/manifest.json +16 -0
- package/agent-meta/skills/web-inquiry/SKILL.md +124 -0
- package/build/client.d.ts +12 -0
- package/build/client.d.ts.map +1 -0
- package/build/client.js +74 -0
- package/build/client.js.map +1 -0
- package/build/consts.d.ts +5 -0
- package/build/consts.d.ts.map +1 -0
- package/build/consts.js +5 -0
- package/build/consts.js.map +1 -0
- package/build/consts.local.d.ts +7 -0
- package/build/consts.local.d.ts.map +1 -0
- package/build/consts.local.js +7 -0
- package/build/consts.local.js.map +1 -0
- package/build/errors.d.ts +7 -0
- package/build/errors.d.ts.map +1 -0
- package/build/errors.js +10 -0
- package/build/errors.js.map +1 -0
- package/build/index.d.ts +7 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +5 -0
- package/build/index.js.map +1 -0
- package/build/types.d.ts +42 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/build/utils/loader/types.d.ts +23 -0
- package/build/utils/loader/types.d.ts.map +1 -0
- package/build/utils/loader/types.js +2 -0
- package/build/utils/loader/types.js.map +1 -0
- package/build/utils/loader.d.ts +4 -0
- package/build/utils/loader.d.ts.map +1 -0
- package/build/utils/loader.js +111 -0
- package/build/utils/loader.js.map +1 -0
- package/package.json +40 -4
package/README.md
CHANGED
|
@@ -1,3 +1,85 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @owlmeans/web-inquiry
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The lightweight browser SDK of the OwlMeans customer inquiry widget. It carries no widget code and
|
|
4
|
+
no React: it injects the widget runtime served by the CRM (`<crm>/inquiry.js`) once per page, waits
|
|
5
|
+
for the runtime of the version it was built for, and opens the dialog from a link, a button, a
|
|
6
|
+
menu entry or a floating button. Every dialog open is reported once as an analytics event.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
bun add @owlmeans/web-inquiry@^0.1.18-rc.1 @owlmeans/common-inquiry@^0.1.18-rc.1
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { makeInquiryClient, type InquiryWidgetConfig } from '@owlmeans/web-inquiry'
|
|
18
|
+
|
|
19
|
+
const inquiry = makeInquiryClient({
|
|
20
|
+
url: 'https://platform.owlmeans.com/crm', // the CRM base, no trailing slash needed
|
|
21
|
+
language: () => document.documentElement.lang, // read at every open
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const quote: InquiryWidgetConfig = {
|
|
25
|
+
id: 'owlmeans-quote',
|
|
26
|
+
tabs: [{ alias: 'quote', title: 'Get a quote' }], // one tab: no tab strip
|
|
27
|
+
legal: { terms: '/legal/terms', privacy: '/legal/privacy' },
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// A trigger keeps its href: when the widget cannot load, the click follows it.
|
|
31
|
+
const unbind = inquiry.bind('[data-inquiry="quote"]', quote, { source: 'pricing-card' })
|
|
32
|
+
|
|
33
|
+
await inquiry.open(quote, { source: 'menu' }) // from code
|
|
34
|
+
const fab = await inquiry.button(quote) // a floating button, bottom-right
|
|
35
|
+
fab.unmount()
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Nothing is fetched until the first `load`, `open`, `button` or bound click — a page that must not
|
|
39
|
+
contact a third party before an interaction stays clean.
|
|
40
|
+
|
|
41
|
+
## Analytics
|
|
42
|
+
|
|
43
|
+
Each open is logged once through `@owlmeans/log` as an analytics-only call:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
logger('inquiry').info('Inquiry dialog opened',
|
|
47
|
+
{ inquiry_widget, inquiry_tab, inquiry_source },
|
|
48
|
+
{ analytics: 'inquiry_dialog_open', console: false })
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The event reaches a tag manager when the host registers the consent-gated plugin of
|
|
52
|
+
`@owlmeans/web-log` — without analytics consent it is dropped:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { addLogPlugin } from '@owlmeans/log'
|
|
56
|
+
import { gtmAnalyticsPlugin } from '@owlmeans/web-log'
|
|
57
|
+
import { INQUIRY_OPEN_EVENT } from '@owlmeans/web-inquiry'
|
|
58
|
+
|
|
59
|
+
addLogPlugin(gtmAnalyticsPlugin({ allow: [INQUIRY_OPEN_EVENT] }))
|
|
60
|
+
// → window.dataLayer.push({ event: 'inquiry_dialog_open', inquiry_widget, inquiry_tab, inquiry_source })
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
In the tag manager, a Custom Event trigger on `inquiry_dialog_open` forwards it to GA4.
|
|
64
|
+
`analytics: 'name'` renames the event; `analytics: false` reports nothing (`onOpen` still runs).
|
|
65
|
+
|
|
66
|
+
## Related
|
|
67
|
+
|
|
68
|
+
- [`@owlmeans/common-inquiry`](../common-inquiry): the runtime contract, config, limits and schemas
|
|
69
|
+
- [`@owlmeans/web-log`](../web-log): the consent-gated analytics plugins
|
|
70
|
+
|
|
71
|
+
<!-- owlmeans:agent-guidance:start -->
|
|
72
|
+
## Agent guidance
|
|
73
|
+
|
|
74
|
+
This package ships embedded agent skills under `agent-meta/`. After installing your
|
|
75
|
+
`@owlmeans/*` packages, run the OwlMeans agent-skills installer to place them into
|
|
76
|
+
your project's skill store (`.agents/skills/`):
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.53
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The embedded files are version-matched to this package release. Do not edit them
|
|
83
|
+
directly — they are regenerated on each publish. To contribute guidance edits,
|
|
84
|
+
open a PR against the source monorepo.
|
|
85
|
+
<!-- owlmeans:agent-guidance:end -->
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 2,
|
|
3
|
+
"package": "@owlmeans/web-inquiry",
|
|
4
|
+
"version": "0.1.18-rc.1",
|
|
5
|
+
"generatedAt": "2026-10-09T11:30:42.748Z",
|
|
6
|
+
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
|
+
"entries": [
|
|
8
|
+
{
|
|
9
|
+
"kind": "skill",
|
|
10
|
+
"name": "web-inquiry",
|
|
11
|
+
"category": "package-specific",
|
|
12
|
+
"file": "skills/web-inquiry/SKILL.md",
|
|
13
|
+
"canonicalPath": ".agents/skills/web-inquiry/SKILL.md"
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: web-inquiry
|
|
3
|
+
description: How to use @owlmeans/web-inquiry — the lightweight browser SDK of the OwlMeans customer inquiry widget. makeInquiryClient injects the widget runtime (<crm>/inquiry.js) once per page, checks its version, and opens the contact dialog from code (open), from triggers that keep their href as a fallback (bind) or from a floating button (button); every open is reported once as the analytics event inquiry_dialog_open through @owlmeans/log, which web-log's gtmAnalyticsPlugin forwards to a tag manager under consent. Auto-invoked when adding a contact/feedback dialog, a "Contact us" or "Get a quote" trigger to a page, importing makeInquiryClient or InquiryLoadError, or wiring the inquiry open event into GTM.
|
|
4
|
+
user-invocable: false
|
|
5
|
+
---
|
|
6
|
+
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
7
|
+
|
|
8
|
+
# @owlmeans/web-inquiry
|
|
9
|
+
|
|
10
|
+
**Layer:** Web (depends on `@owlmeans/common-inquiry` and `@owlmeans/log`; no React, no widget code)
|
|
11
|
+
**Install:** `"@owlmeans/web-inquiry": "^0.1.18-rc.1"` in `dependencies`
|
|
12
|
+
|
|
13
|
+
The host half of the inquiry widget. The dialog itself — React, styles, reCAPTCHA, the upload — is
|
|
14
|
+
a bundle the CRM serves; this package only loads it, opens it and reports the opens. A page pays
|
|
15
|
+
for the widget on the first interaction, never at load.
|
|
16
|
+
|
|
17
|
+
## Use it
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { makeInquiryClient } from '@owlmeans/web-inquiry'
|
|
21
|
+
|
|
22
|
+
const inquiry = makeInquiryClient({
|
|
23
|
+
url: `${platformWeb}/crm`, // the CRM base; a trailing slash is dropped
|
|
24
|
+
language: () => i18n.language, // a string, or a function read at every open
|
|
25
|
+
email: () => accountEmail(), // optional string or lazy sync/async reply address
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
inquiry.bind('[data-inquiry="quote"]', quoteConfig, { source: 'pricing-card' }) // returns unbind
|
|
29
|
+
await inquiry.open(viableConfig, { tab: 'payment', source: 'menu' })
|
|
30
|
+
const fab = await inquiry.button(viableConfig, { position: 'bottom-right' }) // InquiryHandle
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
One client per page and CRM is the usual shape. More are safe: the script is injected once per
|
|
34
|
+
URL, and each open is routed to the client that claimed its widget id (the latest claimant takes
|
|
35
|
+
the opens of an unclaimed widget). The last client to act sets the runtime's language.
|
|
36
|
+
|
|
37
|
+
| Option | Meaning |
|
|
38
|
+
|---|---|
|
|
39
|
+
| `url` | the CRM base, e.g. `https://platform.owlmeans.com/crm` |
|
|
40
|
+
| `language` | the widget's language — string or function; default: the runtime's own choice |
|
|
41
|
+
| `email` | optional string or function returning `string \| null \| undefined`, directly or in a Promise; applied on each open |
|
|
42
|
+
| `analytics` | the open event's name; default `INQUIRY_OPEN_EVENT`; `false` reports nothing |
|
|
43
|
+
| `onOpen(event)` | called once per open, after the analytics event |
|
|
44
|
+
| `timeoutMs` | how long `load` waits; default `INQUIRY_LOAD_TIMEOUT` (10 000) |
|
|
45
|
+
|
|
46
|
+
The client passes the email source to the widget; neither creating a client, binding triggers nor
|
|
47
|
+
`load()` invokes it. Supply `email` in `open`, `bind` or `button` options to override the client's
|
|
48
|
+
default. A floating button's handle carries the same default into its `open` unless overridden.
|
|
49
|
+
The widget resolves it when the dialog opens, so an async lookup can show its spinner immediately
|
|
50
|
+
and disable the email field and Send while leaving other fields editable. Do not await the lookup
|
|
51
|
+
in the host before opening. A failure or missing result leaves an empty editable address; omitting
|
|
52
|
+
`email` preserves the manual draft. Each subsequent open reapplies the supplied preset.
|
|
53
|
+
|
|
54
|
+
Cache identity lookups in the host when needed, scoped to the authenticated session and held in
|
|
55
|
+
memory. Return a string or null synchronously once cached to avoid showing a spinner again. Share
|
|
56
|
+
pending requests, invalidate the cache when authentication changes, and discard results belonging
|
|
57
|
+
to an earlier session. The SDK and widget do not store identity information.
|
|
58
|
+
|
|
59
|
+
## Loading
|
|
60
|
+
|
|
61
|
+
`load()` (and every `open`, `button` or bound click before it) injects
|
|
62
|
+
`<script src="<url>/inquiry.js?v=<INQUIRY_RUNTIME_VERSION>" async data-owlmeans-inquiry>` — unless
|
|
63
|
+
the page already holds that script, which a second copy of the package would have injected — and
|
|
64
|
+
waits for `window.__owlmeansInquiry`. It resolves when the runtime's `version` equals
|
|
65
|
+
`INQUIRY_RUNTIME_VERSION` and then calls `runtime.configure({ url, language, onOpen })`.
|
|
66
|
+
|
|
67
|
+
It rejects with an `InquiryLoadError` whose `failure` says why: `network` (the script failed, or
|
|
68
|
+
loaded without installing the runtime), `timeout`, `version` (another runtime version) or
|
|
69
|
+
`environment` (no document). A failed load removes the script it injected, so the next call
|
|
70
|
+
retries.
|
|
71
|
+
|
|
72
|
+
## Triggers keep their links
|
|
73
|
+
|
|
74
|
+
`bind(target, config, opts?)` takes an element or a selector (every element it matches now). A
|
|
75
|
+
click is taken over and opens the dialog; if the widget cannot load, an anchor follows its own
|
|
76
|
+
`href` (never `#…` or `javascript:`). A modified click on an anchor — ctrl/cmd/shift/alt or a
|
|
77
|
+
non-primary button — is left to the browser, so "open in a new tab" still reaches the page behind
|
|
78
|
+
the link. Keep a real `href` on every trigger: it is the fallback and what a crawler sees.
|
|
79
|
+
|
|
80
|
+
## Analytics
|
|
81
|
+
|
|
82
|
+
Each open, whatever opened it, is reported once:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
logger('inquiry').info('Inquiry dialog opened',
|
|
86
|
+
{ inquiry_widget, inquiry_tab, inquiry_source },
|
|
87
|
+
{ analytics: 'inquiry_dialog_open', console: false })
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The SDK reports from the runtime's `onOpen` only — `open()` itself emits nothing — so an open from
|
|
91
|
+
code, a bound trigger or the floating button is counted exactly once. `inquiry_source` is the
|
|
92
|
+
trigger's `source` (the floating button's defaults to `fab`) and is sent even when undefined, so a
|
|
93
|
+
tag manager's data layer does not keep the previous open's value.
|
|
94
|
+
|
|
95
|
+
To send it to GTM, the host registers the consent-gated plugin once at startup:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import { addLogPlugin } from '@owlmeans/log'
|
|
99
|
+
import { gtmAnalyticsPlugin } from '@owlmeans/web-log'
|
|
100
|
+
import { INQUIRY_OPEN_EVENT } from '@owlmeans/web-inquiry'
|
|
101
|
+
|
|
102
|
+
addLogPlugin(gtmAnalyticsPlugin({ allow: [INQUIRY_OPEN_EVENT] }))
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Without analytics consent the event is dropped, never queued (`web-log`). In the container, a
|
|
106
|
+
Custom Event trigger on `inquiry_dialog_open` forwards it to a GA4 event tag.
|
|
107
|
+
|
|
108
|
+
## Re-exports
|
|
109
|
+
|
|
110
|
+
For a host that depends on this package alone: `INQUIRY_OPEN_EVENT` and the types
|
|
111
|
+
`InquiryWidgetConfig`, `InquiryTab`, `LocalizedText`, `InquiryOpenOptions`, `InquiryButtonOptions`,
|
|
112
|
+
`InquiryEmailOptions`, `InquiryEmailPreset`, `InquiryEmailValue`, `InquiryOpenEvent`, `InquiryHandle`,
|
|
113
|
+
`InquiryRuntime` from `@owlmeans/common-inquiry`.
|
|
114
|
+
|
|
115
|
+
## Testing
|
|
116
|
+
|
|
117
|
+
The SDK runs against a minimal fake `window`/`document` (attributes, listeners, `head.appendChild`,
|
|
118
|
+
`querySelectorAll`, timers, `location.assign`) and a fake runtime that calls `onOpen` once per open;
|
|
119
|
+
the loader is page-wide state, so each spec uses a CRM URL of its own.
|
|
120
|
+
|
|
121
|
+
## Related
|
|
122
|
+
|
|
123
|
+
- `common-inquiry` — the config, the runtime contract, limits and schemas
|
|
124
|
+
- `web-log`, `log` — the analytics routing the open event takes
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { InquiryClient, InquiryClientOptions } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* A host page's inquiry client. Building it costs nothing: the widget runtime is fetched on the
|
|
4
|
+
* first `load`, `open`, `button` or bound click.
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* const inquiry = makeInquiryClient({ url: 'https://platform.owlmeans.com/crm', language: () => i18n.language })
|
|
8
|
+
* inquiry.bind('[data-inquiry="quote"]', quoteConfig, { source: 'pricing-card' })
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
export declare const makeInquiryClient: (options: InquiryClientOptions) => InquiryClient;
|
|
12
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAGrE;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,YAAa,oBAAoB,KAAG,aAqEjE,CAAA"}
|
package/build/client.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { INQUIRY_OPEN_EVENT } from '@owlmeans/common-inquiry';
|
|
2
|
+
import { logger } from '@owlmeans/log';
|
|
3
|
+
import { INQUIRY_LOAD_TIMEOUT } from './consts.js';
|
|
4
|
+
import { LOG_SCOPE, NO_DESTINATION } from './consts.local.js';
|
|
5
|
+
import { inquiryLoaderUtils } from './utils/loader.js';
|
|
6
|
+
/**
|
|
7
|
+
* A host page's inquiry client. Building it costs nothing: the widget runtime is fetched on the
|
|
8
|
+
* first `load`, `open`, `button` or bound click.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* const inquiry = makeInquiryClient({ url: 'https://platform.owlmeans.com/crm', language: () => i18n.language })
|
|
12
|
+
* inquiry.bind('[data-inquiry="quote"]', quoteConfig, { source: 'pricing-card' })
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export const makeInquiryClient = (options) => {
|
|
16
|
+
const url = options.url.replace(/\/+$/, '');
|
|
17
|
+
const timeoutMs = options.timeoutMs ?? INQUIRY_LOAD_TIMEOUT;
|
|
18
|
+
const eventName = options.analytics === false ? null : options.analytics ?? INQUIRY_OPEN_EVENT;
|
|
19
|
+
const log = logger(LOG_SCOPE);
|
|
20
|
+
/** The one place an open is reported — the runtime calls it once per open, whatever opened it. */
|
|
21
|
+
const opened = (event) => {
|
|
22
|
+
if (eventName != null) {
|
|
23
|
+
log.info('Inquiry dialog opened', {
|
|
24
|
+
inquiry_widget: event.widget,
|
|
25
|
+
inquiry_tab: event.tab,
|
|
26
|
+
inquiry_source: event.source,
|
|
27
|
+
}, { analytics: eventName, console: false });
|
|
28
|
+
}
|
|
29
|
+
options.onOpen?.(event);
|
|
30
|
+
};
|
|
31
|
+
const load = async () => {
|
|
32
|
+
const runtime = await inquiryLoaderUtils.load(url, timeoutMs);
|
|
33
|
+
runtime.configure({ url, language: options.language, onOpen: inquiryLoaderUtils.dispatcher(url) });
|
|
34
|
+
return runtime;
|
|
35
|
+
};
|
|
36
|
+
const open = async (config, opts) => {
|
|
37
|
+
const runtime = await load();
|
|
38
|
+
inquiryLoaderUtils.claim(url, config.id, opened);
|
|
39
|
+
runtime.open(config, options.email != null ? { ...opts, email: opts?.email ?? options.email } : opts);
|
|
40
|
+
};
|
|
41
|
+
const button = async (config, opts) => {
|
|
42
|
+
const runtime = await load();
|
|
43
|
+
inquiryLoaderUtils.claim(url, config.id, opened);
|
|
44
|
+
return runtime.button(config, options.email != null ? { ...opts, email: opts?.email ?? options.email } : opts);
|
|
45
|
+
};
|
|
46
|
+
const bind = (target, config, opts) => {
|
|
47
|
+
if (typeof document === 'undefined') {
|
|
48
|
+
return () => { };
|
|
49
|
+
}
|
|
50
|
+
const elements = typeof target === 'string' ? Array.from(document.querySelectorAll(target)) : [target];
|
|
51
|
+
const unbinds = elements.map(element => {
|
|
52
|
+
const onClick = (event) => {
|
|
53
|
+
const href = element.getAttribute('href');
|
|
54
|
+
const mouse = event;
|
|
55
|
+
if (href != null && (mouse.button > 0 || mouse.metaKey || mouse.ctrlKey || mouse.shiftKey || mouse.altKey)) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
event.preventDefault();
|
|
59
|
+
open(config, opts).catch((error) => {
|
|
60
|
+
const follow = href != null && href.trim() !== '' && !NO_DESTINATION.test(href);
|
|
61
|
+
log.warn('Inquiry widget unavailable', { url, widget: config.id, follow, error });
|
|
62
|
+
if (follow) {
|
|
63
|
+
window.location.assign(href);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
element.addEventListener('click', onClick);
|
|
68
|
+
return () => element.removeEventListener('click', onClick);
|
|
69
|
+
});
|
|
70
|
+
return () => unbinds.forEach(unbind => unbind());
|
|
71
|
+
};
|
|
72
|
+
return { url, load, open, bind, button };
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** How long a client waits for the widget runtime by default, in milliseconds. */
|
|
2
|
+
export declare const INQUIRY_LOAD_TIMEOUT = 10000;
|
|
3
|
+
/** The attribute that marks the injected runtime `<script>` (and lets a second client find it). */
|
|
4
|
+
export declare const INQUIRY_SCRIPT_ATTRIBUTE = "data-owlmeans-inquiry";
|
|
5
|
+
//# sourceMappingURL=consts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,eAAO,MAAM,oBAAoB,QAAS,CAAA;AAE1C,mGAAmG;AACnG,eAAO,MAAM,wBAAwB,0BAA0B,CAAA"}
|
package/build/consts.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** How long a client waits for the widget runtime by default, in milliseconds. */
|
|
2
|
+
export const INQUIRY_LOAD_TIMEOUT = 10_000;
|
|
3
|
+
/** The attribute that marks the injected runtime `<script>` (and lets a second client find it). */
|
|
4
|
+
export const INQUIRY_SCRIPT_ATTRIBUTE = 'data-owlmeans-inquiry';
|
|
5
|
+
//# sourceMappingURL=consts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAA;AAE1C,mGAAmG;AACnG,MAAM,CAAC,MAAM,wBAAwB,GAAG,uBAAuB,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** How often a pending load looks for the runtime global, in milliseconds. */
|
|
2
|
+
export declare const POLL_INTERVAL = 50;
|
|
3
|
+
/** The log scope of the SDK. */
|
|
4
|
+
export declare const LOG_SCOPE = "inquiry";
|
|
5
|
+
/** An `href` that is no destination to fall back to. */
|
|
6
|
+
export declare const NO_DESTINATION: RegExp;
|
|
7
|
+
//# 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,8EAA8E;AAC9E,eAAO,MAAM,aAAa,KAAK,CAAA;AAE/B,gCAAgC;AAChC,eAAO,MAAM,SAAS,YAAY,CAAA;AAElC,wDAAwD;AACxD,eAAO,MAAM,cAAc,QAAyB,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** How often a pending load looks for the runtime global, in milliseconds. */
|
|
2
|
+
export const POLL_INTERVAL = 50;
|
|
3
|
+
/** The log scope of the SDK. */
|
|
4
|
+
export const LOG_SCOPE = 'inquiry';
|
|
5
|
+
/** An `href` that is no destination to fall back to. */
|
|
6
|
+
export const NO_DESTINATION = /^\s*(#|javascript:)/i;
|
|
7
|
+
//# sourceMappingURL=consts.local.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.local.js","sourceRoot":"","sources":["../src/consts.local.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,MAAM,CAAC,MAAM,aAAa,GAAG,EAAE,CAAA;AAE/B,gCAAgC;AAChC,MAAM,CAAC,MAAM,SAAS,GAAG,SAAS,CAAA;AAElC,wDAAwD;AACxD,MAAM,CAAC,MAAM,cAAc,GAAG,sBAAsB,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { InquiryLoadFailure } from './types.js';
|
|
2
|
+
/** The widget runtime could not be loaded; `failure` says why. */
|
|
3
|
+
export declare class InquiryLoadError extends Error {
|
|
4
|
+
readonly failure: InquiryLoadFailure;
|
|
5
|
+
constructor(failure: InquiryLoadFailure, message: string);
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAEpD,kEAAkE;AAClE,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAA;IAEpC,YAAY,OAAO,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,EAIvD;CACF"}
|
package/build/errors.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** The widget runtime could not be loaded; `failure` says why. */
|
|
2
|
+
export class InquiryLoadError extends Error {
|
|
3
|
+
failure;
|
|
4
|
+
constructor(failure, message) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = 'InquiryLoadError';
|
|
7
|
+
this.failure = failure;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAEA,kEAAkE;AAClE,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAChC,OAAO,CAAoB;IAEpC,YAAY,OAA2B,EAAE,OAAe;QACtD,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAA;QAC9B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;IACxB,CAAC;CACF"}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type * from './types.js';
|
|
2
|
+
export * from './consts.js';
|
|
3
|
+
export * from './errors.js';
|
|
4
|
+
export * from './client.js';
|
|
5
|
+
export type { InquiryButtonOptions, InquiryEmailOptions, InquiryEmailPreset, InquiryEmailValue, InquiryHandle, InquiryOpenEvent, InquiryOpenOptions, InquiryRuntime, InquiryTab, InquiryWidgetConfig, LocalizedText, } from '@owlmeans/common-inquiry';
|
|
6
|
+
export { INQUIRY_OPEN_EVENT } from '@owlmeans/common-inquiry';
|
|
7
|
+
//# 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,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,YAAY,EACV,oBAAoB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,aAAa,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,cAAc,EAAE,UAAU,EACjK,mBAAmB,EAAE,aAAa,GACnC,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA"}
|
package/build/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAK3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA"}
|
package/build/types.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { InquiryButtonOptions, InquiryEmailOptions, InquiryHandle, InquiryOpenEvent, InquiryOpenOptions, InquiryRuntime, InquiryWidgetConfig } from '@owlmeans/common-inquiry';
|
|
2
|
+
export interface InquiryClientOptions extends InquiryEmailOptions {
|
|
3
|
+
/** The CRM base URL the widget is served from, e.g. `https://platform.owlmeans.com/crm`; a trailing slash is dropped. */
|
|
4
|
+
url: string;
|
|
5
|
+
/** The widget's language, or a function read at every open (so a language switch is honoured). */
|
|
6
|
+
language?: string | (() => string);
|
|
7
|
+
/** The analytics event of a dialog open. Default: `INQUIRY_OPEN_EVENT`; `false` reports nothing. */
|
|
8
|
+
analytics?: string | false;
|
|
9
|
+
/** Called once per dialog open, after the analytics event. */
|
|
10
|
+
onOpen?: (event: InquiryOpenEvent) => void;
|
|
11
|
+
/** How long `load` waits for the runtime, in milliseconds. Default: `INQUIRY_LOAD_TIMEOUT`. */
|
|
12
|
+
timeoutMs?: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The host page's handle on the inquiry widget. Nothing is fetched until the first `load`, `open`,
|
|
16
|
+
* `button` or bound click; the runtime script is injected once per page whatever the number of
|
|
17
|
+
* clients.
|
|
18
|
+
*/
|
|
19
|
+
export interface InquiryClient {
|
|
20
|
+
/** The normalized CRM base URL. */
|
|
21
|
+
readonly url: string;
|
|
22
|
+
/**
|
|
23
|
+
* The widget runtime: injects `<url>/inquiry.js` once, waits for the runtime of
|
|
24
|
+
* `INQUIRY_RUNTIME_VERSION` and configures it. Rejects with an `InquiryLoadError` on a network
|
|
25
|
+
* failure, a timeout or a runtime of another version.
|
|
26
|
+
*/
|
|
27
|
+
load: () => Promise<InquiryRuntime>;
|
|
28
|
+
/** Load, then open the widget's dialog. */
|
|
29
|
+
open: (config: InquiryWidgetConfig, opts?: InquiryOpenOptions) => Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Open the dialog from a trigger's clicks — an element, or every element a selector matches now.
|
|
32
|
+
* A click is taken over (`preventDefault`) and opens the dialog; when the widget cannot load, an
|
|
33
|
+
* anchor trigger follows its own `href` instead. A modified click (new tab, new window) on an
|
|
34
|
+
* anchor is left to the browser. Returns the function that unbinds every bound element.
|
|
35
|
+
*/
|
|
36
|
+
bind: (target: Element | string, config: InquiryWidgetConfig, opts?: InquiryOpenOptions) => () => void;
|
|
37
|
+
/** Load, then mount the widget's floating button. */
|
|
38
|
+
button: (config: InquiryWidgetConfig, opts?: InquiryButtonOptions) => Promise<InquiryHandle>;
|
|
39
|
+
}
|
|
40
|
+
/** Why the runtime could not be loaded. */
|
|
41
|
+
export type InquiryLoadFailure = 'environment' | 'network' | 'timeout' | 'version';
|
|
42
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EAAE,mBAAmB,EAAE,aAAa,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,cAAc,EAAE,mBAAmB,EACpI,MAAM,0BAA0B,CAAA;AAEjC,MAAM,WAAW,oBAAqB,SAAQ,mBAAmB;IAC/D,yHAAyH;IACzH,GAAG,EAAE,MAAM,CAAA;IACX,kGAAkG;IAClG,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAA;IAClC,oGAAoG;IACpG,SAAS,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;IAC1B,8DAA8D;IAC9D,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAA;IAC1C,+FAA+F;IAC/F,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,mCAAmC;IACnC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,IAAI,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,CAAA;IACnC,2CAA2C;IAC3C,IAAI,EAAE,CAAC,MAAM,EAAE,mBAAmB,EAAE,IAAI,CAAC,EAAE,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/E;;;;;OAKG;IACH,IAAI,EAAE,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,EAAE,MAAM,EAAE,mBAAmB,EAAE,IAAI,CAAC,EAAE,kBAAkB,KAAK,MAAM,IAAI,CAAA;IACtG,qDAAqD;IACrD,MAAM,EAAE,CAAC,MAAM,EAAE,mBAAmB,EAAE,IAAI,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,aAAa,CAAC,CAAA;CAC7F;AAED,2CAA2C;AAC3C,MAAM,MAAM,kBAAkB,GAAG,aAAa,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAA"}
|
package/build/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { InquiryOpenEvent, InquiryRuntime } from '@owlmeans/common-inquiry';
|
|
2
|
+
export interface InquiryOpenHandler {
|
|
3
|
+
(event: InquiryOpenEvent): void;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* The page-wide half of the SDK, shared by every client: one script per CRM url, one pending load,
|
|
7
|
+
* and one `onOpen` per runtime that routes each open to the client that owns the widget.
|
|
8
|
+
*/
|
|
9
|
+
export interface InquiryLoaderUtils {
|
|
10
|
+
/** The runtime served at `url` — injected once, its version checked; a failed load can be retried. */
|
|
11
|
+
load: (url: string, timeoutMs: number) => Promise<InquiryRuntime>;
|
|
12
|
+
/** Route the opens of widget `id` (and those of any widget no client claimed) to `handler`. */
|
|
13
|
+
claim: (url: string, id: string, handler: InquiryOpenHandler) => void;
|
|
14
|
+
/** The one `onOpen` the runtime of `url` is configured with. */
|
|
15
|
+
dispatcher: (url: string) => InquiryOpenHandler;
|
|
16
|
+
}
|
|
17
|
+
/** Who hears the opens of one runtime: the claimant of each widget, else the latest claimant. */
|
|
18
|
+
export interface InquiryOpenRoute {
|
|
19
|
+
handlers: Map<string, InquiryOpenHandler>;
|
|
20
|
+
last?: InquiryOpenHandler;
|
|
21
|
+
dispatch: InquiryOpenHandler;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/utils/loader/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAEhF,MAAM,WAAW,kBAAkB;IAAG,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAA;CAAE;AAEvE;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,sGAAsG;IACtG,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAA;IACjE,+FAA+F;IAC/F,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,KAAK,IAAI,CAAA;IACrE,gEAAgE;IAChE,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,kBAAkB,CAAA;CAChD;AAED,iGAAiG;AACjG,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAA;IACzC,IAAI,CAAC,EAAE,kBAAkB,CAAA;IACzB,QAAQ,EAAE,kBAAkB,CAAA;CAC7B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/utils/loader/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/utils/loader.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,kBAAkB,EAAoB,MAAM,mBAAmB,CAAA;AAE7E,eAAO,MAAM,wBAAwB,QAAO,kBA6H3C,CAAA;AAED,eAAO,MAAM,kBAAkB,oBAA6B,CAAA"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { INQUIRY_GLOBAL, INQUIRY_RUNTIME_VERSION, INQUIRY_SCRIPT, } from '@owlmeans/common-inquiry';
|
|
2
|
+
import { INQUIRY_SCRIPT_ATTRIBUTE } from '../consts.js';
|
|
3
|
+
import { POLL_INTERVAL } from '../consts.local.js';
|
|
4
|
+
import { InquiryLoadError } from '../errors.js';
|
|
5
|
+
export const createInquiryLoaderUtils = () => {
|
|
6
|
+
const loads = new Map();
|
|
7
|
+
const routes = new Map();
|
|
8
|
+
const globalOf = () => window[INQUIRY_GLOBAL];
|
|
9
|
+
const scriptUrl = (url) => `${url}/${INQUIRY_SCRIPT}?v=${INQUIRY_RUNTIME_VERSION}`;
|
|
10
|
+
/** A runtime script already in the page — injected by another client or another copy of this package. */
|
|
11
|
+
const existingScript = (src) => Array.from(document.querySelectorAll(`script[${INQUIRY_SCRIPT_ATTRIBUTE}]`))
|
|
12
|
+
.find(script => script.getAttribute('src') === src);
|
|
13
|
+
const inject = (url, timeoutMs) => new Promise((resolve, reject) => {
|
|
14
|
+
const src = scriptUrl(url);
|
|
15
|
+
const found = existingScript(src);
|
|
16
|
+
const script = found ?? document.createElement('script');
|
|
17
|
+
let settled = false;
|
|
18
|
+
let poll;
|
|
19
|
+
let timer;
|
|
20
|
+
const settle = (runtime, error) => {
|
|
21
|
+
if (settled) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
settled = true;
|
|
25
|
+
window.clearInterval(poll);
|
|
26
|
+
window.clearTimeout(timer);
|
|
27
|
+
script.removeEventListener('load', loaded);
|
|
28
|
+
script.removeEventListener('error', failed);
|
|
29
|
+
if (runtime != null) {
|
|
30
|
+
resolve(runtime);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
loads.delete(url);
|
|
34
|
+
if (found == null) {
|
|
35
|
+
script.remove();
|
|
36
|
+
}
|
|
37
|
+
reject(error);
|
|
38
|
+
};
|
|
39
|
+
/** Whether the runtime is there — settling either way once it is. */
|
|
40
|
+
const check = () => {
|
|
41
|
+
const runtime = globalOf();
|
|
42
|
+
if (runtime == null) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
if (runtime.version !== INQUIRY_RUNTIME_VERSION) {
|
|
46
|
+
settle(undefined, new InquiryLoadError('version', `Inquiry runtime version ${String(runtime.version)} is not ${INQUIRY_RUNTIME_VERSION}`));
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
settle(runtime);
|
|
50
|
+
}
|
|
51
|
+
return true;
|
|
52
|
+
};
|
|
53
|
+
const loaded = () => {
|
|
54
|
+
if (!check()) {
|
|
55
|
+
settle(undefined, new InquiryLoadError('network', `${src} loaded without installing the inquiry runtime`));
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const failed = () => {
|
|
59
|
+
settle(undefined, new InquiryLoadError('network', `${src} failed to load`));
|
|
60
|
+
};
|
|
61
|
+
script.addEventListener('load', loaded);
|
|
62
|
+
script.addEventListener('error', failed);
|
|
63
|
+
poll = window.setInterval(check, POLL_INTERVAL);
|
|
64
|
+
timer = window.setTimeout(() => {
|
|
65
|
+
settle(undefined, new InquiryLoadError('timeout', `${src} did not install the inquiry runtime in ${timeoutMs} ms`));
|
|
66
|
+
}, timeoutMs);
|
|
67
|
+
if (found == null) {
|
|
68
|
+
script.src = src;
|
|
69
|
+
script.async = true;
|
|
70
|
+
script.setAttribute(INQUIRY_SCRIPT_ATTRIBUTE, '');
|
|
71
|
+
document.head.appendChild(script);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
const load = (url, timeoutMs) => {
|
|
75
|
+
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
|
76
|
+
return Promise.reject(new InquiryLoadError('environment', 'The inquiry widget needs a browser document'));
|
|
77
|
+
}
|
|
78
|
+
const ready = globalOf();
|
|
79
|
+
if (ready != null && ready.version === INQUIRY_RUNTIME_VERSION) {
|
|
80
|
+
return Promise.resolve(ready);
|
|
81
|
+
}
|
|
82
|
+
const pending = loads.get(url);
|
|
83
|
+
if (pending != null) {
|
|
84
|
+
return pending;
|
|
85
|
+
}
|
|
86
|
+
const loading = inject(url, timeoutMs);
|
|
87
|
+
loads.set(url, loading);
|
|
88
|
+
return loading;
|
|
89
|
+
};
|
|
90
|
+
const routeOf = (url) => {
|
|
91
|
+
const known = routes.get(url);
|
|
92
|
+
if (known != null) {
|
|
93
|
+
return known;
|
|
94
|
+
}
|
|
95
|
+
const route = {
|
|
96
|
+
handlers: new Map(),
|
|
97
|
+
dispatch: event => (route.handlers.get(event.widget) ?? route.last)?.(event),
|
|
98
|
+
};
|
|
99
|
+
routes.set(url, route);
|
|
100
|
+
return route;
|
|
101
|
+
};
|
|
102
|
+
const claim = (url, id, handler) => {
|
|
103
|
+
const route = routeOf(url);
|
|
104
|
+
route.handlers.set(id, handler);
|
|
105
|
+
route.last = handler;
|
|
106
|
+
};
|
|
107
|
+
const dispatcher = url => routeOf(url).dispatch;
|
|
108
|
+
return { load, claim, dispatcher };
|
|
109
|
+
};
|
|
110
|
+
export const inquiryLoaderUtils = createInquiryLoaderUtils();
|
|
111
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/utils/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EAAE,uBAAuB,EAAE,cAAc,GACxD,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAA;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAG/C,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAuB,EAAE;IAC/D,MAAM,KAAK,GAAG,IAAI,GAAG,EAAmC,CAAA;IACxD,MAAM,MAAM,GAAG,IAAI,GAAG,EAA4B,CAAA;IAElD,MAAM,QAAQ,GAAG,GAA+B,EAAE,CAC/C,MAAmC,CAAC,cAAqC,CAAC,CAAA;IAE7E,MAAM,SAAS,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,GAAG,GAAG,IAAI,cAAc,MAAM,uBAAuB,EAAE,CAAA;IAElG,yGAAyG;IACzG,MAAM,cAAc,GAAG,CAAC,GAAW,EAAiC,EAAE,CACpE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAoB,UAAU,wBAAwB,GAAG,CAAC,CAAC;SAC5F,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAA;IAEvD,MAAM,MAAM,GAAG,CAAC,GAAW,EAAE,SAAiB,EAA2B,EAAE,CACzE,IAAI,OAAO,CAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC9C,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,CAAA;QAC1B,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,CAAA;QACjC,MAAM,MAAM,GAAG,KAAK,IAAI,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAA;QACxD,IAAI,OAAO,GAAG,KAAK,CAAA;QACnB,IAAI,IAAwB,CAAA;QAC5B,IAAI,KAAyB,CAAA;QAE7B,MAAM,MAAM,GAAG,CAAC,OAAwB,EAAE,KAAwB,EAAQ,EAAE;YAC1E,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAM;YACR,CAAC;YACD,OAAO,GAAG,IAAI,CAAA;YACd,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAA;YAC1B,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;YAC1B,MAAM,CAAC,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;YAC1C,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;YAC3C,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;gBACpB,OAAO,CAAC,OAAO,CAAC,CAAA;gBAChB,OAAM;YACR,CAAC;YACD,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACjB,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;gBAClB,MAAM,CAAC,MAAM,EAAE,CAAA;YACjB,CAAC;YACD,MAAM,CAAC,KAAK,CAAC,CAAA;QACf,CAAC,CAAA;QAED,qEAAqE;QACrE,MAAM,KAAK,GAAG,GAAY,EAAE;YAC1B,MAAM,OAAO,GAAG,QAAQ,EAAE,CAAA;YAC1B,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;gBACpB,OAAO,KAAK,CAAA;YACd,CAAC;YACD,IAAI,OAAO,CAAC,OAAO,KAAK,uBAAuB,EAAE,CAAC;gBAChD,MAAM,CAAC,SAAS,EAAE,IAAI,gBAAgB,CACpC,SAAS,EAAE,2BAA2B,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,uBAAuB,EAAE,CAClG,CAAC,CAAA;YACJ,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,OAAO,CAAC,CAAA;YACjB,CAAC;YAED,OAAO,IAAI,CAAA;QACb,CAAC,CAAA;QAED,MAAM,MAAM,GAAG,GAAS,EAAE;YACxB,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC;gBACb,MAAM,CAAC,SAAS,EAAE,IAAI,gBAAgB,CAAC,SAAS,EAAE,GAAG,GAAG,gDAAgD,CAAC,CAAC,CAAA;YAC5G,CAAC;QACH,CAAC,CAAA;QACD,MAAM,MAAM,GAAG,GAAS,EAAE;YACxB,MAAM,CAAC,SAAS,EAAE,IAAI,gBAAgB,CAAC,SAAS,EAAE,GAAG,GAAG,iBAAiB,CAAC,CAAC,CAAA;QAC7E,CAAC,CAAA;QAED,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QACvC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QACxC,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,aAAa,CAAC,CAAA;QAC/C,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE;YAC7B,MAAM,CAAC,SAAS,EAAE,IAAI,gBAAgB,CAAC,SAAS,EAAE,GAAG,GAAG,2CAA2C,SAAS,KAAK,CAAC,CAAC,CAAA;QACrH,CAAC,EAAE,SAAS,CAAC,CAAA;QAEb,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;YAClB,MAAM,CAAC,GAAG,GAAG,GAAG,CAAA;YAChB,MAAM,CAAC,KAAK,GAAG,IAAI,CAAA;YACnB,MAAM,CAAC,YAAY,CAAC,wBAAwB,EAAE,EAAE,CAAC,CAAA;YACjD,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;QACnC,CAAC;IACH,CAAC,CAAC,CAAA;IAEJ,MAAM,IAAI,GAA+B,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE;QAC1D,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;YACrE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,gBAAgB,CAAC,aAAa,EAAE,6CAA6C,CAAC,CAAC,CAAA;QAC3G,CAAC;QACD,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAA;QACxB,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,CAAC,OAAO,KAAK,uBAAuB,EAAE,CAAC;YAC/D,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAC/B,CAAC;QACD,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAC9B,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;YACpB,OAAO,OAAO,CAAA;QAChB,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;QACtC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;QAEvB,OAAO,OAAO,CAAA;IAChB,CAAC,CAAA;IAED,MAAM,OAAO,GAAG,CAAC,GAAW,EAAoB,EAAE;QAChD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAC7B,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;YAClB,OAAO,KAAK,CAAA;QACd,CAAC;QACD,MAAM,KAAK,GAAqB;YAC9B,QAAQ,EAAE,IAAI,GAAG,EAAE;YACnB,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC;SAC7E,CAAA;QACD,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QAEtB,OAAO,KAAK,CAAA;IACd,CAAC,CAAA;IAED,MAAM,KAAK,GAAgC,CAAC,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE;QAC9D,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;QAC1B,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;QAC/B,KAAK,CAAC,IAAI,GAAG,OAAO,CAAA;IACtB,CAAC,CAAA;IAED,MAAM,UAAU,GAAqC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAA;IAEjF,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,CAAA;AACpC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,wBAAwB,EAAE,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,42 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/web-inquiry",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
6
|
-
|
|
3
|
+
"version": "0.1.18-rc.1",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"description": "Lightweight browser SDK of the OwlMeans customer inquiry widget — injects the widget runtime once, opens its dialog from any trigger and reports each open as an analytics event.",
|
|
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
|
+
"dependencies": {
|
|
30
|
+
"@owlmeans/common-inquiry": "^0.1.18-rc.1",
|
|
31
|
+
"@owlmeans/log": "^0.1.18-rc.3"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@owlmeans/dep-config": "workspace:*",
|
|
35
|
+
"@types/bun": "^1.4.2",
|
|
36
|
+
"nodemon": "^3.1.14",
|
|
37
|
+
"typescript": "^7.0.2"
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
}
|
|
42
|
+
}
|