You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit fa9836b
Browse filesBrowse the repository at this point in the historyBrowse files
fix(setup): metadata lists under Setup take their title from the sidebar, lead with the label, and keep rows short
6
+
7
+
Clause-②: no
8
+
Metadata-protocol: none
9
+
10
+
A metadata list under Setup (Positions, Permission Sets and the other catalog pages) titled itself with the type's singular label ("Position"), led each row with the API name, and let a long description wrap a row to several lines on a phone. Under Setup the page now takes its title from the app's own navigation entry that opens it, so it reads as the sidebar row that opened it ("Positions", in the served language), and falls back to the type's label when no entry opens exactly that page. Each row leads with the item's label, with its API name beneath it in small monospace type, in place of a separate Label column; an item with no label keeps its API name as the link. A description shows two lines at most, with the whole text on hover. The same page outside Setup is unchanged.
feat(spec): a form view's thank-you panel is translated through `objects.OBJECT._views.VIEW.submitBehavior.title` / `.message`
8
+
9
+
Clause-②: yes
10
+
Metadata-protocol: added
11
+
12
+
A form whose `submitBehavior` is `{ kind: 'thank-you', title, message }` used to confirm a submit in the authoring language only: the strict `_views` translation entry declared no key for the panel, and `translateView` never read `config.submitBehavior`. A public form read in another language showed a translated heading and field labels, then a source-language confirmation.
13
+
14
+
-**The key.**`objects.OBJECT._views.VIEW.submitBehavior` takes `title` and `message`, nested the way the authored copy is nested, so the panel's heading never shares a key with the form's own `title`. A `thankYou` key is refused naming `submitBehavior`, and `url` / `kind` are refused with a prescription, since neither is display copy.
15
+
-**The overlay.**`translateView` overlays the two strings onto the served form's `config.submitBehavior`, on the same locale chain and under the same rule as the form's `title`: only a `kind: 'thank-you'` panel is translated, only copy the form authors (a key cannot invent a `message` the form left to the console's default), a missing key keeps the authored string, and a string edited on top of the packaged view keeps the edit (ADR-0029 D9.2a, judged per string). The anonymous `GET /api/v1/forms/SLUG` already serves the translated view config under `Accept-Language`, so a public form's visitor now reads the panel in their language with no client change.
16
+
-**Extraction and coverage.**`os i18n extract` scaffolds `_views.VIEW.submitBehavior.title` / `.message` for every form a view container serves and for a `viewKind: 'form'` item, keyed by its runtime identity, and the coverage report counts an authored panel a supported locale leaves untranslated.
17
+
-**Lint.**`os lint` accepts a `submitBehavior` key on exactly the views a `title` key is legal on (a named form view, the default form, a form item) and refuses one over a list view.
An upstream that takes no static credential (an OAuth 2.0 API, a Feishu, DingTalk or WeCom app) had no open-tier way to be declared: the instance `auth` stopped at four static kinds, and the runtime `authentication` shape had an `oauth2` variant that held a client secret and a refresh token inline and that nothing ran. ADR-0143 opens the grant-bearing kinds on the instance, with the secret as a reference.
15
+
16
+
- **`@objectstack/spec`**: `ConnectorInstanceAuthSchema` gains `oauth2` (D2.1), one strict shape per `grant` (`authorization_code` with PKCE always on, `client_credentials` for a confidential client), and `app-credential` (D2.2, `vendor` `feishu` / `dingtalk` / `wecom`, `appId`, a required `credentialRef`). The publish door refuses a missing `tokenUrl`, `clientId` or `authorizationUrl` at its key under `auth`, except on `provider: 'mcp'` over `http`, where the MCP authorization flow discovers them. An inline `clientSecret`, `refreshToken`, `accessToken` or `appSecret` is refused by name with the `credentialRef` prescription. `signed` is not a member (#26710). `ConnectorOAuth2Schema` is removed from `ConnectorAuthConfigSchema` (D7), and `ResolvedConnectorAuth` stays the four static kinds. The per-dispatch handle types (`ConnectorCredentialHandle`, `BorrowedConnectorCredential`, `BorrowedConnectorAuth`, `ConnectorCredentialRequest`) move into `@objectstack/spec/integration`, and `ConnectorProviderContext` gains an optional `credentialHandle` (D4). The D3 entry `connector-auth-config-oauth2-retired` names the removal for `os migrate meta`.
17
+
-**`@objectstack/types`**: re-exports the four handle types from `@objectstack/spec/integration`; the same names, structurally unchanged.
18
+
-**`@objectstack/service-automation`**: this server does not run the per-dispatch token resolution yet (ADR-0143 S1). A grant-bearing instance is held **degraded** with a reason that names its kind, and its upstream is never called without the credential. A datasource that borrows it through `external.connector` is refused with `422`, naming the kind.
19
+
20
+
**BREAKING** for a connector that writes `authentication: { type: 'oauth2', ... }`.
21
+
22
+
-**Before.**`authentication: { type: 'oauth2', authorizationUrl, tokenUrl, clientId, clientSecret, refreshToken }` was accepted, with the secret and the refresh token inline, and no runtime obtained or refreshed a token from it.
23
+
-**Now.**`ConnectorAuthConfigSchema` refuses it at `type`, with a prescription naming ADR-0143 D7 and the replacement. No first-party source declares it.
24
+
-**Fix.** Declare the grant on a declarative instance's `auth`, with the secret as a reference: `auth: { type: 'oauth2', grant: 'authorization_code', authorizationUrl, tokenUrl, scopes, clientId, credentialRef: 'VENDOR_CLIENT_SECRET' }`, or `grant: 'client_credentials'` without `authorizationUrl`. Code that registers a connector with a token it already holds passes `{ type: 'bearer', token }`.
What the publish door checks, each refusal located at its key under `auth`:
432
+
433
+
-**`oauth2`** needs `tokenUrl` and `clientId`, plus `authorizationUrl` on
434
+
`authorization_code`. The one exception is `provider: 'mcp'` over an `http`
435
+
transport, which may omit the endpoints and the client id: the MCP
436
+
authorization flow discovers the server's metadata and can register the
437
+
client. `client_credentials` has no authorization step, so
438
+
`authorizationUrl` is refused there, and it requires `credentialRef`.
439
+
A `credentialRef` without its `clientId` is refused. An inline
440
+
`clientSecret`, `refreshToken` or `accessToken` is refused by name, pointing
441
+
at `credentialRef`. There is no PKCE switch.
442
+
-**`app-credential`** takes `vendor` (`feishu`, `dingtalk` or `wecom`), `appId`
443
+
and a required `credentialRef`. An inline `appSecret` is refused by name.
444
+
445
+
A server that does not yet run the per-dispatch token resolution holds such an
446
+
instance **degraded**, with a reason that names the grant-bearing kind, and
447
+
never calls the upstream without its credential. A datasource that borrows
448
+
from it (`external.connector`) is refused with `422`. Until the server serves
449
+
them, declare a static kind (`bearer`, `api-key` or `basic`) to dispatch now;
450
+
don't emulate a grant by putting a short-lived access token behind a `bearer`
451
+
ref.
408
452
409
453
### The runtime shape: `authentication`
410
454
411
-
The `authentication` field is the **runtime** auth config — it carries the
412
-
resolved secret *inline* (`{ type: 'bearer', token }`), because it is supplied
455
+
The `authentication` field is the **runtime** auth config, with four static
456
+
variants (`none`, `bearer`, `api-key`, `basic`). It carries the resolved
457
+
secret *inline* (`{ type: 'bearer', token }`), because it is supplied
413
458
by **host code** (a plugin calling `engine.registerConnector`, or the
414
459
executors' hand-wired instance options reading `process.env`). That is a
415
460
different trust anchor than metadata: code review guards what enters it, and
@@ -418,6 +463,11 @@ leave `authentication` alone — provider-bound instances must use `auth`, and
418
463
catalog descriptors documenting a planned integration must still never carry a
419
464
live secret value.
420
465
466
+
The runtime shape's `oauth2` variant was removed in `@objectstack/spec` 18
467
+
(ADR-0143 D7): it held a client secret and a refresh token inline and nothing
468
+
ran its lifecycle. `authentication: { type: 'oauth2' }` is refused with that
469
+
prescription; declare the grant on an instance's `auth` instead, as above.
470
+
421
471
## Dispatching from a flow
422
472
423
473
A materialized instance is dispatched exactly like any other connector — by
@@ -449,6 +499,7 @@ retry):
449
499
|:---|:---|
450
500
|`provider` names no installed factory |**Hard boot error** naming the entry, the provider, and the plugin that supplies it — add the executor to `plugins:`|
451
501
| Invalid `providerConfig` (missing `baseUrl` / `spec` / `transport`, wrong shape) |**Hard boot error** from the provider factory |
502
+
|`auth` is a grant-bearing kind (`oauth2`, `app-credential`) on a server that does not yet run its per-dispatch resolution |**Not fatal**: the instance registers **degraded**, naming the kind, and the upstream is never called without its credential; a datasource borrowing it is refused with `422`|
452
503
|`credentialRef` resolves to nothing |**Not fatal**: the instance registers **degraded**, naming the reference — set it (`PUT …/credential-refs/:ref`), and it materializes without a restart |
453
504
| The upstream refuses the credential (`401` / `403`) |**Not fatal**: the instance registers **degraded**. A stored credential is marked `rejected` and waits until it is set again (or a restart); an environment or vault credential is retried on the backoff |
454
505
| Instance `name` collides with a plugin-registered connector |**Hard boot error** — there is no silent precedence between the two worlds |
Copy file name to clipboardExpand all lines: content/docs/references/index.mdx
+5-5Lines changed: 5 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,7 +1,7 @@
1
1
---
2
2
title: Protocol reference — every schema by module
3
3
navTitle: Protocol Reference
4
-
description: Every schema published by @objectstack/spec — 1549 schemas across 14 protocol modules
4
+
description: Every schema published by @objectstack/spec — 1555 schemas across 14 protocol modules
5
5
---
6
6
7
7
{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */}
@@ -25,7 +25,7 @@ counts are sums of the rows they head. Regenerate with
25
25
|[Automation Protocol](/docs/references/automation)| 15 | 77 | Flows and their nodes, approvals, ETL pipelines, webhooks, state machines, execution records. |
26
26
|[Data Protocol](/docs/references/data)| 31 | 174 | Objects, fields, queries, filters, datasources and drivers — the ObjectQL layer. |
0 commit comments