Skip to content

Latest commit

 

History

History
698 lines (578 loc) · 38.9 KB

implementation-matrix.md

File metadata and controls

698 lines (578 loc) · 38.9 KB

Forge Platform Implementation Matrix

Complete mapping of every Forge API, hook, component, and platform feature against forge-sim's implementation status.

Last updated: 2026-07-19

2,732 tests across 146 test files (2,566 core / 139 files

  • 166 renderer / 7 files)

41 MCP tools + 4 resources

The stats block above is auto-generated by npm run docs:stats. Do not edit by hand; re-run the script after adding tests.

Legend

Symbol Meaning
✅ Fully implemented and tested
⚠️ Partially implemented or stubbed
❌ Not implemented (will error or return undefined)
🔇 Stubbed no-op (won't crash, but doesn't do anything)

@forge/api

The main backend API package. Imported by resolver/trigger/consumer functions.

Fetch & Product APIs

API Status Tests Notes
requestJira(route, options) ✅ shims.test.ts, simulator.test.ts, my-issues-e2e.test.ts Supports mock + real API proxy
requestConfluence(route, options) ✅ shims.test.ts Same as Jira
requestBitbucket(route, options) ✅ — Same as Jira (no dedicated test)
asApp().requestJira() ✅ shims.test.ts
asUser().requestJira() ✅ shims.test.ts
asUser(accountId).requestJira() ⚠️ — accountId param is ignored; no user impersonation
asApp().requestConfluence() ✅ shims.test.ts
asApp().requestBitbucket() ✅ —
asApp().requestGraph() ✅ graphql.test.ts Mock by operation name + real API fallback via Atlassian Gateway
asUser().requestGraph() ✅ graphql.test.ts Same as asApp
asApp().requestAtlassian() ❌ — Generic Atlassian API not implemented
asUser().requestAtlassian() ❌ — Generic Atlassian API not implemented
asUser().withProvider(provider, remote) ✅ external-auth.test.ts Full ExternalAuthFetchMethods interface
.withProvider().hasCredentials(scopes?) ✅ external-auth.test.ts Checks token existence, expiry, and scopes
.withProvider().requestCredentials(scopes?) ✅ external-auth.test.ts Opens browser for OAuth dance if secret configured; falls back to warning
.withProvider().fetch(url, options) ✅ external-auth.test.ts Mock routes first, then real HTTP with Bearer injection
.withProvider().getAccount() ✅ external-auth.test.ts Returns ExternalAuthAccount from stored token
.withProvider().listAccounts() ✅ external-auth.test.ts Lists linked accounts (max 1 per provider in sim)
.withProvider().asAccount(id) ✅ external-auth.test.ts Returns account-scoped methods
fetch(url, options) ✅ — Passes through to real globalThis.fetch with warning log
route\...`` ✅ shims.test.ts Template tag with encoding
routeFromAbsolute() 🔇 — Exported but untested
assumeTrustedRoute() 🔇 — Exported but untested

Storage (Legacy, deprecated)

API Status Tests Notes
storage.get(key) ✅ shims.test.ts, storage.test.ts Routes to sim.kvs
storage.set(key, value) ✅ shims.test.ts, storage.test.ts Routes to sim.kvs
storage.delete(key) ✅ storage.test.ts Routes to sim.kvs
storage.getSecret(key) ✅ storage.test.ts
storage.setSecret(key, value) ✅ storage.test.ts
storage.deleteSecret(key) ✅ storage.test.ts
storage.query() ⚠️ — Basic query works via KVS shim, but entity-style storage.entity() from legacy API may not
storage.entity() ⚠️ — Routes to entity store if available
storage.transact() ⚠️ — May not fully match legacy API signature

Other APIs

API Status Tests Notes
authorize(provider) 🔇 — No-op, always resolves
invokeRemote(key, payload) ✅ remotes.test.ts Full — RemoteProxy with mock-first routing, real HTTP fallback with FIT auth
invokeService(key, payload) ✅ remotes.test.ts Same system as invokeRemote
webTrigger.getUrl(key) ✅ web-trigger.test.ts Dev server running: real routable local URL (http://localhost:<port>/x1/<id>, served). Headless: Forge-shaped synthetic URL; fire the trigger with sim.fireWebTrigger(key) instead. deleteUrl/queryUrls mirrored, including the real v2-URL parse quirk.
getAppContext() ✅ shims.test.ts Returns real values from manifest (appId, moduleKey) and connected account (cloudId). ARIs match Atlassian format. invocationRemainingTimeInMillis() returns 25s.
__getRuntime() 🔇 — Internal, undocumented; necessary for @forge/api import chain not to explode. Returns { isEcosystemApp: false }
bindInvocationContext(fn) 🔇 — Internal, undocumented; necessary for @forge/api import chain not to explode. Returns the function unchanged
privacy.reportPersonalData(accounts) ✅ shims.test.ts POST /app/report-accounts via product API; batches in groups of 90
permissions.hasPermission(requirements) 🔇 shims.test.ts Always returns { granted: true } in simulation
permissions.hasScope(scope) 🔇 shims.test.ts Always returns true
permissions.canFetchFrom(type, url) 🔇 shims.test.ts Always returns true
permissions.canLoadResource(type, url) 🔇 shims.test.ts Always returns true
i18n.getTranslations(locale, options) ✅ shims.test.ts Backed by I18nStore (reads __LOCALES__/ JSON files)
i18n.createTranslationFunction(locale) ✅ shims.test.ts Backed by I18nStore; dot-path keys, fallback chains
i18n.resetTranslationsCache() ✅ shims.test.ts Clears translation cache and I18nStore
createRequestStargateAsApp() 🔇 — Internal, undocumented; necessary for @forge/api import chain not to explode. Returns same API client
__fetchProduct() ✅ forge-sql.test.ts Internal, undocumented; necessary for @forge/api import chain not to explode. Factory behind requestJira/requestConfluence/SQL; handles { provider, remote, type } descriptors

Error Classes

Export Status Notes
FetchError ✅
HttpError ✅
NotAllowedError ✅
ExternalEndpointNotAllowedError ✅
ProductEndpointNotAllowedError ✅
RequestProductNotAllowedError ✅
NeedsAuthenticationError ✅
InvalidWorkspaceRequestedError ✅
ProxyRequestError ✅
FUNCTION_ERR ✅
isExpectedError() ✅
isForgePlatformError() ✅
isHostedCodeError() ✅

Re-exports from @forge/storage

Export Status Notes
WhereConditions ✅
FilterConditions ✅
SortOrder ✅
startsWith ✅

@forge/kvs

The primary key-value storage package.

API Status Tests Notes
kvs.get(key) ✅ kvs.test.ts, shims.test.ts
kvs.set(key, value) ✅ kvs.test.ts, shims.test.ts
kvs.delete(key) ✅ kvs.test.ts
kvs.getMany(keys) ✅ kvs.test.ts
kvs.query().where().getMany() ✅ kvs.test.ts, shims.test.ts Full query builder
kvs.query().where().cursor().getMany() ✅ kvs.test.ts Cursor-based pagination
kvs.query().where().limit().getMany() ✅ kvs.test.ts
kvs.query().where().sortBy().getMany() ✅ kvs.test.ts
kvs.transact().set().delete().execute() ✅ kvs.test.ts, shims.test.ts Atomic batch operations
kvs.getSecret(key) ✅ shims.test.ts Separate secrets store
kvs.setSecret(key, value) ✅ shims.test.ts
kvs.deleteSecret(key) ✅ shims.test.ts
Entity Store: kvs.entity(name).set() ✅ entity-store.test.ts, entity-store-e2e.test.ts
Entity Store: kvs.entity(name).get() ✅ entity-store.test.ts
Entity Store: kvs.entity(name).delete() ✅ entity-store.test.ts
Entity Store: kvs.entity(name).query() ✅ entity-store.test.ts Indexed queries, filters, sort, pagination
WhereConditions ✅ kvs.test.ts
FilterConditions ✅ kvs.test.ts
ForgeKvsError ✅
ForgeKvsAPIError ✅
MetadataField ✅
Sort ✅

@forge/sql

Forge SQL: relational data with real MySQL.

API Status Tests Notes
sql.prepare(query).bindParams(...).execute() ✅ forge-sql.test.ts, forge-sql-e2e.test.ts Parameterized queries
sql.prepare(query).execute() ✅ forge-sql.test.ts
sql._executeRaw(query) ✅ forge-sql.test.ts
migrationRunner.enqueue(migrations) ✅ forge-sql-e2e.test.ts, deploy-e2e.test.ts Real @forge/sql migrationRunner works through shims
DDL (CREATE TABLE, ALTER, INDEX) ✅ forge-sql-e2e.test.ts Real MySQL 8.4 via mysql-memory-server
JOINs, aggregation, subqueries ✅ deploy-e2e.test.ts AVG, COUNT, SUM, CASE WHEN, etc.
Foreign keys, constraints ✅ persistence.test.ts
Connection pooling / limits ❌ — No simulation of Forge's connection limits

@forge/events

Async events and queue processing.

API Status Tests Notes
new Queue({ key }) ✅ shims.test.ts, queue.test.ts
queue.push(events) ✅ shims.test.ts, queue.test.ts, retro-board-e2e.test.ts Single and batch push
queue.push({ body, delayInSeconds }) ✅ queue.test.ts Delayed delivery
queue.push({ body, concurrencyKey }) ✅ concurrency.test.ts Controls parallel execution
queue.getJob(jobId) ✅ queue.test.ts
InvocationError ✅ eval11-findings.test.ts Returned (not thrown) by consumers to request a retry. Constructor takes RetryOptions and yields the serialized { _retry, retryOptions } form, matching @forge/events v3. Queue engine re-delivers with retryContext, capped at 4 retries; re-delivery is immediate (forge-sim does not wait out retryAfter delays)
QueueResponse / Response ✅ eval11-findings.test.ts queueResponse.retry() also triggers a retry
event.retryContext ✅ eval11-findings.test.ts { retryCount, retryReason, retryData } populated on retry deliveries only
InvocationErrorCode ✅ eval11-findings.test.ts Real FUNCTION_* enum values
JobProgress ✅
InvalidQueueNameError ✅ shims.test.ts
TooManyEventsError ✅
PayloadTooBigError ✅
NoEventsToPushError ✅
RateLimitError ✅
PartialSuccessError ✅
InternalServerError ✅
JobDoesNotExistError ✅
appEvents.publish(events) ✅ shims.test.ts Publishes custom app events; fires matching triggers in same app with platform-generated payload shape

@forge/llm

OpenAI-shaped Anthropic LLM interface. Mock-first; falls through to the real Anthropic Messages API when ANTHROPIC_API_KEY is set (env or via forge-sim auth --llm).

API Status Tests Notes
chat(prompt) ✅ llm.test.ts Mock queue first, then real Anthropic proxy. Translates OpenAI-shaped messages ⇄ Anthropic native format.
stream(prompt) ✅ llm.test.ts Returns full response as a single async-iterable chunk (no SSE parsing; overkill for local dev).
list() ✅ llm.test.ts Returns the static list of supported Claude models.
Tool calls (tools[], tool_choice, tool_calls in response) ✅ llm.test.ts Full agent-loop support; tool_use ⇄ tool_result translation.
System messages ✅ llm.test.ts Translated to Anthropic's top-level system param.
LlmApiError ✅ llm.test.ts Thrown with code NO_API_KEY when no mocks queued and no API key set.
Streaming SSE ⚠️ — Implemented as one-chunk async-iterable; sufficient for tests, not for streaming UX work.

Simulator surface:

sim.llm method Status Notes
mockResponse(mock) ✅ Queue one FIFO mock.
mockResponses(...mocks) ✅ Queue many; spread args.
getHistory() ✅ [{ prompt, response }] for assertions.
reset() ✅ Clears queue + history.
setApiKey(key) / getApiKey() ✅ process.env.ANTHROPIC_API_KEY wins over config.

MCP: forge_llm_mock, forge_llm_history; see mcp.md.


@forge/object-store

Backend Object Store (file storage). Shimmed via loader hooks; pre-signed URLs point at the dev server or a lazily-started ephemeral HTTP server so app code can fetch() them for real. Default and CDN buckets, TTL, checksums, HTTP Range requests.

API Status Tests Notes
objectStore.createUploadUrl(body) ✅ object-store.test.ts Pre-signed PUT URL; checksum (sha256/md5) verified on upload
objectStore.createDownloadUrl(key, options?) ✅ object-store.test.ts Pre-signed GET URL; supports HTTP Range / 206 responses. Throws a helpful TypeError on non-string key
objectStore.createPublicUploadUrl(body) ✅ object-store.test.ts CDN bucket variant
objectStore.createPublicDownloadUrl(key, options?) ✅ object-store.test.ts CDN bucket variant
objectStore.createCDNUrl(key, options?) ✅ object-store.test.ts CDN URL with cache options
objectStore.get(key, options?) ✅ object-store.test.ts Returns ObjectReference metadata or undefined
objectStore.delete(key, options?) ✅ object-store.test.ts Deleting an absent key succeeds (Forge parity)
errorCodes ✅ — UNKNOWN_ERROR, APP_NOT_ENABLED, RATE_LIMIT_EXCEEDED (matches real @forge/object-store 2.0.0 exports)
objectStore.put(key, data, ttl?) / .download(key) ⚠️ object-store.test.ts Sim-only conveniences, marked @deprecated — real package requires the pre-signed URL flow

MCP: forge_objectstore_put, forge_objectstore_get, forge_objectstore_list, forge_objectstore_delete, forge_objectstore_create_download_url.


@forge/resolver

Resolver function registration.

API Status Tests Notes
new Resolver().define(key, handler) ✅ shims.test.ts, deployer.test.ts
resolver.getDefinitions() ✅ shims.test.ts
Multi-function resolvers ✅ deploy-e2e.test.ts Multiple define() calls

@forge/react

UIKit components and hooks. The reconciler produces ForgeDoc.

Core

Export Status Tests Notes
ForgeReconciler (default export) ✅ simulator-ui.test.ts, ui-integration.test.ts Re-exports real @forge/react reconciler
xcss() ✅ — Style objects

Hooks

Hook Status Tests Notes
useProductContext() ✅ — Re-exported from real package
useConfig() ✅ macro-config.test.ts, macro-inline-config.test.ts, macro-config-bridge.test.ts Re-exported from real package; reads extension.config from context. Dev server injects stored config from macro --config viewSubmit payloads (custom config) or submitTree='macroConfig'-tagged submits on flat inline-config macros.
useTheme() ✅ — Re-exported from real package
usePermissions() ✅ — Re-exported from real package
useIssueProperty(key, init) ✅ — Re-exported from real package; routes through bridge shim → PropertyStore
useContentProperty(key, init) ✅ — Re-exported from real package; routes through bridge shim → PropertyStore
useSpaceProperty(key, init) ✅ — Re-exported from real package; routes through bridge shim → PropertyStore
useTranslation() ✅ — Re-exported from real package; reads from I18nProvider context → bridge i18n → I18nStore
I18nProvider ✅ — Re-exported from real package; calls bridge.i18n.createTranslationFunction()
useForm() ✅ — Re-exported from real package (wraps react-hook-form)
useObjectStore() ✅ object-store-bridge.test.ts Re-exported from real package; routes through bridge objectStore.* → SimulatedObjectStore
replaceUnsupportedDocumentNodes() ❌ — ADF utility

UIKit Components (from ui-kit-components.d.ts)

Component Status Tests Notes
Badge ✅ ui-integration.test.ts
BarChart ✅ —
Box ✅ ui-integration.test.ts
Button ✅ ui-integration.test.ts, simulator-ui.test.ts
ButtonGroup ✅ —
Calendar ✅ —
Checkbox ✅ —
CheckboxGroup ✅ —
ChromelessEditor ✅ — Real @atlaskit/editor-core (ComposableEditor, appearance=chromeless)
Code ✅ —
CodeBlock ✅ —
CommentEditor ✅ — Real @atlaskit/editor-core (ComposableEditor, appearance=comment) + Save/Cancel
DatePicker ✅ —
DonutChart ✅ —
EmptyState ✅ —
ErrorMessage ✅ — In renderer mapping, not in shim re-export
FileCard ✅ — In renderer mapping
FilePicker ✅ — In renderer mapping
Form ✅ —
FormFooter ✅ — In renderer mapping
FormHeader ✅ — In renderer mapping
FormSection ✅ — In renderer mapping
Heading ✅ —
HelperMessage ✅ — In renderer mapping
HorizontalBarChart ✅ —
HorizontalStackBarChart ✅ —
Icon ✅ —
Inline ✅ —
Label ✅ — In renderer mapping
LineChart ✅ —
LinkButton ✅ — In renderer mapping
List ✅ — In renderer mapping
ListItem ✅ — In renderer mapping
LoadingButton ✅ — In renderer mapping
Lozenge ✅ —
Modal ✅ —
ModalBody ✅ —
ModalFooter ✅ —
ModalHeader ✅ —
ModalTitle ✅ —
ModalTransition ✅ —
PieChart ✅ —
Pressable ✅ — In renderer mapping
ProgressBar ✅ —
ProgressTracker ✅ — In renderer mapping
Radio ✅ —
RadioGroup ✅ —
Range ✅ —
RequiredAsterisk ✅ — In renderer mapping
SectionMessage ✅ ui-integration.test.ts
SectionMessageAction ✅ — In renderer mapping
Select ✅ —
Spinner ✅ —
Stack ✅ ui-integration.test.ts
StackBarChart ✅ —
Tab ✅ —
TabList ✅ —
TabPanel ✅ —
Tabs ✅ —
Tag ✅ —
TagGroup ✅ —
Text ✅ ui-integration.test.ts
TextArea ✅ —
Textfield ✅ — Lowercase-f only (matches real @forge/react). Note: devs frequently misimport as TextField because it's the conventional React casing. forge-sim deliberately does not alias TextField so the bug fails in tests instead of on deploy.
Tile ✅ — In renderer mapping
AtlassianTile ✅ — In renderer mapping
AtlassianIcon ✅ — In renderer mapping
TimePicker ✅ — In renderer mapping
Toggle ✅ —
Tooltip ⚠️ — Portal flickers under React.StrictMode due to @atlaskit/portal double-effect bug. Works correctly with StrictMode off.
ValidMessage ✅ — In renderer mapping

Non-UIKit Components (from components/index.d.ts)

Component Status Tests Notes
DynamicTable ✅ — Separate module, re-exported
Image ✅ —
Link ✅ —
UserPicker ✅ —
Table / Head / Row / Cell ✅ —
InlineEdit ✅ — Re-exported from @forge/react, rendered via @atlaskit/inline-edit
Popup ⚠️ — Portal flickers under React.StrictMode, same @atlaskit/portal bug as Tooltip. Works with StrictMode off.
Comment ✅ — Re-exported + styled comment block with author/time
AdfRenderer ✅ — Real @atlaskit/renderer (ReactRenderer), pixel-perfect ADF rendering
Global ✅ — Re-exported, renders sidebar + main layout
User ✅ — Re-exported, renders avatar + accountId badge
UserGroup ✅ — Re-exported, renders grouped user avatars
Em ✅ — Re-exported, renders <em>
Strike ✅ — Re-exported, renders <s>
Strong ✅ — Re-exported, renders <strong>
Frame ✅ — Re-exported, renders sandboxed <iframe>
InlineDialog ✅ — Already in shim (via Flag/InlineDialog)
Flag ✅ — Already in shim

Types Only (no runtime needed)

Export Status Notes
XCSSObject ✅ Type
DocNode ✅ Type
Event ✅ Type
All *Props types ✅ Types from @atlaskit/forge-react-types

@forge/bridge

Frontend API for Custom UI apps (runs in iframe).

Core

API Status Tests Notes
invoke(functionKey, payload) ✅ custom-ui-e2e.test.ts Routes through bridge to resolver
requestJira(path, options) ✅ custom-ui-e2e.test.ts Routes through bridge to product API
requestConfluence(path, options) ✅ —
requestBitbucket(path, options) ✅ —
requestRemote(remoteKey, options) ✅ remotes.test.ts Direct fetch with FIT auth, mock-first routing

View

API Status Tests Notes
view.getContext() ✅ custom-ui-e2e.test.ts Full ForgeContext: accountId, cloudId, locale, timezone, theme, license, extension data. Hydrates via product API for Jira Issue + Confluence Content modules
view.submit(payload) ✅ modal-bridge.test.ts In modal: postMessage to parent → closes overlay → fires onClose. Outside modal: RPC to backend
view.close(payload) ✅ modal-bridge.test.ts Same as submit — postMessage in modal, RPC otherwise
view.onClose(callback) ✅ modal-bridge.test.ts Stores callback, fires when modal closes
view.open() 🔇 — No-op
view.refresh(payload) ✅ — Triggers page reload to re-render module
view.createHistory() ✅ create-history.test.ts Full history v5 interface wrapping browser pushState/replaceState/popstate. Works for both UIKit and Custom UI (both run in browser). Back/forward buttons work. Memory history fallback for headless/MCP mode. Compatible with react-router. Available in full-page modules (globalPage, projectPage, adminPage, spacePage, etc.)
view.theme.enable() ✅ bridge-features.test.ts Sets data-color-mode=dark on document root
view.changeWindowTitle(title) ✅ bridge-features.test.ts Sets document.title
view.emitReadyEvent() ✅ bridge-features.test.ts Dispatches forge-sim:ready custom event
view.createAdfRendererIframeProps() ❌ — ADF rendering setup

Modal

API Status Tests Notes
new Modal(options) ✅ modal-bridge.test.ts Full options: resource, onClose, size, context, closeOnEscape, closeOnOverlayClick, title
modal.open() ✅ modal-bridge.test.ts Creates Atlaskit-style overlay + iframe to /module/<resource>/?_modal=true&context=<b64>

Router

API Status Tests Notes
router.navigate(location) ✅ bridge-features.test.ts Resolves NavigationTarget to product URL, navigates
router.open(location) ✅ bridge-features.test.ts Resolves NavigationTarget to product URL, opens in new tab
router.getUrl(location) ✅ bridge-features.test.ts Resolves NavigationTarget → URL (Issue, Content, Space, Dashboard, etc.)
router.reload() ✅ — Calls window.location.reload()
NavigationTarget ✅ — Constant exported

Events (cross-module communication)

API Status Tests Notes
events.emit(event, payload) ✅ — Local dispatch within process (in-memory listener registry)
events.on(event, callback) ✅ — Registers listener, returns unsubscribe handle
events.emitPublic(event, payload) ✅ bridge-features.test.ts Dispatches locally with public: prefix + notifies server
events.onPublic(event, callback) ✅ bridge-features.test.ts Subscribes with public: prefix, returns unsubscribe handle

Realtime (pub/sub)

API Status Tests Notes
realtime.publish(channel, payload) ✅ realtime.test.ts Scoped channel pub/sub. MCP: forge_realtime_publish
realtime.subscribe(channel, callback) ✅ realtime.test.ts Returns unsubscribe handle
realtime.publishGlobal(channel, payload) ✅ realtime.test.ts Cross-experience global channel
realtime.subscribeGlobal(channel, callback) ✅ realtime.test.ts Returns unsubscribe handle

Object Store (file storage)

API Status Tests Notes
objectStore.upload(params) ✅ object-store-bridge.test.ts Upload from Custom UI / UIKit — resolver mints pre-signed PUT URLs, blobs mapped back via checksum
objectStore.download(params) ✅ object-store-bridge.test.ts Pre-signed GET round-trip; absent keys filtered from results
objectStore.getMetadata(params) ✅ object-store-bridge.test.ts Per-key metadata objects
objectStore.delete(params) ✅ object-store-bridge.test.ts Removes objects from the store

Other

API Status Tests Notes
showFlag(options) ✅ bridge-features.test.ts, eval7-f7-bridge-showflag.test.ts Renders Atlaskit-styled toast (stacking, auto-dismiss, actions, close handle) in both the UIKit renderer and the Custom UI dev bridge
rovo.open(payload) ❌ — Rovo AI agent sidebar
rovo.isEnabled() ❌ —
i18n.getTranslations(locale, options) ✅ — Reads from I18nStore (app's LOCALES dir)
i18n.createTranslationFunction(locale) ✅ — Returns t(key, defaultValue) backed by I18nStore
i18n.resetTranslationsCache() ✅ — Clears translation cache and store
permissions.check() ✅ bridge-features.test.ts Always returns { hasPermission: true }
featureFlags.evaluate() 🔇 bridge-features.test.ts Returns undefined (stub; no feature flag backend)
invokeRemote(key, options) ✅ remotes.test.ts, bridge-invoke-routing.test.ts Endpoint resolution, route prefix, FIT auth, mock-first
invokeService(key, options) ✅ remotes.test.ts Same system as invokeRemote

@forge/resolver

API Status Tests Notes
new Resolver() ✅ shims.test.ts
resolver.define(key, handler) ✅ shims.test.ts, deployer.test.ts
resolver.getDefinitions() ✅ shims.test.ts

@forge/jira-bridge

Product-specific bridge APIs for Jira host UI. All no-ops in forge-sim; the host product isn't present. App code that imports these won't crash.

API Status Tests Notes
new ViewIssueModal(opts).open() 🔇 product-bridges.test.ts Logs + resolves. Stores onClose but never fires it (no host)
new CreateIssueModal(opts).open() 🔇 product-bridges.test.ts Logs + resolves. Context and onClose stored but inert
workflowRules.onConfigure(fn) 🔇 product-bridges.test.ts Registers callback (host-driven, never fires in sim)
uiModificationsApi.onInit(cb, registerCb) 🔇 product-bridges.test.ts Registers hooks for issue create/edit forms (host-driven)
uiModificationsApi.onChange(cb, registerCb) 🔇 product-bridges.test.ts Registers field-change hooks (host-driven)
uiModificationsApi.onError(cb) 🔇 product-bridges.test.ts Registers error handler (host-driven)
customFieldApi.getFieldData(cb) 🔇 product-bridges.test.ts Registers callback (host pushes data, no host in sim)
REQUEST_TYPE_CF_TYPE ✅ product-bridges.test.ts String constant: "com.atlassian.servicedesk:vp-origin"

@forge/confluence-bridge

Product-specific bridge APIs for Confluence editor/macro/byline. All no-ops; returns sensible defaults.

API Status Tests Notes
getEditorContent() 🔇 product-bridges.test.ts Returns { data: '' }; no Confluence editor in sim
getMacroContent() 🔇 product-bridges.test.ts Returns { data: '' }
updateMacro(content) 🔇 product-bridges.test.ts Returns true (no-op)
setMacroViewportHeight(height) 🔇 product-bridges.test.ts Returns true (no-op)
updateBylineProperties(payload) 🔇 product-bridges.test.ts No-op

@forge/dashboards-bridge

Product-specific bridge APIs for Jira Dashboard widgets. All no-ops: callback registration stubs.

API Status Tests Notes
widgetEdit.onSave(cb) 🔇 product-bridges.test.ts Registers save callback (host-driven)
widgetEdit.onProductSave(cb) 🔇 product-bridges.test.ts Registers product-save callback (host-driven)
widgetEdit.onSaveError(cb) 🔇 product-bridges.test.ts Registers error callback (host-driven)
widgetEdit.updateConfig(config) 🔇 product-bridges.test.ts Pushes config to host (no-op + log)
widget.setPreviewConfig(config) 🔇 product-bridges.test.ts Pushes preview config to host (no-op + log)

Packages Not Shimmed (direct imports will load real package or fail)

Package Status Notes
@forge/auth ❌ authorizeJiraWithFetch, authorizeConfluenceWithFetch. Not intercepted by loader hooks.
@forge/i18n ⚠️ Not intercepted by loader hooks, but bridge shim's I18nStore provides equivalent functionality. Real package partially works for types/constants.
@forge/egress ❌ Egress filtering rules. Not intercepted. Not commonly imported directly by apps.
@forge/manifest ❌ Manifest types. Not intercepted. Types-only usage would work at compile time.
@forge/storage ⚠️ Not directly shimmed, but @forge/api re-exports its query types. Direct import { storage } from '@forge/storage' would load the real package.

Manifest Modules

Module types recognized by forge-sim manifest parser.

Parsed & Rendered

Module Type Status Notes
jira:issuePanel ✅ Full: deploy, render, dev preview
jira:issueActivity ✅ Parsed and renderable
jira:issueContext ✅ Parsed and renderable
jira:issueGlance ✅ Parsed and renderable
jira:issueAction ✅ Parsed and renderable
jira:globalPage ✅ Parsed and renderable
jira:projectPage ✅ Parsed and renderable
jira:adminPage ✅ Parsed and renderable
jira:dashboardGadget ✅ Parsed and renderable
confluence:globalPage ✅ Parsed and renderable
confluence:spacePage ✅ Parsed and renderable
confluence:contentAction ✅ Parsed and renderable
confluence:contentBylineItem ✅ Parsed and renderable
confluence:contextMenu ✅ Parsed and renderable
macro ✅ Confluence macro — view + custom config sub-module (config: { resource: '...' }) with View/Config tabs in the parent shell, plus inline config (config: true / config: {} with ForgeReconciler.addConfig) rendered as in-iframe View/Config tabs from the reconciler's MacroConfig container. viewSubmit-driven config save (tagged with submitTree), useConfig() reads extension.config.

Parsed but Not Rendered

Module Type Status Notes
function ✅ Loaded and invocable
consumer ✅ Wired to queues
trigger ✅ Event triggers registered. 143 event templates with typed payloads.
scheduledTrigger ✅ Fireable on demand + on startup in dev mode
webtrigger ✅ HTTP endpoints at /__trigger/<key>, full request/response mapping
action ✅ Rovo actions — manifest parsing, input schema validation, invocation via MCP
jira:workflowValidator ⚠️ Config UI renders (create/edit/view resources), function invocable. No workflow transition simulation.
jira:workflowCondition ⚠️ Config UI renders, function invocable. No workflow transition simulation.
jira:workflowPostFunction ⚠️ Config UI renders, function invocable. No workflow transition simulation.
jira:customField ✅ View/edit sub-module extraction, grouped module picker, mock fieldValue in context. Jira Expressions (formatter, edit.validation.expression) not evaluated.
jira:customFieldType ✅ Same as customField. Schema validation not enforced locally.
jira:command ⚠️ Parsed, page targets, resource-based commands. No command palette simulation.

Generic Parse (limited context)

Any module type with a resource: key is parsed by the generic fallthrough at manifest.ts:637-667 and rendered as a UI module. These get only the default { type } extension context: no module-type-specific fields (e.g. sprint, board, portal request). See module-support.md for the per-module breakdown.

Module Type Status Notes
jira:serviceDeskPortalRequestDetail ⚠️ JSM portal module
jira:serviceDeskPortalRequestCreate ⚠️ JSM portal module
jira:serviceDeskPortalRequestList ⚠️ JSM portal module
jira:serviceDeskQueuePage ⚠️ JSM module
jira:backlogItemAction ⚠️ Jira Software action
jira:boardIssueAction ⚠️ Jira Software action
jira:sprintAction ⚠️ Jira Software action
jira:uiModificationsOverride ⚠️ UI modifications variant
confluence:homepageFeed ⚠️ Gets default global Confluence context
confluence:spaceSidebarItem ⚠️ Confluence sidebar item
bitbucket:pipelineStep ⚠️ Bitbucket module
bitbucket:repoPullRequestOverview ⚠️ Bitbucket module
bitbucket:repoPage ⚠️ Bitbucket module
compass:component ⚠️ Compass module
compass:adminPage ⚠️ Compass module

Not Parsed

Modules with no resource: and no resolver wiring: nothing for the simulator to load or render.

Module Type Status Notes
rovo:agent ❌ Rovo AI agent definition (config-only + AI; needs LLM integration)
app:adminPage ❌ Cross-product admin (config-only)

Platform Features

Features beyond individual APIs.

Feature Status Tests Notes
Manifest-driven deploy ✅ deployer.test.ts, deploy-e2e.test.ts Reads manifest.yml, wires everything
Module loader hooks ✅ loader-hooks.test.ts Intercepts @forge/* imports
Function contracts (calling conventions) ✅ function-contracts.test.ts Resolver, trigger, consumer, scheduled, webtrigger
Product API mock + real proxy ✅ product-api-proxy.test.ts Route-level mock priority
OAuth authentication ✅ credentials.test.ts PAT + OAuth 2.0
Persistent state (KVS) ✅ persistence.test.ts Save/restore on exit/start
Persistent state (SQL) ✅ persistence.test.ts, persistence-okr.test.ts MySQL dump/restore
Persistent state (Entities) ✅ persistence.test.ts
Concurrent queue processing ✅ concurrency.test.ts Concurrency keys, parallel execution
Multi-module UI isolation ✅ dual-panel.test.ts Separate ForgeDoc trees per module
UIKit → Atlaskit rendering ✅ — Full UIKit 2 component mappings in renderer (see renderer.md)
Custom UI serving ✅ custom-ui-e2e.test.ts Vite serves resource directory
Dev server (HMR + WebSocket) ✅ — forge-sim dev
Dev server proxy mode ✅ proxy-server.test.ts forge-sim dev --proxy <url> — reverse-proxy with bridge injection, WS passthrough
Stateful daemon (CLI) ✅ — Auto-start, idle timeout, PID management
MCP server (stdio) ✅ mcp-server.test.ts 41 tools, 4 resources (see auto-generated stats block above)
MCP server (HTTP) ✅ — StreamableHTTP transport
Egress filtering ❌ — No enforcement of permissions.external
Content Security Policy ❌ — No CSP enforcement
App installation lifecycle 🔇 — Manifest lifecycle triggers (install/uninstall/enable/disable), not simulated
Scoped permissions enforcement ❌ — No checking of permissions.scopes
Rate limiting simulation ❌ — No simulation of Forge rate limits
Invocation time limits ✅ — Per-function-type timeout warnings matching real Forge limits (25s resolver, 55s trigger, etc.)
Trigger event templates ✅ — 143 centralized templates (76 Confluence + 56 Jira + 9 Jira Software + 2 App Lifecycle) with typed payloads via TriggerPayloadByEvent
Memory limits ❌ — No simulation of 128MB heap limit
Forge Remotes ✅ remotes.test.ts Full: manifest parsing, endpoint resolution, mock routing, real HTTP with FIT JWT auth, JWKS endpoint. See remotes.md
Forge Environments ⚠️ — Always returns "DEVELOPMENT"

Summary

Counts below are per package section (all sub-tables included), recounted 2026-07-19 directly from the row markers in this file.

Category Implemented Partial/Stub Not Implemented Total
@forge/api 50 14 2 66
@forge/kvs 22 0 0 22
@forge/sql 7 0 1 8
@forge/events 19 0 0 19
@forge/llm 11 1 0 12
@forge/object-store 8 1 0 9
@forge/resolver 6 0 0 6
@forge/react 104 2 1 107
@forge/bridge 40 2 3 45
@forge/jira-bridge 1 7 0 8
@forge/confluence-bridge 0 5 0 5
@forge/dashboards-bridge 0 5 0 5
Manifest modules 23 19 2 44
Platform features 20 2 5 27
Total 311 58 14 383

Coverage: 81% implemented, 15% stubbed/partial, 4% missing