@wildo-ai/saas-technical-doc 1.1.1 → 1.1.3

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.
Files changed (123) hide show
  1. package/dist/esm/companion/application-documentation/application-administration-documentation.d.ts +52 -0
  2. package/dist/esm/companion/application-documentation/application-administration-documentation.d.ts.map +1 -0
  3. package/dist/esm/companion/application-documentation/application-administration-documentation.js +58 -0
  4. package/dist/esm/companion/application-documentation/application-administration-documentation.js.map +1 -0
  5. package/dist/esm/companion/application-documentation/application-authentication-documentation.d.ts +76 -0
  6. package/dist/esm/companion/application-documentation/application-authentication-documentation.d.ts.map +1 -0
  7. package/dist/esm/companion/application-documentation/application-authentication-documentation.js +116 -0
  8. package/dist/esm/companion/application-documentation/application-authentication-documentation.js.map +1 -0
  9. package/dist/esm/companion/application-documentation/application-connection-documentation.d.ts +111 -0
  10. package/dist/esm/companion/application-documentation/application-connection-documentation.d.ts.map +1 -0
  11. package/dist/esm/companion/application-documentation/application-connection-documentation.js +165 -0
  12. package/dist/esm/companion/application-documentation/application-connection-documentation.js.map +1 -0
  13. package/dist/esm/companion/application-documentation/application-domain-documentation.d.ts +133 -0
  14. package/dist/esm/companion/application-documentation/application-domain-documentation.d.ts.map +1 -0
  15. package/dist/esm/companion/application-documentation/application-domain-documentation.js +243 -0
  16. package/dist/esm/companion/application-documentation/application-domain-documentation.js.map +1 -0
  17. package/dist/esm/companion/application-documentation/application-integration-documentation.d.ts +48 -0
  18. package/dist/esm/companion/application-documentation/application-integration-documentation.d.ts.map +1 -0
  19. package/dist/esm/companion/application-documentation/application-integration-documentation.js +86 -0
  20. package/dist/esm/companion/application-documentation/application-integration-documentation.js.map +1 -0
  21. package/dist/esm/companion/application-documentation/application-organization-role-documentation.d.ts +30 -0
  22. package/dist/esm/companion/application-documentation/application-organization-role-documentation.d.ts.map +1 -1
  23. package/dist/esm/companion/application-documentation/application-organization-role-documentation.js +38 -0
  24. package/dist/esm/companion/application-documentation/application-organization-role-documentation.js.map +1 -1
  25. package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.d.ts +82 -4
  26. package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.d.ts.map +1 -1
  27. package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.js +412 -219
  28. package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.js.map +1 -1
  29. package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.d.ts +10 -0
  30. package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.d.ts.map +1 -1
  31. package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.js +9 -1
  32. package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.js.map +1 -1
  33. package/dist/esm/companion/application-documentation/technical-documentation-publication-policy.js +1 -1
  34. package/dist/esm/companion/application-documentation/technical-documentation-publication-policy.js.map +1 -1
  35. package/dist/esm/companion/index.d.ts +6 -1
  36. package/dist/esm/companion/index.d.ts.map +1 -1
  37. package/dist/esm/companion/index.js +6 -1
  38. package/dist/esm/companion/index.js.map +1 -1
  39. package/dist/esm/companion/manual-controller-route-projection.d.ts +112 -0
  40. package/dist/esm/companion/manual-controller-route-projection.d.ts.map +1 -0
  41. package/dist/esm/companion/manual-controller-route-projection.js +249 -0
  42. package/dist/esm/companion/manual-controller-route-projection.js.map +1 -0
  43. package/dist/esm/companion/openapi-generator.d.ts +16 -0
  44. package/dist/esm/companion/openapi-generator.d.ts.map +1 -1
  45. package/dist/esm/companion/openapi-generator.js +497 -32
  46. package/dist/esm/companion/openapi-generator.js.map +1 -1
  47. package/dist/esm/companion/operation-projection.schemas.d.ts +44 -0
  48. package/dist/esm/companion/operation-projection.schemas.d.ts.map +1 -1
  49. package/dist/esm/companion/operation-projection.schemas.js +37 -0
  50. package/dist/esm/companion/operation-projection.schemas.js.map +1 -1
  51. package/dist/esm/companion/rendering/technical-documentation-docusaurus-renderer.d.ts +7 -1
  52. package/dist/esm/companion/rendering/technical-documentation-docusaurus-renderer.d.ts.map +1 -1
  53. package/dist/esm/companion/rendering/technical-documentation-docusaurus-renderer.js +44 -20
  54. package/dist/esm/companion/rendering/technical-documentation-docusaurus-renderer.js.map +1 -1
  55. package/dist/esm/companion/rendering/technical-documentation-managed-tree-validator.d.ts.map +1 -1
  56. package/dist/esm/companion/rendering/technical-documentation-managed-tree-validator.js +8 -1
  57. package/dist/esm/companion/rendering/technical-documentation-managed-tree-validator.js.map +1 -1
  58. package/dist/esm/companion/rendering/technical-documentation-markdown-links.d.ts +28 -0
  59. package/dist/esm/companion/rendering/technical-documentation-markdown-links.d.ts.map +1 -0
  60. package/dist/esm/companion/rendering/technical-documentation-markdown-links.js +52 -0
  61. package/dist/esm/companion/rendering/technical-documentation-markdown-links.js.map +1 -0
  62. package/dist/esm/companion/rendering/technical-documentation-markdown-renderer.d.ts +0 -9
  63. package/dist/esm/companion/rendering/technical-documentation-markdown-renderer.d.ts.map +0 -1
  64. package/dist/esm/companion/rendering/technical-documentation-markdown-renderer.js +0 -106
  65. package/dist/esm/companion/rendering/technical-documentation-markdown-renderer.js.map +0 -1
  66. package/dist/esm/companion/rendering/technical-documentation-render-model.d.ts +1 -0
  67. package/dist/esm/companion/rendering/technical-documentation-render-model.d.ts.map +1 -1
  68. package/dist/esm/companion/rendering/technical-documentation-render-model.js +112 -88
  69. package/dist/esm/companion/rendering/technical-documentation-render-model.js.map +1 -1
  70. package/dist/esm/companion/rendering/technical-documentation-search-index-renderer.d.ts +10 -0
  71. package/dist/esm/companion/rendering/technical-documentation-search-index-renderer.d.ts.map +1 -1
  72. package/dist/esm/companion/rendering/technical-documentation-search-index-renderer.js +10 -15
  73. package/dist/esm/companion/rendering/technical-documentation-search-index-renderer.js.map +1 -1
  74. package/dist/esm/companion/technical-documentation-capture-execution-port.d.ts +27 -1
  75. package/dist/esm/companion/technical-documentation-capture-execution-port.d.ts.map +1 -1
  76. package/dist/esm/companion/technical-documentation-capture-execution-port.js.map +1 -1
  77. package/dist/esm/companion/technical-documentation-diagram-definitions.d.ts +33 -0
  78. package/dist/esm/companion/technical-documentation-diagram-definitions.d.ts.map +1 -0
  79. package/dist/esm/companion/technical-documentation-diagram-definitions.js +54 -0
  80. package/dist/esm/companion/technical-documentation-diagram-definitions.js.map +1 -0
  81. package/dist/esm/companion/technical-documentation-diagram-materializer.d.ts +10 -18
  82. package/dist/esm/companion/technical-documentation-diagram-materializer.d.ts.map +1 -1
  83. package/dist/esm/companion/technical-documentation-diagram-materializer.js +9 -39
  84. package/dist/esm/companion/technical-documentation-diagram-materializer.js.map +1 -1
  85. package/dist/esm/config/wildo-tech-doc-config.schemas.d.ts +8 -4
  86. package/dist/esm/config/wildo-tech-doc-config.schemas.d.ts.map +1 -1
  87. package/dist/esm/config/wildo-tech-doc-config.schemas.js +8 -4
  88. package/dist/esm/config/wildo-tech-doc-config.schemas.js.map +1 -1
  89. package/dist/esm/content/application-consumer-documentation-content.techdoc.d.ts +105 -122
  90. package/dist/esm/content/application-consumer-documentation-content.techdoc.d.ts.map +1 -1
  91. package/dist/esm/content/application-consumer-documentation-content.techdoc.js +934 -2161
  92. package/dist/esm/content/application-consumer-documentation-content.techdoc.js.map +1 -1
  93. package/dist/esm/runtime/DocsAuthContext.d.ts +16 -1
  94. package/dist/esm/runtime/DocsAuthContext.d.ts.map +1 -1
  95. package/dist/esm/runtime/DocsAuthContext.js +18 -2
  96. package/dist/esm/runtime/DocsAuthContext.js.map +1 -1
  97. package/dist/esm/runtime/decode-jwt-claims.d.ts +7 -4
  98. package/dist/esm/runtime/decode-jwt-claims.d.ts.map +1 -1
  99. package/dist/esm/runtime/decode-jwt-claims.js +7 -4
  100. package/dist/esm/runtime/decode-jwt-claims.js.map +1 -1
  101. package/dist/esm/runtime/docs-auth-session.schemas.d.ts +16 -5
  102. package/dist/esm/runtime/docs-auth-session.schemas.d.ts.map +1 -1
  103. package/dist/esm/runtime/docs-auth-session.schemas.js +16 -5
  104. package/dist/esm/runtime/docs-auth-session.schemas.js.map +1 -1
  105. package/dist/esm/runtime/frontend-provider-registry.techdoc.d.ts +35 -13
  106. package/dist/esm/runtime/frontend-provider-registry.techdoc.d.ts.map +1 -1
  107. package/dist/esm/runtime/frontend-provider-registry.techdoc.js +28 -19
  108. package/dist/esm/runtime/frontend-provider-registry.techdoc.js.map +1 -1
  109. package/dist/esm/runtime/index.d.ts +1 -0
  110. package/dist/esm/runtime/index.d.ts.map +1 -1
  111. package/dist/esm/runtime/index.js +1 -0
  112. package/dist/esm/runtime/index.js.map +1 -1
  113. package/dist/esm/runtime/use-docs-auth-session.d.ts +9 -7
  114. package/dist/esm/runtime/use-docs-auth-session.d.ts.map +1 -1
  115. package/dist/esm/runtime/use-docs-auth-session.js +9 -7
  116. package/dist/esm/runtime/use-docs-auth-session.js.map +1 -1
  117. package/dist/esm/runtime/use-docs-provider-sdks.d.ts +21 -0
  118. package/dist/esm/runtime/use-docs-provider-sdks.d.ts.map +1 -0
  119. package/dist/esm/runtime/use-docs-provider-sdks.js +49 -0
  120. package/dist/esm/runtime/use-docs-provider-sdks.js.map +1 -0
  121. package/dist/tsconfig.build.tsbuildinfo +1 -1
  122. package/package.json +6 -5
  123. package/dist/esm/.builder.pid +0 -9
@@ -2,7 +2,7 @@ import { type Context, type FC, type ReactNode } from 'react';
2
2
  import type { FrontendProvidersBlock } from '@wildo-ai/saas-models/public-runtime';
3
3
  import { DocsAuthClient } from './docs-auth-client';
4
4
  import type { DocsAuthSession, DocsJwtClaims } from './docs-auth-session.schemas';
5
- import { type FrontendTechdocProviderRegistry } from './frontend-provider-registry.techdoc';
5
+ import { type FrontendTechdocProviderRegistry, type GeneratedTechdocProviderModules } from './frontend-provider-registry.techdoc';
6
6
  /**
7
7
  * Result of a `beginExchange()` call surfaced to `<AuthExchangePage>`.
8
8
  *
@@ -105,6 +105,21 @@ export declare const DocsAuthProvider: FC<{
105
105
  * When omitted, the docs runtime exposes an empty provider registry.
106
106
  */
107
107
  frontendProviders?: FrontendProvidersBlock;
108
+ /**
109
+ * The CODE channel for those providers (#332): the
110
+ * `generatedFrontendProviderModules` export of this docs service's own
111
+ * `src/generated/frontend-providers.generated.ts`, written by
112
+ * `wildo config sync`.
113
+ *
114
+ * `frontendProviders` above says WHICH providers this service turned on, in
115
+ * this environment; this says what code the bundle actually contains for
116
+ * them. Both are needed, because a JSON payload cannot carry an SDK loader
117
+ * and a bundle cannot know which environment it is running in.
118
+ *
119
+ * Omitted is the ordinary case for a docs site declaring no package-shipped
120
+ * provider: no such file is generated, so there is nothing to import.
121
+ */
122
+ frontendProviderModules?: GeneratedTechdocProviderModules;
108
123
  /**
109
124
  * Runtime frontend service identity used for the `X-Frontend-Service-Name`
110
125
  * header on exchange/handoff auth calls.
@@ -1 +1 @@
1
- {"version":3,"file":"DocsAuthContext.d.ts","sourceRoot":"","sources":["../../../../src/runtime/DocsAuthContext.tsx"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,OAAO,EACZ,KAAK,EAAE,EACP,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAEnF,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAClF,OAAO,EAEL,KAAK,+BAA+B,EACrC,MAAM,sCAAsC,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,wBAAwB,EAAE,+BAA+B,CAAC;IACnE,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC9D,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,OAAO,CAAC,oBAAoB,GAAG,IAAI,CACf,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC;IAChC,QAAQ,EAAE,SAAS,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,sBAAsB,CAAC;IAC3C;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC;;;OAGG;IACH,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB,CA0GA,CAAC"}
1
+ {"version":3,"file":"DocsAuthContext.d.ts","sourceRoot":"","sources":["../../../../src/runtime/DocsAuthContext.tsx"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,OAAO,EACZ,KAAK,EAAE,EACP,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAEnF,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAElF,OAAO,EAEL,KAAK,+BAA+B,EACpC,KAAK,+BAA+B,EACrC,MAAM,sCAAsC,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,wBAAwB,EAAE,+BAA+B,CAAC;IACnE,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC9D,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,OAAO,CAAC,oBAAoB,GAAG,IAAI,CACf,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC;IAChC,QAAQ,EAAE,SAAS,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,sBAAsB,CAAC;IAC3C;;;;;;;;;;;;;OAaG;IACH,uBAAuB,CAAC,EAAE,+BAA+B,CAAC;IAC1D;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC;;;OAGG;IACH,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB,CA4HA,CAAC"}
@@ -2,6 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { createContext, useCallback, useEffect, useMemo, useRef, useState, } from 'react';
3
3
  import { decodeJwtClaims } from './decode-jwt-claims.js';
4
4
  import { DocsAuthClient } from './docs-auth-client.js';
5
+ import { useDocsProviderSdks } from './use-docs-provider-sdks.js';
5
6
  import { createFrontendTechdocProviderRegistry, } from './frontend-provider-registry.techdoc.js';
6
7
  /**
7
8
  * @internal — consumers should call `useDocsAuthSession()` instead of
@@ -42,7 +43,7 @@ export const DocsAuthContext = createContext(null);
42
43
  * would force this package to import the inversify-bound `appConfig`
43
44
  * provider — exactly the dependency we are avoiding.
44
45
  */
45
- export const DocsAuthProvider = ({ children, apiBaseUrl, frontendProviders, frontendServiceName = null, client: clientOverride, }) => {
46
+ export const DocsAuthProvider = ({ children, apiBaseUrl, frontendProviders, frontendProviderModules, frontendServiceName = null, client: clientOverride, }) => {
46
47
  const [session, setSession] = useState({ status: 'anonymous' });
47
48
  /**
48
49
  * `getAuthBearer` reads from a closure over `session` so the bearer
@@ -63,7 +64,22 @@ export const DocsAuthProvider = ({ children, apiBaseUrl, frontendProviders, fron
63
64
  : null,
64
65
  });
65
66
  }, [apiBaseUrl, frontendServiceName, clientOverride, sessionRef]);
66
- const frontendProviderRegistry = useMemo(() => createFrontendTechdocProviderRegistry(frontendProviders), [frontendProviders]);
67
+ const frontendProviderRegistry = useMemo(() => createFrontendTechdocProviderRegistry({
68
+ entries: frontendProviders,
69
+ modules: frontendProviderModules,
70
+ onDiagnostic: (diagnostic) => {
71
+ // The docs runtime has no logger service, and a provider that is
72
+ // declared but cannot fully run is a developer-facing fact that must
73
+ // not be silent. Never a throw: a misconfigured provider must not take
74
+ // the documentation site down.
75
+ // eslint-disable-next-line no-console
76
+ console.warn(`[wildo-provider] ${diagnostic.kind}: ${diagnostic.message}`);
77
+ },
78
+ }), [frontendProviders, frontendProviderModules]);
79
+ // Load and start the SDK of every live provider that ships one. Effect-only:
80
+ // Docusaurus server-renders every page at build time, and starting a vendor
81
+ // client there would run it inside the build.
82
+ useDocsProviderSdks(frontendProviderRegistry);
67
83
  /**
68
84
  * Auto-clear when the access token expires.
69
85
  *
@@ -1 +1 @@
1
- {"version":3,"file":"DocsAuthContext.js","sourceRoot":"","sources":["../../../../src/runtime/DocsAuthContext.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n createContext,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type Context,\n type FC,\n type ReactNode,\n} from 'react';\nimport type { FrontendProvidersBlock } from '@wildo-ai/saas-models/public-runtime';\nimport { decodeJwtClaims } from './decode-jwt-claims';\nimport { DocsAuthClient } from './docs-auth-client';\nimport type { DocsAuthSession, DocsJwtClaims } from './docs-auth-session.schemas';\nimport {\n createFrontendTechdocProviderRegistry,\n type FrontendTechdocProviderRegistry,\n} from './frontend-provider-registry.techdoc';\n\n/**\n * Result of a `beginExchange()` call surfaced to `<AuthExchangePage>`.\n *\n * `claims` — decoded `DocsJwtClaims` (or `null` if the access token\n * came back undecodable — treated as anonymous).\n * `returnPath` — the issuer-supplied `returnPath` from the token exchange\n * response (cross-app-jwt-propagation.md Step 5). It is\n * a TOP-LEVEL field on `TokenExchangeResponseSchema` —\n * NOT nested under `metadata`. The earlier draft of this\n * JSDoc said \"metadata.returnPath\" and the implementation\n * read `response.metadata?.returnPath` (always undefined,\n * because no such key exists on the response). H-3 in the\n * Step 5 second deep-review log fixes both the docstring\n * and the read site.\n * `null` for OAuth2-callback codes (which never carry a\n * `returnPath` at all — discriminator invariant pinned by\n * `TokenExchangeResponseSchema` JSDoc); the exchange page\n * falls back to the URL `?return=` parameter in that case\n * (defense-in-depth).\n */\nexport interface DocsBeginExchangeResult {\n readonly claims: DocsJwtClaims | null;\n readonly returnPath: string | null;\n}\n\n/**\n * Public surface of `useDocsAuthSession()`.\n *\n * `session` — discriminated union (anonymous / exchanging / authenticated).\n * `client` — the singleton `DocsAuthClient` for authenticated docs\n * runtime code that needs to request a handoff to another\n * frontend. Anonymous docs gates deep-link to the SaaS app\n * because handoff issuance requires a bearer.\n * `frontendProviderRegistry`\n * — hydrated registry of the frontend-safe provider entries\n * materialized for the active docs service. Browser-only\n * docs widgets (search, analytics, future SDK protocols)\n * read from this instead of importing generated artifacts.\n * `beginExchange` — called by `<AuthExchangePage>` when a `?code=` arrives.\n * Returns the decoded claims AND the issuer-supplied\n * top-level `returnPath` from the exchange response\n * (the SOURCE OF TRUTH for post-exchange navigation;\n * the URL `?return=` is a defense-in-depth fallback\n * only). NOT `response.metadata.returnPath` — the\n * response has no `metadata` envelope (H-3 fix).\n * `clear` — called when the user explicitly closes the docs\n * session (e.g. a \"Sign out of docs\" link). NOT called\n * on tab close — ephemeral state evaporates on its own.\n */\nexport interface DocsAuthContextValue {\n readonly session: DocsAuthSession;\n readonly client: DocsAuthClient;\n readonly frontendProviderRegistry: FrontendTechdocProviderRegistry;\n beginExchange(code: string): Promise<DocsBeginExchangeResult>;\n clear(): void;\n}\n\n/**\n * @internal — consumers should call `useDocsAuthSession()` instead of\n * touching this directly. Exported so the matching hook can `useContext`\n * it from a sibling module (Fast Refresh boundary).\n */\nexport const DocsAuthContext: Context<DocsAuthContextValue | null> =\n createContext<DocsAuthContextValue | null>(null);\n\n/**\n * In-memory React context owning the docs-site authenticated session\n * (saas-technical-doc.md K-9b).\n *\n * Storage characteristics — locked by K-9b:\n *\n * - In-memory only. NO `localStorage`, NO `sessionStorage`, NO cookies.\n * Closing the tab destroys the session.\n * - NO refresh-token loop. `/auth/token/exchange` no longer returns a\n * refresh token in the JSON body; SaaS-app receivers get refresh via the\n * HttpOnly cookie channel, while docs intentionally keeps only the access\n * token in memory. When the access token's `exp` passes, the next access\n * becomes anonymous and the user re-handshakes from the SaaS app on demand.\n * - NO BroadcastChannel cross-tab coordination. Each docs tab owns its\n * own session — opening a new tab is anonymous until it gets its own\n * `?code=` redirect.\n *\n * These choices are deliberate: the docs site is a session RECEIVER\n * (never a session OWNER), and the SaaS app is the authoritative source\n * of authentication. Replicating the SaaS app's session-management stack\n * here would force the docs Docusaurus bundle to ship inversify, the\n * resources framework, and a refresh interceptor — all of which are\n * about to be hardened (auth-hardening.md Slice A) in the SaaS app\n * specifically because they are sensitive surfaces. Keeping the docs\n * site free of those mechanisms keeps its attack surface tiny.\n *\n * The `apiBaseUrl` prop is supplied by the docs site at mount time\n * (typically read from a small `appConfig.json` shipped alongside the\n * Docusaurus bundle, or from an env var injected at build time). It is\n * not pulled from `saas-frontend-lib`'s `useApplication()` because that\n * would force this package to import the inversify-bound `appConfig`\n * provider — exactly the dependency we are avoiding.\n */\nexport const DocsAuthProvider: FC<{\n children: ReactNode;\n apiBaseUrl: string;\n /**\n * Optional materialized provider block for the active docs service.\n * When omitted, the docs runtime exposes an empty provider registry.\n */\n frontendProviders?: FrontendProvidersBlock;\n /**\n * Runtime frontend service identity used for the `X-Frontend-Service-Name`\n * header on exchange/handoff auth calls.\n */\n frontendServiceName?: string | null;\n /**\n * Optional override for tests. Production code constructs a\n * `DocsAuthClient` from `apiBaseUrl` + the in-memory bearer.\n */\n client?: DocsAuthClient;\n}> = ({\n children,\n apiBaseUrl,\n frontendProviders,\n frontendServiceName = null,\n client: clientOverride,\n}) => {\n const [session, setSession] = useState<DocsAuthSession>({ status: 'anonymous' });\n\n /**\n * `getAuthBearer` reads from a closure over `session` so the bearer\n * always reflects the *current* state without re-creating the client\n * on every state change. The `useMemo` below depends only on\n * `apiBaseUrl` so the client identity is stable across re-renders,\n * which keeps `useEffect` dependency arrays in swizzles honest.\n */\n const sessionRef = useLatestRef(session);\n\n const client = useMemo<DocsAuthClient>(() => {\n if (clientOverride) return clientOverride;\n return new DocsAuthClient({\n apiBaseUrl,\n frontendServiceName,\n getAuthBearer: () =>\n sessionRef.current.status === 'authenticated'\n ? sessionRef.current.accessToken\n : null,\n });\n }, [apiBaseUrl, frontendServiceName, clientOverride, sessionRef]);\n const frontendProviderRegistry = useMemo(\n () => createFrontendTechdocProviderRegistry(frontendProviders),\n [frontendProviders],\n );\n\n /**\n * Auto-clear when the access token expires.\n *\n * Sets a single timer based on `claims.exp`; on tick, transitions the\n * session back to `anonymous`. No polling, no refresh — the next\n * gated action will trigger a re-handshake via `requestCrossFrontendHandoff`.\n *\n * The timer is recreated whenever the session transitions to\n * `authenticated`, and cleared on unmount or on transition AWAY from\n * `authenticated` to avoid stale timers firing into a fresh session.\n */\n useEffect(() => {\n if (session.status !== 'authenticated') return;\n const msUntilExpiry = session.claims.exp * 1000 - Date.now();\n if (msUntilExpiry <= 0) {\n setSession({ status: 'anonymous' });\n return;\n }\n const handle = setTimeout(() => {\n setSession({ status: 'anonymous' });\n }, msUntilExpiry);\n return () => clearTimeout(handle);\n }, [session]);\n\n const beginExchange = useCallback(\n async (code: string): Promise<DocsBeginExchangeResult> => {\n setSession({ status: 'exchanging' });\n try {\n const response = await client.exchangeAuthCode(code);\n // `returnPath` lives at the TOP LEVEL of `TokenExchangeResponseSchema`\n // — NOT under `metadata`. Reading `response.metadata?.returnPath`\n // (the previous shape this code targeted) is silently `undefined`\n // because the schema has no `metadata` envelope. The previous\n // implementation made every docs handoff fall through to the URL\n // `?return=` value, defeating Step 5's \"response value is the\n // source of truth\" contract. See H-3 in the Step 5 second\n // deep-review log on `cross-app-jwt-propagation.md`.\n const returnPath = response.returnPath ?? null;\n const claims = decodeJwtClaims(response.accessToken);\n if (!claims) {\n /**\n * The exchange succeeded but the returned token isn't decodable.\n * Treat as anonymous rather than half-authenticated — the\n * swizzles never have to handle a `claims === null &&\n * status === 'authenticated'` corner case. We still surface\n * `returnPath` so the exchange page can navigate the user\n * somewhere sensible (e.g. `/`) instead of stranding them on\n * `/auth/exchange`.\n */\n setSession({ status: 'anonymous' });\n return { claims: null, returnPath };\n }\n setSession({ status: 'authenticated', accessToken: response.accessToken, claims });\n return { claims, returnPath };\n } catch {\n setSession({ status: 'anonymous' });\n return { claims: null, returnPath: null };\n }\n },\n [client],\n );\n\n const clear = useCallback(() => {\n setSession({ status: 'anonymous' });\n }, []);\n\n const value = useMemo<DocsAuthContextValue>(\n () => ({ session, client, frontendProviderRegistry, beginExchange, clear }),\n [session, client, frontendProviderRegistry, beginExchange, clear],\n );\n\n return <DocsAuthContext.Provider value={value}>{children}</DocsAuthContext.Provider>;\n};\n\n/**\n * Tiny ref-of-latest-value helper. Avoids pulling in a utility lib for\n * one ~6-line function. Used here so the `DocsAuthClient`'s\n * `getAuthBearer` callback always sees the freshest session without\n * re-instantiating the client.\n *\n * Implementation discipline (L-NEW-1 fix from the Step 6 third\n * deep-review log): the previous implementation mutated `ref.current`\n * DURING render (the `ref.current = value;` line ran in the function\n * body), which violates React's \"no side effects during render\"\n * invariant and produces inconsistent reads under concurrent\n * rendering — a render that gets discarded by React's scheduler can\n * still leave a stale `ref.current` behind for the next render.\n *\n * The fix is the textbook React 18 pattern: hold the value in a real\n * `useRef`, then sync it inside `useEffect` after commit.\n *\n * Trade-off acknowledged: between render and effect-flush,\n * `ref.current` lags by one render. That is SAFE for this consumer\n * because `getAuthBearer()` is only invoked ASYNCHRONOUSLY (inside a\n * `fetch()` call originated by `requestCrossFrontendHandoff()` /\n * `exchangeAuthCode()`) — by the time the bearer is read, every\n * `useEffect` from the triggering render has already flushed and\n * `ref.current` reflects the latest committed session.\n *\n * Concretely: if the user clicks an org-API navbar entry that promotes\n * the session from `anonymous` → `exchanging` → `authenticated`, the\n * next fetch the client issues sees `authenticated` (ref synced after\n * commit) — never the stale `exchanging` value, even though the\n * `useMemo` factory may have captured the closure at the earlier\n * render.\n */\nfunction useLatestRef<T>(value: T): { current: T } {\n const ref = useRef<T>(value);\n useEffect(() => {\n ref.current = value;\n });\n return ref;\n}\n"]}
1
+ {"version":3,"file":"DocsAuthContext.js","sourceRoot":"","sources":["../../../../src/runtime/DocsAuthContext.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n createContext,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type Context,\n type FC,\n type ReactNode,\n} from 'react';\nimport type { FrontendProvidersBlock } from '@wildo-ai/saas-models/public-runtime';\nimport { decodeJwtClaims } from './decode-jwt-claims';\nimport { DocsAuthClient } from './docs-auth-client';\nimport type { DocsAuthSession, DocsJwtClaims } from './docs-auth-session.schemas';\nimport { useDocsProviderSdks } from './use-docs-provider-sdks';\nimport {\n createFrontendTechdocProviderRegistry,\n type FrontendTechdocProviderRegistry,\n type GeneratedTechdocProviderModules,\n} from './frontend-provider-registry.techdoc';\n\n/**\n * Result of a `beginExchange()` call surfaced to `<AuthExchangePage>`.\n *\n * `claims` — decoded `DocsJwtClaims` (or `null` if the access token\n * came back undecodable — treated as anonymous).\n * `returnPath` — the issuer-supplied `returnPath` from the token exchange\n * response (cross-app-jwt-propagation.md Step 5). It is\n * a TOP-LEVEL field on `TokenExchangeResponseSchema` —\n * NOT nested under `metadata`. The earlier draft of this\n * JSDoc said \"metadata.returnPath\" and the implementation\n * read `response.metadata?.returnPath` (always undefined,\n * because no such key exists on the response). H-3 in the\n * Step 5 second deep-review log fixes both the docstring\n * and the read site.\n * `null` for OAuth2-callback codes (which never carry a\n * `returnPath` at all — discriminator invariant pinned by\n * `TokenExchangeResponseSchema` JSDoc); the exchange page\n * falls back to the URL `?return=` parameter in that case\n * (defense-in-depth).\n */\nexport interface DocsBeginExchangeResult {\n readonly claims: DocsJwtClaims | null;\n readonly returnPath: string | null;\n}\n\n/**\n * Public surface of `useDocsAuthSession()`.\n *\n * `session` — discriminated union (anonymous / exchanging / authenticated).\n * `client` — the singleton `DocsAuthClient` for authenticated docs\n * runtime code that needs to request a handoff to another\n * frontend. Anonymous docs gates deep-link to the SaaS app\n * because handoff issuance requires a bearer.\n * `frontendProviderRegistry`\n * — hydrated registry of the frontend-safe provider entries\n * materialized for the active docs service. Browser-only\n * docs widgets (search, analytics, future SDK protocols)\n * read from this instead of importing generated artifacts.\n * `beginExchange` — called by `<AuthExchangePage>` when a `?code=` arrives.\n * Returns the decoded claims AND the issuer-supplied\n * top-level `returnPath` from the exchange response\n * (the SOURCE OF TRUTH for post-exchange navigation;\n * the URL `?return=` is a defense-in-depth fallback\n * only). NOT `response.metadata.returnPath` — the\n * response has no `metadata` envelope (H-3 fix).\n * `clear` — called when the user explicitly closes the docs\n * session (e.g. a \"Sign out of docs\" link). NOT called\n * on tab close — ephemeral state evaporates on its own.\n */\nexport interface DocsAuthContextValue {\n readonly session: DocsAuthSession;\n readonly client: DocsAuthClient;\n readonly frontendProviderRegistry: FrontendTechdocProviderRegistry;\n beginExchange(code: string): Promise<DocsBeginExchangeResult>;\n clear(): void;\n}\n\n/**\n * @internal — consumers should call `useDocsAuthSession()` instead of\n * touching this directly. Exported so the matching hook can `useContext`\n * it from a sibling module (Fast Refresh boundary).\n */\nexport const DocsAuthContext: Context<DocsAuthContextValue | null> =\n createContext<DocsAuthContextValue | null>(null);\n\n/**\n * In-memory React context owning the docs-site authenticated session\n * (saas-technical-doc.md K-9b).\n *\n * Storage characteristics — locked by K-9b:\n *\n * - In-memory only. NO `localStorage`, NO `sessionStorage`, NO cookies.\n * Closing the tab destroys the session.\n * - NO refresh-token loop. `/auth/token/exchange` no longer returns a\n * refresh token in the JSON body; SaaS-app receivers get refresh via the\n * HttpOnly cookie channel, while docs intentionally keeps only the access\n * token in memory. When the access token's `exp` passes, the next access\n * becomes anonymous and the user re-handshakes from the SaaS app on demand.\n * - NO BroadcastChannel cross-tab coordination. Each docs tab owns its\n * own session — opening a new tab is anonymous until it gets its own\n * `?code=` redirect.\n *\n * These choices are deliberate: the docs site is a session RECEIVER\n * (never a session OWNER), and the SaaS app is the authoritative source\n * of authentication. Replicating the SaaS app's session-management stack\n * here would force the docs Docusaurus bundle to ship inversify, the\n * resources framework, and a refresh interceptor — all of which are\n * about to be hardened (auth-hardening.md Slice A) in the SaaS app\n * specifically because they are sensitive surfaces. Keeping the docs\n * site free of those mechanisms keeps its attack surface tiny.\n *\n * The `apiBaseUrl` prop is supplied by the docs site at mount time\n * (typically read from a small `appConfig.json` shipped alongside the\n * Docusaurus bundle, or from an env var injected at build time). It is\n * not pulled from `saas-frontend-lib`'s `useApplication()` because that\n * would force this package to import the inversify-bound `appConfig`\n * provider — exactly the dependency we are avoiding.\n */\nexport const DocsAuthProvider: FC<{\n children: ReactNode;\n apiBaseUrl: string;\n /**\n * Optional materialized provider block for the active docs service.\n * When omitted, the docs runtime exposes an empty provider registry.\n */\n frontendProviders?: FrontendProvidersBlock;\n /**\n * The CODE channel for those providers (#332): the\n * `generatedFrontendProviderModules` export of this docs service's own\n * `src/generated/frontend-providers.generated.ts`, written by\n * `wildo config sync`.\n *\n * `frontendProviders` above says WHICH providers this service turned on, in\n * this environment; this says what code the bundle actually contains for\n * them. Both are needed, because a JSON payload cannot carry an SDK loader\n * and a bundle cannot know which environment it is running in.\n *\n * Omitted is the ordinary case for a docs site declaring no package-shipped\n * provider: no such file is generated, so there is nothing to import.\n */\n frontendProviderModules?: GeneratedTechdocProviderModules;\n /**\n * Runtime frontend service identity used for the `X-Frontend-Service-Name`\n * header on exchange/handoff auth calls.\n */\n frontendServiceName?: string | null;\n /**\n * Optional override for tests. Production code constructs a\n * `DocsAuthClient` from `apiBaseUrl` + the in-memory bearer.\n */\n client?: DocsAuthClient;\n}> = ({\n children,\n apiBaseUrl,\n frontendProviders,\n frontendProviderModules,\n frontendServiceName = null,\n client: clientOverride,\n}) => {\n const [session, setSession] = useState<DocsAuthSession>({ status: 'anonymous' });\n\n /**\n * `getAuthBearer` reads from a closure over `session` so the bearer\n * always reflects the *current* state without re-creating the client\n * on every state change. The `useMemo` below depends only on\n * `apiBaseUrl` so the client identity is stable across re-renders,\n * which keeps `useEffect` dependency arrays in swizzles honest.\n */\n const sessionRef = useLatestRef(session);\n\n const client = useMemo<DocsAuthClient>(() => {\n if (clientOverride) return clientOverride;\n return new DocsAuthClient({\n apiBaseUrl,\n frontendServiceName,\n getAuthBearer: () =>\n sessionRef.current.status === 'authenticated'\n ? sessionRef.current.accessToken\n : null,\n });\n }, [apiBaseUrl, frontendServiceName, clientOverride, sessionRef]);\n const frontendProviderRegistry = useMemo(\n () =>\n createFrontendTechdocProviderRegistry({\n entries: frontendProviders,\n modules: frontendProviderModules,\n onDiagnostic: (diagnostic) => {\n // The docs runtime has no logger service, and a provider that is\n // declared but cannot fully run is a developer-facing fact that must\n // not be silent. Never a throw: a misconfigured provider must not take\n // the documentation site down.\n // eslint-disable-next-line no-console\n console.warn(`[wildo-provider] ${diagnostic.kind}: ${diagnostic.message}`);\n },\n }),\n [frontendProviders, frontendProviderModules],\n );\n\n // Load and start the SDK of every live provider that ships one. Effect-only:\n // Docusaurus server-renders every page at build time, and starting a vendor\n // client there would run it inside the build.\n useDocsProviderSdks(frontendProviderRegistry);\n\n /**\n * Auto-clear when the access token expires.\n *\n * Sets a single timer based on `claims.exp`; on tick, transitions the\n * session back to `anonymous`. No polling, no refresh — the next\n * gated action will trigger a re-handshake via `requestCrossFrontendHandoff`.\n *\n * The timer is recreated whenever the session transitions to\n * `authenticated`, and cleared on unmount or on transition AWAY from\n * `authenticated` to avoid stale timers firing into a fresh session.\n */\n useEffect(() => {\n if (session.status !== 'authenticated') return;\n const msUntilExpiry = session.claims.exp * 1000 - Date.now();\n if (msUntilExpiry <= 0) {\n setSession({ status: 'anonymous' });\n return;\n }\n const handle = setTimeout(() => {\n setSession({ status: 'anonymous' });\n }, msUntilExpiry);\n return () => clearTimeout(handle);\n }, [session]);\n\n const beginExchange = useCallback(\n async (code: string): Promise<DocsBeginExchangeResult> => {\n setSession({ status: 'exchanging' });\n try {\n const response = await client.exchangeAuthCode(code);\n // `returnPath` lives at the TOP LEVEL of `TokenExchangeResponseSchema`\n // — NOT under `metadata`. Reading `response.metadata?.returnPath`\n // (the previous shape this code targeted) is silently `undefined`\n // because the schema has no `metadata` envelope. The previous\n // implementation made every docs handoff fall through to the URL\n // `?return=` value, defeating Step 5's \"response value is the\n // source of truth\" contract. See H-3 in the Step 5 second\n // deep-review log on `cross-app-jwt-propagation.md`.\n const returnPath = response.returnPath ?? null;\n const claims = decodeJwtClaims(response.accessToken);\n if (!claims) {\n /**\n * The exchange succeeded but the returned token isn't decodable.\n * Treat as anonymous rather than half-authenticated — the\n * swizzles never have to handle a `claims === null &&\n * status === 'authenticated'` corner case. We still surface\n * `returnPath` so the exchange page can navigate the user\n * somewhere sensible (e.g. `/`) instead of stranding them on\n * `/auth/exchange`.\n */\n setSession({ status: 'anonymous' });\n return { claims: null, returnPath };\n }\n setSession({ status: 'authenticated', accessToken: response.accessToken, claims });\n return { claims, returnPath };\n } catch {\n setSession({ status: 'anonymous' });\n return { claims: null, returnPath: null };\n }\n },\n [client],\n );\n\n const clear = useCallback(() => {\n setSession({ status: 'anonymous' });\n }, []);\n\n const value = useMemo<DocsAuthContextValue>(\n () => ({ session, client, frontendProviderRegistry, beginExchange, clear }),\n [session, client, frontendProviderRegistry, beginExchange, clear],\n );\n\n return <DocsAuthContext.Provider value={value}>{children}</DocsAuthContext.Provider>;\n};\n\n/**\n * Tiny ref-of-latest-value helper. Avoids pulling in a utility lib for\n * one ~6-line function. Used here so the `DocsAuthClient`'s\n * `getAuthBearer` callback always sees the freshest session without\n * re-instantiating the client.\n *\n * Implementation discipline (L-NEW-1 fix from the Step 6 third\n * deep-review log): the previous implementation mutated `ref.current`\n * DURING render (the `ref.current = value;` line ran in the function\n * body), which violates React's \"no side effects during render\"\n * invariant and produces inconsistent reads under concurrent\n * rendering — a render that gets discarded by React's scheduler can\n * still leave a stale `ref.current` behind for the next render.\n *\n * The fix is the textbook React 18 pattern: hold the value in a real\n * `useRef`, then sync it inside `useEffect` after commit.\n *\n * Trade-off acknowledged: between render and effect-flush,\n * `ref.current` lags by one render. That is SAFE for this consumer\n * because `getAuthBearer()` is only invoked ASYNCHRONOUSLY (inside a\n * `fetch()` call originated by `requestCrossFrontendHandoff()` /\n * `exchangeAuthCode()`) — by the time the bearer is read, every\n * `useEffect` from the triggering render has already flushed and\n * `ref.current` reflects the latest committed session.\n *\n * Concretely: if the user clicks an org-API navbar entry that promotes\n * the session from `anonymous` → `exchanging` → `authenticated`, the\n * next fetch the client issues sees `authenticated` (ref synced after\n * commit) — never the stale `exchanging` value, even though the\n * `useMemo` factory may have captured the closure at the earlier\n * render.\n */\nfunction useLatestRef<T>(value: T): { current: T } {\n const ref = useRef<T>(value);\n useEffect(() => {\n ref.current = value;\n });\n return ref;\n}\n"]}
@@ -11,10 +11,13 @@ import { type DocsJwtClaims } from './docs-auth-session.schemas';
11
11
  *
12
12
  * This decoder DOES NOT verify the JWT signature. It cannot — the
13
13
  * verification key lives on the backend, not in the browser bundle.
14
- * The decoded claims are treated as DISPLAY HINTS ONLY: the docs
15
- * navbar uses them to decide whether to render the "Organization API"
16
- * link, and the DocItem swizzle uses them to decide whether to gate
17
- * `/api/organization/*` pages.
14
+ * The decoded claims are treated as DISPLAY HINTS ONLY, and today they
15
+ * drive no rendering decision at all: the Navbar and DocItem swizzles
16
+ * this comment used to name were never built, and there is no
17
+ * `/api/organization/*` route family to gate (see `DocsRole` in
18
+ * `docs-auth-session.schemas.ts` for the full measurement). What the
19
+ * decoded claims currently do is populate the session object the
20
+ * `Root` swizzle provides.
18
21
  *
19
22
  * The REAL gating happens server-side: the OpenAPI YAMLs for the
20
23
  * organization API are served by the backend behind the same
@@ -1 +1 @@
1
- {"version":3,"file":"decode-jwt-claims.d.ts","sourceRoot":"","sources":["../../../../src/runtime/decode-jwt-claims.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,6BAA6B,CAAC;AAErC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAoCnE"}
1
+ {"version":3,"file":"decode-jwt-claims.d.ts","sourceRoot":"","sources":["../../../../src/runtime/decode-jwt-claims.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,6BAA6B,CAAC;AAErC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAoCnE"}
@@ -11,10 +11,13 @@ import { DocsJwtClaimsSchema, DocsRole, } from './docs-auth-session.schemas.js';
11
11
  *
12
12
  * This decoder DOES NOT verify the JWT signature. It cannot — the
13
13
  * verification key lives on the backend, not in the browser bundle.
14
- * The decoded claims are treated as DISPLAY HINTS ONLY: the docs
15
- * navbar uses them to decide whether to render the "Organization API"
16
- * link, and the DocItem swizzle uses them to decide whether to gate
17
- * `/api/organization/*` pages.
14
+ * The decoded claims are treated as DISPLAY HINTS ONLY, and today they
15
+ * drive no rendering decision at all: the Navbar and DocItem swizzles
16
+ * this comment used to name were never built, and there is no
17
+ * `/api/organization/*` route family to gate (see `DocsRole` in
18
+ * `docs-auth-session.schemas.ts` for the full measurement). What the
19
+ * decoded claims currently do is populate the session object the
20
+ * `Root` swizzle provides.
18
21
  *
19
22
  * The REAL gating happens server-side: the OpenAPI YAMLs for the
20
23
  * organization API are served by the backend behind the same
@@ -1 +1 @@
1
- {"version":3,"file":"decode-jwt-claims.js","sourceRoot":"","sources":["../../../../src/runtime/decode-jwt-claims.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,QAAQ,GAET,MAAM,6BAA6B,CAAC;AAErC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvC,MAAM,cAAc,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,CAAC,cAAc;QAAE,OAAO,IAAI,CAAC;IAEjC,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,cAAc,CAAC,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAE/D;;;;;;OAMG;IACH,MAAM,GAAG,GAAG,MAAiC,CAAC;IAC9C,MAAM,OAAO,GAAG,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7D,MAAM,IAAI,GAAG,OAAO,KAAK,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;IAElF,MAAM,SAAS,GAAG;QAChB,MAAM,EAAE,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG;QAC7D,KAAK,EAAE,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;QAC5D,IAAI;QACJ,GAAG,EAAE,OAAO,GAAG,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;KACjD,CAAC;IAEF,MAAM,MAAM,GAAG,mBAAmB,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACxD,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,eAAe,CAAC,KAAa;IACpC,MAAM,MAAM,GAAG,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAChE,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC5D,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC","sourcesContent":["import {\n DocsJwtClaimsSchema,\n DocsRole,\n type DocsJwtClaims,\n} from './docs-auth-session.schemas';\n\n/**\n * Hand-rolled JWT-claims decoder for the docs-site auth runtime.\n *\n * Rationale (saas-technical-doc.md K-9b): the docs Docusaurus bundle is\n * intentionally lean. Pulling in `jwt-decode` (or any general-purpose\n * JWT library) for the SOLE purpose of base64-decoding the middle segment\n * is a 30 KB+ bundle cost we refuse to pay for ~20 lines of code.\n *\n * SECURITY MODEL — important:\n *\n * This decoder DOES NOT verify the JWT signature. It cannot — the\n * verification key lives on the backend, not in the browser bundle.\n * The decoded claims are treated as DISPLAY HINTS ONLY: the docs\n * navbar uses them to decide whether to render the \"Organization API\"\n * link, and the DocItem swizzle uses them to decide whether to gate\n * `/api/organization/*` pages.\n *\n * The REAL gating happens server-side: the OpenAPI YAMLs for the\n * organization API are served by the backend behind the same\n * authorization decorators as the underlying resources. A user who\n * forges a JWT with `role: 'org_admin'` will see the docs navbar link\n * appear, but every actual API call from those docs to the backend\n * will still 401/403. The docs-site gating exists for UX, not security.\n *\n * This is the SAME contract the SaaS app's frontend has: it decodes\n * the access-token claims for UI gating without verifying signatures,\n * and the backend is the authoritative authorizer.\n *\n * Returns `null` for any malformed input — never throws. The session\n * context (`DocsAuthContext`) treats `null` as \"fall back to anonymous\"\n * rather than surfacing a UI error, because by the time we are decoding\n * the token we have already accepted it from the `/auth/token/exchange`\n * response and the only remaining failure modes are clock skew, library\n * mis-issuance, or actual tampering — none of which yield a useful error\n * message at the docs-site level.\n */\nexport function decodeJwtClaims(token: string): DocsJwtClaims | null {\n const segments = token.split('.');\n if (segments.length !== 3) return null;\n\n const payloadSegment = segments[1];\n if (!payloadSegment) return null;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(base64UrlDecode(payloadSegment));\n } catch {\n return null;\n }\n\n if (typeof parsed !== 'object' || parsed === null) return null;\n\n /**\n * Normalize the raw role string → `DocsRole`.\n *\n * The access token's `role` claim can be any of the SaaS app's roles\n * (`org_admin`, `org_member`, `app_user`, …); the docs site only cares\n * about the org-admin / not-org-admin distinction (K-11).\n */\n const raw = parsed as Record<string, unknown>;\n const rawRole = typeof raw.role === 'string' ? raw.role : '';\n const role = rawRole === DocsRole.ORG_ADMIN ? DocsRole.ORG_ADMIN : DocsRole.OTHER;\n\n const candidate = {\n userId: typeof raw.userId === 'string' ? raw.userId : raw.sub,\n email: typeof raw.email === 'string' ? raw.email : undefined,\n role,\n exp: typeof raw.exp === 'number' ? raw.exp : NaN,\n };\n\n const result = DocsJwtClaimsSchema.safeParse(candidate);\n return result.success ? result.data : null;\n}\n\n/**\n * Base64url → string. Pads the input to a multiple of 4 and translates\n * `-`/`_` back to `+`/`/` before delegating to the platform's `atob`.\n *\n * `atob` is available in every browser and in Node ≥ 16 — both of which\n * the docs site supports (Docusaurus build runs in Node, runtime in the\n * browser).\n */\nfunction base64UrlDecode(input: string): string {\n const padded = input + '='.repeat((4 - (input.length % 4)) % 4);\n const base64 = padded.replace(/-/g, '+').replace(/_/g, '/');\n return atob(base64);\n}\n"]}
1
+ {"version":3,"file":"decode-jwt-claims.js","sourceRoot":"","sources":["../../../../src/runtime/decode-jwt-claims.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,QAAQ,GAET,MAAM,6BAA6B,CAAC;AAErC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvC,MAAM,cAAc,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,CAAC,cAAc;QAAE,OAAO,IAAI,CAAC;IAEjC,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,cAAc,CAAC,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAE/D;;;;;;OAMG;IACH,MAAM,GAAG,GAAG,MAAiC,CAAC;IAC9C,MAAM,OAAO,GAAG,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7D,MAAM,IAAI,GAAG,OAAO,KAAK,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;IAElF,MAAM,SAAS,GAAG;QAChB,MAAM,EAAE,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG;QAC7D,KAAK,EAAE,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;QAC5D,IAAI;QACJ,GAAG,EAAE,OAAO,GAAG,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;KACjD,CAAC;IAEF,MAAM,MAAM,GAAG,mBAAmB,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACxD,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,eAAe,CAAC,KAAa;IACpC,MAAM,MAAM,GAAG,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAChE,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC5D,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC","sourcesContent":["import {\n DocsJwtClaimsSchema,\n DocsRole,\n type DocsJwtClaims,\n} from './docs-auth-session.schemas';\n\n/**\n * Hand-rolled JWT-claims decoder for the docs-site auth runtime.\n *\n * Rationale (saas-technical-doc.md K-9b): the docs Docusaurus bundle is\n * intentionally lean. Pulling in `jwt-decode` (or any general-purpose\n * JWT library) for the SOLE purpose of base64-decoding the middle segment\n * is a 30 KB+ bundle cost we refuse to pay for ~20 lines of code.\n *\n * SECURITY MODEL — important:\n *\n * This decoder DOES NOT verify the JWT signature. It cannot — the\n * verification key lives on the backend, not in the browser bundle.\n * The decoded claims are treated as DISPLAY HINTS ONLY, and today they\n * drive no rendering decision at all: the Navbar and DocItem swizzles\n * this comment used to name were never built, and there is no\n * `/api/organization/*` route family to gate (see `DocsRole` in\n * `docs-auth-session.schemas.ts` for the full measurement). What the\n * decoded claims currently do is populate the session object the\n * `Root` swizzle provides.\n *\n * The REAL gating happens server-side: the OpenAPI YAMLs for the\n * organization API are served by the backend behind the same\n * authorization decorators as the underlying resources. A user who\n * forges a JWT with `role: 'org_admin'` will see the docs navbar link\n * appear, but every actual API call from those docs to the backend\n * will still 401/403. The docs-site gating exists for UX, not security.\n *\n * This is the SAME contract the SaaS app's frontend has: it decodes\n * the access-token claims for UI gating without verifying signatures,\n * and the backend is the authoritative authorizer.\n *\n * Returns `null` for any malformed input — never throws. The session\n * context (`DocsAuthContext`) treats `null` as \"fall back to anonymous\"\n * rather than surfacing a UI error, because by the time we are decoding\n * the token we have already accepted it from the `/auth/token/exchange`\n * response and the only remaining failure modes are clock skew, library\n * mis-issuance, or actual tampering — none of which yield a useful error\n * message at the docs-site level.\n */\nexport function decodeJwtClaims(token: string): DocsJwtClaims | null {\n const segments = token.split('.');\n if (segments.length !== 3) return null;\n\n const payloadSegment = segments[1];\n if (!payloadSegment) return null;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(base64UrlDecode(payloadSegment));\n } catch {\n return null;\n }\n\n if (typeof parsed !== 'object' || parsed === null) return null;\n\n /**\n * Normalize the raw role string → `DocsRole`.\n *\n * The access token's `role` claim can be any of the SaaS app's roles\n * (`org_admin`, `org_member`, `app_user`, …); the docs site only cares\n * about the org-admin / not-org-admin distinction (K-11).\n */\n const raw = parsed as Record<string, unknown>;\n const rawRole = typeof raw.role === 'string' ? raw.role : '';\n const role = rawRole === DocsRole.ORG_ADMIN ? DocsRole.ORG_ADMIN : DocsRole.OTHER;\n\n const candidate = {\n userId: typeof raw.userId === 'string' ? raw.userId : raw.sub,\n email: typeof raw.email === 'string' ? raw.email : undefined,\n role,\n exp: typeof raw.exp === 'number' ? raw.exp : NaN,\n };\n\n const result = DocsJwtClaimsSchema.safeParse(candidate);\n return result.success ? result.data : null;\n}\n\n/**\n * Base64url → string. Pads the input to a multiple of 4 and translates\n * `-`/`_` back to `+`/`/` before delegating to the platform's `atob`.\n *\n * `atob` is available in every browser and in Node ≥ 16 — both of which\n * the docs site supports (Docusaurus build runs in Node, runtime in the\n * browser).\n */\nfunction base64UrlDecode(input: string): string {\n const padded = input + '='.repeat((4 - (input.length % 4)) % 4);\n const base64 = padded.replace(/-/g, '+').replace(/_/g, '/');\n return atob(base64);\n}\n"]}
@@ -4,15 +4,26 @@ import { z } from 'zod';
4
4
  *
5
5
  * Mirrors the role axis the SaaS app uses on access tokens. The docs site
6
6
  * itself only cares about ONE distinction: "is this user an org admin or
7
- * not?" — used by the Navbar swizzle to hide the "Organization API" link
8
- * and by the DocItem swizzle to gate `/api/organization/*` pages
9
- * (saas-technical-doc.md K-11).
7
+ * not?"
10
8
  *
11
9
  * `ORG_ADMIN` value matches the string carried by the access token's
12
10
  * `role` claim issued by `auth-token-issuer.backend.service.ts`. The
13
11
  * generic `OTHER` bucket covers every other role (regular org member,
14
- * viewer, application-level admin, etc.) — none of them grant Org-API
15
- * visibility on the docs site.
12
+ * viewer, application-level admin, etc.).
13
+ *
14
+ * ⚠️ NOTHING BRANCHES ON THIS TODAY. This comment used to say the value was
15
+ * "used by the Navbar swizzle to hide the 'Organization API' link and by the
16
+ * DocItem swizzle to gate `/api/organization/*` pages". Neither exists: the
17
+ * only swizzles in the tree are `Root` and `SearchBar`, `OpenApiSection` has
18
+ * exactly two members (`API_REFERENCE`, `APPLICATION_ADMINISTRATION_API_REFERENCE`)
19
+ * and neither is organizational, and `/api/organization` appears nowhere but in
20
+ * comments like this one and a single test fixture string. `openapi-generator.test.ts`
21
+ * even pins that the emitted title does NOT contain "Organization API".
22
+ *
23
+ * The enum is still decoded and carried on the session (`decode-jwt-claims.ts`
24
+ * normalizes the raw claim into it), so the axis is available the moment a
25
+ * gated surface is built. Until then it is a claim projection, not a control —
26
+ * do not cite it as evidence that the docs site gates anything.
16
27
  */
17
28
  export declare enum DocsRole {
18
29
  ORG_ADMIN = "org_admin",
@@ -1 +1 @@
1
- {"version":3,"file":"docs-auth-session.schemas.d.ts","sourceRoot":"","sources":["../../../../src/runtime/docs-auth-session.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;GAcG;AACH,oBAAY,QAAQ;IAClB,SAAS,cAAc;IACvB,KAAK,UAAU;CAChB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,mBAAmB;;;;;kBAK9B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,GACvB;IAAE,MAAM,EAAE,YAAY,CAAA;CAAE,GACxB;IAAE,MAAM,EAAE,eAAe,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,CAAC"}
1
+ {"version":3,"file":"docs-auth-session.schemas.d.ts","sourceRoot":"","sources":["../../../../src/runtime/docs-auth-session.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,oBAAY,QAAQ;IAClB,SAAS,cAAc;IACvB,KAAK,UAAU;CAChB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,mBAAmB;;;;;kBAK9B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,GACvB;IAAE,MAAM,EAAE,YAAY,CAAA;CAAE,GACxB;IAAE,MAAM,EAAE,eAAe,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,CAAC"}
@@ -4,15 +4,26 @@ import { z } from 'zod';
4
4
  *
5
5
  * Mirrors the role axis the SaaS app uses on access tokens. The docs site
6
6
  * itself only cares about ONE distinction: "is this user an org admin or
7
- * not?" — used by the Navbar swizzle to hide the "Organization API" link
8
- * and by the DocItem swizzle to gate `/api/organization/*` pages
9
- * (saas-technical-doc.md K-11).
7
+ * not?"
10
8
  *
11
9
  * `ORG_ADMIN` value matches the string carried by the access token's
12
10
  * `role` claim issued by `auth-token-issuer.backend.service.ts`. The
13
11
  * generic `OTHER` bucket covers every other role (regular org member,
14
- * viewer, application-level admin, etc.) — none of them grant Org-API
15
- * visibility on the docs site.
12
+ * viewer, application-level admin, etc.).
13
+ *
14
+ * ⚠️ NOTHING BRANCHES ON THIS TODAY. This comment used to say the value was
15
+ * "used by the Navbar swizzle to hide the 'Organization API' link and by the
16
+ * DocItem swizzle to gate `/api/organization/*` pages". Neither exists: the
17
+ * only swizzles in the tree are `Root` and `SearchBar`, `OpenApiSection` has
18
+ * exactly two members (`API_REFERENCE`, `APPLICATION_ADMINISTRATION_API_REFERENCE`)
19
+ * and neither is organizational, and `/api/organization` appears nowhere but in
20
+ * comments like this one and a single test fixture string. `openapi-generator.test.ts`
21
+ * even pins that the emitted title does NOT contain "Organization API".
22
+ *
23
+ * The enum is still decoded and carried on the session (`decode-jwt-claims.ts`
24
+ * normalizes the raw claim into it), so the axis is available the moment a
25
+ * gated surface is built. Until then it is a claim projection, not a control —
26
+ * do not cite it as evidence that the docs site gates anything.
16
27
  */
17
28
  export var DocsRole;
18
29
  (function (DocsRole) {
@@ -1 +1 @@
1
- {"version":3,"file":"docs-auth-session.schemas.js","sourceRoot":"","sources":["../../../../src/runtime/docs-auth-session.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAN,IAAY,QAGX;AAHD,WAAY,QAAQ;IAClB,mCAAuB,CAAA;IACvB,2BAAe,CAAA;AACjB,CAAC,EAHW,QAAQ,KAAR,QAAQ,QAGnB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,YAAY,CAAC;IAChD,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACzB,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;IAC3B,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;IACtB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAC","sourcesContent":["import { z } from 'zod';\n\n/**\n * Roles relevant to the docs-site gating decisions.\n *\n * Mirrors the role axis the SaaS app uses on access tokens. The docs site\n * itself only cares about ONE distinction: \"is this user an org admin or\n * not?\" — used by the Navbar swizzle to hide the \"Organization API\" link\n * and by the DocItem swizzle to gate `/api/organization/*` pages\n * (saas-technical-doc.md K-11).\n *\n * `ORG_ADMIN` value matches the string carried by the access token's\n * `role` claim issued by `auth-token-issuer.backend.service.ts`. The\n * generic `OTHER` bucket covers every other role (regular org member,\n * viewer, application-level admin, etc.) — none of them grant Org-API\n * visibility on the docs site.\n */\nexport enum DocsRole {\n ORG_ADMIN = 'org_admin',\n OTHER = 'other',\n}\n\n/**\n * Subset of access-token claims the docs site cares about.\n *\n * The full access-token payload issued by the SaaS backend carries many\n * more fields (organization id, application id, scopes, …) — we\n * deliberately project only the minimum needed by the docs-site swizzles\n * so that:\n * 1. A future change to the access-token shape that adds fields\n * doesn't ripple into the docs site.\n * 2. The docs site never accidentally renders or transmits sensitive\n * claims it has no business consuming.\n *\n * `userId` and `email` are present for display purposes (\"Signed in as\n * <email>\" in the navbar — done by the Navbar swizzle, not this package).\n *\n * `role` is the gating axis (see {@link DocsRole}).\n *\n * `exp` (UNIX seconds) lets the context clear the in-memory session as\n * soon as the access token expires — without ever calling the network.\n * No refresh loop (K-9b): when `exp` passes, the user is anonymous again\n * until they re-handshake from the SaaS app.\n */\nexport const DocsJwtClaimsSchema = z.strictObject({\n userId: z.string().min(1),\n email: z.email().optional(),\n role: z.enum(DocsRole),\n exp: z.number().int().positive(),\n});\nexport type DocsJwtClaims = z.infer<typeof DocsJwtClaimsSchema>;\n\n/**\n * Public shape exposed by `useDocsAuthSession()` (saas-technical-doc.md K-11).\n *\n * Three mutually-exclusive states:\n * - `status: 'anonymous'` — no handoff has been completed.\n * - `status: 'exchanging'` — `/auth/exchange?code=…` is in flight.\n * - `status: 'authenticated'` — `claims` and `accessToken` are present.\n *\n * Consumers (the three swizzles) discriminate on `status` and never reach\n * for `accessToken`/`claims` while in the `anonymous` or `exchanging`\n * states — the type narrows correctly thanks to the discriminated union.\n *\n * Does NOT model an `error` state directly: errors during the exchange\n * are surfaced via the `AuthExchangePage` component's local UI, after\n * which the session falls back to `anonymous`. Keeping the session shape\n * tight prevents the swizzles from having to render error-recovery UI\n * for events they did not cause.\n */\nexport type DocsAuthSession =\n | { status: 'anonymous' }\n | { status: 'exchanging' }\n | { status: 'authenticated'; accessToken: string; claims: DocsJwtClaims };\n"]}
1
+ {"version":3,"file":"docs-auth-session.schemas.js","sourceRoot":"","sources":["../../../../src/runtime/docs-auth-session.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,CAAN,IAAY,QAGX;AAHD,WAAY,QAAQ;IAClB,mCAAuB,CAAA;IACvB,2BAAe,CAAA;AACjB,CAAC,EAHW,QAAQ,KAAR,QAAQ,QAGnB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,YAAY,CAAC;IAChD,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACzB,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;IAC3B,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;IACtB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAC","sourcesContent":["import { z } from 'zod';\n\n/**\n * Roles relevant to the docs-site gating decisions.\n *\n * Mirrors the role axis the SaaS app uses on access tokens. The docs site\n * itself only cares about ONE distinction: \"is this user an org admin or\n * not?\"\n *\n * `ORG_ADMIN` value matches the string carried by the access token's\n * `role` claim issued by `auth-token-issuer.backend.service.ts`. The\n * generic `OTHER` bucket covers every other role (regular org member,\n * viewer, application-level admin, etc.).\n *\n * ⚠️ NOTHING BRANCHES ON THIS TODAY. This comment used to say the value was\n * \"used by the Navbar swizzle to hide the 'Organization API' link and by the\n * DocItem swizzle to gate `/api/organization/*` pages\". Neither exists: the\n * only swizzles in the tree are `Root` and `SearchBar`, `OpenApiSection` has\n * exactly two members (`API_REFERENCE`, `APPLICATION_ADMINISTRATION_API_REFERENCE`)\n * and neither is organizational, and `/api/organization` appears nowhere but in\n * comments like this one and a single test fixture string. `openapi-generator.test.ts`\n * even pins that the emitted title does NOT contain \"Organization API\".\n *\n * The enum is still decoded and carried on the session (`decode-jwt-claims.ts`\n * normalizes the raw claim into it), so the axis is available the moment a\n * gated surface is built. Until then it is a claim projection, not a control —\n * do not cite it as evidence that the docs site gates anything.\n */\nexport enum DocsRole {\n ORG_ADMIN = 'org_admin',\n OTHER = 'other',\n}\n\n/**\n * Subset of access-token claims the docs site cares about.\n *\n * The full access-token payload issued by the SaaS backend carries many\n * more fields (organization id, application id, scopes, …) — we\n * deliberately project only the minimum needed by the docs-site swizzles\n * so that:\n * 1. A future change to the access-token shape that adds fields\n * doesn't ripple into the docs site.\n * 2. The docs site never accidentally renders or transmits sensitive\n * claims it has no business consuming.\n *\n * `userId` and `email` are present for display purposes (\"Signed in as\n * <email>\" in the navbar — done by the Navbar swizzle, not this package).\n *\n * `role` is the gating axis (see {@link DocsRole}).\n *\n * `exp` (UNIX seconds) lets the context clear the in-memory session as\n * soon as the access token expires — without ever calling the network.\n * No refresh loop (K-9b): when `exp` passes, the user is anonymous again\n * until they re-handshake from the SaaS app.\n */\nexport const DocsJwtClaimsSchema = z.strictObject({\n userId: z.string().min(1),\n email: z.email().optional(),\n role: z.enum(DocsRole),\n exp: z.number().int().positive(),\n});\nexport type DocsJwtClaims = z.infer<typeof DocsJwtClaimsSchema>;\n\n/**\n * Public shape exposed by `useDocsAuthSession()` (saas-technical-doc.md K-11).\n *\n * Three mutually-exclusive states:\n * - `status: 'anonymous'` — no handoff has been completed.\n * - `status: 'exchanging'` — `/auth/exchange?code=…` is in flight.\n * - `status: 'authenticated'` — `claims` and `accessToken` are present.\n *\n * Consumers (the three swizzles) discriminate on `status` and never reach\n * for `accessToken`/`claims` while in the `anonymous` or `exchanging`\n * states — the type narrows correctly thanks to the discriminated union.\n *\n * Does NOT model an `error` state directly: errors during the exchange\n * are surfaced via the `AuthExchangePage` component's local UI, after\n * which the session falls back to `anonymous`. Keeping the session shape\n * tight prevents the swizzles from having to render error-recovery UI\n * for events they did not cause.\n */\nexport type DocsAuthSession =\n | { status: 'anonymous' }\n | { status: 'exchanging' }\n | { status: 'authenticated'; accessToken: string; claims: DocsJwtClaims };\n"]}
@@ -1,17 +1,39 @@
1
- import type { FrontendProviderEntry, FrontendProvidersBlock, ProviderCapability } from '@wildo-ai/saas-models/public-runtime';
2
- export type FrontendTechdocProviderRef = string & {
3
- readonly __brand: 'FrontendTechdocProviderRef';
4
- };
5
- export type FrontendTechdocProviderModule = FrontendProviderEntry;
6
- export interface FrontendTechdocProviderRegistry {
7
- readonly modules: ReadonlyMap<FrontendTechdocProviderRef, FrontendTechdocProviderModule>;
8
- getProviderByRef(ref: FrontendTechdocProviderRef): FrontendTechdocProviderModule | undefined;
9
- getProvidersByProviderCapability(providerCapability: ProviderCapability): ReadonlyArray<FrontendTechdocProviderModule>;
10
- findProviderByProviderCapability(providerCapability: ProviderCapability): FrontendTechdocProviderModule | undefined;
1
+ /**
2
+ * The technical doc's provider registry — now composed from BOTH channels.
3
+ *
4
+ * It used to build itself by casting each served `FrontendProviderEntry` to a
5
+ * module type that was an alias of that entry, which made the cast true and
6
+ * useless: the registry could never hold anything a JSON payload could not
7
+ * carry, so a provider's SDK loader had nowhere to arrive.
8
+ *
9
+ * - **DATA** — the materialized frontend-services block for THIS docs service.
10
+ * Authoritative for which providers are on, in this environment.
11
+ * - **CODE** — `generatedFrontendProviderModules` from the docs site's own
12
+ * `src/generated/frontend-providers.generated.ts`, written by
13
+ * `wildo config sync` and handed to `DocsAuthProvider` by the Root swizzle.
14
+ *
15
+ * The types are now the engine's own techdoc-facet types rather than local
16
+ * aliases, so a provider module authored against
17
+ * `@wildo-ai/external-connectors-public/techdoc` is the same type this registry
18
+ * holds. Re-exported under the same names so every consumer's import is
19
+ * unchanged.
20
+ */
21
+ import { type FrontendProviderHydrationDiagnostic, type FrontendTechdocProviderRegistry, type GeneratedTechdocProviderModules } from '@wildo-ai/external-connectors-public/techdoc';
22
+ import type { FrontendProvidersBlock } from '@wildo-ai/saas-models/public-runtime';
23
+ export type { FrontendTechdocProviderModule, FrontendTechdocProviderRef, FrontendTechdocProviderRegistry, GeneratedTechdocProviderModules, } from '@wildo-ai/external-connectors-public/techdoc';
24
+ export interface CreateFrontendTechdocProviderRegistryInput {
25
+ /** The DATA channel: the materialized block for this docs service. */
26
+ readonly entries?: FrontendProvidersBlock;
27
+ /**
28
+ * The CODE channel. Absent is the ordinary case for a docs site that declares
29
+ * no package-shipped provider — `wildo config sync` writes no generated file,
30
+ * so there is nothing to import and nothing to pass.
31
+ */
32
+ readonly modules?: GeneratedTechdocProviderModules;
33
+ readonly onDiagnostic?: (diagnostic: FrontendProviderHydrationDiagnostic) => void;
11
34
  }
12
35
  /**
13
- * Tech-doc runtime registry hydrated from the materialized frontend-provider
14
- * block for the active docs service.
36
+ * Tech-doc runtime registry, hydrated from both channels.
15
37
  */
16
- export declare function createFrontendTechdocProviderRegistry(frontendProviders?: FrontendProvidersBlock): FrontendTechdocProviderRegistry;
38
+ export declare function createFrontendTechdocProviderRegistry(input?: CreateFrontendTechdocProviderRegistryInput): FrontendTechdocProviderRegistry;
17
39
  //# sourceMappingURL=frontend-provider-registry.techdoc.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"frontend-provider-registry.techdoc.d.ts","sourceRoot":"","sources":["../../../../src/runtime/frontend-provider-registry.techdoc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,sBAAsB,EACtB,kBAAkB,EACnB,MAAM,sCAAsC,CAAC;AAE9C,MAAM,MAAM,0BAA0B,GAAG,MAAM,GAAG;IAChD,QAAQ,CAAC,OAAO,EAAE,4BAA4B,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG,qBAAqB,CAAC;AAElE,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,OAAO,EAAE,WAAW,CAC3B,0BAA0B,EAC1B,6BAA6B,CAC9B,CAAC;IAEF,gBAAgB,CACd,GAAG,EAAE,0BAA0B,GAC9B,6BAA6B,GAAG,SAAS,CAAC;IAE7C,gCAAgC,CAC9B,kBAAkB,EAAE,kBAAkB,GACrC,aAAa,CAAC,6BAA6B,CAAC,CAAC;IAEhD,gCAAgC,CAC9B,kBAAkB,EAAE,kBAAkB,GACrC,6BAA6B,GAAG,SAAS,CAAC;CAC9C;AAED;;;GAGG;AACH,wBAAgB,qCAAqC,CACnD,iBAAiB,CAAC,EAAE,sBAAsB,GACzC,+BAA+B,CAwBjC"}
1
+ {"version":3,"file":"frontend-provider-registry.techdoc.d.ts","sourceRoot":"","sources":["../../../../src/runtime/frontend-provider-registry.techdoc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAEL,KAAK,mCAAmC,EACxC,KAAK,+BAA+B,EACpC,KAAK,+BAA+B,EACrC,MAAM,8CAA8C,CAAC;AACtD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAEnF,YAAY,EACV,6BAA6B,EAC7B,0BAA0B,EAC1B,+BAA+B,EAC/B,+BAA+B,GAChC,MAAM,8CAA8C,CAAC;AAEtD,MAAM,WAAW,0CAA0C;IACzD,sEAAsE;IACtE,QAAQ,CAAC,OAAO,CAAC,EAAE,sBAAsB,CAAC;IAC1C;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,+BAA+B,CAAC;IACnD,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,mCAAmC,KAAK,IAAI,CAAC;CACnF;AAED;;GAEG;AACH,wBAAgB,qCAAqC,CACnD,KAAK,CAAC,EAAE,0CAA0C,GACjD,+BAA+B,CAMjC"}
@@ -1,23 +1,32 @@
1
1
  /**
2
- * Tech-doc runtime registry hydrated from the materialized frontend-provider
3
- * block for the active docs service.
2
+ * The technical doc's provider registry — now composed from BOTH channels.
3
+ *
4
+ * It used to build itself by casting each served `FrontendProviderEntry` to a
5
+ * module type that was an alias of that entry, which made the cast true and
6
+ * useless: the registry could never hold anything a JSON payload could not
7
+ * carry, so a provider's SDK loader had nowhere to arrive.
8
+ *
9
+ * - **DATA** — the materialized frontend-services block for THIS docs service.
10
+ * Authoritative for which providers are on, in this environment.
11
+ * - **CODE** — `generatedFrontendProviderModules` from the docs site's own
12
+ * `src/generated/frontend-providers.generated.ts`, written by
13
+ * `wildo config sync` and handed to `DocsAuthProvider` by the Root swizzle.
14
+ *
15
+ * The types are now the engine's own techdoc-facet types rather than local
16
+ * aliases, so a provider module authored against
17
+ * `@wildo-ai/external-connectors-public/techdoc` is the same type this registry
18
+ * holds. Re-exported under the same names so every consumer's import is
19
+ * unchanged.
4
20
  */
5
- export function createFrontendTechdocProviderRegistry(frontendProviders) {
6
- const modules = new Map(Object.entries(frontendProviders?.providers ?? {}).map(([ref, provider]) => [
7
- ref,
8
- provider,
9
- ]));
10
- return {
11
- modules,
12
- getProviderByRef(ref) {
13
- return modules.get(ref);
14
- },
15
- getProvidersByProviderCapability(providerCapability) {
16
- return [...modules.values()].filter((provider) => provider.providerCapabilities.includes(providerCapability));
17
- },
18
- findProviderByProviderCapability(providerCapability) {
19
- return [...modules.values()].find((provider) => provider.providerCapabilities.includes(providerCapability));
20
- },
21
- };
21
+ import { composeHydratedFrontendTechdocProviders, } from '@wildo-ai/external-connectors-public/techdoc';
22
+ /**
23
+ * Tech-doc runtime registry, hydrated from both channels.
24
+ */
25
+ export function createFrontendTechdocProviderRegistry(input) {
26
+ return composeHydratedFrontendTechdocProviders({
27
+ entries: input?.entries,
28
+ modules: input?.modules,
29
+ onDiagnostic: input?.onDiagnostic,
30
+ });
22
31
  }
23
32
  //# sourceMappingURL=frontend-provider-registry.techdoc.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"frontend-provider-registry.techdoc.js","sourceRoot":"","sources":["../../../../src/runtime/frontend-provider-registry.techdoc.ts"],"names":[],"mappings":"AA+BA;;;GAGG;AACH,MAAM,UAAU,qCAAqC,CACnD,iBAA0C;IAE1C,MAAM,OAAO,GAAG,IAAI,GAAG,CACrB,MAAM,CAAC,OAAO,CAAC,iBAAiB,EAAE,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC;QAC1E,GAAiC;QACjC,QAAyC;KAC1C,CAAC,CACH,CAAC;IAEF,OAAO;QACL,OAAO;QACP,gBAAgB,CAAC,GAA+B;YAC9C,OAAO,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC;QACD,gCAAgC,CAAC,kBAAsC;YACrE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAC/C,QAAQ,CAAC,oBAAoB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAC3D,CAAC;QACJ,CAAC;QACD,gCAAgC,CAAC,kBAAsC;YACrE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAC7C,QAAQ,CAAC,oBAAoB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAC3D,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type {\n FrontendProviderEntry,\n FrontendProvidersBlock,\n ProviderCapability,\n} from '@wildo-ai/saas-models/public-runtime';\n\nexport type FrontendTechdocProviderRef = string & {\n readonly __brand: 'FrontendTechdocProviderRef';\n};\n\nexport type FrontendTechdocProviderModule = FrontendProviderEntry;\n\nexport interface FrontendTechdocProviderRegistry {\n readonly modules: ReadonlyMap<\n FrontendTechdocProviderRef,\n FrontendTechdocProviderModule\n >;\n\n getProviderByRef(\n ref: FrontendTechdocProviderRef,\n ): FrontendTechdocProviderModule | undefined;\n\n getProvidersByProviderCapability(\n providerCapability: ProviderCapability,\n ): ReadonlyArray<FrontendTechdocProviderModule>;\n\n findProviderByProviderCapability(\n providerCapability: ProviderCapability,\n ): FrontendTechdocProviderModule | undefined;\n}\n\n/**\n * Tech-doc runtime registry hydrated from the materialized frontend-provider\n * block for the active docs service.\n */\nexport function createFrontendTechdocProviderRegistry(\n frontendProviders?: FrontendProvidersBlock,\n): FrontendTechdocProviderRegistry {\n const modules = new Map<FrontendTechdocProviderRef, FrontendTechdocProviderModule>(\n Object.entries(frontendProviders?.providers ?? {}).map(([ref, provider]) => [\n ref as FrontendTechdocProviderRef,\n provider as FrontendTechdocProviderModule,\n ]),\n );\n\n return {\n modules,\n getProviderByRef(ref: FrontendTechdocProviderRef) {\n return modules.get(ref);\n },\n getProvidersByProviderCapability(providerCapability: ProviderCapability) {\n return [...modules.values()].filter((provider) =>\n provider.providerCapabilities.includes(providerCapability),\n );\n },\n findProviderByProviderCapability(providerCapability: ProviderCapability) {\n return [...modules.values()].find((provider) =>\n provider.providerCapabilities.includes(providerCapability),\n );\n },\n };\n}\n"]}
1
+ {"version":3,"file":"frontend-provider-registry.techdoc.js","sourceRoot":"","sources":["../../../../src/runtime/frontend-provider-registry.techdoc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EACL,uCAAuC,GAIxC,MAAM,8CAA8C,CAAC;AAsBtD;;GAEG;AACH,MAAM,UAAU,qCAAqC,CACnD,KAAkD;IAElD,OAAO,uCAAuC,CAAC;QAC7C,OAAO,EAAE,KAAK,EAAE,OAAO;QACvB,OAAO,EAAE,KAAK,EAAE,OAAO;QACvB,YAAY,EAAE,KAAK,EAAE,YAAY;KAClC,CAAC,CAAC;AACL,CAAC","sourcesContent":["/**\n * The technical doc's provider registry — now composed from BOTH channels.\n *\n * It used to build itself by casting each served `FrontendProviderEntry` to a\n * module type that was an alias of that entry, which made the cast true and\n * useless: the registry could never hold anything a JSON payload could not\n * carry, so a provider's SDK loader had nowhere to arrive.\n *\n * - **DATA** — the materialized frontend-services block for THIS docs service.\n * Authoritative for which providers are on, in this environment.\n * - **CODE** — `generatedFrontendProviderModules` from the docs site's own\n * `src/generated/frontend-providers.generated.ts`, written by\n * `wildo config sync` and handed to `DocsAuthProvider` by the Root swizzle.\n *\n * The types are now the engine's own techdoc-facet types rather than local\n * aliases, so a provider module authored against\n * `@wildo-ai/external-connectors-public/techdoc` is the same type this registry\n * holds. Re-exported under the same names so every consumer's import is\n * unchanged.\n */\n\nimport {\n composeHydratedFrontendTechdocProviders,\n type FrontendProviderHydrationDiagnostic,\n type FrontendTechdocProviderRegistry,\n type GeneratedTechdocProviderModules,\n} from '@wildo-ai/external-connectors-public/techdoc';\nimport type { FrontendProvidersBlock } from '@wildo-ai/saas-models/public-runtime';\n\nexport type {\n FrontendTechdocProviderModule,\n FrontendTechdocProviderRef,\n FrontendTechdocProviderRegistry,\n GeneratedTechdocProviderModules,\n} from '@wildo-ai/external-connectors-public/techdoc';\n\nexport interface CreateFrontendTechdocProviderRegistryInput {\n /** The DATA channel: the materialized block for this docs service. */\n readonly entries?: FrontendProvidersBlock;\n /**\n * The CODE channel. Absent is the ordinary case for a docs site that declares\n * no package-shipped provider — `wildo config sync` writes no generated file,\n * so there is nothing to import and nothing to pass.\n */\n readonly modules?: GeneratedTechdocProviderModules;\n readonly onDiagnostic?: (diagnostic: FrontendProviderHydrationDiagnostic) => void;\n}\n\n/**\n * Tech-doc runtime registry, hydrated from both channels.\n */\nexport function createFrontendTechdocProviderRegistry(\n input?: CreateFrontendTechdocProviderRegistryInput,\n): FrontendTechdocProviderRegistry {\n return composeHydratedFrontendTechdocProviders({\n entries: input?.entries,\n modules: input?.modules,\n onDiagnostic: input?.onDiagnostic,\n });\n}\n"]}
@@ -50,6 +50,7 @@ export * from './frontend-provider-registry.techdoc';
50
50
  export { FrontendProviderEntrySchema, FrontendProvidersBlockSchema, type FrontendProviderEntry, type FrontendProvidersBlock, } from '@wildo-ai/saas-models/public-runtime';
51
51
  export * from './use-docs-auth-session';
52
52
  export * from './use-docs-frontend-provider-registry';
53
+ export * from './use-docs-provider-sdks';
53
54
  export * from './AuthExchangePage';
54
55
  export * from './openapi-reference-model';
55
56
  export * from './openapi-reference-conservation';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/runtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAuBH,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sCAAsC,CAAC;AACrD,OAAO,EACL,2BAA2B,EAC3B,4BAA4B,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,GAC5B,MAAM,sCAAsC,CAAC;AAC9C,cAAc,yBAAyB,CAAC;AACxC,cAAc,uCAAuC,CAAC;AACtD,cAAc,oBAAoB,CAAC;AACnC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AACjD,cAAc,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/runtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAuBH,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sCAAsC,CAAC;AACrD,OAAO,EACL,2BAA2B,EAC3B,4BAA4B,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,GAC5B,MAAM,sCAAsC,CAAC;AAC9C,cAAc,yBAAyB,CAAC;AACxC,cAAc,uCAAuC,CAAC;AACtD,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AACjD,cAAc,0BAA0B,CAAC"}
@@ -69,6 +69,7 @@ export * from './frontend-provider-registry.techdoc.js';
69
69
  export { FrontendProviderEntrySchema, FrontendProvidersBlockSchema, } from '@wildo-ai/saas-models/public-runtime';
70
70
  export * from './use-docs-auth-session.js';
71
71
  export * from './use-docs-frontend-provider-registry.js';
72
+ export * from './use-docs-provider-sdks.js';
72
73
  export * from './AuthExchangePage.js';
73
74
  export * from './openapi-reference-model.js';
74
75
  export * from './openapi-reference-conservation.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/runtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAErE,yBAAyB,CAAC,CAAC,CAAC,CAAC;AAE7B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sCAAsC,CAAC;AACrD,OAAO,EACL,2BAA2B,EAC3B,4BAA4B,GAG7B,MAAM,sCAAsC,CAAC;AAC9C,cAAc,yBAAyB,CAAC;AACxC,cAAc,uCAAuC,CAAC;AACtD,cAAc,oBAAoB,CAAC;AACnC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AACjD,cAAc,0BAA0B,CAAC","sourcesContent":["/**\n * `@wildo-ai/saas-technical-doc/runtime` — browser-only auth runtime\n * for the Docusaurus-served docs site (saas-technical-doc.md K-9b).\n *\n * Public surface (consumed by the three Docusaurus swizzles per K-11):\n *\n * - `<DocsAuthProvider apiBaseUrl=\"…\">` — Root swizzle wraps children.\n * - `useDocsAuthSession()` — Navbar + DocItem swizzles read.\n * - `<AuthExchangePage />` — mounted at `/auth/exchange`.\n * - `DocsAuthClient` — direct access for the DocItem\n * swizzle's \"request handoff back\n * to app\" code path.\n * - `DocsAuthClientError` + code type — typed error branch surface.\n * - `DocsRole` / `DocsAuthSession` — discriminated-union types.\n * - `useDocsFrontendProviderRegistry()` — read the materialized frontend\n * provider registry for this docs\n * service (search / future SDK\n * widgets).\n * - `decodeJwtClaims` — exposed so apps can decode\n * access tokens issued by\n * non-handoff flows (rare;\n * reserved for advanced use).\n *\n * @wildo-boundary\n * - This sub-tree MAY use React, `react-dom`, the browser `fetch`, and\n * the browser `atob` global. It MUST NOT import:\n * - Node built-ins (`fs`, `path`, …) — would break Docusaurus\n * client bundle.\n * - `@wildo-ai/saas-frontend-lib` — entire point of K-9b\n * is to NOT pull this.\n * - inversify — reserved for the SaaS\n * app DI stack.\n * - This sub-tree MAY import shared schemas + DTO types from\n * `@wildo-ai/saas-models/public-runtime` (the lightweight subset\n * allow-listed by `runtime-bundle-isolation.test.ts`).\n * - This sub-tree MUST initialize `@wildo-ai/zod-decorators` at runtime\n * entry — see the `ensureZodDecoratorsLoaded(z)` side-effect below.\n * Skipping this leaves the docs runtime with an under-augmented Zod\n * `ZodObject` declaration, which historically caused cross-package\n * `z.infer` widening (the H-3 / M-7 cross-frontend-handoff incident,\n * see `.cursor/plans/cross-app-jwt-propagation.md`).\n * - The package's `./companion` and `./` (root) entries MUST NOT import\n * from this sub-tree (see those files' boundary blocks).\n */\n\n/**\n * Boot the project's Zod decorator augmentation for this bundle.\n *\n * `@wildo-ai/saas-models/public-runtime` re-exports schemas authored\n * against the augmented `ZodObject` interface declared by\n * `@wildo-ai/zod-decorators`. Without `ensureZodDecoratorsLoaded(z)`\n * being called once on this bundle's Zod instance, the docs runtime sees\n * a schema graph whose `.shape` access paths and `z.infer` results don't\n * match what the SaaS app sees — a silent contract drift that bit us in\n * H-3 / M-7. The call is idempotent (guarded inside the function) so\n * importing this module multiple times is a no-op after the first load.\n *\n * The bare-specifier import is allow-listed by\n * `runtime-bundle-isolation.test.ts` (revised 2026-04-19); the package\n * itself is browser-safe (it only mutates `z.ZodType.prototype`).\n */\nimport { z } from 'zod';\nimport { ensureZodDecoratorsLoaded } from '@wildo-ai/zod-decorators';\n\nensureZodDecoratorsLoaded(z);\n\nexport * from './docs-auth-session.schemas';\nexport * from './decode-jwt-claims';\nexport * from './docs-auth-client';\nexport * from './DocsAuthContext';\nexport * from './frontend-provider-registry.techdoc';\nexport {\n FrontendProviderEntrySchema,\n FrontendProvidersBlockSchema,\n type FrontendProviderEntry,\n type FrontendProvidersBlock,\n} from '@wildo-ai/saas-models/public-runtime';\nexport * from './use-docs-auth-session';\nexport * from './use-docs-frontend-provider-registry';\nexport * from './AuthExchangePage';\nexport * from './openapi-reference-model';\nexport * from './openapi-reference-conservation';\nexport * from './openapi-reference-view';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/runtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAErE,yBAAyB,CAAC,CAAC,CAAC,CAAC;AAE7B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sCAAsC,CAAC;AACrD,OAAO,EACL,2BAA2B,EAC3B,4BAA4B,GAG7B,MAAM,sCAAsC,CAAC;AAC9C,cAAc,yBAAyB,CAAC;AACxC,cAAc,uCAAuC,CAAC;AACtD,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AACjD,cAAc,0BAA0B,CAAC","sourcesContent":["/**\n * `@wildo-ai/saas-technical-doc/runtime` — browser-only auth runtime\n * for the Docusaurus-served docs site (saas-technical-doc.md K-9b).\n *\n * Public surface (consumed by the three Docusaurus swizzles per K-11):\n *\n * - `<DocsAuthProvider apiBaseUrl=\"…\">` — Root swizzle wraps children.\n * - `useDocsAuthSession()` — Navbar + DocItem swizzles read.\n * - `<AuthExchangePage />` — mounted at `/auth/exchange`.\n * - `DocsAuthClient` — direct access for the DocItem\n * swizzle's \"request handoff back\n * to app\" code path.\n * - `DocsAuthClientError` + code type — typed error branch surface.\n * - `DocsRole` / `DocsAuthSession` — discriminated-union types.\n * - `useDocsFrontendProviderRegistry()` — read the materialized frontend\n * provider registry for this docs\n * service (search / future SDK\n * widgets).\n * - `decodeJwtClaims` — exposed so apps can decode\n * access tokens issued by\n * non-handoff flows (rare;\n * reserved for advanced use).\n *\n * @wildo-boundary\n * - This sub-tree MAY use React, `react-dom`, the browser `fetch`, and\n * the browser `atob` global. It MUST NOT import:\n * - Node built-ins (`fs`, `path`, …) — would break Docusaurus\n * client bundle.\n * - `@wildo-ai/saas-frontend-lib` — entire point of K-9b\n * is to NOT pull this.\n * - inversify — reserved for the SaaS\n * app DI stack.\n * - This sub-tree MAY import shared schemas + DTO types from\n * `@wildo-ai/saas-models/public-runtime` (the lightweight subset\n * allow-listed by `runtime-bundle-isolation.test.ts`).\n * - This sub-tree MUST initialize `@wildo-ai/zod-decorators` at runtime\n * entry — see the `ensureZodDecoratorsLoaded(z)` side-effect below.\n * Skipping this leaves the docs runtime with an under-augmented Zod\n * `ZodObject` declaration, which historically caused cross-package\n * `z.infer` widening (the H-3 / M-7 cross-frontend-handoff incident,\n * see `.cursor/plans/cross-app-jwt-propagation.md`).\n * - The package's `./companion` and `./` (root) entries MUST NOT import\n * from this sub-tree (see those files' boundary blocks).\n */\n\n/**\n * Boot the project's Zod decorator augmentation for this bundle.\n *\n * `@wildo-ai/saas-models/public-runtime` re-exports schemas authored\n * against the augmented `ZodObject` interface declared by\n * `@wildo-ai/zod-decorators`. Without `ensureZodDecoratorsLoaded(z)`\n * being called once on this bundle's Zod instance, the docs runtime sees\n * a schema graph whose `.shape` access paths and `z.infer` results don't\n * match what the SaaS app sees — a silent contract drift that bit us in\n * H-3 / M-7. The call is idempotent (guarded inside the function) so\n * importing this module multiple times is a no-op after the first load.\n *\n * The bare-specifier import is allow-listed by\n * `runtime-bundle-isolation.test.ts` (revised 2026-04-19); the package\n * itself is browser-safe (it only mutates `z.ZodType.prototype`).\n */\nimport { z } from 'zod';\nimport { ensureZodDecoratorsLoaded } from '@wildo-ai/zod-decorators';\n\nensureZodDecoratorsLoaded(z);\n\nexport * from './docs-auth-session.schemas';\nexport * from './decode-jwt-claims';\nexport * from './docs-auth-client';\nexport * from './DocsAuthContext';\nexport * from './frontend-provider-registry.techdoc';\nexport {\n FrontendProviderEntrySchema,\n FrontendProvidersBlockSchema,\n type FrontendProviderEntry,\n type FrontendProvidersBlock,\n} from '@wildo-ai/saas-models/public-runtime';\nexport * from './use-docs-auth-session';\nexport * from './use-docs-frontend-provider-registry';\nexport * from './use-docs-provider-sdks';\nexport * from './AuthExchangePage';\nexport * from './openapi-reference-model';\nexport * from './openapi-reference-conservation';\nexport * from './openapi-reference-view';\n"]}
@@ -2,17 +2,19 @@ import { type DocsAuthContextValue } from './DocsAuthContext';
2
2
  /**
3
3
  * Read the current docs-site auth session.
4
4
  *
5
- * The three Docusaurus swizzles (Root, Navbar, DocItem — see
6
- * saas-technical-doc.md K-11) all consume the same hook:
5
+ * ONE Docusaurus swizzle consumes this hook today:
7
6
  *
8
- * - Navbar : `session.status === 'authenticated' && session.claims.role === DocsRole.ORG_ADMIN`
9
- * decides whether the "Organization API" link is rendered.
10
- * - DocItem : on `/api/organization/*` routes, branches on the same
11
- * check; if anonymous, deep-links to the SaaS app because
12
- * handoff issuance requires a bearer.
13
7
  * - Root : the `<AuthExchangePage>` wired at `/auth/exchange` calls
14
8
  * `beginExchange(code)` on mount.
15
9
  *
10
+ * This list used to name three (Root, Navbar, DocItem). The Navbar swizzle
11
+ * gating an "Organization API" link and the DocItem swizzle gating
12
+ * `/api/organization/*` were never built, and there is no organization
13
+ * OpenAPI section for them to gate — see `DocsRole` in
14
+ * `docs-auth-session.schemas.ts` for the measurement. The hook's
15
+ * role-carrying shape is unchanged and ready for such a surface; it simply
16
+ * has no second or third consumer at present.
17
+ *
16
18
  * Throws when used outside `<DocsAuthProvider>` so misconfigured swizzles
17
19
  * fail loud during the Docusaurus build (rather than silently rendering
18
20
  * "anonymous" for every reader). This mirrors the pattern in
@@ -1 +1 @@
1
- {"version":3,"file":"use-docs-auth-session.d.ts","sourceRoot":"","sources":["../../../../src/runtime/use-docs-auth-session.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,kBAAkB,IAAI,oBAAoB,CASzD"}
1
+ {"version":3,"file":"use-docs-auth-session.d.ts","sourceRoot":"","sources":["../../../../src/runtime/use-docs-auth-session.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,kBAAkB,IAAI,oBAAoB,CASzD"}
@@ -3,17 +3,19 @@ import { DocsAuthContext } from './DocsAuthContext.js';
3
3
  /**
4
4
  * Read the current docs-site auth session.
5
5
  *
6
- * The three Docusaurus swizzles (Root, Navbar, DocItem — see
7
- * saas-technical-doc.md K-11) all consume the same hook:
6
+ * ONE Docusaurus swizzle consumes this hook today:
8
7
  *
9
- * - Navbar : `session.status === 'authenticated' && session.claims.role === DocsRole.ORG_ADMIN`
10
- * decides whether the "Organization API" link is rendered.
11
- * - DocItem : on `/api/organization/*` routes, branches on the same
12
- * check; if anonymous, deep-links to the SaaS app because
13
- * handoff issuance requires a bearer.
14
8
  * - Root : the `<AuthExchangePage>` wired at `/auth/exchange` calls
15
9
  * `beginExchange(code)` on mount.
16
10
  *
11
+ * This list used to name three (Root, Navbar, DocItem). The Navbar swizzle
12
+ * gating an "Organization API" link and the DocItem swizzle gating
13
+ * `/api/organization/*` were never built, and there is no organization
14
+ * OpenAPI section for them to gate — see `DocsRole` in
15
+ * `docs-auth-session.schemas.ts` for the measurement. The hook's
16
+ * role-carrying shape is unchanged and ready for such a surface; it simply
17
+ * has no second or third consumer at present.
18
+ *
17
19
  * Throws when used outside `<DocsAuthProvider>` so misconfigured swizzles
18
20
  * fail loud during the Docusaurus build (rather than silently rendering
19
21
  * "anonymous" for every reader). This mirrors the pattern in