Repository navigation
feat(connector-docusign): DocuSign eSignature connector app over the installer's OAuth client, sandbox first - #29813
Conversation
…installer's OAuth client A declarative `openapi` instance over DocuSign's eSignature document, trimmed offline to three envelope operations, authorized by OAuth 2.0 `authorization_code` with `clientSource: 'installer'` (no client of anyone's in the package), sandbox first; an envelope object and three flows (send, get, poll status changes in place of Connect callbacks). Claude-Session: https://claude.ai/code/session_01JQwxbX1cvwSxDEYCkfDcLg Co-Authored-By: Claude <noreply@anthropic.com>
… README and test tightening Claude-Session: https://claude.ai/code/session_01JQwxbX1cvwSxDEYCkfDcLg Co-Authored-By: Claude <noreply@anthropic.com>
…onnector-stripe does Claude-Session: https://claude.ai/code/session_01JQwxbX1cvwSxDEYCkfDcLg Co-Authored-By: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 65 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 13 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 66b4ddcad6b548235855a5615ab9d6b5dec66699 && git checkout 66b4ddcad6b548235855a5615ab9d6b5dec66699
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin b0ef25f524b870433424b8ad797ef3801374f745 a7e2abd1d461730ee8da94e6cebbc3c06aa8d5ff && git checkout -B drift-repro b0ef25f524b870433424b8ad797ef3801374f745 && git merge --no-ff a7e2abd1d461730ee8da94e6cebbc3c06aa8d5ff
node scripts/docs-audit/affected-docs.mjs --json b0ef25f524b870433424b8ad797ef3801374f745
|
…listings out An app package with an `objectstack.manifest.json` listing at its root is installed like a third-party app; its objects are its own, not platform-provided. The scan now keys the exclusion on that file (the platform apps under packages/apps carry none and stay scanned), pins it, and refuses a listing that declares a platform-prefixed object. Claude-Session: https://claude.ai/code/session_01JQwxbX1cvwSxDEYCkfDcLg Co-Authored-By: Claude <noreply@anthropic.com>
|
domain:server#2 · os-warren · session_01JQwxbXKRzgnVvjzxaYxLUf 维护者速读
席位核对ACCEPT ·
|
Requested by Warren · project thread
Fixes #28277
Clause-②: no
Metadata-protocol: none
维护者速读
packages/apps/connector-docusign(仿connector-stripe):DocuSign 电子签的openapi连接器(只含建信封、读信封、列状态变更三个操作)、docusign_envelope对象及其列表视图、三个流程(发送、刷新单个信封、轮询状态变更)、上架清单、README 与测试。clientIdis fixed by the package and the redirect URI is per deployment #28702 裁决 B 落地后(spec: anoauth2authorization_codeinstance takes its OAuth client from the installer (a per-connection client record), not a packagedclientId— ADR-0143 D2.1 amendment (#28702 B) #28864/automation: asys_connector_connectionstores and uses the installer-supplied OAuth client for anauthorization_codeinstance (#28702 B, server slice) #28866/console: the connector connection form asks the administrator for the OAuth client (client id + secret) when the instance takes an installer-supplied client (#28702 B, ui slice) #28869),OAuth 客户端由每个部署的管理员自己注册并在连接时填入;本包用clientSource: 'installer',仓库里没有任何人的 clientId 或密钥,先走沙箱。private: true),不改平台代码、不改任何已发布键;回滚即 revert。实时沙箱往返未测(本容器网络策略拒绝 DocuSign 沙箱主机),欠验收运行。src/connectors/docusign.connector.ts的auth(无 clientId、无 credentialRef);②test/boot.test.ts的连接用例(管理员客户端 → 授权 URL → 回调换码);③ README 的 Credentials 与 Callbacks 两节。pnpm --filter @objectstack/connector-app-docusign test,预期objectstack validate通过且 2 个测试文件 27 个用例全绿。What changes
A new npm-private metadata package,
@objectstack/connector-app-docusigninpackages/apps/connector-docusign, laid out likepackages/apps/connector-stripe:openapi/docusign-esignature.openapi.json: DocuSign's eSignature document (docusign/OpenAPI-Specificationsesignature.rest.swagger-v2.1.jsonat858a3ae59b0edbc8beea4fa3a6d7fe803833dd68, MIT, licence notice inopenapi/LICENSE), converted from Swagger 2.0 and trimmed offline bynormalize-openapitoEnvelopes_PostEnvelopes,Envelopes_GetEnvelopeandEnvelopes_GetEnvelopes, with the 187 emptyconsumeslists filled (--empty-consumes application/json). The README's Provenance section records the command, the printed figures and the sha256 the listing test recomputes.src/connectors/docusign.connector.ts: a declarativeprovider: 'openapi'instance nameddocusign.providerConfig.baseUrlpoints it at the sandbox API host (https://demo.docusign.net/restapi), andincludenames the three operations.authisoauth2authorization_codeagainstaccount-d.docusign.comwithscopes: ['signature']andclientSource: 'installer'. NoclientIdand nocredentialRef: per ruling 6566728470 (letter B), the administrator of each deployment registers their own DocuSign integration key against that deployment's redirect URI and enters it on the connection. No key value is in the repository.src/objects/docusign-envelope.object.tsandsrc/views/docusign-envelope.view.ts:docusign_envelopewith the two fields the skill eval names,envelope_idandsignature_status, plusemail_subjectandstatus_changed_at, and one grid list view.src/flows/docusign.flows.ts:docusign_send_envelope(create and send one envelope, record it only when DocuSign accepted it),docusign_get_envelope(read one envelope, refresh its record), anddocusign_poll_status_changes(list changes sincefrom_date, copy each status onto its record; each update contained in atry_catch).objectstack.manifest.jsonwith aniconUrlat the package's ownassets/icon.svg,README.md(what it adds, credentials, running it, callbacks, limits, provenance), andtest/listing.test.tsplustest/boot.test.ts.pnpm-lock.yaml, regenerated bypnpm installonly. Besides the new importer, pnpm re-recordedknex@3.3.0's optional peers (mysql2,pg,tedious, already in the lock) on its two importers. Apnpm install --lockfile-onlyon cleanorigin/mainf87239aechanges nothing, while the same command with this importer added writes exactly this diff, so the peer re-resolution is pnpm's own response to the importer set changing.packages/spec/src/system/constants/platform-object-names.test.ts: the platform-object registry scan now leaves out installable app listings (a package root carryingobjectstack.manifest.json), with two pin cases: the exclusion keys on the listing file and nothing broader (a lit control seesdocusign_envelopeand keeps it out), and an installable listing may declare no platform-prefixed object. The platform apps underpackages/apps(account,setup,studio) carry no listing and stay scanned. Nothing is added toPLATFORM_OBJECTS_BY_PACKAGE; the file is outside spec'sfiles[], soskip-changesetstill holds.No changeset: the package is
private: trueand publishes nothing, so this PR carriesskip-changeset.Why
#28277 is E4 batch 2 of #27293: DocuSign as the first declarative verification of the outbound OAuth path. Its blocker was the OAuth client. A packaged
clientIdworks only on deployments whose callback the client's owner registered (report 6559204204). Ruling 6566728470 chose letter B, executed as #28864 (spec,clientSource: 'installer'onConnectorInstanceOAuth2AuthorizationCodeAuthSchema,packages/spec/src/shared/connector-auth.zod.ts), #28866 (server:installerClientOfBeginandkeptInstallerClientinpackages/services/service-automation/src/plugin.ts,takesInstallerClientinoauth2-grant/installer-client.ts) and #28869 (the Console's Connect dialog). This package is the first listing on that shape.Tests
pnpm --filter @objectstack/connector-app-docusign testat headd9a09f83:objectstack validateexit 0 (1 object, 4 fields, 1 view, 3 flows, no warning), then vitestTest Files 2 passed (2),Tests 27 passed (27)(lockVERDICT command-exit 0).pnpm --filter @objectstack/connector-app-docusign typecheckexit 0.test/listing.test.ts(17): the manifest parses againstTemplateManifestSchema, names the stack id and an owned http(s) icon; the connector'sauthis exactly the installer-client shape and parses againstDeclarativeConnectorEntrySchema; no file the package owns (outside DocuSign's document) carries a GUID-shaped value; the README's Credentials and Callbacks sections name the redirect URI path, the connection door and the poll flow; the packaged document's sha256 equals the README's record, it is OpenAPI 3.x with no security scheme, carries exactly the three included operations, and givesEnvelopes_PostEnvelopesa JSON body.test/boot.test.ts(10): booted withbootStackagainst a fake DocuSign (the API throughConnectorOpenApiPlugin'sfetchImpl, the sandbox token endpoint through afetchstub). Before a connect the instance is degraded "not connected" and the connection read answersredirectUri; a flow run failsFLOW_FAILEDnaming the connector and sends nothing; a connect naming no client is refused400 VALIDATION_ERRORnaming the vendor registration step and the redirect URI; a connect with the administrator's integration key sends the browser toaccount-d.docusign.com/oauth/authas that client (scope=signature,code_challenge_method=S256), the callback exchanges the code in HTTP Basic as that client, and the read shows the client without its secret; the instance then materializes with exactly the three actions; the three flows send the expected requests todemo.docusign.netas the bearer of the connection's token and write or refresh the record; a refused envelope writes no record.pnpm --filter @objectstack/spec test:repoat heada7e2abd1: 89 files and 1524 tests passed. Reverse verification: the pre-fixplatform-object-names.test.tsfails 1 of 12 on this tree with the CI message; the fixed file passes 14 of 14.No other ablation: the rest of the diff adds a package and changes no tested behaviour of existing code.
Acceptance notes
curl https://account-d.docusign.com/.well-known/openid-configurationfrom this container: the egress proxy answered the CONNECT with403 Forbidden(demo.docusign.net and developers.docusign.com: no answer either). No integration key exists for this repository either, by design. The DocuSign console steps in the README follow DocuSign's documentation and say so.--max-depth 0(304,080 bytes, sha256b741ded5cfc4d0291d7f0e26559f8583f8c9a783f8711d8f9a98405cb27f7cb4, 1,438 lines), asconnector-stripedoes. At the default depth of 2 the same run writes 553,922 bytes, sha256e1051eb4bbc381d879e979beac8cb64ead24531c93a19fc26e950a12d9fc961d(the epic probe's hash, re-derived here independently), 4,737 lines, which takes this PR to 6,130 changed lines, over the 3,000-line human-merge threshold. At depth 0 the PR is 2,841 changed lines. The cost:Envelopes_PostEnvelopes's body is described as DocuSign's envelope definition (type and description) rather than with its fields expanded. Switching is one normalizer run plus the README figures and one listing-test assertion.account.docusign.comand has a per-account API host (base_urifrom/oauth/userinfo) that a packaged instance cannot name; the README's Limits section says production is not supported yet. No follow-up card is filed here.apiflow door does not verify, so the app takes no Connect posts and polls instead (docusign_poll_status_changes); the README says so.dyn(…)at every nesting level;os validaterefused the first draft that wrapped only the top level (expression-invalid, "Map value uses wrong type"). The Stripe README already states the rule for the top level.Verification
node scripts/check-package-naming.mjs: exit 0 (129 workspace package(s), the@objectstack/plugin-*set exactly the 10 frozen names; this package is@objectstack/connector-app-docusign, besideconnector-app-stripeandconnector-app-github).node scripts/pm/dispatch-gates.mjs --commandson this diff at heada7e2abd1derived 85 families; all 85 ran, every one exit 0 (four spec dist gates re-run after a spec build);--ranreconciliation: 85 run, 0 NOT-MEASURED. Changed lines: 2923.pnpm lint(eslint . --no-inline-config): exit 0 (ond9a09f83; the patch round changes one test file).Human Minimum
packages/specholds no runtime logic. (No spec change.)pnpm lintpasses.main, one pull request.skip-changeset.)packages/spectouched: its generated artifacts are regenerated and committed. (Not touched.)content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.🤖 Generated with Claude Code
https://claude.ai/code/session_01JQwxbX1cvwSxDEYCkfDcLg
Generated by Claude Code