Skip to content

Commit ce6d4e9

Browse files
yinlianghuiclaude
andauthored
docs(api): correct the environment-routing scoping instructions for standalone os serve (#12487)
The "Server configuration" section told authors to enable environment-scoped routing by declaring `api.enableProjectScoping: true` in `objectstack.config.ts`, and the info Callout below it reinforced that promise. On the default `os serve` path neither is true: a bare `defineStack()` config is not host-shaped, so the CLI boots `createStandaloneStack()` and `mergeBootConfig` lets the boot result win those two scoping keys. The section now states the override, separates the two keys (one is contradicted, the other merely redundant), names the config shape in which the flag is actually live, and corrects the Callout's claim about when the CLI reads `config.api`. The `os:check` marker and the snippet under it are unchanged — the block is valid authoring, and it still type-checks. Claude-Session: https://claude.ai/code/session_01UjM2ia8Av1v5NqfqQEQmC6 Co-authored-by: Claude <noreply@anthropic.com>
1 parent e966c59 commit ce6d4e9

1 file changed

Lines changed: 40 additions & 2 deletions

File tree

content/docs/api/environment-routing.mdx

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ depending on request context.
2020

2121
## Server configuration
2222

23-
Enable scoped route registration in `objectstack.config.ts`:
23+
Environment scoping is a **host** decision, not an application one. The two keys
24+
are declared on the stack's top-level `api` block, but the host that boots the
25+
stack is what decides whether they take effect:
2426

2527
{/* os:check */}
2628
```typescript
@@ -35,18 +37,54 @@ export default defineStack({
3537
});
3638
```
3739

40+
<Callout type="warn">
41+
**On the default `os serve` path this block does not turn scoping on.** A bare
42+
`defineStack()` config carries no instantiated plugins, so the CLI boots
43+
`createStandaloneStack()` and merges that boot result over the authored config
44+
(`mergeBootConfig`). The boot builder ships
45+
`api: { enableProjectScoping: false, projectResolution: 'auto' }` and wins on
46+
exactly those two keys — deliberately, because scoping is not the author's call
47+
on a standalone host.
48+
49+
The two keys are not overridden the same way:
50+
51+
- `enableProjectScoping: true` is **contradicted**. The value forwarded to the
52+
REST and dispatcher plugins is `false`, and no scoped routes are registered.
53+
- `projectResolution: 'auto'` is **redundant**. The boot builder pins the same
54+
value, so writing it changes nothing; declaring any *other* strategy here is
55+
silently replaced by `'auto'`.
56+
57+
Every other authored `api` key — `enforceProjectMembership`, for example —
58+
survives the merge untouched.
59+
</Callout>
60+
61+
The block above is live when the CLI does **not** boot the standalone stack:
62+
when the exported config is host-shaped, meaning its `plugins` array already
63+
carries instantiated plugin objects. That is the shape a multi-environment host
64+
assembles, and this open-core CLI supports the `standalone` boot mode only —
65+
cloud / multi-environment hosts ship from a separate distribution. Setting
66+
`OS_MODE=off` (or `bootMode: 'off'` on the exported config) also skips the
67+
standalone boot, but it drops the CLI to its legacy lightweight assembler rather
68+
than producing a scoped standalone host; `bootMode` is additionally not a
69+
declared stack key, so `defineStack()` rejects it as an unrecognized key.
70+
3871
<Callout type="info">
3972
`api` is a declared top-level field on `ObjectStackDefinitionSchema`, so it
4073
survives `defineStack`'s strict parsing — you can pass it directly inside the
4174
`defineStack({ ... })` call as shown above. (Older stacks that instead spread
4275
it onto the exported config object, e.g. `export default { ...stack, api: {...} }`,
4376
still work the same way.) The CLI reads the resolved value from the exported
44-
config (`config.api`) when registering the REST and dispatcher plugins.
77+
config (`config.api`) when registering the REST and dispatcher plugins — but it
78+
reads it *after* the boot result has been merged in, which is why the standalone
79+
path forwards the boot builder's scoping decision rather than the author's.
4580
</Callout>
4681

4782
The option names are historical for compatibility with existing config files;
4883
the route, header, env var, and request context all use `environment`.
4984

85+
Once scoping is enabled by the host, `projectResolution` selects the route
86+
surface:
87+
5088
| Strategy | Behavior | When to use |
5189
|:---|:---|:---|
5290
| `auto` | Registers both unscoped `/api/v1/...` and scoped `/api/v1/environments/:environmentId/...` routes. | Default migration mode. |

0 commit comments

Comments
 (0)