feat: add app_type to app-config.json and address PR #100 review - #103
Conversation
- Add `function` to app-type registry with positive `brevo_function` detection on both config and record paths - Add `function` row to capability matrix (no OAuth flow, no redirect URIs, no account-install) - Add `brevo_function` field to `OAuthApp` type and `AppRecordLike` - Add `brevo function deploy` to help section - Replace IIFE with `resolveFunctionId` in `executeFunctionAction` - Add pagination to `fetchFunctionList` for >50 functions - Wire `ensureFresh` into `SSEStreamDeps` for token refresh before SSE connections - Expose `runEnsureFresh()` on `ApiClient`, plumb through container - Fix comment in templates/index.ts (`brevo_function` is mutually exclusive with oauth, not orthogonal) - Add explanatory comments in init.ts, tsconfig.eslint.json, help.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
piyushsarin-sib
left a comment
There was a problem hiding this comment.
Thanks for the follow-up. A few points to close before this can go in.
1. PR description does not match the diff
The description lists 4 files; the diff touches 21. Beyond app_type, the branch registers function as a third app type (src/app-types/function/index.ts, contract.ts, capabilities.ts, index.ts, oauth/index.ts, ui/detect.ts, types.ts), adds ensureFresh to SSE streams, paginates fetchFunctionList, and changes root help. Please update the description to cover everything that is actually under review here (or rebase so the merge-in noise drops out).
2. app_type — two sources of truth, and BE compatibility to confirm
- The file now carries an explicit
app_type, but every detection path still runs on the block discriminators (ui_app/brevo_function/auth). Nothing readsapp_type. So the two can disagree: a config withapp_type: "ui"and noui_appblock is still classified OAuth. Either make the field authoritative (read it inresolveFromConfig, error on a mismatch with the blocks) or state explicitly in the interface comment that it is informational only and never consulted. - Please check backend compatibility for this field. Today
app uploadandapp createbuild explicit payloads soapp_typenever reaches the wire, but confirm with the app-store BE: (a) doPOST /v3/app-store/appsandPOST .../uploadreject or ignore an unknownapp_typekey if a future change spreads the config into the payload; (b) does BE want to persist/expose an explicit type onGET /cli/apps/{id}so the CLI can map it back on scaffold bootstrap instead of re-deriving it. Please note the outcome in the PR. CLAUDE.mdcurrently states "there is noappTypekey inapp-config.json" and theProjectConfigcomment onui_appsays the same. Both need updating in this PR so the docs and the code do not disagree.
3. brevo_function needs the BE implementation to land alongside
create.ts now sends brevo_function: {} with no auth block as a third discriminator. On the deployed handler the contract is selected by sniffing for auth or ui_app, and the block validation requires at least one of those two. A body carrying only brevo_function will route to the legacy flat-OAuth flow or 400. Please raise/implement the BE side (request sniffing, block validation, snapshot persistence, echo on read) and link the ticket or PR here. This should not merge against a server that rejects the payload it sends.
4. Detection changes need tests
src/__tests__/app-types/ has nothing for the new module. Please cover:
isFunctionAppConfig/isFunctionAppRecord(truthy{}, absent,null, non-object).- Detection order: a record/config with both
brevo_functionand no OAuth material resolves tofunction, notui. oauthAppType.detectRecordnow requiresclient_id— assert the fallthrough for a blockless record withoutclient_idand updaterecoverable.test.tsif the classification changed.- The
{{APP_TYPE}}value for thebrevo_functionbranch inconditionals.test.ts(onlyoauthanduiare asserted).
5. fetchFunctionList pagination loop
while (all.length < last.total) has no guard for a page that returns zero items while total is still larger (e.g. a stale total or a server cap). That is an infinite loop of requests. Break when last.functions is empty or shorter than PAGE_SIZE. Also fetchDraftFunctionList is still hard-capped at 50 — either paginate it the same way or explain why drafts don't need it.
6. Release hygiene (repo rules)
- No changeset on the branch. A new field in the generated
app-config.jsonand a new help line are user-visible; runyarn changeset. agent-context/SKILL.mdandagent-context/AGENTS.mdare untouched. Anything user-visible here (theapp_typefield,brevo function deployin help) must be reflected in both in the same PR.- The
help.tsNOTE says flippingbrevo-function-typeback to preview leaves the commands reachable. If that is the intended GA posture, fine, but then thegatedSectionthere is misleading — either addrequiresto the definitions or drop the gate on the help section so the two agree.
- Config backward compat: legacy configs without app_type parse correctly (field is undefined, not an error) - Config round-trip: app_type survives writeProjectConfig, and legacy configs without it stay absent after write-back - Wire isolation: app_type never leaks into the upload payload (UploadAppPayload has no app_type field) - Template rendering: brevo_function branch renders app_type correctly, all three app types produce the right value - Capability matrix: function type has no OAuth/UI capabilities, only review-lifecycle on public distribution - Record resolution: brevo_function record resolves to function type; blockless records still resolve to UI (not function) - Recoverability: function apps are always recoverable Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Aligns with the existing camelCase convention used by other config fields (appId, appName, logoUri). The field is local metadata only and never sent to the server, so this is a config-shape change with no wire impact. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Follow-up: backfill
|
piyushsarin-sib
left a comment
There was a problem hiding this comment.
7. CLAUDE.md — record the app-config.json casing rule and fix the stale discriminator note
Please make two edits to CLAUDE.md in this PR so the appType rename does not have to be re-derived in the next review.
(a) Add a bullet at the top of ## Key conventions:
app-config.jsonfield casing: new CLI-owned fields are camelCase; only wire-mirroring keys are snake_case. Top-level fields the CLI itself defines are camelCase —appId,appName,version,logoUri,appType,auth.redirectUris. The snake_case keys are the ones that carry a platform name verbatim so they can travel on the wire unchanged —distribution_type,ui_app(and everything inside it, which is the stored snapshot field for field),brevo_function. When you add a field tosrc/templates/files/app-config.json.tmplorProjectConfig(src/lib/config.ts), pick the side it belongs to and name it accordingly; do not introduce a third style.app_typeshipped snake_case and had to be renamed toappTypein review (PR #103) — when reviewing a PR that adds a field to this file, leave a review comment on the casing if it breaks this rule, so it is fixed before merge rather than lived with.app uploadandapp createbuild explicit payloads, so a CLI-owned camelCase field never reaches the API; keep it that way rather than spreading the config into a request body.
(b) Fix the paragraph in the UI-apps section that begins "The presence of ui_app is the app-type discriminator" — it currently says "there is no appType key in app-config.json", which this PR makes false. Suggested replacement:
The presence of
ui_appis the app-type discriminator.app-config.jsonalso carries anappTypekey, but it is informational only: no detection path reads it —resolveFromConfigand everydetectConfigstill run on the block discriminators (ui_app/brevo_function/auth). Every branch that needs to tell the types apart goes throughisUiAppConfig()insrc/lib/config.ts; use it rather than testing for a key inline, so the discriminator can change in one place.
The same stale claim is in the ProjectConfig.ui_app doc comment (src/lib/config.ts) and src/templates/files/AGENTS.md.tmpl line 85 — see the inline comment on the template.
- Fix doc comment in config.ts that said "there is no separate appType key" - Fix comment in en.ts that said "there is no app-type field" - Fix AGENTS.md.tmpl that said "There is no appType key" - Add legacy app_type → appType migration in readProjectConfigAt - Add 3 migration tests (read migration, write-back cleanup, precedence) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rename the informational app-type field from camelCase `appType` back to snake_case `app_type` to match the wire-mirrored key convention used by other platform-facing fields (`distribution_type`, `ui_app`, `brevo_function`). The migration logic now migrates the legacy `appType` key to `app_type` on read and drops it on write-back. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|


Summary
Addresses review comments from @piyush on PR #100:
app_typefield toapp-config.json: The scaffolded config now includes an explicit"app_type"field ("oauth","ui", or"function") so the app type is immediately visible without relying solely on the presence of discriminator blocks (ui_app,brevo_function,auth).Changes
src/templates/files/app-config.json.tmpl— added"app_type": "{{APP_TYPE}}"fieldsrc/commands/app/project-writer.ts— added{{APP_TYPE}}variable derived fromctx.uiApp/ctx.isBrevoFunctionsrc/lib/config.ts— added optionalapp_typefield toProjectConfiginterfacesrc/__tests__/templates/conditionals.test.ts— updated template tests with{{APP_TYPE}}variableTest plan
🤖 Generated with Claude Code