@burdenoff/fe-libs 2026.1021.12 → 2026.1021.14
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/dist/shared/assistant/api.d.ts +2 -0
- package/dist/shared/assistant/api.js +133 -132
- package/dist/shared/assistant/index.d.ts +1 -0
- package/dist/shared/assistant/pageContextKeys.d.ts +46 -0
- package/dist/shared/assistant/pageContextKeys.js +46 -0
- package/dist/shared/components/DocsLink.d.ts +56 -0
- package/dist/shared/components/DocsLink.js +97 -0
- package/dist/shared/components/index.d.ts +2 -0
- package/dist/shared/config/docsUrls.d.ts +91 -0
- package/dist/shared/config/docsUrls.js +70 -0
- package/dist/shared/config/index.d.ts +2 -0
- package/dist/shared-assistant.js +298 -297
- package/dist/shared-components.js +7 -6
- package/dist/shared-config.js +10 -9
- package/dist/shared.js +132 -130
- package/package.json +2 -2
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The page-context keys the assistant sandbox actually reads, and the host-side
|
|
3
|
+
* filter that keeps every other key in the browser (G52, PR-AI-03 / BOFF-3908).
|
|
4
|
+
*
|
|
5
|
+
* The sandbox (`ai-assistant`) reads `pageContext` in exactly two places:
|
|
6
|
+
*
|
|
7
|
+
* - `src/context-loader.ts` `ALLOWED_CONTEXT_KEYS` — the keys `injectPageContext`
|
|
8
|
+
* writes into the session for the model. Any other key is skipped there.
|
|
9
|
+
* - `src/context-redaction.ts` `CONTEXT_ID_KEYS` — the opaque ids whose values
|
|
10
|
+
* are redacted from the assistant's replies. `organizationId` is on this list
|
|
11
|
+
* but NOT the first, so it must still be forwarded: dropping it would stop the
|
|
12
|
+
* sandbox from redacting an organisation id the model learnt from a tool call.
|
|
13
|
+
*
|
|
14
|
+
* Both lists are private Sets in that repo, and ai-assistant cannot import
|
|
15
|
+
* fe-libs, so they are mirrored here and pinned by a drift test against
|
|
16
|
+
* `__fixtures__/aiAssistantContextKeys.json`, which
|
|
17
|
+
* `scripts/assistant-context-keys/vendor.ts` cuts from an ai-assistant checkout
|
|
18
|
+
* (it records the commit and each source file's SHA-256). Re-vendor, then
|
|
19
|
+
* update these lists, whenever either Set changes.
|
|
20
|
+
*
|
|
21
|
+
* The filter is defence in depth: the sandbox already drops unknown keys before
|
|
22
|
+
* the model sees them, so this changes nothing the model receives. It stops the
|
|
23
|
+
* browser from sending data nobody reads (the user agent, a timestamp, anything
|
|
24
|
+
* a product adds by accident) through the gateway and the sandbox proxy.
|
|
25
|
+
*/
|
|
26
|
+
/** Mirror of ai-assistant `ALLOWED_CONTEXT_KEYS`: the keys the model is shown. */
|
|
27
|
+
export declare const ASSISTANT_MODEL_CONTEXT_KEYS: readonly ["currentUrl", "currentPage", "entityType", "entityId", "entityName", "pageTitle", "pageType", "activeTab", "activeTool", "selectedText", "workspaceId", "workspaceName", "projectId", "projectName", "platform", "version", "viewportSize", "vibeId", "vibeName", "vibePath", "sessionId", "sessionName", "agentId", "agentName"];
|
|
28
|
+
/** Mirror of ai-assistant `CONTEXT_ID_KEYS`: the ids redacted from replies. */
|
|
29
|
+
export declare const ASSISTANT_REDACTED_CONTEXT_ID_KEYS: readonly ["workspaceId", "organizationId", "projectId", "entityId", "vibeId", "sessionId", "agentId"];
|
|
30
|
+
export type AssistantPageContextKey = (typeof ASSISTANT_MODEL_CONTEXT_KEYS)[number] | (typeof ASSISTANT_REDACTED_CONTEXT_ID_KEYS)[number];
|
|
31
|
+
/**
|
|
32
|
+
* Every key a host may send in `pageContext`: the union of the two server
|
|
33
|
+
* lists, in a stable order (model keys first, then the redaction-only ones).
|
|
34
|
+
*/
|
|
35
|
+
export declare const ASSISTANT_PAGE_CONTEXT_KEYS: readonly AssistantPageContextKey[];
|
|
36
|
+
/** Whether the sandbox reads `key` from `pageContext`. */
|
|
37
|
+
export declare function isAssistantPageContextKey(key: string): key is AssistantPageContextKey;
|
|
38
|
+
/**
|
|
39
|
+
* The part of a host's page context that goes on the wire: only allow-listed
|
|
40
|
+
* keys, with their values untouched. `undefined` stays `undefined`, so a turn
|
|
41
|
+
* with no context still produces the body it always did; a context with no
|
|
42
|
+
* allow-listed key becomes `{}`, which the sandbox treats as "no context".
|
|
43
|
+
*
|
|
44
|
+
* Own enumerable keys only — an inherited or prototype key is never forwarded.
|
|
45
|
+
*/
|
|
46
|
+
export declare function filterAssistantPageContext(pageContext: Readonly<Record<string, unknown>> | undefined): Record<string, unknown> | undefined;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
//#region src/shared/assistant/pageContextKeys.ts
|
|
2
|
+
var e = [
|
|
3
|
+
"currentUrl",
|
|
4
|
+
"currentPage",
|
|
5
|
+
"entityType",
|
|
6
|
+
"entityId",
|
|
7
|
+
"entityName",
|
|
8
|
+
"pageTitle",
|
|
9
|
+
"pageType",
|
|
10
|
+
"activeTab",
|
|
11
|
+
"activeTool",
|
|
12
|
+
"selectedText",
|
|
13
|
+
"workspaceId",
|
|
14
|
+
"workspaceName",
|
|
15
|
+
"projectId",
|
|
16
|
+
"projectName",
|
|
17
|
+
"platform",
|
|
18
|
+
"version",
|
|
19
|
+
"viewportSize",
|
|
20
|
+
"vibeId",
|
|
21
|
+
"vibeName",
|
|
22
|
+
"vibePath",
|
|
23
|
+
"sessionId",
|
|
24
|
+
"sessionName",
|
|
25
|
+
"agentId",
|
|
26
|
+
"agentName"
|
|
27
|
+
], t = [
|
|
28
|
+
"workspaceId",
|
|
29
|
+
"organizationId",
|
|
30
|
+
"projectId",
|
|
31
|
+
"entityId",
|
|
32
|
+
"vibeId",
|
|
33
|
+
"sessionId",
|
|
34
|
+
"agentId"
|
|
35
|
+
], n = Object.freeze(Array.from(new Set([...e, ...t]))), r = new Set(n);
|
|
36
|
+
function i(e) {
|
|
37
|
+
return r.has(e);
|
|
38
|
+
}
|
|
39
|
+
function a(e) {
|
|
40
|
+
if (e === void 0) return;
|
|
41
|
+
let t = {};
|
|
42
|
+
for (let [n, i] of Object.entries(e)) r.has(n) && (t[n] = i);
|
|
43
|
+
return t;
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
export { e as ASSISTANT_MODEL_CONTEXT_KEYS, n as ASSISTANT_PAGE_CONTEXT_KEYS, t as ASSISTANT_REDACTED_CONTEXT_ID_KEYS, a as filterAssistantPageContext, i as isAssistantPageContextKey };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { AnchorHTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { DocsEnvironment } from '../config/docsUrls';
|
|
3
|
+
export declare const PUBLIC_PRODUCT_DOCS_URL_QUERY: import('graphql').DocumentNode;
|
|
4
|
+
/** Minimal client surface the registry lookup needs (an ApolloClient satisfies it). */
|
|
5
|
+
export interface DocsRegistryClient {
|
|
6
|
+
query: (options: {
|
|
7
|
+
query: typeof PUBLIC_PRODUCT_DOCS_URL_QUERY;
|
|
8
|
+
variables: {
|
|
9
|
+
slug: string;
|
|
10
|
+
};
|
|
11
|
+
fetchPolicy: 'cache-first';
|
|
12
|
+
}) => Promise<{
|
|
13
|
+
data?: unknown;
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
16
|
+
/** Read `publicProduct.docsUrl` out of a query result, trusted origins only. */
|
|
17
|
+
export declare function readRegistryDocsUrl(data: unknown): string | null;
|
|
18
|
+
/** The cached registry docsUrl for a slug: string, `null` (none), or undefined (not fetched). */
|
|
19
|
+
export declare function getCachedRegistryDocsUrl(productSlug: string): string | null | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Look up the registry docsUrl once per slug. Failures resolve to `null` (the
|
|
22
|
+
* catalog default stays in use) and are not cached, so a later mount retries.
|
|
23
|
+
*/
|
|
24
|
+
export declare function fetchRegistryDocsUrl(client: DocsRegistryClient, productSlug: string): Promise<string | null>;
|
|
25
|
+
/** Test seam: forget every cached registry answer. */
|
|
26
|
+
export declare function resetRegistryDocsUrlCache(): void;
|
|
27
|
+
export interface UseProductDocsOptions {
|
|
28
|
+
/** Another product's docs instead of the running shell's. */
|
|
29
|
+
productSlug?: string;
|
|
30
|
+
/** Skip the registry lookup and use the static catalog default only. */
|
|
31
|
+
registry?: boolean;
|
|
32
|
+
/** Override the detected environment (tests, previews). */
|
|
33
|
+
environment?: DocsEnvironment;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The environment-correct docs origin for the running shell's product, e.g.
|
|
37
|
+
* `https://docs.vibecontrols.com` or `https://alphadocs.vibecontrols.com`.
|
|
38
|
+
*/
|
|
39
|
+
export declare function useProductDocsOrigin(options?: UseProductDocsOptions): string | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* The environment-correct docs URL for a page of the running shell's product.
|
|
42
|
+
* `path` is site-relative (`/users/workflows`); undefined when it is not, or
|
|
43
|
+
* when the product has no trusted docs host.
|
|
44
|
+
*/
|
|
45
|
+
export declare function useProductDocsUrl(path?: string, options?: UseProductDocsOptions): string | undefined;
|
|
46
|
+
export interface DocsLinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href' | 'target' | 'rel'>, UseProductDocsOptions {
|
|
47
|
+
/** Site-relative docs path, e.g. `/users/workflows`. Defaults to the docs home. */
|
|
48
|
+
path?: string;
|
|
49
|
+
children: ReactNode;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* A new-tab link to the product's docs for the current environment. Renders
|
|
53
|
+
* its children without a link when no trusted docs URL resolves, so a page
|
|
54
|
+
* never shows a dead "Learn more".
|
|
55
|
+
*/
|
|
56
|
+
export declare function DocsLink({ path, productSlug, registry, environment, children, ...anchorProps }: DocsLinkProps): import('react/jsx-runtime').JSX.Element;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { normalizeProductSlug as e } from "../config/productSlug.js";
|
|
2
|
+
import { buildProductDocsUrl as t, resolveProductDocsOrigin as n, toTrustedDocsOrigin as r } from "../config/docsUrls.js";
|
|
3
|
+
import { useSafeGateway as i } from "../graphql/GatewayContext.js";
|
|
4
|
+
import { useAppShell as a } from "../providers/shell/AppShellContext.js";
|
|
5
|
+
import { useEffect as o, useState as s } from "react";
|
|
6
|
+
import { Fragment as c, jsx as l } from "react/jsx-runtime";
|
|
7
|
+
import { gql as u } from "@apollo/client/core";
|
|
8
|
+
//#region src/shared/components/DocsLink.tsx
|
|
9
|
+
var d = u`
|
|
10
|
+
query PublicProductDocsUrl($slug: String!) {
|
|
11
|
+
publicProduct(slug: $slug) {
|
|
12
|
+
docsUrl
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
`, f = /* @__PURE__ */ new Map(), p = /* @__PURE__ */ new Map();
|
|
16
|
+
function m(e) {
|
|
17
|
+
if (!e || typeof e != "object") return null;
|
|
18
|
+
let t = e.publicProduct;
|
|
19
|
+
if (!t || typeof t != "object") return null;
|
|
20
|
+
let n = t.docsUrl;
|
|
21
|
+
return typeof n == "string" && r(n) ? n : null;
|
|
22
|
+
}
|
|
23
|
+
function h(t) {
|
|
24
|
+
return f.get(e(t));
|
|
25
|
+
}
|
|
26
|
+
function g(t, n) {
|
|
27
|
+
let r = e(n), i = f.get(r);
|
|
28
|
+
if (i !== void 0) return Promise.resolve(i);
|
|
29
|
+
let a = p.get(r);
|
|
30
|
+
if (a) return a;
|
|
31
|
+
let o = t.query({
|
|
32
|
+
query: d,
|
|
33
|
+
variables: { slug: r },
|
|
34
|
+
fetchPolicy: "cache-first"
|
|
35
|
+
}).then((e) => {
|
|
36
|
+
let t = m(e.data);
|
|
37
|
+
return f.set(r, t), t;
|
|
38
|
+
}).catch(() => null).finally(() => {
|
|
39
|
+
p.delete(r);
|
|
40
|
+
});
|
|
41
|
+
return p.set(r, o), o;
|
|
42
|
+
}
|
|
43
|
+
function _(e, t) {
|
|
44
|
+
let n = i(), [r, a] = s(() => h(e) ?? null);
|
|
45
|
+
return o(() => {
|
|
46
|
+
if (!t || !n) return;
|
|
47
|
+
let r = h(e);
|
|
48
|
+
if (r !== void 0) {
|
|
49
|
+
a(r);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
a(null);
|
|
53
|
+
let i = !0;
|
|
54
|
+
return g(n.getClient("global"), e).then((e) => {
|
|
55
|
+
i && a(e);
|
|
56
|
+
}), () => {
|
|
57
|
+
i = !1;
|
|
58
|
+
};
|
|
59
|
+
}, [
|
|
60
|
+
t,
|
|
61
|
+
n,
|
|
62
|
+
e
|
|
63
|
+
]), t ? r : null;
|
|
64
|
+
}
|
|
65
|
+
function v(e = {}) {
|
|
66
|
+
let t = a(), r = e.productSlug ?? t.productSlug;
|
|
67
|
+
return n(r, {
|
|
68
|
+
registryDocsUrl: _(r, e.registry !== !1),
|
|
69
|
+
domain: e.productSlug ? void 0 : t.domain,
|
|
70
|
+
environment: e.environment
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function y(e, n = {}) {
|
|
74
|
+
let r = a(), i = n.productSlug ?? r.productSlug;
|
|
75
|
+
return t(i, e, {
|
|
76
|
+
registryDocsUrl: _(i, n.registry !== !1),
|
|
77
|
+
domain: n.productSlug ? void 0 : r.domain,
|
|
78
|
+
environment: n.environment
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function b({ path: e, productSlug: t, registry: n, environment: r, children: i, ...a }) {
|
|
82
|
+
let o = y(e, {
|
|
83
|
+
productSlug: t,
|
|
84
|
+
registry: n,
|
|
85
|
+
environment: r
|
|
86
|
+
});
|
|
87
|
+
return o ? /* @__PURE__ */ l("a", {
|
|
88
|
+
...a,
|
|
89
|
+
href: o,
|
|
90
|
+
target: "_blank",
|
|
91
|
+
rel: "noopener noreferrer",
|
|
92
|
+
"data-docs-link": "",
|
|
93
|
+
children: i
|
|
94
|
+
}) : /* @__PURE__ */ l(c, { children: i });
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
export { b as DocsLink, d as PUBLIC_PRODUCT_DOCS_URL_QUERY, g as fetchRegistryDocsUrl, m as readRegistryDocsUrl, v as useProductDocsOrigin, y as useProductDocsUrl };
|
|
@@ -30,6 +30,8 @@ export type { QuotaUpgradeBridgeProps, QuotaUpgradeBridgeOptions, QuotaUpgradeCo
|
|
|
30
30
|
export { getSSORedirectUrl, redirectToSSO, SSORedirectSpinner, checkSLO, checkRemoteSLO, clearLocalAuthState, } from './SSORedirectGuard';
|
|
31
31
|
export { MAIN_CONTENT_ID, MainLandmark, PublicLayout, SkipToContentLink, focusSkipTarget, useInsideMainLandmark, } from './SkipToContent';
|
|
32
32
|
export type { MainLandmarkProps, PublicLayoutProps, SkipTarget, SkipToContentLinkProps, } from './SkipToContent';
|
|
33
|
+
export { DocsLink, useProductDocsOrigin, useProductDocsUrl, fetchRegistryDocsUrl, readRegistryDocsUrl, PUBLIC_PRODUCT_DOCS_URL_QUERY, } from './DocsLink';
|
|
34
|
+
export type { DocsLinkProps, DocsRegistryClient, UseProductDocsOptions } from './DocsLink';
|
|
33
35
|
export { LandingOrDashboardRedirect, LandingGateView, resolveLandingGate, hasStoredValidSession, } from './LandingOrDashboardRedirect';
|
|
34
36
|
export type { LandingOrDashboardRedirectProps, LandingGateViewProps, LandingGateDecision, LandingGateInput, } from './LandingOrDashboardRedirect';
|
|
35
37
|
export { AssistantWidget, ASSISTANT_WIDGET_TOGGLE_EVENT } from './assistantWidget/AssistantWidget';
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment-aware product documentation URLs (G91).
|
|
3
|
+
*
|
|
4
|
+
* Every product publishes its docs at `docs.<product-domain>` in production
|
|
5
|
+
* and `alphadocs.<product-domain>` in alpha (behind Cloudflare Access, like
|
|
6
|
+
* every other alpha host). In-app "Learn more" and Help links must follow the
|
|
7
|
+
* environment the shell is running in: an alpha shell that links to the prod
|
|
8
|
+
* docs shows readers documentation for a build they are not using.
|
|
9
|
+
*
|
|
10
|
+
* Resolution, highest precedence first:
|
|
11
|
+
* 1. The product registry `docsUrl` (`publicProduct(slug).docsUrl`), when it
|
|
12
|
+
* is an https URL on a trusted product domain.
|
|
13
|
+
* 2. The static catalog: the product's production app host with `app.`
|
|
14
|
+
* swapped for `docs.`.
|
|
15
|
+
* 3. `docs.<domain>` from the shell's own `domain`, for a product the static
|
|
16
|
+
* catalog does not know yet.
|
|
17
|
+
*
|
|
18
|
+
* The chosen origin is then canonicalised (legacy docs hosts are mapped to
|
|
19
|
+
* their canonical twin — FluidGrids' canonical domain is fluidgrids.ai) and
|
|
20
|
+
* converted to the current environment (`docs.` ↔ `alphadocs.`).
|
|
21
|
+
*
|
|
22
|
+
* @module @burdenoff/fe-libs/shared/config/docsUrls
|
|
23
|
+
*/
|
|
24
|
+
/** The docs estate a link should point at. Local dev servers read the prod docs. */
|
|
25
|
+
export type DocsEnvironment = 'prod' | 'alpha';
|
|
26
|
+
/**
|
|
27
|
+
* Legacy docs hosts and the canonical host each one 301s to. A registry row or
|
|
28
|
+
* shell config that still carries the legacy host resolves straight to the
|
|
29
|
+
* canonical one, so a link never relies on the redirect.
|
|
30
|
+
*/
|
|
31
|
+
export declare const CANONICAL_DOCS_HOSTS: Readonly<Record<string, string>>;
|
|
32
|
+
/**
|
|
33
|
+
* Parse a docs base URL and return its `https://host` origin, or null when it
|
|
34
|
+
* is not a usable docs origin: not https, not on a known product domain,
|
|
35
|
+
* or not parseable. Registry values are user-editable admin data, so an
|
|
36
|
+
* arbitrary host must never become an in-app link.
|
|
37
|
+
*/
|
|
38
|
+
export declare function toTrustedDocsOrigin(url: string | null | undefined): string | null;
|
|
39
|
+
/** Map a legacy docs origin to its canonical twin; other origins are returned unchanged. */
|
|
40
|
+
export declare function canonicalizeDocsOrigin(origin: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* Convert a docs origin to the given environment: `docs.x` ↔ `alphadocs.x`.
|
|
43
|
+
* An origin that follows neither convention is returned unchanged, because
|
|
44
|
+
* guessing an alpha twin for it could produce a host that does not exist.
|
|
45
|
+
*/
|
|
46
|
+
export declare function toEnvironmentDocsOrigin(origin: string, environment: DocsEnvironment): string;
|
|
47
|
+
/**
|
|
48
|
+
* The default prod docs origin for a product from the static catalog
|
|
49
|
+
* (`app.<domain>` → `docs.<domain>`), canonicalised. Undefined when the
|
|
50
|
+
* catalog does not know the product.
|
|
51
|
+
*/
|
|
52
|
+
export declare function getCatalogDocsOrigin(productSlug: string): string | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* Which docs estate the running shell belongs to.
|
|
55
|
+
*
|
|
56
|
+
* - Desktop (Electron): the baked runtime config's `environment`.
|
|
57
|
+
* - Capacitor: the build's deploy target (the WebView origin is always localhost).
|
|
58
|
+
* - Web: `alphaapp.*` / `alphaadmin.*` hosts are alpha; everything else is prod.
|
|
59
|
+
* A localhost dev server built for alpha (`VITE_DEPLOY_ENV=alpha` or
|
|
60
|
+
* `VITE_GATEWAY_TARGET=alpha`) reads the alpha docs; otherwise prod, because
|
|
61
|
+
* docs are not served by the local stack.
|
|
62
|
+
*/
|
|
63
|
+
export declare function resolveDocsEnvironment(hostname?: string): DocsEnvironment;
|
|
64
|
+
export interface ResolveDocsOriginOptions {
|
|
65
|
+
/** The registry's `docsUrl` for the product, when the shell has it. */
|
|
66
|
+
registryDocsUrl?: string | null;
|
|
67
|
+
/** The shell's own domain (AppShellConfig `domain`), for products missing from the catalog. */
|
|
68
|
+
domain?: string;
|
|
69
|
+
/** Override the detected environment (tests, previews). */
|
|
70
|
+
environment?: DocsEnvironment;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The environment-correct docs origin for a product, e.g.
|
|
74
|
+
* `https://alphadocs.vibecontrols.com` on alphaapp.vibecontrols.com.
|
|
75
|
+
* Undefined only when no source names a trusted docs host.
|
|
76
|
+
*/
|
|
77
|
+
export declare function resolveProductDocsOrigin(productSlug: string, options?: ResolveDocsOriginOptions): string | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* Normalise a docs path: must be site-relative. Absolute URLs and
|
|
80
|
+
* protocol-relative `//host` paths are rejected (they would let a caller turn
|
|
81
|
+
* a "docs" link into an arbitrary external link). Query and hash are kept.
|
|
82
|
+
*/
|
|
83
|
+
export declare function normalizeDocsPath(path: string | undefined): string | null;
|
|
84
|
+
/**
|
|
85
|
+
* Full docs URL for a product page, e.g.
|
|
86
|
+
* `buildProductDocsUrl('fluidgrids', '/users/workflows')` →
|
|
87
|
+
* `https://docs.fluidgrids.ai/users/workflows` in prod and
|
|
88
|
+
* `https://alphadocs.fluidgrids.ai/users/workflows` in alpha.
|
|
89
|
+
* Undefined when there is no trusted docs origin or the path is not site-relative.
|
|
90
|
+
*/
|
|
91
|
+
export declare function buildProductDocsUrl(productSlug: string, path?: string, options?: ResolveDocsOriginOptions): string | undefined;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { isCapacitorNative as e } from "../native/capacitor.js";
|
|
2
|
+
import { getDesktopRuntimeConfig as t } from "../native/desktop.js";
|
|
3
|
+
import { ALL_PRODUCT_DOMAINS as n, ALPHA_HOSTS as r, getCurrentHostname as i, resolveNativeDeployTarget as a } from "./gatewayUrls.js";
|
|
4
|
+
import { legacyProductSlug as o, normalizeProductSlug as s } from "./productSlug.js";
|
|
5
|
+
import { PRODUCT_URLS as c } from "./products.js";
|
|
6
|
+
//#region src/shared/config/docsUrls.ts
|
|
7
|
+
var l = "docs.", u = "alphadocs.", d = {
|
|
8
|
+
"docs.fluidgrids.com": "docs.fluidgrids.ai",
|
|
9
|
+
"alphadocs.fluidgrids.com": "alphadocs.fluidgrids.ai"
|
|
10
|
+
}, f = new Set(n);
|
|
11
|
+
function p(e) {
|
|
12
|
+
let t = e.toLowerCase();
|
|
13
|
+
for (let e of f) if (t === e || t.endsWith(`.${e}`)) return !0;
|
|
14
|
+
return !1;
|
|
15
|
+
}
|
|
16
|
+
function m(e) {
|
|
17
|
+
if (typeof e != "string" || e.trim() === "") return null;
|
|
18
|
+
let t;
|
|
19
|
+
try {
|
|
20
|
+
t = new URL(e.trim());
|
|
21
|
+
} catch {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return t.protocol !== "https:" || t.username || t.password || t.port || !p(t.hostname) ? null : `https://${t.hostname.toLowerCase()}`;
|
|
25
|
+
}
|
|
26
|
+
function h(e) {
|
|
27
|
+
let t = d[e.replace(/^https:\/\//, "")];
|
|
28
|
+
return t ? `https://${t}` : e;
|
|
29
|
+
}
|
|
30
|
+
function g(e, t) {
|
|
31
|
+
let n = e.replace(/^https:\/\//, ""), r = null;
|
|
32
|
+
return n.startsWith(u) ? r = n.slice(10) : n.startsWith(l) && (r = n.slice(5)), r ? `https://${t === "alpha" ? u : l}${r}` : e;
|
|
33
|
+
}
|
|
34
|
+
function _(e) {
|
|
35
|
+
let t = c.production, n = s(e), r = t[n] ?? t[o(n)];
|
|
36
|
+
if (!r) return;
|
|
37
|
+
let i;
|
|
38
|
+
try {
|
|
39
|
+
i = new URL(r).hostname;
|
|
40
|
+
} catch {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
return h(`https://${l}${i.startsWith("app.") ? i.slice(4) : i}`);
|
|
44
|
+
}
|
|
45
|
+
function v(n = i()) {
|
|
46
|
+
let o = t()?.environment;
|
|
47
|
+
if (o) return o === "alpha" ? "alpha" : "prod";
|
|
48
|
+
if (e()) return a() === "alpha" ? "alpha" : "prod";
|
|
49
|
+
let s = n.toLowerCase(), c = () => a() === "alpha" ? "alpha" : "prod";
|
|
50
|
+
return r.has(s) ? "alpha" : s.endsWith(".local.burdenoff.com") ? c() : s.startsWith("alpha") && p(s) ? "alpha" : p(s) ? "prod" : c();
|
|
51
|
+
}
|
|
52
|
+
function y(e, t = {}) {
|
|
53
|
+
let n = t.domain ? m(`https://${l}${t.domain.replace(/^www\./, "")}`) : null, r = m(t.registryDocsUrl) ?? _(e) ?? n ?? void 0;
|
|
54
|
+
if (!r) return;
|
|
55
|
+
let i = t.environment ?? v();
|
|
56
|
+
return g(h(r), i);
|
|
57
|
+
}
|
|
58
|
+
function b(e) {
|
|
59
|
+
if (e === void 0 || e === "") return "";
|
|
60
|
+
let t = e.trim();
|
|
61
|
+
return /^[a-z][a-z0-9+.-]*:/i.test(t) || t.startsWith("//") || t.includes("\\") ? null : t.startsWith("/") || t.startsWith("#") || t.startsWith("?") ? t : `/${t}`;
|
|
62
|
+
}
|
|
63
|
+
function x(e, t, n = {}) {
|
|
64
|
+
let r = y(e, n);
|
|
65
|
+
if (!r) return;
|
|
66
|
+
let i = b(t);
|
|
67
|
+
if (i !== null) return `${r}${i}`;
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
export { d as CANONICAL_DOCS_HOSTS, x as buildProductDocsUrl, h as canonicalizeDocsOrigin, _ as getCatalogDocsOrigin, b as normalizeDocsPath, v as resolveDocsEnvironment, y as resolveProductDocsOrigin, g as toEnvironmentDocsOrigin, m as toTrustedDocsOrigin };
|
|
@@ -68,6 +68,8 @@ export { resolveGatewayUrls } from './gatewayUrls';
|
|
|
68
68
|
export type { RuntimeGatewayUrls } from './gatewayUrls';
|
|
69
69
|
export { resolveAuthBridgeConfig, resolveShellAuthBridgeConfig } from './authBridgeUrls';
|
|
70
70
|
export type { RuntimeAuthBridgeConfig } from './authBridgeUrls';
|
|
71
|
+
export { CANONICAL_DOCS_HOSTS, buildProductDocsUrl, canonicalizeDocsOrigin, getCatalogDocsOrigin, normalizeDocsPath, resolveDocsEnvironment, resolveProductDocsOrigin, toEnvironmentDocsOrigin, toTrustedDocsOrigin, } from './docsUrls';
|
|
72
|
+
export type { DocsEnvironment, ResolveDocsOriginOptions } from './docsUrls';
|
|
71
73
|
export { PRODUCTS, PRODUCT_URLS, BOTMANOR_PRODUCT_SLUG, getProductUrl, getProductsWithUrls, findProductConfig, } from './products';
|
|
72
74
|
export type { ProductConfig } from './products';
|
|
73
75
|
export { PRODUCT_SLUG_RENAMES, PRODUCT_SLUG_EMIT, normalizeProductSlug, legacyProductSlug, isSameProductSlug, emitProductSlug, } from './productSlug';
|