@wildo-ai/saas-technical-doc 1.1.2 → 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.
- package/dist/esm/companion/application-documentation/application-connection-documentation.d.ts +25 -1
- package/dist/esm/companion/application-documentation/application-connection-documentation.d.ts.map +1 -1
- package/dist/esm/companion/application-documentation/application-connection-documentation.js +28 -1
- package/dist/esm/companion/application-documentation/application-connection-documentation.js.map +1 -1
- package/dist/esm/companion/application-documentation/application-domain-documentation.d.ts +133 -0
- package/dist/esm/companion/application-documentation/application-domain-documentation.d.ts.map +1 -0
- package/dist/esm/companion/application-documentation/application-domain-documentation.js +243 -0
- package/dist/esm/companion/application-documentation/application-domain-documentation.js.map +1 -0
- package/dist/esm/companion/application-documentation/application-integration-documentation.d.ts.map +1 -1
- package/dist/esm/companion/application-documentation/application-integration-documentation.js +23 -0
- package/dist/esm/companion/application-documentation/application-integration-documentation.js.map +1 -1
- package/dist/esm/companion/application-documentation/application-organization-role-documentation.d.ts +30 -0
- package/dist/esm/companion/application-documentation/application-organization-role-documentation.d.ts.map +1 -1
- package/dist/esm/companion/application-documentation/application-organization-role-documentation.js +38 -0
- package/dist/esm/companion/application-documentation/application-organization-role-documentation.js.map +1 -1
- package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.d.ts +61 -1
- package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.d.ts.map +1 -1
- package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.js +255 -218
- package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.js.map +1 -1
- package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.d.ts +2 -0
- package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.d.ts.map +1 -1
- package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.js +1 -0
- package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.js.map +1 -1
- package/dist/esm/companion/application-documentation/technical-documentation-publication-policy.js +1 -1
- package/dist/esm/companion/application-documentation/technical-documentation-publication-policy.js.map +1 -1
- package/dist/esm/companion/index.d.ts +2 -1
- package/dist/esm/companion/index.d.ts.map +1 -1
- package/dist/esm/companion/index.js +2 -1
- package/dist/esm/companion/index.js.map +1 -1
- package/dist/esm/companion/manual-controller-route-projection.d.ts +112 -0
- package/dist/esm/companion/manual-controller-route-projection.d.ts.map +1 -0
- package/dist/esm/companion/manual-controller-route-projection.js +249 -0
- package/dist/esm/companion/manual-controller-route-projection.js.map +1 -0
- package/dist/esm/companion/openapi-generator.d.ts +16 -0
- package/dist/esm/companion/openapi-generator.d.ts.map +1 -1
- package/dist/esm/companion/openapi-generator.js +489 -26
- package/dist/esm/companion/openapi-generator.js.map +1 -1
- package/dist/esm/companion/operation-projection.schemas.d.ts +44 -0
- package/dist/esm/companion/operation-projection.schemas.d.ts.map +1 -1
- package/dist/esm/companion/operation-projection.schemas.js +37 -0
- package/dist/esm/companion/operation-projection.schemas.js.map +1 -1
- package/dist/esm/companion/rendering/technical-documentation-docusaurus-renderer.d.ts +7 -1
- package/dist/esm/companion/rendering/technical-documentation-docusaurus-renderer.d.ts.map +1 -1
- package/dist/esm/companion/rendering/technical-documentation-docusaurus-renderer.js +34 -18
- package/dist/esm/companion/rendering/technical-documentation-docusaurus-renderer.js.map +1 -1
- package/dist/esm/companion/rendering/technical-documentation-managed-tree-validator.d.ts.map +1 -1
- package/dist/esm/companion/rendering/technical-documentation-managed-tree-validator.js +8 -1
- package/dist/esm/companion/rendering/technical-documentation-managed-tree-validator.js.map +1 -1
- package/dist/esm/companion/rendering/technical-documentation-markdown-renderer.d.ts +0 -9
- package/dist/esm/companion/rendering/technical-documentation-markdown-renderer.d.ts.map +0 -1
- package/dist/esm/companion/rendering/technical-documentation-markdown-renderer.js +0 -111
- package/dist/esm/companion/rendering/technical-documentation-markdown-renderer.js.map +0 -1
- package/dist/esm/companion/rendering/technical-documentation-render-model.d.ts.map +1 -1
- package/dist/esm/companion/rendering/technical-documentation-render-model.js +30 -13
- package/dist/esm/companion/rendering/technical-documentation-render-model.js.map +1 -1
- package/dist/esm/companion/rendering/technical-documentation-search-index-renderer.d.ts +10 -0
- package/dist/esm/companion/rendering/technical-documentation-search-index-renderer.d.ts.map +1 -1
- package/dist/esm/companion/rendering/technical-documentation-search-index-renderer.js +10 -15
- package/dist/esm/companion/rendering/technical-documentation-search-index-renderer.js.map +1 -1
- package/dist/esm/companion/technical-documentation-capture-execution-port.d.ts +27 -1
- package/dist/esm/companion/technical-documentation-capture-execution-port.d.ts.map +1 -1
- package/dist/esm/companion/technical-documentation-capture-execution-port.js.map +1 -1
- package/dist/esm/companion/technical-documentation-diagram-definitions.d.ts +33 -0
- package/dist/esm/companion/technical-documentation-diagram-definitions.d.ts.map +1 -0
- package/dist/esm/companion/technical-documentation-diagram-definitions.js +54 -0
- package/dist/esm/companion/technical-documentation-diagram-definitions.js.map +1 -0
- package/dist/esm/companion/technical-documentation-diagram-materializer.d.ts +10 -18
- package/dist/esm/companion/technical-documentation-diagram-materializer.d.ts.map +1 -1
- package/dist/esm/companion/technical-documentation-diagram-materializer.js +9 -39
- package/dist/esm/companion/technical-documentation-diagram-materializer.js.map +1 -1
- package/dist/esm/config/wildo-tech-doc-config.schemas.d.ts +8 -4
- package/dist/esm/config/wildo-tech-doc-config.schemas.d.ts.map +1 -1
- package/dist/esm/config/wildo-tech-doc-config.schemas.js +8 -4
- package/dist/esm/config/wildo-tech-doc-config.schemas.js.map +1 -1
- package/dist/esm/content/application-consumer-documentation-content.techdoc.d.ts +42 -64
- package/dist/esm/content/application-consumer-documentation-content.techdoc.d.ts.map +1 -1
- package/dist/esm/content/application-consumer-documentation-content.techdoc.js +164 -925
- package/dist/esm/content/application-consumer-documentation-content.techdoc.js.map +1 -1
- package/dist/esm/runtime/DocsAuthContext.d.ts +16 -1
- package/dist/esm/runtime/DocsAuthContext.d.ts.map +1 -1
- package/dist/esm/runtime/DocsAuthContext.js +18 -2
- package/dist/esm/runtime/DocsAuthContext.js.map +1 -1
- package/dist/esm/runtime/frontend-provider-registry.techdoc.d.ts +35 -13
- package/dist/esm/runtime/frontend-provider-registry.techdoc.d.ts.map +1 -1
- package/dist/esm/runtime/frontend-provider-registry.techdoc.js +28 -19
- package/dist/esm/runtime/frontend-provider-registry.techdoc.js.map +1 -1
- package/dist/esm/runtime/index.d.ts +1 -0
- package/dist/esm/runtime/index.d.ts.map +1 -1
- package/dist/esm/runtime/index.js +1 -0
- package/dist/esm/runtime/index.js.map +1 -1
- package/dist/esm/runtime/use-docs-provider-sdks.d.ts +21 -0
- package/dist/esm/runtime/use-docs-provider-sdks.d.ts.map +1 -0
- package/dist/esm/runtime/use-docs-provider-sdks.js +49 -0
- package/dist/esm/runtime/use-docs-provider-sdks.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +6 -5
package/dist/esm/companion/application-documentation/application-connection-documentation.d.ts
CHANGED
|
@@ -68,7 +68,31 @@ export declare enum ApplicationConnectionInlineValue {
|
|
|
68
68
|
/** The full agent-card URL an A2A peer fetches. */
|
|
69
69
|
AGENT_CARD_URL = "agentCardUrl",
|
|
70
70
|
/** The full A2A task endpoint URL. */
|
|
71
|
-
AGENT_TASK_URL = "agentTaskUrl"
|
|
71
|
+
AGENT_TASK_URL = "agentTaskUrl",
|
|
72
|
+
/**
|
|
73
|
+
* The full SCIM base URL an administrator pastes into their identity provider.
|
|
74
|
+
*
|
|
75
|
+
* Unlike the endpoints above this one is NOT gated on an observed surface, because SCIM is
|
|
76
|
+
* configured in the IdP rather than advertised by the application: the base is where traffic
|
|
77
|
+
* would be pushed, and whether a given organization has enabled provisioning is a tenant setting
|
|
78
|
+
* the page discusses separately. Derived from `SCIM_SERVICE_BASE_PATH` for the same reason the
|
|
79
|
+
* others derive from the route map — the engine owns the mount.
|
|
80
|
+
*/
|
|
81
|
+
SCIM_BASE_URL = "scimBaseUrl",
|
|
82
|
+
/** The OAuth issuer a client configures, and checks the discovery document's `issuer` against. */
|
|
83
|
+
OAUTH_ISSUER = "oauthIssuer",
|
|
84
|
+
/**
|
|
85
|
+
* Where RFC 8414 authorization-server metadata is served.
|
|
86
|
+
*
|
|
87
|
+
* Derived with the engine's own `rfc8414AuthorizationServerMetadataPath`, never by appending the
|
|
88
|
+
* well-known segment to the issuer. The RFC inserts it BETWEEN the host and the issuer's path, so
|
|
89
|
+
* an issuer of `…/api/v1` publishes at `/.well-known/oauth-authorization-server/api/v1` — the
|
|
90
|
+
* opposite construction from OIDC discovery. Getting that backwards is not hypothetical: a real
|
|
91
|
+
* MCP client derived the RFC location, received the SPA shell, and abandoned authorization
|
|
92
|
+
* without opening a browser. Documentation that showed a hand-built path would be teaching the
|
|
93
|
+
* shape that failed.
|
|
94
|
+
*/
|
|
95
|
+
OAUTH_METADATA_URL = "oauthMetadataUrl"
|
|
72
96
|
}
|
|
73
97
|
export interface ApplicationConnectionDocumentationFact {
|
|
74
98
|
readonly sourceRef: string;
|
package/dist/esm/companion/application-documentation/application-connection-documentation.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"application-connection-documentation.d.ts","sourceRoot":"","sources":["../../../../../src/companion/application-documentation/application-connection-documentation.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,+CAA+C,EAAG,oDAA6D,CAAC;AAC7H,eAAO,MAAM,mDAAmD,IAAI,CAAC;AAErE,kFAAkF;AAClF,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,wCAAwC;IACvD,mFAAmF;IACnF,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,0FAA0F;IAC1F,QAAQ,CAAC,UAAU,EAAE,SAAS,2BAA2B,EAAE,CAAC;IAC5D,QAAQ,CAAC,QAAQ,EAAE;QACjB,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;QAChC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;KAC5B,CAAC;CACH;AAED,2FAA2F;AAC3F,oBAAY,iCAAiC;IAC3C,uFAAuF;IACvF,kBAAkB,sBAAsB;IACxC,gFAAgF;IAChF,SAAS,aAAa;IACtB;;;;;OAKG;IACH,YAAY,gBAAgB;IAC5B,yFAAyF;IACzF,cAAc,iBAAiB;CAChC;AAED;;;GAGG;AACH,oBAAY,gCAAgC;IAC1C,oGAAoG;IACpG,QAAQ,YAAY;IACpB,qDAAqD;IACrD,gBAAgB,mBAAmB;IACnC,mDAAmD;IACnD,cAAc,iBAAiB;IAC/B,sCAAsC;IACtC,cAAc,iBAAiB;
|
|
1
|
+
{"version":3,"file":"application-connection-documentation.d.ts","sourceRoot":"","sources":["../../../../../src/companion/application-documentation/application-connection-documentation.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,+CAA+C,EAAG,oDAA6D,CAAC;AAC7H,eAAO,MAAM,mDAAmD,IAAI,CAAC;AAErE,kFAAkF;AAClF,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,wCAAwC;IACvD,mFAAmF;IACnF,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,0FAA0F;IAC1F,QAAQ,CAAC,UAAU,EAAE,SAAS,2BAA2B,EAAE,CAAC;IAC5D,QAAQ,CAAC,QAAQ,EAAE;QACjB,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;QAChC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;KAC5B,CAAC;CACH;AAED,2FAA2F;AAC3F,oBAAY,iCAAiC;IAC3C,uFAAuF;IACvF,kBAAkB,sBAAsB;IACxC,gFAAgF;IAChF,SAAS,aAAa;IACtB;;;;;OAKG;IACH,YAAY,gBAAgB;IAC5B,yFAAyF;IACzF,cAAc,iBAAiB;CAChC;AAED;;;GAGG;AACH,oBAAY,gCAAgC;IAC1C,oGAAoG;IACpG,QAAQ,YAAY;IACpB,qDAAqD;IACrD,gBAAgB,mBAAmB;IACnC,mDAAmD;IACnD,cAAc,iBAAiB;IAC/B,sCAAsC;IACtC,cAAc,iBAAiB;IAC/B;;;;;;;;OAQG;IACH,aAAa,gBAAgB;IAC7B,kGAAkG;IAClG,YAAY,gBAAgB;IAC5B;;;;;;;;;;OAUG;IACH,kBAAkB,qBAAqB;CACxC;AAED,MAAM,WAAW,sCAAsC;IACrD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,4EAA4E;IAC5E,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,iCAAiC,EAAE,MAAM,CAAC,CAAC,CAAC;IACpF,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,gCAAgC,EAAE,MAAM,CAAC,CAAC,CAAC;CACnF;AA0DD;;;;GAIG;AACH,wBAAgB,yCAAyC,CACvD,MAAM,EAAE,wCAAwC,GAC/C,sCAAsC,CA2BxC"}
|
package/dist/esm/companion/application-documentation/application-connection-documentation.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MAIN_API_BASE_PATH, MANUAL_CONTROLLER_ROUTES_URLS, ManualControllerRouteKey } from '@wildo-ai/saas-models';
|
|
1
|
+
import { MAIN_API_BASE_PATH, MANUAL_CONTROLLER_ROUTES_URLS, ManualControllerRouteKey, rfc8414AuthorizationServerMetadataPath, SCIM_SERVICE_BASE_PATH } from '@wildo-ai/saas-models';
|
|
2
2
|
/**
|
|
3
3
|
* The application's own name and the addresses an integrator connects to.
|
|
4
4
|
*
|
|
@@ -50,6 +50,30 @@ export var ApplicationConnectionInlineValue;
|
|
|
50
50
|
ApplicationConnectionInlineValue["AGENT_CARD_URL"] = "agentCardUrl";
|
|
51
51
|
/** The full A2A task endpoint URL. */
|
|
52
52
|
ApplicationConnectionInlineValue["AGENT_TASK_URL"] = "agentTaskUrl";
|
|
53
|
+
/**
|
|
54
|
+
* The full SCIM base URL an administrator pastes into their identity provider.
|
|
55
|
+
*
|
|
56
|
+
* Unlike the endpoints above this one is NOT gated on an observed surface, because SCIM is
|
|
57
|
+
* configured in the IdP rather than advertised by the application: the base is where traffic
|
|
58
|
+
* would be pushed, and whether a given organization has enabled provisioning is a tenant setting
|
|
59
|
+
* the page discusses separately. Derived from `SCIM_SERVICE_BASE_PATH` for the same reason the
|
|
60
|
+
* others derive from the route map — the engine owns the mount.
|
|
61
|
+
*/
|
|
62
|
+
ApplicationConnectionInlineValue["SCIM_BASE_URL"] = "scimBaseUrl";
|
|
63
|
+
/** The OAuth issuer a client configures, and checks the discovery document's `issuer` against. */
|
|
64
|
+
ApplicationConnectionInlineValue["OAUTH_ISSUER"] = "oauthIssuer";
|
|
65
|
+
/**
|
|
66
|
+
* Where RFC 8414 authorization-server metadata is served.
|
|
67
|
+
*
|
|
68
|
+
* Derived with the engine's own `rfc8414AuthorizationServerMetadataPath`, never by appending the
|
|
69
|
+
* well-known segment to the issuer. The RFC inserts it BETWEEN the host and the issuer's path, so
|
|
70
|
+
* an issuer of `…/api/v1` publishes at `/.well-known/oauth-authorization-server/api/v1` — the
|
|
71
|
+
* opposite construction from OIDC discovery. Getting that backwards is not hypothetical: a real
|
|
72
|
+
* MCP client derived the RFC location, received the SPA shell, and abandoned authorization
|
|
73
|
+
* without opening a browser. Documentation that showed a hand-built path would be teaching the
|
|
74
|
+
* shape that failed.
|
|
75
|
+
*/
|
|
76
|
+
ApplicationConnectionInlineValue["OAUTH_METADATA_URL"] = "oauthMetadataUrl";
|
|
53
77
|
})(ApplicationConnectionInlineValue || (ApplicationConnectionInlineValue = {}));
|
|
54
78
|
/** A manual route as a reader must call it: the mount plus the engine-owned path segment. */
|
|
55
79
|
function publicRoutePath(routeKey) {
|
|
@@ -132,6 +156,9 @@ export function projectApplicationConnectionDocumentation(source) {
|
|
|
132
156
|
[ApplicationConnectionInlineValue.MCP_ENDPOINT_URL]: `${primaryBaseUrl(named)}${publicRoutePath(ManualControllerRouteKey.MCP_ENDPOINT)}`,
|
|
133
157
|
[ApplicationConnectionInlineValue.AGENT_CARD_URL]: `${primaryBaseUrl(named)}${publicRoutePath(ManualControllerRouteKey.A2A_AGENT_CARD)}`,
|
|
134
158
|
[ApplicationConnectionInlineValue.AGENT_TASK_URL]: `${primaryBaseUrl(named)}${publicRoutePath(ManualControllerRouteKey.A2A_TASKS)}`,
|
|
159
|
+
[ApplicationConnectionInlineValue.SCIM_BASE_URL]: `${primaryBaseUrl(named)}${SCIM_SERVICE_BASE_PATH}`,
|
|
160
|
+
[ApplicationConnectionInlineValue.OAUTH_ISSUER]: `${primaryBaseUrl(named)}${MAIN_API_BASE_PATH}`,
|
|
161
|
+
[ApplicationConnectionInlineValue.OAUTH_METADATA_URL]: `${primaryBaseUrl(named)}${rfc8414AuthorizationServerMetadataPath(MAIN_API_BASE_PATH)}`,
|
|
135
162
|
}),
|
|
136
163
|
};
|
|
137
164
|
}
|
package/dist/esm/companion/application-documentation/application-connection-documentation.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"application-connection-documentation.js","sourceRoot":"","sources":["../../../../../src/companion/application-documentation/application-connection-documentation.ts"],"names":[],"mappings":"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","sourcesContent":["import { MAIN_API_BASE_PATH, MANUAL_CONTROLLER_ROUTES_URLS, ManualControllerRouteKey } from '@wildo-ai/saas-models';\n\n/**\n * The application's own name and the addresses an integrator connects to.\n *\n * Engine documentation is written once for every generated application, so it\n * used to hedge everything an application knows about itself: \"the server origin\n * from this application's API reference\", \"the address published for this\n * environment\", \"the application\". Every one of those values is available to the\n * companion at derivation time, and this projection is how they reach the page.\n *\n * The split is deliberate. The APPLICATION supplies what only it knows — its\n * customer-facing name and the base URLs it publishes. The ENGINE supplies the\n * paths, because a route is the engine's own contract and an application that\n * restated it would hold a second copy that can drift (see\n * `MANUAL_CONTROLLER_ROUTES_URLS`, whose values are mounted under\n * `MAIN_API_BASE_PATH`). An endpoint appears only when the companion has\n * observed that the application configures that surface, so a page never\n * advertises a door this application does not open.\n */\nexport const APPLICATION_CONNECTION_DOCUMENTATION_SOURCE_REF = 'source:companion-projection:application-connection' as const;\nexport const APPLICATION_CONNECTION_DOCUMENTATION_SOURCE_VERSION = 1;\n\n/** One base URL an application publishes for an environment a reader may call. */\nexport interface ApplicationConnectionServer {\n readonly url: string;\n readonly description?: string;\n}\n\n/**\n * What the companion measures about this application. `surfaces` mirrors the\n * evidence the derivation already computes for applicability gating: the same\n * observation that decides whether the MCP pages are published decides whether\n * the MCP endpoint is printed, so a published address and a published page can\n * never disagree.\n */\nexport interface ApplicationConnectionDocumentationSource {\n /** The name customers see. The application's `displayName`, else its `appName`. */\n readonly applicationName: string;\n /** Base URLs the application publishes, in the order it authored them. Possibly empty. */\n readonly apiServers: readonly ApplicationConnectionServer[];\n readonly surfaces: {\n readonly mcpToolServer: boolean;\n readonly a2aAgent: boolean;\n };\n}\n\n/** Named presentations a page may request with `{{APPLICATION_CONNECTION:<selector>}}`. */\nexport enum ApplicationConnectionPresentation {\n /** Every connection detail as one table: base URLs, the API mount, agent endpoints. */\n CONNECTION_DETAILS = 'connectionDetails',\n /** The base URLs alone, for a page that only needs to say where requests go. */\n BASE_URLS = 'baseUrls',\n /**\n * The MCP endpoint sentence. Never empty: an application that exposes no MCP surface gets a\n * sentence saying so. Projection runs for every unit and gating happens afterwards, so a\n * presentation that rendered nothing would leave a blank where a suppressed page's prose was,\n * and would say nothing at all if the page were ever published without its gate.\n */\n MCP_ENDPOINT = 'mcpEndpoint',\n /** The A2A agent-card sentence. Never empty, for the same reason as the MCP endpoint. */\n A2A_AGENT_CARD = 'a2aAgentCard',\n}\n\n/**\n * Values a page substitutes INSIDE a sample — a JSON client configuration, an HTTP request line —\n * where a block presentation cannot go. Each is a single string, never markdown.\n */\nexport enum ApplicationConnectionInlineValue {\n /** The first base URL the application publishes, or an explicit stand-in when it publishes none. */\n BASE_URL = 'baseUrl',\n /** The full MCP endpoint URL a client configures. */\n MCP_ENDPOINT_URL = 'mcpEndpointUrl',\n /** The full agent-card URL an A2A peer fetches. */\n AGENT_CARD_URL = 'agentCardUrl',\n /** The full A2A task endpoint URL. */\n AGENT_TASK_URL = 'agentTaskUrl',\n}\n\nexport interface ApplicationConnectionDocumentationFact {\n readonly sourceRef: string;\n readonly sourceVersion: number;\n /** Substituted wherever a page writes the inline application-name token. */\n readonly applicationName: string;\n readonly presentations: Readonly<Record<ApplicationConnectionPresentation, string>>;\n readonly inlineValues: Readonly<Record<ApplicationConnectionInlineValue, string>>;\n}\n\n/** A manual route as a reader must call it: the mount plus the engine-owned path segment. */\nfunction publicRoutePath(routeKey: ManualControllerRouteKey): string {\n return `${MAIN_API_BASE_PATH}${MANUAL_CONTROLLER_ROUTES_URLS[routeKey]}`;\n}\n\nfunction baseUrlsMarkdown(source: ApplicationConnectionDocumentationSource): string {\n if (source.apiServers.length === 0) {\n // Honest rather than invented: an application that publishes no base URL cannot have one\n // printed for it, and the reader is told where the answer actually lives.\n return `${source.applicationName} does not publish its base URLs in this documentation. Read them from the **Servers** list at the top of the API reference, or ask whoever operates the environment you are calling.`;\n }\n const rows = source.apiServers\n .map((server) => `| \\`${server.url}\\` | ${server.description ?? 'Published base URL'} |`)\n .join('\\n');\n return `| Base URL | Environment |\\n| --- | --- |\\n${rows}`;\n}\n\nfunction mcpEndpointMarkdown(source: ApplicationConnectionDocumentationSource): string {\n if (!source.surfaces.mcpToolServer) return `${source.applicationName} does not publish a Model Context Protocol endpoint.`;\n return `${source.applicationName} serves its Model Context Protocol endpoint at \\`${publicRoutePath(ManualControllerRouteKey.MCP_ENDPOINT)}\\`, under the base URL of the environment you are connecting to.`;\n}\n\nfunction a2aAgentCardMarkdown(source: ApplicationConnectionDocumentationSource): string {\n if (!source.surfaces.a2aAgent) return `${source.applicationName} does not publish an agent card.`;\n return `${source.applicationName} publishes its agent card at \\`${publicRoutePath(ManualControllerRouteKey.A2A_AGENT_CARD)}\\` and accepts task calls at \\`${publicRoutePath(ManualControllerRouteKey.A2A_TASKS)}\\`, under the base URL of the environment you are connecting to.`;\n}\n\nfunction connectionDetailsMarkdown(source: ApplicationConnectionDocumentationSource): string {\n const rows: string[] = [];\n for (const server of source.apiServers) {\n rows.push(`| Base URL${server.description === undefined ? '' : ` (${server.description})`} | \\`${server.url}\\` |`);\n }\n rows.push(`| API mount | \\`${MAIN_API_BASE_PATH}\\` — every path in the API reference already includes it |`);\n if (source.surfaces.mcpToolServer) {\n rows.push(`| MCP endpoint | \\`${publicRoutePath(ManualControllerRouteKey.MCP_ENDPOINT)}\\` |`);\n }\n if (source.surfaces.a2aAgent) {\n rows.push(`| A2A agent card | \\`${publicRoutePath(ManualControllerRouteKey.A2A_AGENT_CARD)}\\` |`);\n rows.push(`| A2A task endpoint | \\`${publicRoutePath(ManualControllerRouteKey.A2A_TASKS)}\\` |`);\n }\n const table = `| What | Value |\\n| --- | --- |\\n${rows.join('\\n')}`;\n return source.apiServers.length > 0\n ? table\n : `${table}\\n\\nThis application publishes no base URL here; read it from the **Servers** list at the top of the API reference.`;\n}\n\n/**\n * The origin a sample should show. An application that publishes no base URL gets an explicit\n * stand-in rather than a fabricated host: the reader must substitute their own environment, and the\n * sample says so in the place where the value belongs.\n */\nfunction primaryBaseUrl(source: ApplicationConnectionDocumentationSource): string {\n const first = source.apiServers[0];\n return first === undefined ? 'https://your-environment.example' : first.url.replace(/\\/+$/, '');\n}\n\n/**\n * Projects the application's connection facts into the presentations a page may\n * request. Every presentation is a pure function of the source, so two runs over\n * the same application produce identical bytes.\n */\nexport function projectApplicationConnectionDocumentation(\n source: ApplicationConnectionDocumentationSource,\n): ApplicationConnectionDocumentationFact {\n const applicationName = source.applicationName.trim();\n if (applicationName.length === 0) throw new Error('application connection projection requires a customer-facing application name');\n for (const server of source.apiServers) {\n if (server.url.trim().length === 0) throw new Error('application connection projection received an empty base URL');\n }\n const named: ApplicationConnectionDocumentationSource = { ...source, applicationName };\n return {\n sourceRef: APPLICATION_CONNECTION_DOCUMENTATION_SOURCE_REF,\n sourceVersion: APPLICATION_CONNECTION_DOCUMENTATION_SOURCE_VERSION,\n applicationName,\n presentations: Object.freeze({\n [ApplicationConnectionPresentation.CONNECTION_DETAILS]: connectionDetailsMarkdown(named),\n [ApplicationConnectionPresentation.BASE_URLS]: baseUrlsMarkdown(named),\n [ApplicationConnectionPresentation.MCP_ENDPOINT]: mcpEndpointMarkdown(named),\n [ApplicationConnectionPresentation.A2A_AGENT_CARD]: a2aAgentCardMarkdown(named),\n }),\n inlineValues: Object.freeze({\n [ApplicationConnectionInlineValue.BASE_URL]: primaryBaseUrl(named),\n [ApplicationConnectionInlineValue.MCP_ENDPOINT_URL]: `${primaryBaseUrl(named)}${publicRoutePath(ManualControllerRouteKey.MCP_ENDPOINT)}`,\n [ApplicationConnectionInlineValue.AGENT_CARD_URL]: `${primaryBaseUrl(named)}${publicRoutePath(ManualControllerRouteKey.A2A_AGENT_CARD)}`,\n [ApplicationConnectionInlineValue.AGENT_TASK_URL]: `${primaryBaseUrl(named)}${publicRoutePath(ManualControllerRouteKey.A2A_TASKS)}`,\n }),\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"application-connection-documentation.js","sourceRoot":"","sources":["../../../../../src/companion/application-documentation/application-connection-documentation.ts"],"names":[],"mappings":"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","sourcesContent":["import { MAIN_API_BASE_PATH, MANUAL_CONTROLLER_ROUTES_URLS, ManualControllerRouteKey, rfc8414AuthorizationServerMetadataPath, SCIM_SERVICE_BASE_PATH } from '@wildo-ai/saas-models';\n\n/**\n * The application's own name and the addresses an integrator connects to.\n *\n * Engine documentation is written once for every generated application, so it\n * used to hedge everything an application knows about itself: \"the server origin\n * from this application's API reference\", \"the address published for this\n * environment\", \"the application\". Every one of those values is available to the\n * companion at derivation time, and this projection is how they reach the page.\n *\n * The split is deliberate. The APPLICATION supplies what only it knows — its\n * customer-facing name and the base URLs it publishes. The ENGINE supplies the\n * paths, because a route is the engine's own contract and an application that\n * restated it would hold a second copy that can drift (see\n * `MANUAL_CONTROLLER_ROUTES_URLS`, whose values are mounted under\n * `MAIN_API_BASE_PATH`). An endpoint appears only when the companion has\n * observed that the application configures that surface, so a page never\n * advertises a door this application does not open.\n */\nexport const APPLICATION_CONNECTION_DOCUMENTATION_SOURCE_REF = 'source:companion-projection:application-connection' as const;\nexport const APPLICATION_CONNECTION_DOCUMENTATION_SOURCE_VERSION = 1;\n\n/** One base URL an application publishes for an environment a reader may call. */\nexport interface ApplicationConnectionServer {\n readonly url: string;\n readonly description?: string;\n}\n\n/**\n * What the companion measures about this application. `surfaces` mirrors the\n * evidence the derivation already computes for applicability gating: the same\n * observation that decides whether the MCP pages are published decides whether\n * the MCP endpoint is printed, so a published address and a published page can\n * never disagree.\n */\nexport interface ApplicationConnectionDocumentationSource {\n /** The name customers see. The application's `displayName`, else its `appName`. */\n readonly applicationName: string;\n /** Base URLs the application publishes, in the order it authored them. Possibly empty. */\n readonly apiServers: readonly ApplicationConnectionServer[];\n readonly surfaces: {\n readonly mcpToolServer: boolean;\n readonly a2aAgent: boolean;\n };\n}\n\n/** Named presentations a page may request with `{{APPLICATION_CONNECTION:<selector>}}`. */\nexport enum ApplicationConnectionPresentation {\n /** Every connection detail as one table: base URLs, the API mount, agent endpoints. */\n CONNECTION_DETAILS = 'connectionDetails',\n /** The base URLs alone, for a page that only needs to say where requests go. */\n BASE_URLS = 'baseUrls',\n /**\n * The MCP endpoint sentence. Never empty: an application that exposes no MCP surface gets a\n * sentence saying so. Projection runs for every unit and gating happens afterwards, so a\n * presentation that rendered nothing would leave a blank where a suppressed page's prose was,\n * and would say nothing at all if the page were ever published without its gate.\n */\n MCP_ENDPOINT = 'mcpEndpoint',\n /** The A2A agent-card sentence. Never empty, for the same reason as the MCP endpoint. */\n A2A_AGENT_CARD = 'a2aAgentCard',\n}\n\n/**\n * Values a page substitutes INSIDE a sample — a JSON client configuration, an HTTP request line —\n * where a block presentation cannot go. Each is a single string, never markdown.\n */\nexport enum ApplicationConnectionInlineValue {\n /** The first base URL the application publishes, or an explicit stand-in when it publishes none. */\n BASE_URL = 'baseUrl',\n /** The full MCP endpoint URL a client configures. */\n MCP_ENDPOINT_URL = 'mcpEndpointUrl',\n /** The full agent-card URL an A2A peer fetches. */\n AGENT_CARD_URL = 'agentCardUrl',\n /** The full A2A task endpoint URL. */\n AGENT_TASK_URL = 'agentTaskUrl',\n /**\n * The full SCIM base URL an administrator pastes into their identity provider.\n *\n * Unlike the endpoints above this one is NOT gated on an observed surface, because SCIM is\n * configured in the IdP rather than advertised by the application: the base is where traffic\n * would be pushed, and whether a given organization has enabled provisioning is a tenant setting\n * the page discusses separately. Derived from `SCIM_SERVICE_BASE_PATH` for the same reason the\n * others derive from the route map — the engine owns the mount.\n */\n SCIM_BASE_URL = 'scimBaseUrl',\n /** The OAuth issuer a client configures, and checks the discovery document's `issuer` against. */\n OAUTH_ISSUER = 'oauthIssuer',\n /**\n * Where RFC 8414 authorization-server metadata is served.\n *\n * Derived with the engine's own `rfc8414AuthorizationServerMetadataPath`, never by appending the\n * well-known segment to the issuer. The RFC inserts it BETWEEN the host and the issuer's path, so\n * an issuer of `…/api/v1` publishes at `/.well-known/oauth-authorization-server/api/v1` — the\n * opposite construction from OIDC discovery. Getting that backwards is not hypothetical: a real\n * MCP client derived the RFC location, received the SPA shell, and abandoned authorization\n * without opening a browser. Documentation that showed a hand-built path would be teaching the\n * shape that failed.\n */\n OAUTH_METADATA_URL = 'oauthMetadataUrl',\n}\n\nexport interface ApplicationConnectionDocumentationFact {\n readonly sourceRef: string;\n readonly sourceVersion: number;\n /** Substituted wherever a page writes the inline application-name token. */\n readonly applicationName: string;\n readonly presentations: Readonly<Record<ApplicationConnectionPresentation, string>>;\n readonly inlineValues: Readonly<Record<ApplicationConnectionInlineValue, string>>;\n}\n\n/** A manual route as a reader must call it: the mount plus the engine-owned path segment. */\nfunction publicRoutePath(routeKey: ManualControllerRouteKey): string {\n return `${MAIN_API_BASE_PATH}${MANUAL_CONTROLLER_ROUTES_URLS[routeKey]}`;\n}\n\nfunction baseUrlsMarkdown(source: ApplicationConnectionDocumentationSource): string {\n if (source.apiServers.length === 0) {\n // Honest rather than invented: an application that publishes no base URL cannot have one\n // printed for it, and the reader is told where the answer actually lives.\n return `${source.applicationName} does not publish its base URLs in this documentation. Read them from the **Servers** list at the top of the API reference, or ask whoever operates the environment you are calling.`;\n }\n const rows = source.apiServers\n .map((server) => `| \\`${server.url}\\` | ${server.description ?? 'Published base URL'} |`)\n .join('\\n');\n return `| Base URL | Environment |\\n| --- | --- |\\n${rows}`;\n}\n\nfunction mcpEndpointMarkdown(source: ApplicationConnectionDocumentationSource): string {\n if (!source.surfaces.mcpToolServer) return `${source.applicationName} does not publish a Model Context Protocol endpoint.`;\n return `${source.applicationName} serves its Model Context Protocol endpoint at \\`${publicRoutePath(ManualControllerRouteKey.MCP_ENDPOINT)}\\`, under the base URL of the environment you are connecting to.`;\n}\n\nfunction a2aAgentCardMarkdown(source: ApplicationConnectionDocumentationSource): string {\n if (!source.surfaces.a2aAgent) return `${source.applicationName} does not publish an agent card.`;\n return `${source.applicationName} publishes its agent card at \\`${publicRoutePath(ManualControllerRouteKey.A2A_AGENT_CARD)}\\` and accepts task calls at \\`${publicRoutePath(ManualControllerRouteKey.A2A_TASKS)}\\`, under the base URL of the environment you are connecting to.`;\n}\n\nfunction connectionDetailsMarkdown(source: ApplicationConnectionDocumentationSource): string {\n const rows: string[] = [];\n for (const server of source.apiServers) {\n rows.push(`| Base URL${server.description === undefined ? '' : ` (${server.description})`} | \\`${server.url}\\` |`);\n }\n rows.push(`| API mount | \\`${MAIN_API_BASE_PATH}\\` — every path in the API reference already includes it |`);\n if (source.surfaces.mcpToolServer) {\n rows.push(`| MCP endpoint | \\`${publicRoutePath(ManualControllerRouteKey.MCP_ENDPOINT)}\\` |`);\n }\n if (source.surfaces.a2aAgent) {\n rows.push(`| A2A agent card | \\`${publicRoutePath(ManualControllerRouteKey.A2A_AGENT_CARD)}\\` |`);\n rows.push(`| A2A task endpoint | \\`${publicRoutePath(ManualControllerRouteKey.A2A_TASKS)}\\` |`);\n }\n const table = `| What | Value |\\n| --- | --- |\\n${rows.join('\\n')}`;\n return source.apiServers.length > 0\n ? table\n : `${table}\\n\\nThis application publishes no base URL here; read it from the **Servers** list at the top of the API reference.`;\n}\n\n/**\n * The origin a sample should show. An application that publishes no base URL gets an explicit\n * stand-in rather than a fabricated host: the reader must substitute their own environment, and the\n * sample says so in the place where the value belongs.\n */\nfunction primaryBaseUrl(source: ApplicationConnectionDocumentationSource): string {\n const first = source.apiServers[0];\n return first === undefined ? 'https://your-environment.example' : first.url.replace(/\\/+$/, '');\n}\n\n/**\n * Projects the application's connection facts into the presentations a page may\n * request. Every presentation is a pure function of the source, so two runs over\n * the same application produce identical bytes.\n */\nexport function projectApplicationConnectionDocumentation(\n source: ApplicationConnectionDocumentationSource,\n): ApplicationConnectionDocumentationFact {\n const applicationName = source.applicationName.trim();\n if (applicationName.length === 0) throw new Error('application connection projection requires a customer-facing application name');\n for (const server of source.apiServers) {\n if (server.url.trim().length === 0) throw new Error('application connection projection received an empty base URL');\n }\n const named: ApplicationConnectionDocumentationSource = { ...source, applicationName };\n return {\n sourceRef: APPLICATION_CONNECTION_DOCUMENTATION_SOURCE_REF,\n sourceVersion: APPLICATION_CONNECTION_DOCUMENTATION_SOURCE_VERSION,\n applicationName,\n presentations: Object.freeze({\n [ApplicationConnectionPresentation.CONNECTION_DETAILS]: connectionDetailsMarkdown(named),\n [ApplicationConnectionPresentation.BASE_URLS]: baseUrlsMarkdown(named),\n [ApplicationConnectionPresentation.MCP_ENDPOINT]: mcpEndpointMarkdown(named),\n [ApplicationConnectionPresentation.A2A_AGENT_CARD]: a2aAgentCardMarkdown(named),\n }),\n inlineValues: Object.freeze({\n [ApplicationConnectionInlineValue.BASE_URL]: primaryBaseUrl(named),\n [ApplicationConnectionInlineValue.MCP_ENDPOINT_URL]: `${primaryBaseUrl(named)}${publicRoutePath(ManualControllerRouteKey.MCP_ENDPOINT)}`,\n [ApplicationConnectionInlineValue.AGENT_CARD_URL]: `${primaryBaseUrl(named)}${publicRoutePath(ManualControllerRouteKey.A2A_AGENT_CARD)}`,\n [ApplicationConnectionInlineValue.AGENT_TASK_URL]: `${primaryBaseUrl(named)}${publicRoutePath(ManualControllerRouteKey.A2A_TASKS)}`,\n [ApplicationConnectionInlineValue.SCIM_BASE_URL]: `${primaryBaseUrl(named)}${SCIM_SERVICE_BASE_PATH}`,\n [ApplicationConnectionInlineValue.OAUTH_ISSUER]: `${primaryBaseUrl(named)}${MAIN_API_BASE_PATH}`,\n [ApplicationConnectionInlineValue.OAUTH_METADATA_URL]: `${primaryBaseUrl(named)}${rfc8414AuthorizationServerMetadataPath(MAIN_API_BASE_PATH)}`,\n }),\n };\n}\n"]}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What THIS application is actually for.
|
|
3
|
+
*
|
|
4
|
+
* The documentation covered access, user administration, integrations, security and billing, and
|
|
5
|
+
* said nothing about the product. A Wonder Todos customer could learn how to verify a webhook
|
|
6
|
+
* signature before learning what a todo is — 104 published operations over the application's own
|
|
7
|
+
* domain and not one page about them. The content module stated the omission as policy, which is
|
|
8
|
+
* how it survived: a deliberate gap reads as a decision rather than a defect.
|
|
9
|
+
*
|
|
10
|
+
* Nothing here is authored per application, and nothing is inferred from a name. Every sentence
|
|
11
|
+
* comes from a source the application already accepted:
|
|
12
|
+
*
|
|
13
|
+
* | what the page says | where it comes from |
|
|
14
|
+
* | --- | --- |
|
|
15
|
+
* | which resources are the product's domain | the application's own resource registry, not the core map |
|
|
16
|
+
* | how they group, and what the group is called | `apiReferenceResourceCategories` in the app's tech-doc config |
|
|
17
|
+
* | what each resource IS | the resource specification's `purpose`, carried on its OpenAPI tag |
|
|
18
|
+
* | how it changes over time | the specification's lifecycle prose |
|
|
19
|
+
* | who may do what to it | the resolved role list on each operation |
|
|
20
|
+
*
|
|
21
|
+
* The application/core split is what keeps this page from restating the rest of the site. An
|
|
22
|
+
* application-owned resource has no framework page to belong to; a core one already has several.
|
|
23
|
+
*/
|
|
24
|
+
export declare const APPLICATION_DOMAIN_DOCUMENTATION_SOURCE_REF: "source:companion-projection:application-domain";
|
|
25
|
+
export declare const APPLICATION_DOMAIN_DOCUMENTATION_SOURCE_VERSION = 1;
|
|
26
|
+
export interface ApplicationDomainOperationSource {
|
|
27
|
+
readonly operationIdentifier: string;
|
|
28
|
+
/** The operation's own summary, when its specification authored one. */
|
|
29
|
+
readonly summary?: string;
|
|
30
|
+
/** Labels of the organization roles that may call it, in the application's own words. */
|
|
31
|
+
readonly roleLabels: readonly string[];
|
|
32
|
+
/** True when the operation declares no required role — a real state, said explicitly. */
|
|
33
|
+
readonly openToEveryMember: boolean;
|
|
34
|
+
/** The method a client sends, e.g. `POST`. */
|
|
35
|
+
readonly httpMethod?: string;
|
|
36
|
+
/** The mounted path a client sends it to, parameters and all. */
|
|
37
|
+
readonly path?: string;
|
|
38
|
+
/**
|
|
39
|
+
* One worked call, when the operation's specification authored one.
|
|
40
|
+
*
|
|
41
|
+
* A single example per RESOURCE reaches the page, not one per operation: the point is to show
|
|
42
|
+
* what this application's payloads look like, and twenty near-identical bodies would bury the
|
|
43
|
+
* page a reader came to for orientation. The API reference carries every operation's own.
|
|
44
|
+
*/
|
|
45
|
+
readonly example?: {
|
|
46
|
+
readonly title: string;
|
|
47
|
+
readonly request?: unknown;
|
|
48
|
+
readonly response?: unknown;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* One connection between this resource and another, as a page may state it.
|
|
53
|
+
*
|
|
54
|
+
* `cascade` is the part that had to be earned rather than read off. The framework's own
|
|
55
|
+
* `onParentDelete` lives under CHILD operations — it says what happens to the child when the
|
|
56
|
+
* parent is deleted — but the fact is copied onto BOTH sides of the relationship, so a row alone
|
|
57
|
+
* does not say which side this resource is on. Measured on a real application: the policy sits on
|
|
58
|
+
* a many-side row 36 times and on a shape that resolves neither way 51 times.
|
|
59
|
+
*
|
|
60
|
+
* So the companion resolves the direction where the cardinality settles it (the ONE side of a
|
|
61
|
+
* one-to-many is the parent, and the FK sits on the many side), and passes NOTHING where it does
|
|
62
|
+
* not. A page that told somebody their data survives a delete when it does not is the most
|
|
63
|
+
* expensive sentence this corpus could contain; an absent sentence costs a lookup.
|
|
64
|
+
*/
|
|
65
|
+
export interface ApplicationDomainRelationshipSource {
|
|
66
|
+
readonly relatedResourceIdentifier: string;
|
|
67
|
+
/** How many of the related thing participate, in consumer words. */
|
|
68
|
+
readonly relatedCardinalityWords: string;
|
|
69
|
+
/** What kind of link it is, in consumer words. */
|
|
70
|
+
readonly natureWords: string;
|
|
71
|
+
/** The field that carries the link, when one does. */
|
|
72
|
+
readonly foreignKeyField?: string;
|
|
73
|
+
/**
|
|
74
|
+
* What a delete does, stated only when the direction is unambiguous AND a cascade is enabled.
|
|
75
|
+
* Absent means "not stated here", never "nothing happens".
|
|
76
|
+
*/
|
|
77
|
+
readonly cascade?: string;
|
|
78
|
+
}
|
|
79
|
+
export interface ApplicationDomainResourceSource {
|
|
80
|
+
readonly resourceIdentifier: string;
|
|
81
|
+
/** The specification's `purpose`: what this thing IS, in the product's words. */
|
|
82
|
+
readonly purpose?: string;
|
|
83
|
+
/** The specification's account of how the resource changes over time. */
|
|
84
|
+
readonly lifecycleRole?: string;
|
|
85
|
+
readonly operations: readonly ApplicationDomainOperationSource[];
|
|
86
|
+
readonly relationships?: readonly ApplicationDomainRelationshipSource[];
|
|
87
|
+
}
|
|
88
|
+
export interface ApplicationDomainCategorySource {
|
|
89
|
+
readonly id: string;
|
|
90
|
+
/** The application's own name for this part of its domain, e.g. "Work management". */
|
|
91
|
+
readonly label: string;
|
|
92
|
+
readonly description?: string;
|
|
93
|
+
readonly resources: readonly ApplicationDomainResourceSource[];
|
|
94
|
+
}
|
|
95
|
+
export interface ApplicationDomainDocumentationSource {
|
|
96
|
+
readonly applicationName: string;
|
|
97
|
+
readonly categories: readonly ApplicationDomainCategorySource[];
|
|
98
|
+
}
|
|
99
|
+
/** Named presentations a page may request with `{{APPLICATION_DOMAIN:<selector>}}`. */
|
|
100
|
+
export declare enum ApplicationDomainPresentation {
|
|
101
|
+
/** One line per thing the application manages, grouped the way the application groups it. */
|
|
102
|
+
DOMAIN_OVERVIEW = "domainOverview",
|
|
103
|
+
/** Per resource: what it is, how it changes, and who may act on it. */
|
|
104
|
+
DOMAIN_RESOURCE_DETAILS = "domainResourceDetails"
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* One complete page about one resource, ready to become a published unit.
|
|
108
|
+
*
|
|
109
|
+
* The projection emits the whole page rather than a fragment because the unit set is VARIABLE —
|
|
110
|
+
* there is no authored Markdown for `todos` to carry a token, and there cannot be: the resources
|
|
111
|
+
* are the application's, and an engine that authored a page per possible resource would be
|
|
112
|
+
* authoring the application.
|
|
113
|
+
*/
|
|
114
|
+
export interface ApplicationDomainResourcePage {
|
|
115
|
+
readonly resourceIdentifier: string;
|
|
116
|
+
readonly title: string;
|
|
117
|
+
/** A complete page body: `# Title` followed by `##` sections, as the engine content parser expects. */
|
|
118
|
+
readonly markdown: string;
|
|
119
|
+
}
|
|
120
|
+
export interface ApplicationDomainDocumentationFact {
|
|
121
|
+
readonly sourceRef: string;
|
|
122
|
+
readonly sourceVersion: number;
|
|
123
|
+
readonly presentations: Readonly<Record<ApplicationDomainPresentation, string>>;
|
|
124
|
+
readonly resourcePages: readonly ApplicationDomainResourcePage[];
|
|
125
|
+
}
|
|
126
|
+
/** The route every generated resource page lives at, and the only place that shape is written. */
|
|
127
|
+
export declare function applicationDomainResourcePageSlug(resourceIdentifier: string): string;
|
|
128
|
+
/**
|
|
129
|
+
* Projects the application's own domain. A pure function of the source, so two runs over the same
|
|
130
|
+
* application produce identical bytes.
|
|
131
|
+
*/
|
|
132
|
+
export declare function projectApplicationDomainDocumentation(source: ApplicationDomainDocumentationSource): ApplicationDomainDocumentationFact;
|
|
133
|
+
//# sourceMappingURL=application-domain-documentation.d.ts.map
|
package/dist/esm/companion/application-documentation/application-domain-documentation.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"application-domain-documentation.d.ts","sourceRoot":"","sources":["../../../../../src/companion/application-documentation/application-domain-documentation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What THIS application is actually for.
|
|
3
|
+
*
|
|
4
|
+
* The documentation covered access, user administration, integrations, security and billing, and
|
|
5
|
+
* said nothing about the product. A Wonder Todos customer could learn how to verify a webhook
|
|
6
|
+
* signature before learning what a todo is — 104 published operations over the application's own
|
|
7
|
+
* domain and not one page about them. The content module stated the omission as policy, which is
|
|
8
|
+
* how it survived: a deliberate gap reads as a decision rather than a defect.
|
|
9
|
+
*
|
|
10
|
+
* Nothing here is authored per application, and nothing is inferred from a name. Every sentence
|
|
11
|
+
* comes from a source the application already accepted:
|
|
12
|
+
*
|
|
13
|
+
* | what the page says | where it comes from |
|
|
14
|
+
* | --- | --- |
|
|
15
|
+
* | which resources are the product's domain | the application's own resource registry, not the core map |
|
|
16
|
+
* | how they group, and what the group is called | `apiReferenceResourceCategories` in the app's tech-doc config |
|
|
17
|
+
* | what each resource IS | the resource specification's `purpose`, carried on its OpenAPI tag |
|
|
18
|
+
* | how it changes over time | the specification's lifecycle prose |
|
|
19
|
+
* | who may do what to it | the resolved role list on each operation |
|
|
20
|
+
*
|
|
21
|
+
* The application/core split is what keeps this page from restating the rest of the site. An
|
|
22
|
+
* application-owned resource has no framework page to belong to; a core one already has several.
|
|
23
|
+
*/
|
|
24
|
+
export const APPLICATION_DOMAIN_DOCUMENTATION_SOURCE_REF = 'source:companion-projection:application-domain';
|
|
25
|
+
export const APPLICATION_DOMAIN_DOCUMENTATION_SOURCE_VERSION = 1;
|
|
26
|
+
/** Named presentations a page may request with `{{APPLICATION_DOMAIN:<selector>}}`. */
|
|
27
|
+
export var ApplicationDomainPresentation;
|
|
28
|
+
(function (ApplicationDomainPresentation) {
|
|
29
|
+
/** One line per thing the application manages, grouped the way the application groups it. */
|
|
30
|
+
ApplicationDomainPresentation["DOMAIN_OVERVIEW"] = "domainOverview";
|
|
31
|
+
/** Per resource: what it is, how it changes, and who may act on it. */
|
|
32
|
+
ApplicationDomainPresentation["DOMAIN_RESOURCE_DETAILS"] = "domainResourceDetails";
|
|
33
|
+
})(ApplicationDomainPresentation || (ApplicationDomainPresentation = {}));
|
|
34
|
+
/**
|
|
35
|
+
* The sentence a page shows when an application publishes no domain of its own.
|
|
36
|
+
*
|
|
37
|
+
* Said explicitly rather than left blank, for the reason every empty inventory in this family is:
|
|
38
|
+
* a reader who sees nothing cannot tell an application that manages nothing through its API from
|
|
39
|
+
* documentation that failed to describe it.
|
|
40
|
+
*/
|
|
41
|
+
const NO_DOMAIN_MESSAGE = 'publishes no resources of its own through its API, so everything it exposes is described by the framework pages in this documentation.';
|
|
42
|
+
function whoMayAct(operation) {
|
|
43
|
+
if (operation.openToEveryMember)
|
|
44
|
+
return 'Any active member';
|
|
45
|
+
if (operation.roleLabels.length === 0)
|
|
46
|
+
return 'Not published for organization roles';
|
|
47
|
+
return operation.roleLabels.join(', ');
|
|
48
|
+
}
|
|
49
|
+
function domainOverviewMarkdown(source) {
|
|
50
|
+
if (source.categories.length === 0)
|
|
51
|
+
return `${source.applicationName} ${NO_DOMAIN_MESSAGE}`;
|
|
52
|
+
const blocks = source.categories.map((category) => {
|
|
53
|
+
const heading = category.description === undefined
|
|
54
|
+
? `### ${category.label}`
|
|
55
|
+
: `### ${category.label}\n\n${category.description}`;
|
|
56
|
+
const rows = category.resources
|
|
57
|
+
.map((resource) => {
|
|
58
|
+
// Linked, because each resource now HAS a page. The link text stays the API's own name so
|
|
59
|
+
// a reader can match it against a payload, an error message or the reference.
|
|
60
|
+
const name = `[\`${resource.resourceIdentifier}\`](/what-this-application-manages/${applicationDomainResourcePageSlug(resource.resourceIdentifier)})`;
|
|
61
|
+
return `| ${name} | ${resource.purpose ?? 'Not described by its specification.'} |`;
|
|
62
|
+
})
|
|
63
|
+
.join('\n');
|
|
64
|
+
return `${heading}\n\n| Resource | What it is |\n| --- | --- |\n${rows}`;
|
|
65
|
+
});
|
|
66
|
+
return `${blocks.join('\n\n')}\n\nEach name above is the one the API uses, so it is also what you will find in the API reference and in any tool or webhook payload that mentions it.`;
|
|
67
|
+
}
|
|
68
|
+
function domainResourceDetailsMarkdown(source) {
|
|
69
|
+
if (source.categories.length === 0)
|
|
70
|
+
return `${source.applicationName} ${NO_DOMAIN_MESSAGE}`;
|
|
71
|
+
const blocks = [];
|
|
72
|
+
for (const category of source.categories) {
|
|
73
|
+
for (const resource of category.resources) {
|
|
74
|
+
const lines = [`### \`${resource.resourceIdentifier}\``, ''];
|
|
75
|
+
if (resource.purpose !== undefined)
|
|
76
|
+
lines.push(resource.purpose, '');
|
|
77
|
+
if (resource.lifecycleRole !== undefined)
|
|
78
|
+
lines.push(resource.lifecycleRole, '');
|
|
79
|
+
if (resource.operations.length === 0) {
|
|
80
|
+
lines.push('This resource publishes no operations a client may call directly.');
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
lines.push('| Operation | What it does | Who may call it |', '| --- | --- | --- |');
|
|
84
|
+
for (const operation of resource.operations) {
|
|
85
|
+
lines.push(`| \`${operation.operationIdentifier}\` | ${operation.summary ?? '—'} | ${whoMayAct(operation)} |`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
blocks.push(lines.join('\n').trim());
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return `${blocks.join('\n\n')}\n\nA role higher in the inheritance chain can do everything the roles below it can, so a role that is not named here may still qualify through the role it includes. The API reference carries each operation's exact arguments and responses.`;
|
|
92
|
+
}
|
|
93
|
+
/** The route every generated resource page lives at, and the only place that shape is written. */
|
|
94
|
+
export function applicationDomainResourcePageSlug(resourceIdentifier) {
|
|
95
|
+
return resourceIdentifier;
|
|
96
|
+
}
|
|
97
|
+
function jsonBlock(label, value) {
|
|
98
|
+
return ['', `**${label}**`, '', '~~~json', JSON.stringify(value, null, 2), '~~~'];
|
|
99
|
+
}
|
|
100
|
+
function operationsTable(resource) {
|
|
101
|
+
if (resource.operations.length === 0) {
|
|
102
|
+
return ['This resource publishes no operations a client may call directly.'];
|
|
103
|
+
}
|
|
104
|
+
/*
|
|
105
|
+
* The `Send` column only appears when at least one operation resolved a method and a path. A
|
|
106
|
+
* column of dashes is worse than no column: it reads as "this cannot be called" rather than
|
|
107
|
+
* "this projection did not resolve it".
|
|
108
|
+
*/
|
|
109
|
+
const anyWire = resource.operations.some((operation) => operation.httpMethod !== undefined && operation.path !== undefined);
|
|
110
|
+
const columns = anyWire
|
|
111
|
+
? ['Operation', 'What it does', 'Send', 'Who may call it']
|
|
112
|
+
: ['Operation', 'What it does', 'Who may call it'];
|
|
113
|
+
const header = [`| ${columns.join(' | ')} |`, `| ${columns.map(() => '---').join(' | ')} |`];
|
|
114
|
+
const rows = resource.operations.map((operation) => {
|
|
115
|
+
const wire = operation.httpMethod !== undefined && operation.path !== undefined
|
|
116
|
+
? `\`${operation.httpMethod} ${operation.path}\``
|
|
117
|
+
: '—';
|
|
118
|
+
const cells = anyWire
|
|
119
|
+
? [`\`${operation.operationIdentifier}\``, operation.summary ?? '—', wire, whoMayAct(operation)]
|
|
120
|
+
: [`\`${operation.operationIdentifier}\``, operation.summary ?? '—', whoMayAct(operation)];
|
|
121
|
+
return `| ${cells.join(' | ')} |`;
|
|
122
|
+
});
|
|
123
|
+
return [...header, ...rows];
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Builds the page for one resource.
|
|
127
|
+
*
|
|
128
|
+
* Deliberately NOT a summary of the API reference. The reference answers "what are this
|
|
129
|
+
* operation's exact arguments"; this page answers "what is this thing, what can I do with it, and
|
|
130
|
+
* may I". So it carries the specification's own prose, one worked call, and a route onward — and
|
|
131
|
+
* refuses to restate field tables that would go stale the moment a schema moves.
|
|
132
|
+
*/
|
|
133
|
+
function resourcePageMarkdown(applicationName, category, resource, describedResourceIdentifiers) {
|
|
134
|
+
const lines = [`# ${resource.resourceIdentifier}`, ''];
|
|
135
|
+
lines.push(resource.purpose ?? `\`${resource.resourceIdentifier}\` is published by ${applicationName} under ${category.label}. Its specification authored no description, so this page can only show what the application exposes.`);
|
|
136
|
+
/*
|
|
137
|
+
* The purpose is the page's opening line, which the engine content parser reads as the unit
|
|
138
|
+
* SUMMARY — so it becomes the description in navigation and search, which is exactly what a
|
|
139
|
+
* one-line "what is this thing" belongs in. The lifecycle then gets its own section, under a
|
|
140
|
+
* heading that says what it actually answers.
|
|
141
|
+
*/
|
|
142
|
+
lines.push('', '## How it changes', '');
|
|
143
|
+
lines.push(resource.lifecycleRole ?? 'Its specification does not describe how it changes over time.');
|
|
144
|
+
lines.push('', '## What you can do', '', ...operationsTable(resource));
|
|
145
|
+
const relationships = resource.relationships ?? [];
|
|
146
|
+
if (relationships.length > 0) {
|
|
147
|
+
lines.push('', '## What it connects to', '');
|
|
148
|
+
const anyCascade = relationships.some((relationship) => relationship.cascade !== undefined);
|
|
149
|
+
const columns = anyCascade
|
|
150
|
+
? ['Related', 'How many', 'Link', 'Field', 'When something is deleted']
|
|
151
|
+
: ['Related', 'How many', 'Link', 'Field'];
|
|
152
|
+
lines.push(`| ${columns.join(' | ')} |`, `| ${columns.map(() => '---').join(' | ')} |`);
|
|
153
|
+
for (const relationship of relationships) {
|
|
154
|
+
/*
|
|
155
|
+
* Linked only when the related resource HAS a page. A domain resource usually relates
|
|
156
|
+
* outward as well — every one is organization-scoped, and many point at a user — and those
|
|
157
|
+
* facts belong on the page even though the framework, not this section, documents them.
|
|
158
|
+
* Dropping them was the first cut and it was wrong: Wonder CRM's `deal` relates to
|
|
159
|
+
* `organizations` and `users` and to none of its own resources, so an owned-only filter left
|
|
160
|
+
* the section empty on a resource that has two real connections.
|
|
161
|
+
*/
|
|
162
|
+
const name = describedResourceIdentifiers.has(relationship.relatedResourceIdentifier)
|
|
163
|
+
? `[\`${relationship.relatedResourceIdentifier}\`](/what-this-application-manages/${applicationDomainResourcePageSlug(relationship.relatedResourceIdentifier)})`
|
|
164
|
+
: `\`${relationship.relatedResourceIdentifier}\``;
|
|
165
|
+
const cells = [
|
|
166
|
+
name,
|
|
167
|
+
relationship.relatedCardinalityWords,
|
|
168
|
+
relationship.natureWords,
|
|
169
|
+
relationship.foreignKeyField === undefined ? '—' : `\`${relationship.foreignKeyField}\``,
|
|
170
|
+
];
|
|
171
|
+
if (anyCascade)
|
|
172
|
+
cells.push(relationship.cascade ?? 'Not stated here');
|
|
173
|
+
lines.push(`| ${cells.join(' | ')} |`);
|
|
174
|
+
}
|
|
175
|
+
if (anyCascade) {
|
|
176
|
+
lines.push('', 'An empty **When something is deleted** cell means this page does not state it, not that nothing happens — the relationship is one whose direction the documentation cannot resolve on its own. Check the operation contract before relying on a delete either way.');
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const exampleOperation = resource.operations.find((operation) => operation.example !== undefined);
|
|
180
|
+
if (exampleOperation?.example !== undefined) {
|
|
181
|
+
const { example } = exampleOperation;
|
|
182
|
+
lines.push('', `## Worked example: \`${exampleOperation.operationIdentifier}\``, '', example.title);
|
|
183
|
+
if (example.request !== undefined)
|
|
184
|
+
lines.push(...jsonBlock('Request', example.request));
|
|
185
|
+
if (example.response !== undefined)
|
|
186
|
+
lines.push(...jsonBlock('Response', example.response));
|
|
187
|
+
lines.push('', 'Identifiers and values above are illustrative; every field is defined in the API reference.');
|
|
188
|
+
}
|
|
189
|
+
lines.push('', '## Where to go next', '', '| You need to | Go to |', '| --- | --- |', '| The exact fields, arguments and responses | [API reference](/api) |', '| To call this from your own code | [Send your first API request](/integrations/rest/send-request) |', '| To be told when one changes | [Webhooks](/integrations/webhooks) |', `| Everything else this application manages | [What ${applicationName} manages](/what-this-application-manages) |`);
|
|
190
|
+
return lines.join('\n');
|
|
191
|
+
}
|
|
192
|
+
function resourcePages(source) {
|
|
193
|
+
// Exactly the resources this projection gives a page, which is what a link may point at.
|
|
194
|
+
const describedResourceIdentifiers = new Set(source.categories.flatMap((category) => category.resources.map((resource) => resource.resourceIdentifier)));
|
|
195
|
+
const pages = [];
|
|
196
|
+
for (const category of source.categories) {
|
|
197
|
+
for (const resource of category.resources) {
|
|
198
|
+
pages.push({
|
|
199
|
+
resourceIdentifier: resource.resourceIdentifier,
|
|
200
|
+
title: resource.resourceIdentifier,
|
|
201
|
+
markdown: resourcePageMarkdown(source.applicationName, category, resource, describedResourceIdentifiers),
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return pages;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Projects the application's own domain. A pure function of the source, so two runs over the same
|
|
209
|
+
* application produce identical bytes.
|
|
210
|
+
*/
|
|
211
|
+
export function projectApplicationDomainDocumentation(source) {
|
|
212
|
+
if (source.applicationName.trim().length === 0) {
|
|
213
|
+
throw new Error('application domain projection requires a customer-facing application name');
|
|
214
|
+
}
|
|
215
|
+
const seenResources = new Set();
|
|
216
|
+
for (const category of source.categories) {
|
|
217
|
+
if (category.label.trim().length === 0) {
|
|
218
|
+
throw new Error(`application domain projection received category '${category.id}' with no label`);
|
|
219
|
+
}
|
|
220
|
+
for (const resource of category.resources) {
|
|
221
|
+
if (resource.resourceIdentifier.trim().length === 0) {
|
|
222
|
+
throw new Error('application domain projection received a resource with no identifier');
|
|
223
|
+
}
|
|
224
|
+
// A resource belongs to exactly one part of the domain. Two categories claiming the same one
|
|
225
|
+
// would describe it twice with no way for a reader to tell which reading is current — and the
|
|
226
|
+
// config's own contract is that every published resource is listed exactly once.
|
|
227
|
+
if (seenResources.has(resource.resourceIdentifier)) {
|
|
228
|
+
throw new Error(`application domain projection received resource '${resource.resourceIdentifier}' in more than one category`);
|
|
229
|
+
}
|
|
230
|
+
seenResources.add(resource.resourceIdentifier);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return {
|
|
234
|
+
sourceRef: APPLICATION_DOMAIN_DOCUMENTATION_SOURCE_REF,
|
|
235
|
+
sourceVersion: APPLICATION_DOMAIN_DOCUMENTATION_SOURCE_VERSION,
|
|
236
|
+
presentations: Object.freeze({
|
|
237
|
+
[ApplicationDomainPresentation.DOMAIN_OVERVIEW]: domainOverviewMarkdown(source),
|
|
238
|
+
[ApplicationDomainPresentation.DOMAIN_RESOURCE_DETAILS]: domainResourceDetailsMarkdown(source),
|
|
239
|
+
}),
|
|
240
|
+
resourcePages: resourcePages(source),
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
//# sourceMappingURL=application-domain-documentation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"application-domain-documentation.js","sourceRoot":"","sources":["../../../../../src/companion/application-documentation/application-domain-documentation.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What THIS application is actually for.\n *\n * The documentation covered access, user administration, integrations, security and billing, and\n * said nothing about the product. A Wonder Todos customer could learn how to verify a webhook\n * signature before learning what a todo is — 104 published operations over the application's own\n * domain and not one page about them. The content module stated the omission as policy, which is\n * how it survived: a deliberate gap reads as a decision rather than a defect.\n *\n * Nothing here is authored per application, and nothing is inferred from a name. Every sentence\n * comes from a source the application already accepted:\n *\n * | what the page says | where it comes from |\n * | --- | --- |\n * | which resources are the product's domain | the application's own resource registry, not the core map |\n * | how they group, and what the group is called | `apiReferenceResourceCategories` in the app's tech-doc config |\n * | what each resource IS | the resource specification's `purpose`, carried on its OpenAPI tag |\n * | how it changes over time | the specification's lifecycle prose |\n * | who may do what to it | the resolved role list on each operation |\n *\n * The application/core split is what keeps this page from restating the rest of the site. An\n * application-owned resource has no framework page to belong to; a core one already has several.\n */\nexport const APPLICATION_DOMAIN_DOCUMENTATION_SOURCE_REF = 'source:companion-projection:application-domain' as const;\nexport const APPLICATION_DOMAIN_DOCUMENTATION_SOURCE_VERSION = 1;\n\nexport interface ApplicationDomainOperationSource {\n readonly operationIdentifier: string;\n /** The operation's own summary, when its specification authored one. */\n readonly summary?: string;\n /** Labels of the organization roles that may call it, in the application's own words. */\n readonly roleLabels: readonly string[];\n /** True when the operation declares no required role — a real state, said explicitly. */\n readonly openToEveryMember: boolean;\n /** The method a client sends, e.g. `POST`. */\n readonly httpMethod?: string;\n /** The mounted path a client sends it to, parameters and all. */\n readonly path?: string;\n /**\n * One worked call, when the operation's specification authored one.\n *\n * A single example per RESOURCE reaches the page, not one per operation: the point is to show\n * what this application's payloads look like, and twenty near-identical bodies would bury the\n * page a reader came to for orientation. The API reference carries every operation's own.\n */\n readonly example?: {\n readonly title: string;\n readonly request?: unknown;\n readonly response?: unknown;\n };\n}\n\n/**\n * One connection between this resource and another, as a page may state it.\n *\n * `cascade` is the part that had to be earned rather than read off. The framework's own\n * `onParentDelete` lives under CHILD operations — it says what happens to the child when the\n * parent is deleted — but the fact is copied onto BOTH sides of the relationship, so a row alone\n * does not say which side this resource is on. Measured on a real application: the policy sits on\n * a many-side row 36 times and on a shape that resolves neither way 51 times.\n *\n * So the companion resolves the direction where the cardinality settles it (the ONE side of a\n * one-to-many is the parent, and the FK sits on the many side), and passes NOTHING where it does\n * not. A page that told somebody their data survives a delete when it does not is the most\n * expensive sentence this corpus could contain; an absent sentence costs a lookup.\n */\nexport interface ApplicationDomainRelationshipSource {\n readonly relatedResourceIdentifier: string;\n /** How many of the related thing participate, in consumer words. */\n readonly relatedCardinalityWords: string;\n /** What kind of link it is, in consumer words. */\n readonly natureWords: string;\n /** The field that carries the link, when one does. */\n readonly foreignKeyField?: string;\n /**\n * What a delete does, stated only when the direction is unambiguous AND a cascade is enabled.\n * Absent means \"not stated here\", never \"nothing happens\".\n */\n readonly cascade?: string;\n}\n\nexport interface ApplicationDomainResourceSource {\n readonly resourceIdentifier: string;\n /** The specification's `purpose`: what this thing IS, in the product's words. */\n readonly purpose?: string;\n /** The specification's account of how the resource changes over time. */\n readonly lifecycleRole?: string;\n readonly operations: readonly ApplicationDomainOperationSource[];\n readonly relationships?: readonly ApplicationDomainRelationshipSource[];\n}\n\nexport interface ApplicationDomainCategorySource {\n readonly id: string;\n /** The application's own name for this part of its domain, e.g. \"Work management\". */\n readonly label: string;\n readonly description?: string;\n readonly resources: readonly ApplicationDomainResourceSource[];\n}\n\nexport interface ApplicationDomainDocumentationSource {\n readonly applicationName: string;\n readonly categories: readonly ApplicationDomainCategorySource[];\n}\n\n/** Named presentations a page may request with `{{APPLICATION_DOMAIN:<selector>}}`. */\nexport enum ApplicationDomainPresentation {\n /** One line per thing the application manages, grouped the way the application groups it. */\n DOMAIN_OVERVIEW = 'domainOverview',\n /** Per resource: what it is, how it changes, and who may act on it. */\n DOMAIN_RESOURCE_DETAILS = 'domainResourceDetails',\n}\n\n/**\n * One complete page about one resource, ready to become a published unit.\n *\n * The projection emits the whole page rather than a fragment because the unit set is VARIABLE —\n * there is no authored Markdown for `todos` to carry a token, and there cannot be: the resources\n * are the application's, and an engine that authored a page per possible resource would be\n * authoring the application.\n */\nexport interface ApplicationDomainResourcePage {\n readonly resourceIdentifier: string;\n readonly title: string;\n /** A complete page body: `# Title` followed by `##` sections, as the engine content parser expects. */\n readonly markdown: string;\n}\n\nexport interface ApplicationDomainDocumentationFact {\n readonly sourceRef: string;\n readonly sourceVersion: number;\n readonly presentations: Readonly<Record<ApplicationDomainPresentation, string>>;\n readonly resourcePages: readonly ApplicationDomainResourcePage[];\n}\n\n/**\n * The sentence a page shows when an application publishes no domain of its own.\n *\n * Said explicitly rather than left blank, for the reason every empty inventory in this family is:\n * a reader who sees nothing cannot tell an application that manages nothing through its API from\n * documentation that failed to describe it.\n */\nconst NO_DOMAIN_MESSAGE = 'publishes no resources of its own through its API, so everything it exposes is described by the framework pages in this documentation.';\n\nfunction whoMayAct(operation: ApplicationDomainOperationSource): string {\n if (operation.openToEveryMember) return 'Any active member';\n if (operation.roleLabels.length === 0) return 'Not published for organization roles';\n return operation.roleLabels.join(', ');\n}\n\nfunction domainOverviewMarkdown(source: ApplicationDomainDocumentationSource): string {\n if (source.categories.length === 0) return `${source.applicationName} ${NO_DOMAIN_MESSAGE}`;\n const blocks = source.categories.map((category) => {\n const heading = category.description === undefined\n ? `### ${category.label}`\n : `### ${category.label}\\n\\n${category.description}`;\n const rows = category.resources\n .map((resource) => {\n // Linked, because each resource now HAS a page. The link text stays the API's own name so\n // a reader can match it against a payload, an error message or the reference.\n const name = `[\\`${resource.resourceIdentifier}\\`](/what-this-application-manages/${applicationDomainResourcePageSlug(resource.resourceIdentifier)})`;\n return `| ${name} | ${resource.purpose ?? 'Not described by its specification.'} |`;\n })\n .join('\\n');\n return `${heading}\\n\\n| Resource | What it is |\\n| --- | --- |\\n${rows}`;\n });\n return `${blocks.join('\\n\\n')}\\n\\nEach name above is the one the API uses, so it is also what you will find in the API reference and in any tool or webhook payload that mentions it.`;\n}\n\nfunction domainResourceDetailsMarkdown(source: ApplicationDomainDocumentationSource): string {\n if (source.categories.length === 0) return `${source.applicationName} ${NO_DOMAIN_MESSAGE}`;\n const blocks: string[] = [];\n for (const category of source.categories) {\n for (const resource of category.resources) {\n const lines = [`### \\`${resource.resourceIdentifier}\\``, ''];\n if (resource.purpose !== undefined) lines.push(resource.purpose, '');\n if (resource.lifecycleRole !== undefined) lines.push(resource.lifecycleRole, '');\n if (resource.operations.length === 0) {\n lines.push('This resource publishes no operations a client may call directly.');\n } else {\n lines.push('| Operation | What it does | Who may call it |', '| --- | --- | --- |');\n for (const operation of resource.operations) {\n lines.push(`| \\`${operation.operationIdentifier}\\` | ${operation.summary ?? '—'} | ${whoMayAct(operation)} |`);\n }\n }\n blocks.push(lines.join('\\n').trim());\n }\n }\n return `${blocks.join('\\n\\n')}\\n\\nA role higher in the inheritance chain can do everything the roles below it can, so a role that is not named here may still qualify through the role it includes. The API reference carries each operation's exact arguments and responses.`;\n}\n\n/** The route every generated resource page lives at, and the only place that shape is written. */\nexport function applicationDomainResourcePageSlug(resourceIdentifier: string): string {\n return resourceIdentifier;\n}\n\nfunction jsonBlock(label: string, value: unknown): string[] {\n return ['', `**${label}**`, '', '~~~json', JSON.stringify(value, null, 2), '~~~'];\n}\n\nfunction operationsTable(resource: ApplicationDomainResourceSource): string[] {\n if (resource.operations.length === 0) {\n return ['This resource publishes no operations a client may call directly.'];\n }\n /*\n * The `Send` column only appears when at least one operation resolved a method and a path. A\n * column of dashes is worse than no column: it reads as \"this cannot be called\" rather than\n * \"this projection did not resolve it\".\n */\n const anyWire = resource.operations.some((operation) => operation.httpMethod !== undefined && operation.path !== undefined);\n const columns = anyWire\n ? ['Operation', 'What it does', 'Send', 'Who may call it']\n : ['Operation', 'What it does', 'Who may call it'];\n const header = [`| ${columns.join(' | ')} |`, `| ${columns.map(() => '---').join(' | ')} |`];\n const rows = resource.operations.map((operation) => {\n const wire = operation.httpMethod !== undefined && operation.path !== undefined\n ? `\\`${operation.httpMethod} ${operation.path}\\``\n : '—';\n const cells = anyWire\n ? [`\\`${operation.operationIdentifier}\\``, operation.summary ?? '—', wire, whoMayAct(operation)]\n : [`\\`${operation.operationIdentifier}\\``, operation.summary ?? '—', whoMayAct(operation)];\n return `| ${cells.join(' | ')} |`;\n });\n return [...header, ...rows];\n}\n\n/**\n * Builds the page for one resource.\n *\n * Deliberately NOT a summary of the API reference. The reference answers \"what are this\n * operation's exact arguments\"; this page answers \"what is this thing, what can I do with it, and\n * may I\". So it carries the specification's own prose, one worked call, and a route onward — and\n * refuses to restate field tables that would go stale the moment a schema moves.\n */\nfunction resourcePageMarkdown(\n applicationName: string,\n category: ApplicationDomainCategorySource,\n resource: ApplicationDomainResourceSource,\n describedResourceIdentifiers: ReadonlySet<string>,\n): string {\n const lines: string[] = [`# ${resource.resourceIdentifier}`, ''];\n lines.push(resource.purpose ?? `\\`${resource.resourceIdentifier}\\` is published by ${applicationName} under ${category.label}. Its specification authored no description, so this page can only show what the application exposes.`);\n /*\n * The purpose is the page's opening line, which the engine content parser reads as the unit\n * SUMMARY — so it becomes the description in navigation and search, which is exactly what a\n * one-line \"what is this thing\" belongs in. The lifecycle then gets its own section, under a\n * heading that says what it actually answers.\n */\n lines.push('', '## How it changes', '');\n lines.push(resource.lifecycleRole ?? 'Its specification does not describe how it changes over time.');\n lines.push('', '## What you can do', '', ...operationsTable(resource));\n\n const relationships = resource.relationships ?? [];\n if (relationships.length > 0) {\n lines.push('', '## What it connects to', '');\n const anyCascade = relationships.some((relationship) => relationship.cascade !== undefined);\n const columns = anyCascade\n ? ['Related', 'How many', 'Link', 'Field', 'When something is deleted']\n : ['Related', 'How many', 'Link', 'Field'];\n lines.push(`| ${columns.join(' | ')} |`, `| ${columns.map(() => '---').join(' | ')} |`);\n for (const relationship of relationships) {\n /*\n * Linked only when the related resource HAS a page. A domain resource usually relates\n * outward as well — every one is organization-scoped, and many point at a user — and those\n * facts belong on the page even though the framework, not this section, documents them.\n * Dropping them was the first cut and it was wrong: Wonder CRM's `deal` relates to\n * `organizations` and `users` and to none of its own resources, so an owned-only filter left\n * the section empty on a resource that has two real connections.\n */\n const name = describedResourceIdentifiers.has(relationship.relatedResourceIdentifier)\n ? `[\\`${relationship.relatedResourceIdentifier}\\`](/what-this-application-manages/${applicationDomainResourcePageSlug(relationship.relatedResourceIdentifier)})`\n : `\\`${relationship.relatedResourceIdentifier}\\``;\n const cells = [\n name,\n relationship.relatedCardinalityWords,\n relationship.natureWords,\n relationship.foreignKeyField === undefined ? '—' : `\\`${relationship.foreignKeyField}\\``,\n ];\n if (anyCascade) cells.push(relationship.cascade ?? 'Not stated here');\n lines.push(`| ${cells.join(' | ')} |`);\n }\n if (anyCascade) {\n lines.push(\n '',\n 'An empty **When something is deleted** cell means this page does not state it, not that nothing happens — the relationship is one whose direction the documentation cannot resolve on its own. Check the operation contract before relying on a delete either way.',\n );\n }\n }\n\n const exampleOperation = resource.operations.find((operation) => operation.example !== undefined);\n if (exampleOperation?.example !== undefined) {\n const { example } = exampleOperation;\n lines.push('', `## Worked example: \\`${exampleOperation.operationIdentifier}\\``, '', example.title);\n if (example.request !== undefined) lines.push(...jsonBlock('Request', example.request));\n if (example.response !== undefined) lines.push(...jsonBlock('Response', example.response));\n lines.push('', 'Identifiers and values above are illustrative; every field is defined in the API reference.');\n }\n\n lines.push(\n '',\n '## Where to go next',\n '',\n '| You need to | Go to |',\n '| --- | --- |',\n '| The exact fields, arguments and responses | [API reference](/api) |',\n '| To call this from your own code | [Send your first API request](/integrations/rest/send-request) |',\n '| To be told when one changes | [Webhooks](/integrations/webhooks) |',\n `| Everything else this application manages | [What ${applicationName} manages](/what-this-application-manages) |`,\n );\n return lines.join('\\n');\n}\n\nfunction resourcePages(source: ApplicationDomainDocumentationSource): ApplicationDomainResourcePage[] {\n // Exactly the resources this projection gives a page, which is what a link may point at.\n const describedResourceIdentifiers = new Set(\n source.categories.flatMap((category) => category.resources.map((resource) => resource.resourceIdentifier)),\n );\n const pages: ApplicationDomainResourcePage[] = [];\n for (const category of source.categories) {\n for (const resource of category.resources) {\n pages.push({\n resourceIdentifier: resource.resourceIdentifier,\n title: resource.resourceIdentifier,\n markdown: resourcePageMarkdown(source.applicationName, category, resource, describedResourceIdentifiers),\n });\n }\n }\n return pages;\n}\n\n/**\n * Projects the application's own domain. A pure function of the source, so two runs over the same\n * application produce identical bytes.\n */\nexport function projectApplicationDomainDocumentation(\n source: ApplicationDomainDocumentationSource,\n): ApplicationDomainDocumentationFact {\n if (source.applicationName.trim().length === 0) {\n throw new Error('application domain projection requires a customer-facing application name');\n }\n const seenResources = new Set<string>();\n for (const category of source.categories) {\n if (category.label.trim().length === 0) {\n throw new Error(`application domain projection received category '${category.id}' with no label`);\n }\n for (const resource of category.resources) {\n if (resource.resourceIdentifier.trim().length === 0) {\n throw new Error('application domain projection received a resource with no identifier');\n }\n // A resource belongs to exactly one part of the domain. Two categories claiming the same one\n // would describe it twice with no way for a reader to tell which reading is current — and the\n // config's own contract is that every published resource is listed exactly once.\n if (seenResources.has(resource.resourceIdentifier)) {\n throw new Error(`application domain projection received resource '${resource.resourceIdentifier}' in more than one category`);\n }\n seenResources.add(resource.resourceIdentifier);\n }\n }\n return {\n sourceRef: APPLICATION_DOMAIN_DOCUMENTATION_SOURCE_REF,\n sourceVersion: APPLICATION_DOMAIN_DOCUMENTATION_SOURCE_VERSION,\n presentations: Object.freeze({\n [ApplicationDomainPresentation.DOMAIN_OVERVIEW]: domainOverviewMarkdown(source),\n [ApplicationDomainPresentation.DOMAIN_RESOURCE_DETAILS]: domainResourceDetailsMarkdown(source),\n }),\n resourcePages: resourcePages(source),\n };\n}\n"]}
|
package/dist/esm/companion/application-documentation/application-integration-documentation.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"application-integration-documentation.d.ts","sourceRoot":"","sources":["../../../../../src/companion/application-documentation/application-integration-documentation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,gDAAgD,EAAG,qDAA8D,CAAC;AAC/H,eAAO,MAAM,oDAAoD,IAAI,CAAC;AAEtE,MAAM,WAAW,wBAAwB;IACvC,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;CACtC;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,kFAAkF;IAClF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,yCAAyC;IACxD,QAAQ,CAAC,QAAQ,EAAE,SAAS,wBAAwB,EAAE,CAAC;IACvD,QAAQ,CAAC,aAAa,EAAE,SAAS,6BAA6B,EAAE,CAAC;CAClE;AAED,4FAA4F;AAC5F,oBAAY,kCAAkC;IAC5C,4DAA4D;IAC5D,SAAS,aAAa;IACtB,2EAA2E;IAC3E,cAAc,kBAAkB;CACjC;AAED,MAAM,WAAW,uCAAuC;IACtD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,kCAAkC,EAAE,MAAM,CAAC,CAAC,CAAC;CACtF;AAsBD;;;GAGG;AACH,wBAAgB,0CAA0C,CACxD,MAAM,EAAE,yCAAyC,GAChD,uCAAuC,
|
|
1
|
+
{"version":3,"file":"application-integration-documentation.d.ts","sourceRoot":"","sources":["../../../../../src/companion/application-documentation/application-integration-documentation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,gDAAgD,EAAG,qDAA8D,CAAC;AAC/H,eAAO,MAAM,oDAAoD,IAAI,CAAC;AAEtE,MAAM,WAAW,wBAAwB;IACvC,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;CACtC;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,kFAAkF;IAClF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,yCAAyC;IACxD,QAAQ,CAAC,QAAQ,EAAE,SAAS,wBAAwB,EAAE,CAAC;IACvD,QAAQ,CAAC,aAAa,EAAE,SAAS,6BAA6B,EAAE,CAAC;CAClE;AAED,4FAA4F;AAC5F,oBAAY,kCAAkC;IAC5C,4DAA4D;IAC5D,SAAS,aAAa;IACtB,2EAA2E;IAC3E,cAAc,kBAAkB;CACjC;AAED,MAAM,WAAW,uCAAuC;IACtD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,kCAAkC,EAAE,MAAM,CAAC,CAAC,CAAC;CACtF;AAsBD;;;GAGG;AACH,wBAAgB,0CAA0C,CACxD,MAAM,EAAE,yCAAyC,GAChD,uCAAuC,CAsCzC"}
|