@immediately-run/sdk 0.57.4 → 0.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/theme.cjs +93 -9
- package/dist/theme.cjs.map +1 -1
- package/dist/theme.d.cts +133 -16
- package/dist/theme.d.ts +133 -16
- package/dist/theme.js +84 -9
- package/dist/theme.js.map +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.cjs.map +1 -1
- package/dist/version.d.cts +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/workspace.cjs +53 -0
- package/dist/workspace.cjs.map +1 -0
- package/dist/workspace.d.cts +58 -0
- package/dist/workspace.d.ts +58 -0
- package/dist/workspace.js +28 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -45,6 +45,7 @@ __reExport(index_exports, require("./editorContext"), module.exports);
|
|
|
45
45
|
__reExport(index_exports, require("./editor"), module.exports);
|
|
46
46
|
__reExport(index_exports, require("./formFactor"), module.exports);
|
|
47
47
|
__reExport(index_exports, require("./chromeState"), module.exports);
|
|
48
|
+
__reExport(index_exports, require("./workspace"), module.exports);
|
|
48
49
|
__reExport(index_exports, require("./hostAttention"), module.exports);
|
|
49
50
|
__reExport(index_exports, require("./region"), module.exports);
|
|
50
51
|
__reExport(index_exports, require("./mounts"), module.exports);
|
|
@@ -104,6 +105,7 @@ __reExport(index_exports, require("./fence"), module.exports);
|
|
|
104
105
|
...require("./editor"),
|
|
105
106
|
...require("./formFactor"),
|
|
106
107
|
...require("./chromeState"),
|
|
108
|
+
...require("./workspace"),
|
|
107
109
|
...require("./hostAttention"),
|
|
108
110
|
...require("./region"),
|
|
109
111
|
...require("./mounts"),
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './MDXProvider';\nexport * from './routing';\nexport * from './boot';\nexport * from './components/Include';\n// Only the component is public. `stripFrontmatter`/`appMountRelative` are module-level\n// exports so they can be unit-tested directly, NOT public API — the SDK's surface is\n// backwards-compatible forever, so an internal helper exported for a test's convenience is a\n// permanent commitment made for the wrong reason.\nexport { SafeInclude } from './components/SafeInclude';\nexport * from './sourceCache';\nexport * from './components/MDXComponents';\nexport * from './linkSpace';\nexport * from './bundle';\n// Deprecated `Corpus*` spellings of the above (R3-482); see `src/corpus.ts`.\nexport * from './corpus';\nexport * from './components/MountImage';\nexport * from './components/Routes';\nexport * from './hooks';\n// R3-276: the supported way for a viewer app to provide its own metadata store,\n// replacing a wholesale re-provision of `TinkerableContext` in app code.\nexport * from './metadataSource';\n// The deprecated injected-bundler adapters, re-exported so their deprecation notices\n// are visible in the published docs (R3-278; the window only narrows).\nexport { getInjectedMetadataEmitter, getInjectedMetadataSnapshot } from './injectedBundler';\nexport * from './auth';\nexport * from './theme';\nexport * from './editorContext';\nexport * from './editor';\nexport * from './formFactor';\nexport * from './chromeState';\nexport * from './hostAttention';\nexport * from './region';\nexport * from './mounts';\nexport * from './analytics';\nexport * from './contribute';\nexport * from './catalog';\nexport * from './ipc';\nexport * from './dnd';\nexport * from './netFetch';\nexport * from './feed';\nexport * from './secrets';\nexport * from './recents'; // R3-485: the gated recent-projects read (page.home)\nexport * from './llm';\nexport * from './diagnostics';\nexport * from './vcs';\nexport * from './onFsChange';\nexport * from './fs';\nexport * from './debug';\nexport * from './tasks';\nexport * from './launch';\nexport * from './runtime';\nexport * from './irMarkers';\nexport * from './ready';\nexport * from './loading';\nexport * from './protocolStream';\nexport * from './protocolDeadline';\nexport * from './sandboxTypes';\nexport * from './safeContent';\n// R3-489 (GROVE_AGENT_SPEC): the embedded-agent seam every app shares — the tool-use\n// loop ported from agent-demo (`runAgent` over the host chat slot), the MDX metadata\n// query tool, the headings index collector, the deixis context block, and the fence\n// for corpus-derived bytes entering a loop.\nexport * from './agentLoop';\nexport * from './agentSteering';\nexport * from './agentChatClient';\nexport * from './metadataQueryTool';\nexport * from './collectHeadings';\nexport * from './agentContext';\nexport * from './fence';\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAAc,0BAAd;AACA,0BAAc,sBADd;AAEA,0BAAc,mBAFd;AAGA,0BAAc,iCAHd;AAQA,yBAA4B;AAC5B,0BAAc,0BATd;AAUA,0BAAc,uCAVd;AAWA,0BAAc,wBAXd;AAYA,0BAAc,qBAZd;AAcA,0BAAc,qBAdd;AAeA,0BAAc,oCAfd;AAgBA,0BAAc,gCAhBd;AAiBA,0BAAc,oBAjBd;AAoBA,0BAAc,6BApBd;AAuBA,6BAAwE;AACxE,0BAAc,mBAxBd;AAyBA,0BAAc,oBAzBd;AA0BA,0BAAc,4BA1Bd;AA2BA,0BAAc,qBA3Bd;AA4BA,0BAAc,yBA5Bd;AA6BA,0BAAc,0BA7Bd;AA8BA,0BAAc,
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './MDXProvider';\nexport * from './routing';\nexport * from './boot';\nexport * from './components/Include';\n// Only the component is public. `stripFrontmatter`/`appMountRelative` are module-level\n// exports so they can be unit-tested directly, NOT public API — the SDK's surface is\n// backwards-compatible forever, so an internal helper exported for a test's convenience is a\n// permanent commitment made for the wrong reason.\nexport { SafeInclude } from './components/SafeInclude';\nexport * from './sourceCache';\nexport * from './components/MDXComponents';\nexport * from './linkSpace';\nexport * from './bundle';\n// Deprecated `Corpus*` spellings of the above (R3-482); see `src/corpus.ts`.\nexport * from './corpus';\nexport * from './components/MountImage';\nexport * from './components/Routes';\nexport * from './hooks';\n// R3-276: the supported way for a viewer app to provide its own metadata store,\n// replacing a wholesale re-provision of `TinkerableContext` in app code.\nexport * from './metadataSource';\n// The deprecated injected-bundler adapters, re-exported so their deprecation notices\n// are visible in the published docs (R3-278; the window only narrows).\nexport { getInjectedMetadataEmitter, getInjectedMetadataSnapshot } from './injectedBundler';\nexport * from './auth';\nexport * from './theme';\nexport * from './editorContext';\nexport * from './editor';\nexport * from './formFactor';\nexport * from './chromeState';\nexport * from './workspace';\nexport * from './hostAttention';\nexport * from './region';\nexport * from './mounts';\nexport * from './analytics';\nexport * from './contribute';\nexport * from './catalog';\nexport * from './ipc';\nexport * from './dnd';\nexport * from './netFetch';\nexport * from './feed';\nexport * from './secrets';\nexport * from './recents'; // R3-485: the gated recent-projects read (page.home)\nexport * from './llm';\nexport * from './diagnostics';\nexport * from './vcs';\nexport * from './onFsChange';\nexport * from './fs';\nexport * from './debug';\nexport * from './tasks';\nexport * from './launch';\nexport * from './runtime';\nexport * from './irMarkers';\nexport * from './ready';\nexport * from './loading';\nexport * from './protocolStream';\nexport * from './protocolDeadline';\nexport * from './sandboxTypes';\nexport * from './safeContent';\n// R3-489 (GROVE_AGENT_SPEC): the embedded-agent seam every app shares — the tool-use\n// loop ported from agent-demo (`runAgent` over the host chat slot), the MDX metadata\n// query tool, the headings index collector, the deixis context block, and the fence\n// for corpus-derived bytes entering a loop.\nexport * from './agentLoop';\nexport * from './agentSteering';\nexport * from './agentChatClient';\nexport * from './metadataQueryTool';\nexport * from './collectHeadings';\nexport * from './agentContext';\nexport * from './fence';\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAAc,0BAAd;AACA,0BAAc,sBADd;AAEA,0BAAc,mBAFd;AAGA,0BAAc,iCAHd;AAQA,yBAA4B;AAC5B,0BAAc,0BATd;AAUA,0BAAc,uCAVd;AAWA,0BAAc,wBAXd;AAYA,0BAAc,qBAZd;AAcA,0BAAc,qBAdd;AAeA,0BAAc,oCAfd;AAgBA,0BAAc,gCAhBd;AAiBA,0BAAc,oBAjBd;AAoBA,0BAAc,6BApBd;AAuBA,6BAAwE;AACxE,0BAAc,mBAxBd;AAyBA,0BAAc,oBAzBd;AA0BA,0BAAc,4BA1Bd;AA2BA,0BAAc,qBA3Bd;AA4BA,0BAAc,yBA5Bd;AA6BA,0BAAc,0BA7Bd;AA8BA,0BAAc,wBA9Bd;AA+BA,0BAAc,4BA/Bd;AAgCA,0BAAc,qBAhCd;AAiCA,0BAAc,qBAjCd;AAkCA,0BAAc,wBAlCd;AAmCA,0BAAc,yBAnCd;AAoCA,0BAAc,sBApCd;AAqCA,0BAAc,kBArCd;AAsCA,0BAAc,kBAtCd;AAuCA,0BAAc,uBAvCd;AAwCA,0BAAc,mBAxCd;AAyCA,0BAAc,sBAzCd;AA0CA,0BAAc,sBA1Cd;AA2CA,0BAAc,kBA3Cd;AA4CA,0BAAc,0BA5Cd;AA6CA,0BAAc,kBA7Cd;AA8CA,0BAAc,yBA9Cd;AA+CA,0BAAc,iBA/Cd;AAgDA,0BAAc,oBAhDd;AAiDA,0BAAc,oBAjDd;AAkDA,0BAAc,qBAlDd;AAmDA,0BAAc,sBAnDd;AAoDA,0BAAc,wBApDd;AAqDA,0BAAc,oBArDd;AAsDA,0BAAc,sBAtDd;AAuDA,0BAAc,6BAvDd;AAwDA,0BAAc,+BAxDd;AAyDA,0BAAc,2BAzDd;AA0DA,0BAAc,0BA1Dd;AA+DA,0BAAc,wBA/Dd;AAgEA,0BAAc,4BAhEd;AAiEA,0BAAc,8BAjEd;AAkEA,0BAAc,gCAlEd;AAmEA,0BAAc,8BAnEd;AAoEA,0BAAc,2BApEd;AAqEA,0BAAc,oBArEd;","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -13,11 +13,12 @@ export { ObjectUrlState, useAllMetadata, useFileMetadata, useMetadataQuery, useO
|
|
|
13
13
|
export { MetadataSource, MetadataSourceMode, MetadataSourceProps, useMetadataStore } from './metadataSource.cjs';
|
|
14
14
|
export { getInjectedMetadataEmitter, getInjectedMetadataSnapshot } from './injectedBundler.cjs';
|
|
15
15
|
export { AuthState, AuthStatus, SandboxUser, getAuthState, onAuthChange, useAuth } from './auth.cjs';
|
|
16
|
-
export { HostTheme, getHostTheme, onHostThemeChange, setHostTheme, useHostTheme } from './theme.cjs';
|
|
16
|
+
export { HostTheme, HostThemeSelection, SetHostThemeSelectionParams, ThemeBundleLocation, ThemeCatalog, ThemeCatalogEntry, addThemeSource, getHostTheme, getHostThemeSelection, getThemeCatalog, onHostThemeChange, onHostThemeSelectionChange, onThemeCatalogChange, removeThemeSource, setHostTheme, setHostThemeSelection, useHostTheme, useHostThemeSelection, useThemeCatalog } from './theme.cjs';
|
|
17
17
|
export { EditorContext, getEditorContext, onEditorContextChange, useEditorContext } from './editorContext.cjs';
|
|
18
18
|
export { EditTarget, EditorOpenError, EditorOpenOptions, EditorSelection, EditorSessionError, EditorWriteError, RequestEditError, closeFile, createFile, createFolder, deleteEntry, openInEditor, renameEntry, requestEdit, setActiveFile, uploadFile } from './editor.cjs';
|
|
19
19
|
export { FormFactor, FormFactorClass, Orientation, getFormFactor, onFormFactorChange, useFormFactor } from './formFactor.cjs';
|
|
20
20
|
export { ChromeState, getChromeState, onChromeStateChange, useChromeState } from './chromeState.cjs';
|
|
21
|
+
export { Workspace, getWorkspace, onWorkspaceChange, useWorkspace } from './workspace.cjs';
|
|
21
22
|
export { HostAttention, HostAttentionKind, NO_HOST_ATTENTION, getHostAttention, onHostAttentionChange, useHostAttention } from './hostAttention.cjs';
|
|
22
23
|
export { getRegion, useRegion } from './region.cjs';
|
|
23
24
|
export { Invite, MountQuery, MountRemoveReason, MountRule, RemovedMount, SandboxMount, SessionMount, SpaceError, acceptInvite, awaitMatchingMount, createSpace, declineInvite, findMount, getAppMountPath, getInvites, getMounts, getSessionMounts, importSettingsFromParent, listMyInvites, listPendingInvites, listSettingsApps, makeContentRef, mount, mountSpace, onInvitesChange, onMountsChange, onSessionMountsChange, openSettings, openSettingsOf, requestMount, requestSpace, resolveContentRef, resolveContentRefs, revokeInvite, unmountSpace, useInvites, useMounts, useSessionMounts, waitForMount } from './mounts.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -13,11 +13,12 @@ export { ObjectUrlState, useAllMetadata, useFileMetadata, useMetadataQuery, useO
|
|
|
13
13
|
export { MetadataSource, MetadataSourceMode, MetadataSourceProps, useMetadataStore } from './metadataSource.js';
|
|
14
14
|
export { getInjectedMetadataEmitter, getInjectedMetadataSnapshot } from './injectedBundler.js';
|
|
15
15
|
export { AuthState, AuthStatus, SandboxUser, getAuthState, onAuthChange, useAuth } from './auth.js';
|
|
16
|
-
export { HostTheme, getHostTheme, onHostThemeChange, setHostTheme, useHostTheme } from './theme.js';
|
|
16
|
+
export { HostTheme, HostThemeSelection, SetHostThemeSelectionParams, ThemeBundleLocation, ThemeCatalog, ThemeCatalogEntry, addThemeSource, getHostTheme, getHostThemeSelection, getThemeCatalog, onHostThemeChange, onHostThemeSelectionChange, onThemeCatalogChange, removeThemeSource, setHostTheme, setHostThemeSelection, useHostTheme, useHostThemeSelection, useThemeCatalog } from './theme.js';
|
|
17
17
|
export { EditorContext, getEditorContext, onEditorContextChange, useEditorContext } from './editorContext.js';
|
|
18
18
|
export { EditTarget, EditorOpenError, EditorOpenOptions, EditorSelection, EditorSessionError, EditorWriteError, RequestEditError, closeFile, createFile, createFolder, deleteEntry, openInEditor, renameEntry, requestEdit, setActiveFile, uploadFile } from './editor.js';
|
|
19
19
|
export { FormFactor, FormFactorClass, Orientation, getFormFactor, onFormFactorChange, useFormFactor } from './formFactor.js';
|
|
20
20
|
export { ChromeState, getChromeState, onChromeStateChange, useChromeState } from './chromeState.js';
|
|
21
|
+
export { Workspace, getWorkspace, onWorkspaceChange, useWorkspace } from './workspace.js';
|
|
21
22
|
export { HostAttention, HostAttentionKind, NO_HOST_ATTENTION, getHostAttention, onHostAttentionChange, useHostAttention } from './hostAttention.js';
|
|
22
23
|
export { getRegion, useRegion } from './region.js';
|
|
23
24
|
export { Invite, MountQuery, MountRemoveReason, MountRule, RemovedMount, SandboxMount, SessionMount, SpaceError, acceptInvite, awaitMatchingMount, createSpace, declineInvite, findMount, getAppMountPath, getInvites, getMounts, getSessionMounts, importSettingsFromParent, listMyInvites, listPendingInvites, listSettingsApps, makeContentRef, mount, mountSpace, onInvitesChange, onMountsChange, onSessionMountsChange, openSettings, openSettingsOf, requestMount, requestSpace, resolveContentRef, resolveContentRefs, revokeInvite, unmountSpace, useInvites, useMounts, useSessionMounts, waitForMount } from './mounts.js';
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './MDXProvider';\nexport * from './routing';\nexport * from './boot';\nexport * from './components/Include';\n// Only the component is public. `stripFrontmatter`/`appMountRelative` are module-level\n// exports so they can be unit-tested directly, NOT public API — the SDK's surface is\n// backwards-compatible forever, so an internal helper exported for a test's convenience is a\n// permanent commitment made for the wrong reason.\nexport { SafeInclude } from './components/SafeInclude';\nexport * from './sourceCache';\nexport * from './components/MDXComponents';\nexport * from './linkSpace';\nexport * from './bundle';\n// Deprecated `Corpus*` spellings of the above (R3-482); see `src/corpus.ts`.\nexport * from './corpus';\nexport * from './components/MountImage';\nexport * from './components/Routes';\nexport * from './hooks';\n// R3-276: the supported way for a viewer app to provide its own metadata store,\n// replacing a wholesale re-provision of `TinkerableContext` in app code.\nexport * from './metadataSource';\n// The deprecated injected-bundler adapters, re-exported so their deprecation notices\n// are visible in the published docs (R3-278; the window only narrows).\nexport { getInjectedMetadataEmitter, getInjectedMetadataSnapshot } from './injectedBundler';\nexport * from './auth';\nexport * from './theme';\nexport * from './editorContext';\nexport * from './editor';\nexport * from './formFactor';\nexport * from './chromeState';\nexport * from './hostAttention';\nexport * from './region';\nexport * from './mounts';\nexport * from './analytics';\nexport * from './contribute';\nexport * from './catalog';\nexport * from './ipc';\nexport * from './dnd';\nexport * from './netFetch';\nexport * from './feed';\nexport * from './secrets';\nexport * from './recents'; // R3-485: the gated recent-projects read (page.home)\nexport * from './llm';\nexport * from './diagnostics';\nexport * from './vcs';\nexport * from './onFsChange';\nexport * from './fs';\nexport * from './debug';\nexport * from './tasks';\nexport * from './launch';\nexport * from './runtime';\nexport * from './irMarkers';\nexport * from './ready';\nexport * from './loading';\nexport * from './protocolStream';\nexport * from './protocolDeadline';\nexport * from './sandboxTypes';\nexport * from './safeContent';\n// R3-489 (GROVE_AGENT_SPEC): the embedded-agent seam every app shares — the tool-use\n// loop ported from agent-demo (`runAgent` over the host chat slot), the MDX metadata\n// query tool, the headings index collector, the deixis context block, and the fence\n// for corpus-derived bytes entering a loop.\nexport * from './agentLoop';\nexport * from './agentSteering';\nexport * from './agentChatClient';\nexport * from './metadataQueryTool';\nexport * from './collectHeadings';\nexport * from './agentContext';\nexport * from './fence';\n"],"mappings":";AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAKd,SAAS,mBAAmB;AAC5B,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAEd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AAGd,SAAS,4BAA4B,mCAAmC;AACxE,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAKd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './MDXProvider';\nexport * from './routing';\nexport * from './boot';\nexport * from './components/Include';\n// Only the component is public. `stripFrontmatter`/`appMountRelative` are module-level\n// exports so they can be unit-tested directly, NOT public API — the SDK's surface is\n// backwards-compatible forever, so an internal helper exported for a test's convenience is a\n// permanent commitment made for the wrong reason.\nexport { SafeInclude } from './components/SafeInclude';\nexport * from './sourceCache';\nexport * from './components/MDXComponents';\nexport * from './linkSpace';\nexport * from './bundle';\n// Deprecated `Corpus*` spellings of the above (R3-482); see `src/corpus.ts`.\nexport * from './corpus';\nexport * from './components/MountImage';\nexport * from './components/Routes';\nexport * from './hooks';\n// R3-276: the supported way for a viewer app to provide its own metadata store,\n// replacing a wholesale re-provision of `TinkerableContext` in app code.\nexport * from './metadataSource';\n// The deprecated injected-bundler adapters, re-exported so their deprecation notices\n// are visible in the published docs (R3-278; the window only narrows).\nexport { getInjectedMetadataEmitter, getInjectedMetadataSnapshot } from './injectedBundler';\nexport * from './auth';\nexport * from './theme';\nexport * from './editorContext';\nexport * from './editor';\nexport * from './formFactor';\nexport * from './chromeState';\nexport * from './workspace';\nexport * from './hostAttention';\nexport * from './region';\nexport * from './mounts';\nexport * from './analytics';\nexport * from './contribute';\nexport * from './catalog';\nexport * from './ipc';\nexport * from './dnd';\nexport * from './netFetch';\nexport * from './feed';\nexport * from './secrets';\nexport * from './recents'; // R3-485: the gated recent-projects read (page.home)\nexport * from './llm';\nexport * from './diagnostics';\nexport * from './vcs';\nexport * from './onFsChange';\nexport * from './fs';\nexport * from './debug';\nexport * from './tasks';\nexport * from './launch';\nexport * from './runtime';\nexport * from './irMarkers';\nexport * from './ready';\nexport * from './loading';\nexport * from './protocolStream';\nexport * from './protocolDeadline';\nexport * from './sandboxTypes';\nexport * from './safeContent';\n// R3-489 (GROVE_AGENT_SPEC): the embedded-agent seam every app shares — the tool-use\n// loop ported from agent-demo (`runAgent` over the host chat slot), the MDX metadata\n// query tool, the headings index collector, the deixis context block, and the fence\n// for corpus-derived bytes entering a loop.\nexport * from './agentLoop';\nexport * from './agentSteering';\nexport * from './agentChatClient';\nexport * from './metadataQueryTool';\nexport * from './collectHeadings';\nexport * from './agentContext';\nexport * from './fence';\n"],"mappings":";AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAKd,SAAS,mBAAmB;AAC5B,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAEd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AAGd,SAAS,4BAA4B,mCAAmC;AACxE,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAKd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
|
package/dist/theme.cjs
CHANGED
|
@@ -18,38 +18,122 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var theme_exports = {};
|
|
20
20
|
__export(theme_exports, {
|
|
21
|
+
addThemeSource: () => addThemeSource,
|
|
21
22
|
getHostTheme: () => getHostTheme,
|
|
23
|
+
getHostThemeSelection: () => getHostThemeSelection,
|
|
24
|
+
getThemeCatalog: () => getThemeCatalog,
|
|
22
25
|
onHostThemeChange: () => onHostThemeChange,
|
|
26
|
+
onHostThemeSelectionChange: () => onHostThemeSelectionChange,
|
|
27
|
+
onThemeCatalogChange: () => onThemeCatalogChange,
|
|
28
|
+
removeThemeSource: () => removeThemeSource,
|
|
23
29
|
setHostTheme: () => setHostTheme,
|
|
24
|
-
|
|
30
|
+
setHostThemeSelection: () => setHostThemeSelection,
|
|
31
|
+
useHostTheme: () => useHostTheme,
|
|
32
|
+
useHostThemeSelection: () => useHostThemeSelection,
|
|
33
|
+
useThemeCatalog: () => useThemeCatalog
|
|
25
34
|
});
|
|
26
35
|
module.exports = __toCommonJS(theme_exports);
|
|
27
36
|
var import_pushChannel = require("./pushChannel");
|
|
28
37
|
var import_sandboxUtils = require("./sandboxUtils");
|
|
29
38
|
var import_protocol = require("./generated/protocol");
|
|
30
39
|
var import_protocolSchemes = require("./protocolSchemes");
|
|
40
|
+
const DEFAULT_SELECTION = {
|
|
41
|
+
theme: "dark",
|
|
42
|
+
themeKey: "immediately-run-default",
|
|
43
|
+
modeId: "dark"
|
|
44
|
+
};
|
|
31
45
|
const channel = (0, import_pushChannel.createPushChannel)({
|
|
32
46
|
pushType: import_protocol.THEME,
|
|
33
47
|
requestType: import_protocol.REQUEST_THEME,
|
|
34
|
-
initial:
|
|
35
|
-
parse: (msg) =>
|
|
48
|
+
initial: DEFAULT_SELECTION,
|
|
49
|
+
parse: (msg) => {
|
|
50
|
+
if (msg.theme !== "light" && msg.theme !== "dark") return void 0;
|
|
51
|
+
if (typeof msg.themeKey !== "string" || typeof msg.modeId !== "string") return void 0;
|
|
52
|
+
return { theme: msg.theme, themeKey: msg.themeKey, modeId: msg.modeId };
|
|
53
|
+
}
|
|
36
54
|
});
|
|
37
|
-
const getHostTheme = () => channel.get();
|
|
38
|
-
const onHostThemeChange = (listener) => channel.onChange(listener);
|
|
39
|
-
const useHostTheme = () => channel.use();
|
|
40
|
-
const
|
|
41
|
-
|
|
55
|
+
const getHostTheme = () => channel.get().theme;
|
|
56
|
+
const onHostThemeChange = (listener) => channel.onChange((sel) => listener(sel.theme));
|
|
57
|
+
const useHostTheme = () => channel.use().theme;
|
|
58
|
+
const getHostThemeSelection = () => channel.get();
|
|
59
|
+
const onHostThemeSelectionChange = (listener) => channel.onChange(listener);
|
|
60
|
+
const useHostThemeSelection = () => channel.use();
|
|
61
|
+
const DEFAULT_CATALOG = { themes: [] };
|
|
62
|
+
const catalogChannel = (0, import_pushChannel.createPushChannel)({
|
|
63
|
+
pushType: import_protocol.THEME_CATALOG,
|
|
64
|
+
requestType: import_protocol.REQUEST_THEME_CATALOG,
|
|
65
|
+
initial: DEFAULT_CATALOG,
|
|
66
|
+
parse: (msg) => {
|
|
67
|
+
const themes = msg.themes;
|
|
68
|
+
if (!Array.isArray(themes)) return void 0;
|
|
69
|
+
const out = [];
|
|
70
|
+
for (const t of themes) {
|
|
71
|
+
if (!t || typeof t !== "object") return void 0;
|
|
72
|
+
const entry = t;
|
|
73
|
+
if (typeof entry.themeKey !== "string" || typeof entry.label !== "string" || !Array.isArray(entry.modes)) {
|
|
74
|
+
return void 0;
|
|
75
|
+
}
|
|
76
|
+
const modes = [];
|
|
77
|
+
for (const m of entry.modes) {
|
|
78
|
+
if (!m || typeof m !== "object") return void 0;
|
|
79
|
+
const mode = m;
|
|
80
|
+
if (typeof mode.id !== "string" || mode.polarity !== "light" && mode.polarity !== "dark") {
|
|
81
|
+
return void 0;
|
|
82
|
+
}
|
|
83
|
+
modes.push({ id: mode.id, polarity: mode.polarity });
|
|
84
|
+
}
|
|
85
|
+
out.push({ themeKey: entry.themeKey, label: entry.label, modes });
|
|
86
|
+
}
|
|
87
|
+
return { themes: out };
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
const getThemeCatalog = () => catalogChannel.get();
|
|
91
|
+
const onThemeCatalogChange = (listener) => catalogChannel.onChange(listener);
|
|
92
|
+
const useThemeCatalog = () => catalogChannel.use();
|
|
93
|
+
const setTheme = async (params) => {
|
|
94
|
+
const res = await (0, import_sandboxUtils.protocolRequest)(import_protocolSchemes.SCHEMES[import_protocol.PROTOCOL_THEME], "set", [params]);
|
|
42
95
|
if (!res || res.ok !== true) {
|
|
43
96
|
const err = new Error(res?.message ?? "setHostTheme failed");
|
|
44
97
|
err.code = (res && "code" in res ? res.code : void 0) ?? "unknown";
|
|
45
98
|
throw err;
|
|
46
99
|
}
|
|
47
100
|
};
|
|
101
|
+
const setHostThemeSelection = async (selection) => {
|
|
102
|
+
await setTheme(selection);
|
|
103
|
+
};
|
|
104
|
+
const setHostTheme = async (theme) => {
|
|
105
|
+
await setTheme({ theme });
|
|
106
|
+
};
|
|
107
|
+
const addThemeSource = async (location) => {
|
|
108
|
+
const res = await (0, import_sandboxUtils.protocolRequest)(import_protocolSchemes.SCHEMES[import_protocol.PROTOCOL_THEME], "add-source", [{ location }]);
|
|
109
|
+
if (!res || res.ok !== true) {
|
|
110
|
+
const err = new Error(res?.message ?? "addThemeSource failed");
|
|
111
|
+
err.code = (res && "code" in res ? res.code : void 0) ?? "unknown";
|
|
112
|
+
throw err;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const removeThemeSource = async (themeKey) => {
|
|
116
|
+
const res = await (0, import_sandboxUtils.protocolRequest)(import_protocolSchemes.SCHEMES[import_protocol.PROTOCOL_THEME], "remove-source", [{ themeKey }]);
|
|
117
|
+
if (!res || res.ok !== true) {
|
|
118
|
+
const err = new Error(res?.message ?? "removeThemeSource failed");
|
|
119
|
+
err.code = (res && "code" in res ? res.code : void 0) ?? "unknown";
|
|
120
|
+
throw err;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
48
123
|
// Annotate the CommonJS export names for ESM import in node:
|
|
49
124
|
0 && (module.exports = {
|
|
125
|
+
addThemeSource,
|
|
50
126
|
getHostTheme,
|
|
127
|
+
getHostThemeSelection,
|
|
128
|
+
getThemeCatalog,
|
|
51
129
|
onHostThemeChange,
|
|
130
|
+
onHostThemeSelectionChange,
|
|
131
|
+
onThemeCatalogChange,
|
|
132
|
+
removeThemeSource,
|
|
52
133
|
setHostTheme,
|
|
53
|
-
|
|
134
|
+
setHostThemeSelection,
|
|
135
|
+
useHostTheme,
|
|
136
|
+
useHostThemeSelection,
|
|
137
|
+
useThemeCatalog
|
|
54
138
|
});
|
|
55
139
|
//# sourceMappingURL=theme.cjs.map
|
package/dist/theme.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/theme.ts"],"sourcesContent":["import { createPushChannel } from './pushChannel';\nimport { protocolRequest } from './sandboxUtils';\nimport { PROTOCOL_THEME, REQUEST_THEME, THEME } from './generated/protocol';\nimport { SCHEMES } from './protocolSchemes';\n\n/**\n * The host UI theme, mirrored from the immediately.run host window into the\n * sandbox. Your app can read this to render in step with the host chrome\n * (light / dark).\n *\n * This is the baseline `theme:read` capability — every app may read it. Changing\n * the host theme is a separate, elevated action (`theme:set`), available only to\n * the theme-toggle system app.\n */\nexport type HostTheme = 'light' | 'dark';\n\n// Read over the transport (SDK_PACKAGING_SPEC §4): the host pushes `theme` and\n// answers `request-theme` (wire format: site-main channelBridge.ts). The host's\n// default before it reports is `dark` (sandbox themeState.DEFAULT_THEME).\nconst channel = createPushChannel<HostTheme>({\n pushType: THEME,\n requestType: REQUEST_THEME,\n initial: 'dark',\n parse: (msg) => (msg.theme === 'light' || msg.theme === 'dark' ? msg.theme : undefined),\n});\n\n/**\n * Returns the current host theme. Poll this for a one-off read; use\n * {@link onHostThemeChange} or {@link useHostTheme} to react to changes.\n */\nexport const getHostTheme = (): HostTheme => channel.get();\n\n/**\n * Subscribe to host theme changes. The listener is invoked immediately with the\n * current theme, then again on every change. Returns an unsubscribe fn.\n */\nexport const onHostThemeChange = (listener: (theme: HostTheme) => void): (() => void) => channel.onChange(listener);\n\n/**\n * React hook returning the current host theme, re-rendering when it changes.\n * The recommended way to implement an app's own `useTheme`: follow the host,\n * allow a local override.\n */\nexport const useHostTheme = (): HostTheme => channel.use();\n\n/**\n * Set the host UI theme — the ELEVATED `theme:set` action (§8.5). The host\n * applies it and re-pushes the new value to every `theme:read` iframe, so your\n * own {@link useHostTheme} confirms the change (the loop closes with no special\n * case). Only a grant holding `theme:set` (e.g. the theme-toggle system app) may\n * call this; any other app is rejected host-side with a `forbidden`\n * {@link Error} (carrying `.code`), regardless of what the app claims. Update\n * optimistically and let the re-push confirm.\n */\nexport const setHostTheme = async (theme: HostTheme): Promise<void> => {\n const res = (await protocolRequest(SCHEMES[PROTOCOL_THEME], 'set', [{ theme }])) as\n | { ok: true; data?: unknown }\n | { ok: false; code?: string; message?: string }\n | undefined;\n if (!res || res.ok !== true) {\n const err = new Error(res?.message ?? 'setHostTheme failed') as Error & {\n code?: string;\n };\n err.code = (res && 'code' in res ? res.code : undefined) ?? 'unknown';\n throw err;\n }\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAkC;AAClC,0BAAgC;AAChC,sBAAqD;AACrD,6BAAwB;AAgBxB,MAAM,cAAU,sCAA6B;AAAA,EAC3C,UAAU;AAAA,EACV,aAAa;AAAA,EACb,SAAS;AAAA,EACT,OAAO,CAAC,QAAS,IAAI,UAAU,WAAW,IAAI,UAAU,SAAS,IAAI,QAAQ;AAC/E,CAAC;AAMM,MAAM,eAAe,MAAiB,QAAQ,IAAI;AAMlD,MAAM,oBAAoB,CAAC,aAAuD,QAAQ,SAAS,QAAQ;AAO3G,MAAM,eAAe,MAAiB,QAAQ,IAAI;AAWlD,MAAM,eAAe,OAAO,UAAoC;AACrE,QAAM,MAAO,UAAM,qCAAgB,+BAAQ,8BAAc,GAAG,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;AAI9E,MAAI,CAAC,OAAO,IAAI,OAAO,MAAM;AAC3B,UAAM,MAAM,IAAI,MAAM,KAAK,WAAW,qBAAqB;AAG3D,QAAI,QAAQ,OAAO,UAAU,MAAM,IAAI,OAAO,WAAc;AAC5D,UAAM;AAAA,EACR;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/theme.ts"],"sourcesContent":["import { createPushChannel } from './pushChannel';\nimport { protocolRequest } from './sandboxUtils';\nimport { PROTOCOL_THEME, REQUEST_THEME, REQUEST_THEME_CATALOG, THEME, THEME_CATALOG } from './generated/protocol';\nimport { SCHEMES } from './protocolSchemes';\n\n/**\n * The host UI theme polarity, mirrored from the immediately.run host window into\n * the sandbox. Your app can read this to render in step with the host chrome\n * (light / dark).\n *\n * This is the baseline `theme:read` capability — every app may read it. Changing\n * the host theme is a separate, elevated action (`theme:set`), available only to\n * the theme-toggle system app.\n *\n * `HostTheme` is the RESOLVED POLARITY only. The full selection — which theme is\n * active and which of its modes — is {@link HostThemeSelection}.\n */\nexport type HostTheme = 'light' | 'dark';\n\n/**\n * The full host theme selection (HOST_THEMING_SPEC §2/§9.1): the resolved polarity\n * plus the active theme's registry key and resolved mode. Carried on the widened\n * `theme` push. `modeId` is always the RESOLVED mode (never the literal `system` —\n * an app wants to know what is on screen).\n */\nexport interface HostThemeSelection {\n /** Resolved polarity — the same value the legacy `theme` field carried. */\n theme: HostTheme;\n /** The host-minted registry key of the active theme. */\n themeKey: string;\n /** The resolved active mode id of the active theme. */\n modeId: string;\n}\n\n/**\n * The selection assumed before the host reports. The platform default theme is\n * `immediately-run-default` (dark polarity first-paint, matching the shipped\n * provider default — HOST_THEMING_SPEC §3 build-time correction).\n */\nconst DEFAULT_SELECTION: HostThemeSelection = {\n theme: 'dark',\n themeKey: 'immediately-run-default',\n modeId: 'dark',\n};\n\n// Read over the transport (SDK_PACKAGING_SPEC §4): the host pushes `theme` and\n// answers `request-theme` (wire format: site-main channelBridge.ts). The parse\n// reads ALL THREE fields so the full selection survives the transport; the\n// polarity-only surface derives from it.\nconst channel = createPushChannel<HostThemeSelection>({\n pushType: THEME,\n requestType: REQUEST_THEME,\n initial: DEFAULT_SELECTION,\n parse: (msg) => {\n if (msg.theme !== 'light' && msg.theme !== 'dark') return undefined;\n if (typeof msg.themeKey !== 'string' || typeof msg.modeId !== 'string') return undefined;\n return { theme: msg.theme, themeKey: msg.themeKey, modeId: msg.modeId };\n },\n});\n\n/**\n * Returns the current host theme polarity. Poll this for a one-off read; use\n * {@link onHostThemeChange} or {@link useHostTheme} to react to changes.\n */\nexport const getHostTheme = (): HostTheme => channel.get().theme;\n\n/**\n * Subscribe to host theme polarity changes. The listener is invoked immediately\n * with the current polarity, then again on every change. Returns an unsubscribe fn.\n */\nexport const onHostThemeChange = (listener: (theme: HostTheme) => void): (() => void) =>\n channel.onChange((sel) => listener(sel.theme));\n\n/**\n * React hook returning the current host theme polarity, re-rendering when it\n * changes. The recommended way to implement an app's own `useTheme`: follow the\n * host, allow a local override.\n */\nexport const useHostTheme = (): HostTheme => channel.use().theme;\n\n/**\n * Returns the current full host theme selection — polarity, active theme key, and\n * resolved mode. Use {@link useHostThemeSelection} to react to changes.\n */\nexport const getHostThemeSelection = (): HostThemeSelection => channel.get();\n\n/**\n * Subscribe to full host theme selection changes. The listener is invoked\n * immediately with the current selection, then again on every change. Returns an\n * unsubscribe fn.\n */\nexport const onHostThemeSelectionChange = (listener: (selection: HostThemeSelection) => void): (() => void) =>\n channel.onChange(listener);\n\n/** React hook returning the current full host theme selection. */\nexport const useHostThemeSelection = (): HostThemeSelection => channel.use();\n\n/**\n * One entry of the theme catalogue: a selectable theme and its modes. The\n * catalogue is projected per grant — the baseline `theme:read` projection carries\n * NO source identities (no repo coordinates, no spaceIds), and labels are bounded.\n */\nexport interface ThemeCatalogEntry {\n themeKey: string;\n label: string;\n modes: { id: string; polarity: 'light' | 'dark' }[];\n}\n\n/**\n * The loaded-theme catalogue (HOST_THEMING_SPEC §9.2): every selectable theme, so\n * a theme-aware app can render a picker and match chrome. Pushed on\n * `theme-catalog` / polled with `request-theme-catalog`.\n */\nexport interface ThemeCatalog {\n themes: ThemeCatalogEntry[];\n}\n\nconst DEFAULT_CATALOG: ThemeCatalog = { themes: [] };\n\nconst catalogChannel = createPushChannel<ThemeCatalog>({\n pushType: THEME_CATALOG,\n requestType: REQUEST_THEME_CATALOG,\n initial: DEFAULT_CATALOG,\n parse: (msg) => {\n const themes = msg.themes;\n if (!Array.isArray(themes)) return undefined;\n const out: ThemeCatalogEntry[] = [];\n for (const t of themes as unknown[]) {\n if (!t || typeof t !== 'object') return undefined;\n const entry = t as { themeKey?: unknown; label?: unknown; modes?: unknown };\n if (typeof entry.themeKey !== 'string' || typeof entry.label !== 'string' || !Array.isArray(entry.modes)) {\n return undefined;\n }\n const modes: ThemeCatalogEntry['modes'] = [];\n for (const m of entry.modes) {\n if (!m || typeof m !== 'object') return undefined;\n const mode = m as { id?: unknown; polarity?: unknown };\n if (typeof mode.id !== 'string' || (mode.polarity !== 'light' && mode.polarity !== 'dark')) {\n return undefined;\n }\n modes.push({ id: mode.id, polarity: mode.polarity });\n }\n out.push({ themeKey: entry.themeKey, label: entry.label, modes });\n }\n return { themes: out };\n },\n});\n\n/**\n * Returns the current theme catalogue (themes + their modes). Use\n * {@link useThemeCatalog} to react to changes.\n */\nexport const getThemeCatalog = (): ThemeCatalog => catalogChannel.get();\n\n/**\n * Subscribe to theme catalogue changes. The listener is invoked immediately with\n * the current catalogue, then again on every change. Returns an unsubscribe fn.\n */\nexport const onThemeCatalogChange = (listener: (catalog: ThemeCatalog) => void): (() => void) =>\n catalogChannel.onChange(listener);\n\n/** React hook returning the current theme catalogue. */\nexport const useThemeCatalog = (): ThemeCatalog => catalogChannel.use();\n\n/**\n * A location the open-bundle picker returned — a repo or a space, with a\n * confined in-bundle path (OPEN_BUNDLE_SPEC §2). Carried to the host's\n * `theme:sources` `add-source` verb.\n */\nexport type ThemeBundleLocation =\n | { kind: 'repo'; repo: string; ref?: string; path: string }\n | { kind: 'space'; spaceId: string; path: string };\n\n/**\n * The canonical `theme:set` params (HOST_THEMING_SPEC §9.3). `theme` is the\n * registry key of the theme to select (or the legacy `'light' | 'dark'` polarity —\n * the host disambiguates by the reserved-id rule: legacy iff the value is\n * light/dark AND `mode` is absent). `mode` is one of that theme's modes or\n * `'system'`.\n */\nexport interface SetHostThemeSelectionParams {\n theme: string;\n mode?: string;\n}\n\n/** The one `set` call site, so the wire shape is fingerprint-stable. */\nconst setTheme = async (params: SetHostThemeSelectionParams): Promise<void> => {\n const res = (await protocolRequest(SCHEMES[PROTOCOL_THEME], 'set', [params])) as\n | { ok: true; data?: unknown }\n | { ok: false; code?: string; message?: string }\n | undefined;\n if (!res || res.ok !== true) {\n const err = new Error(res?.message ?? 'setHostTheme failed') as Error & {\n code?: string;\n };\n err.code = (res && 'code' in res ? res.code : undefined) ?? 'unknown';\n throw err;\n }\n};\n\n/**\n * Set the host theme selection — the ELEVATED `theme:set` action\n * (HOST_THEMING_SPEC §9.3). `theme` is the registry key of the theme to select,\n * `mode` is one of that theme's modes or `'system'`. The host applies it and\n * re-pushes the new selection to every `theme:read` iframe, so your own\n * {@link useHostThemeSelection} confirms the change (the loop closes with no\n * special case). Only a grant holding `theme:set` (e.g. the theme-toggle system\n * app) may call this; any other app is rejected host-side with a `forbidden`\n * {@link Error} (carrying `.code`), regardless of what the app claims.\n */\nexport const setHostThemeSelection = async (selection: { theme: string; mode: string }): Promise<void> => {\n await setTheme(selection);\n};\n\n/**\n * Set the host UI theme polarity — the LEGACY form of `theme:set` (§9.3). The host\n * applies that polarity to the CURRENT theme (never resets to the default), then\n * re-pushes. Keep this alias for old-SDK callers; new code should prefer\n * {@link setHostThemeSelection}.\n */\nexport const setHostTheme = async (theme: HostTheme): Promise<void> => {\n await setTheme({ theme });\n};\n\n/**\n * Add a theme source — the ELEVATED `theme:sources` `add-source` verb\n * (HOST_THEMING_SPEC §9.3). `location` must be a location the host journal saw a\n * RECENT open-bundle invocation OF THIS APP return (the picker-provenance rule —\n * \"the pick is the consent\", machine-checked); anything else is rejected with a\n * readable reason. The host fetches, gates, and registers the theme before\n * returning, so a rejected pick surfaces inline in the switcher. Only a grant\n * holding `theme:sources` (the theme switcher) may call this.\n */\nexport const addThemeSource = async (location: ThemeBundleLocation): Promise<void> => {\n const res = (await protocolRequest(SCHEMES[PROTOCOL_THEME], 'add-source', [{ location }])) as\n | { ok: true; data?: unknown }\n | { ok: false; code?: string; message?: string }\n | undefined;\n if (!res || res.ok !== true) {\n const err = new Error(res?.message ?? 'addThemeSource failed') as Error & {\n code?: string;\n };\n err.code = (res && 'code' in res ? res.code : undefined) ?? 'unknown';\n throw err;\n }\n};\n\n/**\n * Remove a theme source — the `theme:sources` `remove-source` verb (§9.3). If the\n * removed theme is the current selection, the host falls back to the default theme\n * (keeping the mode selection where it exists). The default theme is never\n * removable. Only a grant holding `theme:sources` may call this.\n */\nexport const removeThemeSource = async (themeKey: string): Promise<void> => {\n const res = (await protocolRequest(SCHEMES[PROTOCOL_THEME], 'remove-source', [{ themeKey }])) as\n | { ok: true; data?: unknown }\n | { ok: false; code?: string; message?: string }\n | undefined;\n if (!res || res.ok !== true) {\n const err = new Error(res?.message ?? 'removeThemeSource failed') as Error & {\n code?: string;\n };\n err.code = (res && 'code' in res ? res.code : undefined) ?? 'unknown';\n throw err;\n }\n};\n"],"mappings":"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","names":[]}
|
package/dist/theme.d.cts
CHANGED
|
@@ -1,38 +1,155 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The host UI theme, mirrored from the immediately.run host window into
|
|
3
|
-
* sandbox. Your app can read this to render in step with the host chrome
|
|
2
|
+
* The host UI theme polarity, mirrored from the immediately.run host window into
|
|
3
|
+
* the sandbox. Your app can read this to render in step with the host chrome
|
|
4
4
|
* (light / dark).
|
|
5
5
|
*
|
|
6
6
|
* This is the baseline `theme:read` capability — every app may read it. Changing
|
|
7
7
|
* the host theme is a separate, elevated action (`theme:set`), available only to
|
|
8
8
|
* the theme-toggle system app.
|
|
9
|
+
*
|
|
10
|
+
* `HostTheme` is the RESOLVED POLARITY only. The full selection — which theme is
|
|
11
|
+
* active and which of its modes — is {@link HostThemeSelection}.
|
|
9
12
|
*/
|
|
10
13
|
type HostTheme = 'light' | 'dark';
|
|
11
14
|
/**
|
|
12
|
-
*
|
|
15
|
+
* The full host theme selection (HOST_THEMING_SPEC §2/§9.1): the resolved polarity
|
|
16
|
+
* plus the active theme's registry key and resolved mode. Carried on the widened
|
|
17
|
+
* `theme` push. `modeId` is always the RESOLVED mode (never the literal `system` —
|
|
18
|
+
* an app wants to know what is on screen).
|
|
19
|
+
*/
|
|
20
|
+
interface HostThemeSelection {
|
|
21
|
+
/** Resolved polarity — the same value the legacy `theme` field carried. */
|
|
22
|
+
theme: HostTheme;
|
|
23
|
+
/** The host-minted registry key of the active theme. */
|
|
24
|
+
themeKey: string;
|
|
25
|
+
/** The resolved active mode id of the active theme. */
|
|
26
|
+
modeId: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Returns the current host theme polarity. Poll this for a one-off read; use
|
|
13
30
|
* {@link onHostThemeChange} or {@link useHostTheme} to react to changes.
|
|
14
31
|
*/
|
|
15
32
|
declare const getHostTheme: () => HostTheme;
|
|
16
33
|
/**
|
|
17
|
-
* Subscribe to host theme changes. The listener is invoked immediately
|
|
18
|
-
* current
|
|
34
|
+
* Subscribe to host theme polarity changes. The listener is invoked immediately
|
|
35
|
+
* with the current polarity, then again on every change. Returns an unsubscribe fn.
|
|
19
36
|
*/
|
|
20
37
|
declare const onHostThemeChange: (listener: (theme: HostTheme) => void) => (() => void);
|
|
21
38
|
/**
|
|
22
|
-
* React hook returning the current host theme, re-rendering when it
|
|
23
|
-
* The recommended way to implement an app's own `useTheme`: follow the
|
|
24
|
-
* allow a local override.
|
|
39
|
+
* React hook returning the current host theme polarity, re-rendering when it
|
|
40
|
+
* changes. The recommended way to implement an app's own `useTheme`: follow the
|
|
41
|
+
* host, allow a local override.
|
|
25
42
|
*/
|
|
26
43
|
declare const useHostTheme: () => HostTheme;
|
|
27
44
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
*
|
|
34
|
-
*
|
|
45
|
+
* Returns the current full host theme selection — polarity, active theme key, and
|
|
46
|
+
* resolved mode. Use {@link useHostThemeSelection} to react to changes.
|
|
47
|
+
*/
|
|
48
|
+
declare const getHostThemeSelection: () => HostThemeSelection;
|
|
49
|
+
/**
|
|
50
|
+
* Subscribe to full host theme selection changes. The listener is invoked
|
|
51
|
+
* immediately with the current selection, then again on every change. Returns an
|
|
52
|
+
* unsubscribe fn.
|
|
53
|
+
*/
|
|
54
|
+
declare const onHostThemeSelectionChange: (listener: (selection: HostThemeSelection) => void) => (() => void);
|
|
55
|
+
/** React hook returning the current full host theme selection. */
|
|
56
|
+
declare const useHostThemeSelection: () => HostThemeSelection;
|
|
57
|
+
/**
|
|
58
|
+
* One entry of the theme catalogue: a selectable theme and its modes. The
|
|
59
|
+
* catalogue is projected per grant — the baseline `theme:read` projection carries
|
|
60
|
+
* NO source identities (no repo coordinates, no spaceIds), and labels are bounded.
|
|
61
|
+
*/
|
|
62
|
+
interface ThemeCatalogEntry {
|
|
63
|
+
themeKey: string;
|
|
64
|
+
label: string;
|
|
65
|
+
modes: {
|
|
66
|
+
id: string;
|
|
67
|
+
polarity: 'light' | 'dark';
|
|
68
|
+
}[];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The loaded-theme catalogue (HOST_THEMING_SPEC §9.2): every selectable theme, so
|
|
72
|
+
* a theme-aware app can render a picker and match chrome. Pushed on
|
|
73
|
+
* `theme-catalog` / polled with `request-theme-catalog`.
|
|
74
|
+
*/
|
|
75
|
+
interface ThemeCatalog {
|
|
76
|
+
themes: ThemeCatalogEntry[];
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Returns the current theme catalogue (themes + their modes). Use
|
|
80
|
+
* {@link useThemeCatalog} to react to changes.
|
|
81
|
+
*/
|
|
82
|
+
declare const getThemeCatalog: () => ThemeCatalog;
|
|
83
|
+
/**
|
|
84
|
+
* Subscribe to theme catalogue changes. The listener is invoked immediately with
|
|
85
|
+
* the current catalogue, then again on every change. Returns an unsubscribe fn.
|
|
86
|
+
*/
|
|
87
|
+
declare const onThemeCatalogChange: (listener: (catalog: ThemeCatalog) => void) => (() => void);
|
|
88
|
+
/** React hook returning the current theme catalogue. */
|
|
89
|
+
declare const useThemeCatalog: () => ThemeCatalog;
|
|
90
|
+
/**
|
|
91
|
+
* A location the open-bundle picker returned — a repo or a space, with a
|
|
92
|
+
* confined in-bundle path (OPEN_BUNDLE_SPEC §2). Carried to the host's
|
|
93
|
+
* `theme:sources` `add-source` verb.
|
|
94
|
+
*/
|
|
95
|
+
type ThemeBundleLocation = {
|
|
96
|
+
kind: 'repo';
|
|
97
|
+
repo: string;
|
|
98
|
+
ref?: string;
|
|
99
|
+
path: string;
|
|
100
|
+
} | {
|
|
101
|
+
kind: 'space';
|
|
102
|
+
spaceId: string;
|
|
103
|
+
path: string;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* The canonical `theme:set` params (HOST_THEMING_SPEC §9.3). `theme` is the
|
|
107
|
+
* registry key of the theme to select (or the legacy `'light' | 'dark'` polarity —
|
|
108
|
+
* the host disambiguates by the reserved-id rule: legacy iff the value is
|
|
109
|
+
* light/dark AND `mode` is absent). `mode` is one of that theme's modes or
|
|
110
|
+
* `'system'`.
|
|
111
|
+
*/
|
|
112
|
+
interface SetHostThemeSelectionParams {
|
|
113
|
+
theme: string;
|
|
114
|
+
mode?: string;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Set the host theme selection — the ELEVATED `theme:set` action
|
|
118
|
+
* (HOST_THEMING_SPEC §9.3). `theme` is the registry key of the theme to select,
|
|
119
|
+
* `mode` is one of that theme's modes or `'system'`. The host applies it and
|
|
120
|
+
* re-pushes the new selection to every `theme:read` iframe, so your own
|
|
121
|
+
* {@link useHostThemeSelection} confirms the change (the loop closes with no
|
|
122
|
+
* special case). Only a grant holding `theme:set` (e.g. the theme-toggle system
|
|
123
|
+
* app) may call this; any other app is rejected host-side with a `forbidden`
|
|
124
|
+
* {@link Error} (carrying `.code`), regardless of what the app claims.
|
|
125
|
+
*/
|
|
126
|
+
declare const setHostThemeSelection: (selection: {
|
|
127
|
+
theme: string;
|
|
128
|
+
mode: string;
|
|
129
|
+
}) => Promise<void>;
|
|
130
|
+
/**
|
|
131
|
+
* Set the host UI theme polarity — the LEGACY form of `theme:set` (§9.3). The host
|
|
132
|
+
* applies that polarity to the CURRENT theme (never resets to the default), then
|
|
133
|
+
* re-pushes. Keep this alias for old-SDK callers; new code should prefer
|
|
134
|
+
* {@link setHostThemeSelection}.
|
|
35
135
|
*/
|
|
36
136
|
declare const setHostTheme: (theme: HostTheme) => Promise<void>;
|
|
137
|
+
/**
|
|
138
|
+
* Add a theme source — the ELEVATED `theme:sources` `add-source` verb
|
|
139
|
+
* (HOST_THEMING_SPEC §9.3). `location` must be a location the host journal saw a
|
|
140
|
+
* RECENT open-bundle invocation OF THIS APP return (the picker-provenance rule —
|
|
141
|
+
* "the pick is the consent", machine-checked); anything else is rejected with a
|
|
142
|
+
* readable reason. The host fetches, gates, and registers the theme before
|
|
143
|
+
* returning, so a rejected pick surfaces inline in the switcher. Only a grant
|
|
144
|
+
* holding `theme:sources` (the theme switcher) may call this.
|
|
145
|
+
*/
|
|
146
|
+
declare const addThemeSource: (location: ThemeBundleLocation) => Promise<void>;
|
|
147
|
+
/**
|
|
148
|
+
* Remove a theme source — the `theme:sources` `remove-source` verb (§9.3). If the
|
|
149
|
+
* removed theme is the current selection, the host falls back to the default theme
|
|
150
|
+
* (keeping the mode selection where it exists). The default theme is never
|
|
151
|
+
* removable. Only a grant holding `theme:sources` may call this.
|
|
152
|
+
*/
|
|
153
|
+
declare const removeThemeSource: (themeKey: string) => Promise<void>;
|
|
37
154
|
|
|
38
|
-
export { type HostTheme, getHostTheme, onHostThemeChange, setHostTheme, useHostTheme };
|
|
155
|
+
export { type HostTheme, type HostThemeSelection, type SetHostThemeSelectionParams, type ThemeBundleLocation, type ThemeCatalog, type ThemeCatalogEntry, addThemeSource, getHostTheme, getHostThemeSelection, getThemeCatalog, onHostThemeChange, onHostThemeSelectionChange, onThemeCatalogChange, removeThemeSource, setHostTheme, setHostThemeSelection, useHostTheme, useHostThemeSelection, useThemeCatalog };
|
package/dist/theme.d.ts
CHANGED
|
@@ -1,38 +1,155 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The host UI theme, mirrored from the immediately.run host window into
|
|
3
|
-
* sandbox. Your app can read this to render in step with the host chrome
|
|
2
|
+
* The host UI theme polarity, mirrored from the immediately.run host window into
|
|
3
|
+
* the sandbox. Your app can read this to render in step with the host chrome
|
|
4
4
|
* (light / dark).
|
|
5
5
|
*
|
|
6
6
|
* This is the baseline `theme:read` capability — every app may read it. Changing
|
|
7
7
|
* the host theme is a separate, elevated action (`theme:set`), available only to
|
|
8
8
|
* the theme-toggle system app.
|
|
9
|
+
*
|
|
10
|
+
* `HostTheme` is the RESOLVED POLARITY only. The full selection — which theme is
|
|
11
|
+
* active and which of its modes — is {@link HostThemeSelection}.
|
|
9
12
|
*/
|
|
10
13
|
type HostTheme = 'light' | 'dark';
|
|
11
14
|
/**
|
|
12
|
-
*
|
|
15
|
+
* The full host theme selection (HOST_THEMING_SPEC §2/§9.1): the resolved polarity
|
|
16
|
+
* plus the active theme's registry key and resolved mode. Carried on the widened
|
|
17
|
+
* `theme` push. `modeId` is always the RESOLVED mode (never the literal `system` —
|
|
18
|
+
* an app wants to know what is on screen).
|
|
19
|
+
*/
|
|
20
|
+
interface HostThemeSelection {
|
|
21
|
+
/** Resolved polarity — the same value the legacy `theme` field carried. */
|
|
22
|
+
theme: HostTheme;
|
|
23
|
+
/** The host-minted registry key of the active theme. */
|
|
24
|
+
themeKey: string;
|
|
25
|
+
/** The resolved active mode id of the active theme. */
|
|
26
|
+
modeId: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Returns the current host theme polarity. Poll this for a one-off read; use
|
|
13
30
|
* {@link onHostThemeChange} or {@link useHostTheme} to react to changes.
|
|
14
31
|
*/
|
|
15
32
|
declare const getHostTheme: () => HostTheme;
|
|
16
33
|
/**
|
|
17
|
-
* Subscribe to host theme changes. The listener is invoked immediately
|
|
18
|
-
* current
|
|
34
|
+
* Subscribe to host theme polarity changes. The listener is invoked immediately
|
|
35
|
+
* with the current polarity, then again on every change. Returns an unsubscribe fn.
|
|
19
36
|
*/
|
|
20
37
|
declare const onHostThemeChange: (listener: (theme: HostTheme) => void) => (() => void);
|
|
21
38
|
/**
|
|
22
|
-
* React hook returning the current host theme, re-rendering when it
|
|
23
|
-
* The recommended way to implement an app's own `useTheme`: follow the
|
|
24
|
-
* allow a local override.
|
|
39
|
+
* React hook returning the current host theme polarity, re-rendering when it
|
|
40
|
+
* changes. The recommended way to implement an app's own `useTheme`: follow the
|
|
41
|
+
* host, allow a local override.
|
|
25
42
|
*/
|
|
26
43
|
declare const useHostTheme: () => HostTheme;
|
|
27
44
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
*
|
|
34
|
-
*
|
|
45
|
+
* Returns the current full host theme selection — polarity, active theme key, and
|
|
46
|
+
* resolved mode. Use {@link useHostThemeSelection} to react to changes.
|
|
47
|
+
*/
|
|
48
|
+
declare const getHostThemeSelection: () => HostThemeSelection;
|
|
49
|
+
/**
|
|
50
|
+
* Subscribe to full host theme selection changes. The listener is invoked
|
|
51
|
+
* immediately with the current selection, then again on every change. Returns an
|
|
52
|
+
* unsubscribe fn.
|
|
53
|
+
*/
|
|
54
|
+
declare const onHostThemeSelectionChange: (listener: (selection: HostThemeSelection) => void) => (() => void);
|
|
55
|
+
/** React hook returning the current full host theme selection. */
|
|
56
|
+
declare const useHostThemeSelection: () => HostThemeSelection;
|
|
57
|
+
/**
|
|
58
|
+
* One entry of the theme catalogue: a selectable theme and its modes. The
|
|
59
|
+
* catalogue is projected per grant — the baseline `theme:read` projection carries
|
|
60
|
+
* NO source identities (no repo coordinates, no spaceIds), and labels are bounded.
|
|
61
|
+
*/
|
|
62
|
+
interface ThemeCatalogEntry {
|
|
63
|
+
themeKey: string;
|
|
64
|
+
label: string;
|
|
65
|
+
modes: {
|
|
66
|
+
id: string;
|
|
67
|
+
polarity: 'light' | 'dark';
|
|
68
|
+
}[];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The loaded-theme catalogue (HOST_THEMING_SPEC §9.2): every selectable theme, so
|
|
72
|
+
* a theme-aware app can render a picker and match chrome. Pushed on
|
|
73
|
+
* `theme-catalog` / polled with `request-theme-catalog`.
|
|
74
|
+
*/
|
|
75
|
+
interface ThemeCatalog {
|
|
76
|
+
themes: ThemeCatalogEntry[];
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Returns the current theme catalogue (themes + their modes). Use
|
|
80
|
+
* {@link useThemeCatalog} to react to changes.
|
|
81
|
+
*/
|
|
82
|
+
declare const getThemeCatalog: () => ThemeCatalog;
|
|
83
|
+
/**
|
|
84
|
+
* Subscribe to theme catalogue changes. The listener is invoked immediately with
|
|
85
|
+
* the current catalogue, then again on every change. Returns an unsubscribe fn.
|
|
86
|
+
*/
|
|
87
|
+
declare const onThemeCatalogChange: (listener: (catalog: ThemeCatalog) => void) => (() => void);
|
|
88
|
+
/** React hook returning the current theme catalogue. */
|
|
89
|
+
declare const useThemeCatalog: () => ThemeCatalog;
|
|
90
|
+
/**
|
|
91
|
+
* A location the open-bundle picker returned — a repo or a space, with a
|
|
92
|
+
* confined in-bundle path (OPEN_BUNDLE_SPEC §2). Carried to the host's
|
|
93
|
+
* `theme:sources` `add-source` verb.
|
|
94
|
+
*/
|
|
95
|
+
type ThemeBundleLocation = {
|
|
96
|
+
kind: 'repo';
|
|
97
|
+
repo: string;
|
|
98
|
+
ref?: string;
|
|
99
|
+
path: string;
|
|
100
|
+
} | {
|
|
101
|
+
kind: 'space';
|
|
102
|
+
spaceId: string;
|
|
103
|
+
path: string;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* The canonical `theme:set` params (HOST_THEMING_SPEC §9.3). `theme` is the
|
|
107
|
+
* registry key of the theme to select (or the legacy `'light' | 'dark'` polarity —
|
|
108
|
+
* the host disambiguates by the reserved-id rule: legacy iff the value is
|
|
109
|
+
* light/dark AND `mode` is absent). `mode` is one of that theme's modes or
|
|
110
|
+
* `'system'`.
|
|
111
|
+
*/
|
|
112
|
+
interface SetHostThemeSelectionParams {
|
|
113
|
+
theme: string;
|
|
114
|
+
mode?: string;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Set the host theme selection — the ELEVATED `theme:set` action
|
|
118
|
+
* (HOST_THEMING_SPEC §9.3). `theme` is the registry key of the theme to select,
|
|
119
|
+
* `mode` is one of that theme's modes or `'system'`. The host applies it and
|
|
120
|
+
* re-pushes the new selection to every `theme:read` iframe, so your own
|
|
121
|
+
* {@link useHostThemeSelection} confirms the change (the loop closes with no
|
|
122
|
+
* special case). Only a grant holding `theme:set` (e.g. the theme-toggle system
|
|
123
|
+
* app) may call this; any other app is rejected host-side with a `forbidden`
|
|
124
|
+
* {@link Error} (carrying `.code`), regardless of what the app claims.
|
|
125
|
+
*/
|
|
126
|
+
declare const setHostThemeSelection: (selection: {
|
|
127
|
+
theme: string;
|
|
128
|
+
mode: string;
|
|
129
|
+
}) => Promise<void>;
|
|
130
|
+
/**
|
|
131
|
+
* Set the host UI theme polarity — the LEGACY form of `theme:set` (§9.3). The host
|
|
132
|
+
* applies that polarity to the CURRENT theme (never resets to the default), then
|
|
133
|
+
* re-pushes. Keep this alias for old-SDK callers; new code should prefer
|
|
134
|
+
* {@link setHostThemeSelection}.
|
|
35
135
|
*/
|
|
36
136
|
declare const setHostTheme: (theme: HostTheme) => Promise<void>;
|
|
137
|
+
/**
|
|
138
|
+
* Add a theme source — the ELEVATED `theme:sources` `add-source` verb
|
|
139
|
+
* (HOST_THEMING_SPEC §9.3). `location` must be a location the host journal saw a
|
|
140
|
+
* RECENT open-bundle invocation OF THIS APP return (the picker-provenance rule —
|
|
141
|
+
* "the pick is the consent", machine-checked); anything else is rejected with a
|
|
142
|
+
* readable reason. The host fetches, gates, and registers the theme before
|
|
143
|
+
* returning, so a rejected pick surfaces inline in the switcher. Only a grant
|
|
144
|
+
* holding `theme:sources` (the theme switcher) may call this.
|
|
145
|
+
*/
|
|
146
|
+
declare const addThemeSource: (location: ThemeBundleLocation) => Promise<void>;
|
|
147
|
+
/**
|
|
148
|
+
* Remove a theme source — the `theme:sources` `remove-source` verb (§9.3). If the
|
|
149
|
+
* removed theme is the current selection, the host falls back to the default theme
|
|
150
|
+
* (keeping the mode selection where it exists). The default theme is never
|
|
151
|
+
* removable. Only a grant holding `theme:sources` may call this.
|
|
152
|
+
*/
|
|
153
|
+
declare const removeThemeSource: (themeKey: string) => Promise<void>;
|
|
37
154
|
|
|
38
|
-
export { type HostTheme, getHostTheme, onHostThemeChange, setHostTheme, useHostTheme };
|
|
155
|
+
export { type HostTheme, type HostThemeSelection, type SetHostThemeSelectionParams, type ThemeBundleLocation, type ThemeCatalog, type ThemeCatalogEntry, addThemeSource, getHostTheme, getHostThemeSelection, getThemeCatalog, onHostThemeChange, onHostThemeSelectionChange, onThemeCatalogChange, removeThemeSource, setHostTheme, setHostThemeSelection, useHostTheme, useHostThemeSelection, useThemeCatalog };
|
package/dist/theme.js
CHANGED
|
@@ -1,29 +1,104 @@
|
|
|
1
1
|
import "./chunk-VHAA22YE.js";
|
|
2
2
|
import { createPushChannel } from "./pushChannel";
|
|
3
3
|
import { protocolRequest } from "./sandboxUtils";
|
|
4
|
-
import { PROTOCOL_THEME, REQUEST_THEME, THEME } from "./generated/protocol";
|
|
4
|
+
import { PROTOCOL_THEME, REQUEST_THEME, REQUEST_THEME_CATALOG, THEME, THEME_CATALOG } from "./generated/protocol";
|
|
5
5
|
import { SCHEMES } from "./protocolSchemes";
|
|
6
|
+
const DEFAULT_SELECTION = {
|
|
7
|
+
theme: "dark",
|
|
8
|
+
themeKey: "immediately-run-default",
|
|
9
|
+
modeId: "dark"
|
|
10
|
+
};
|
|
6
11
|
const channel = createPushChannel({
|
|
7
12
|
pushType: THEME,
|
|
8
13
|
requestType: REQUEST_THEME,
|
|
9
|
-
initial:
|
|
10
|
-
parse: (msg) =>
|
|
14
|
+
initial: DEFAULT_SELECTION,
|
|
15
|
+
parse: (msg) => {
|
|
16
|
+
if (msg.theme !== "light" && msg.theme !== "dark") return void 0;
|
|
17
|
+
if (typeof msg.themeKey !== "string" || typeof msg.modeId !== "string") return void 0;
|
|
18
|
+
return { theme: msg.theme, themeKey: msg.themeKey, modeId: msg.modeId };
|
|
19
|
+
}
|
|
11
20
|
});
|
|
12
|
-
const getHostTheme = () => channel.get();
|
|
13
|
-
const onHostThemeChange = (listener) => channel.onChange(listener);
|
|
14
|
-
const useHostTheme = () => channel.use();
|
|
15
|
-
const
|
|
16
|
-
|
|
21
|
+
const getHostTheme = () => channel.get().theme;
|
|
22
|
+
const onHostThemeChange = (listener) => channel.onChange((sel) => listener(sel.theme));
|
|
23
|
+
const useHostTheme = () => channel.use().theme;
|
|
24
|
+
const getHostThemeSelection = () => channel.get();
|
|
25
|
+
const onHostThemeSelectionChange = (listener) => channel.onChange(listener);
|
|
26
|
+
const useHostThemeSelection = () => channel.use();
|
|
27
|
+
const DEFAULT_CATALOG = { themes: [] };
|
|
28
|
+
const catalogChannel = createPushChannel({
|
|
29
|
+
pushType: THEME_CATALOG,
|
|
30
|
+
requestType: REQUEST_THEME_CATALOG,
|
|
31
|
+
initial: DEFAULT_CATALOG,
|
|
32
|
+
parse: (msg) => {
|
|
33
|
+
const themes = msg.themes;
|
|
34
|
+
if (!Array.isArray(themes)) return void 0;
|
|
35
|
+
const out = [];
|
|
36
|
+
for (const t of themes) {
|
|
37
|
+
if (!t || typeof t !== "object") return void 0;
|
|
38
|
+
const entry = t;
|
|
39
|
+
if (typeof entry.themeKey !== "string" || typeof entry.label !== "string" || !Array.isArray(entry.modes)) {
|
|
40
|
+
return void 0;
|
|
41
|
+
}
|
|
42
|
+
const modes = [];
|
|
43
|
+
for (const m of entry.modes) {
|
|
44
|
+
if (!m || typeof m !== "object") return void 0;
|
|
45
|
+
const mode = m;
|
|
46
|
+
if (typeof mode.id !== "string" || mode.polarity !== "light" && mode.polarity !== "dark") {
|
|
47
|
+
return void 0;
|
|
48
|
+
}
|
|
49
|
+
modes.push({ id: mode.id, polarity: mode.polarity });
|
|
50
|
+
}
|
|
51
|
+
out.push({ themeKey: entry.themeKey, label: entry.label, modes });
|
|
52
|
+
}
|
|
53
|
+
return { themes: out };
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
const getThemeCatalog = () => catalogChannel.get();
|
|
57
|
+
const onThemeCatalogChange = (listener) => catalogChannel.onChange(listener);
|
|
58
|
+
const useThemeCatalog = () => catalogChannel.use();
|
|
59
|
+
const setTheme = async (params) => {
|
|
60
|
+
const res = await protocolRequest(SCHEMES[PROTOCOL_THEME], "set", [params]);
|
|
17
61
|
if (!res || res.ok !== true) {
|
|
18
62
|
const err = new Error(res?.message ?? "setHostTheme failed");
|
|
19
63
|
err.code = (res && "code" in res ? res.code : void 0) ?? "unknown";
|
|
20
64
|
throw err;
|
|
21
65
|
}
|
|
22
66
|
};
|
|
67
|
+
const setHostThemeSelection = async (selection) => {
|
|
68
|
+
await setTheme(selection);
|
|
69
|
+
};
|
|
70
|
+
const setHostTheme = async (theme) => {
|
|
71
|
+
await setTheme({ theme });
|
|
72
|
+
};
|
|
73
|
+
const addThemeSource = async (location) => {
|
|
74
|
+
const res = await protocolRequest(SCHEMES[PROTOCOL_THEME], "add-source", [{ location }]);
|
|
75
|
+
if (!res || res.ok !== true) {
|
|
76
|
+
const err = new Error(res?.message ?? "addThemeSource failed");
|
|
77
|
+
err.code = (res && "code" in res ? res.code : void 0) ?? "unknown";
|
|
78
|
+
throw err;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
const removeThemeSource = async (themeKey) => {
|
|
82
|
+
const res = await protocolRequest(SCHEMES[PROTOCOL_THEME], "remove-source", [{ themeKey }]);
|
|
83
|
+
if (!res || res.ok !== true) {
|
|
84
|
+
const err = new Error(res?.message ?? "removeThemeSource failed");
|
|
85
|
+
err.code = (res && "code" in res ? res.code : void 0) ?? "unknown";
|
|
86
|
+
throw err;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
23
89
|
export {
|
|
90
|
+
addThemeSource,
|
|
24
91
|
getHostTheme,
|
|
92
|
+
getHostThemeSelection,
|
|
93
|
+
getThemeCatalog,
|
|
25
94
|
onHostThemeChange,
|
|
95
|
+
onHostThemeSelectionChange,
|
|
96
|
+
onThemeCatalogChange,
|
|
97
|
+
removeThemeSource,
|
|
26
98
|
setHostTheme,
|
|
27
|
-
|
|
99
|
+
setHostThemeSelection,
|
|
100
|
+
useHostTheme,
|
|
101
|
+
useHostThemeSelection,
|
|
102
|
+
useThemeCatalog
|
|
28
103
|
};
|
|
29
104
|
//# sourceMappingURL=theme.js.map
|
package/dist/theme.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/theme.ts"],"sourcesContent":["import { createPushChannel } from './pushChannel';\nimport { protocolRequest } from './sandboxUtils';\nimport { PROTOCOL_THEME, REQUEST_THEME, THEME } from './generated/protocol';\nimport { SCHEMES } from './protocolSchemes';\n\n/**\n * The host UI theme, mirrored from the immediately.run host window into the\n * sandbox. Your app can read this to render in step with the host chrome\n * (light / dark).\n *\n * This is the baseline `theme:read` capability — every app may read it. Changing\n * the host theme is a separate, elevated action (`theme:set`), available only to\n * the theme-toggle system app.\n */\nexport type HostTheme = 'light' | 'dark';\n\n// Read over the transport (SDK_PACKAGING_SPEC §4): the host pushes `theme` and\n// answers `request-theme` (wire format: site-main channelBridge.ts). The host's\n// default before it reports is `dark` (sandbox themeState.DEFAULT_THEME).\nconst channel = createPushChannel<HostTheme>({\n pushType: THEME,\n requestType: REQUEST_THEME,\n initial: 'dark',\n parse: (msg) => (msg.theme === 'light' || msg.theme === 'dark' ? msg.theme : undefined),\n});\n\n/**\n * Returns the current host theme. Poll this for a one-off read; use\n * {@link onHostThemeChange} or {@link useHostTheme} to react to changes.\n */\nexport const getHostTheme = (): HostTheme => channel.get();\n\n/**\n * Subscribe to host theme changes. The listener is invoked immediately with the\n * current theme, then again on every change. Returns an unsubscribe fn.\n */\nexport const onHostThemeChange = (listener: (theme: HostTheme) => void): (() => void) => channel.onChange(listener);\n\n/**\n * React hook returning the current host theme, re-rendering when it changes.\n * The recommended way to implement an app's own `useTheme`: follow the host,\n * allow a local override.\n */\nexport const useHostTheme = (): HostTheme => channel.use();\n\n/**\n * Set the host UI theme — the ELEVATED `theme:set` action (§8.5). The host\n * applies it and re-pushes the new value to every `theme:read` iframe, so your\n * own {@link useHostTheme} confirms the change (the loop closes with no special\n * case). Only a grant holding `theme:set` (e.g. the theme-toggle system app) may\n * call this; any other app is rejected host-side with a `forbidden`\n * {@link Error} (carrying `.code`), regardless of what the app claims. Update\n * optimistically and let the re-push confirm.\n */\nexport const setHostTheme = async (theme: HostTheme): Promise<void> => {\n const res = (await protocolRequest(SCHEMES[PROTOCOL_THEME], 'set', [{ theme }])) as\n | { ok: true; data?: unknown }\n | { ok: false; code?: string; message?: string }\n | undefined;\n if (!res || res.ok !== true) {\n const err = new Error(res?.message ?? 'setHostTheme failed') as Error & {\n code?: string;\n };\n err.code = (res && 'code' in res ? res.code : undefined) ?? 'unknown';\n throw err;\n }\n};\n"],"mappings":";AAAA,SAAS,yBAAyB;AAClC,SAAS,uBAAuB;AAChC,SAAS,gBAAgB,eAAe,aAAa;AACrD,SAAS,eAAe;AAgBxB,MAAM,UAAU,kBAA6B;AAAA,EAC3C,UAAU;AAAA,EACV,aAAa;AAAA,EACb,SAAS;AAAA,EACT,OAAO,CAAC,QAAS,IAAI,UAAU,WAAW,IAAI,UAAU,SAAS,IAAI,QAAQ;AAC/E,CAAC;AAMM,MAAM,eAAe,MAAiB,QAAQ,IAAI;AAMlD,MAAM,oBAAoB,CAAC,aAAuD,QAAQ,SAAS,QAAQ;AAO3G,MAAM,eAAe,MAAiB,QAAQ,IAAI;AAWlD,MAAM,eAAe,OAAO,UAAoC;AACrE,QAAM,MAAO,MAAM,gBAAgB,QAAQ,cAAc,GAAG,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;AAI9E,MAAI,CAAC,OAAO,IAAI,OAAO,MAAM;AAC3B,UAAM,MAAM,IAAI,MAAM,KAAK,WAAW,qBAAqB;AAG3D,QAAI,QAAQ,OAAO,UAAU,MAAM,IAAI,OAAO,WAAc;AAC5D,UAAM;AAAA,EACR;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/theme.ts"],"sourcesContent":["import { createPushChannel } from './pushChannel';\nimport { protocolRequest } from './sandboxUtils';\nimport { PROTOCOL_THEME, REQUEST_THEME, REQUEST_THEME_CATALOG, THEME, THEME_CATALOG } from './generated/protocol';\nimport { SCHEMES } from './protocolSchemes';\n\n/**\n * The host UI theme polarity, mirrored from the immediately.run host window into\n * the sandbox. Your app can read this to render in step with the host chrome\n * (light / dark).\n *\n * This is the baseline `theme:read` capability — every app may read it. Changing\n * the host theme is a separate, elevated action (`theme:set`), available only to\n * the theme-toggle system app.\n *\n * `HostTheme` is the RESOLVED POLARITY only. The full selection — which theme is\n * active and which of its modes — is {@link HostThemeSelection}.\n */\nexport type HostTheme = 'light' | 'dark';\n\n/**\n * The full host theme selection (HOST_THEMING_SPEC §2/§9.1): the resolved polarity\n * plus the active theme's registry key and resolved mode. Carried on the widened\n * `theme` push. `modeId` is always the RESOLVED mode (never the literal `system` —\n * an app wants to know what is on screen).\n */\nexport interface HostThemeSelection {\n /** Resolved polarity — the same value the legacy `theme` field carried. */\n theme: HostTheme;\n /** The host-minted registry key of the active theme. */\n themeKey: string;\n /** The resolved active mode id of the active theme. */\n modeId: string;\n}\n\n/**\n * The selection assumed before the host reports. The platform default theme is\n * `immediately-run-default` (dark polarity first-paint, matching the shipped\n * provider default — HOST_THEMING_SPEC §3 build-time correction).\n */\nconst DEFAULT_SELECTION: HostThemeSelection = {\n theme: 'dark',\n themeKey: 'immediately-run-default',\n modeId: 'dark',\n};\n\n// Read over the transport (SDK_PACKAGING_SPEC §4): the host pushes `theme` and\n// answers `request-theme` (wire format: site-main channelBridge.ts). The parse\n// reads ALL THREE fields so the full selection survives the transport; the\n// polarity-only surface derives from it.\nconst channel = createPushChannel<HostThemeSelection>({\n pushType: THEME,\n requestType: REQUEST_THEME,\n initial: DEFAULT_SELECTION,\n parse: (msg) => {\n if (msg.theme !== 'light' && msg.theme !== 'dark') return undefined;\n if (typeof msg.themeKey !== 'string' || typeof msg.modeId !== 'string') return undefined;\n return { theme: msg.theme, themeKey: msg.themeKey, modeId: msg.modeId };\n },\n});\n\n/**\n * Returns the current host theme polarity. Poll this for a one-off read; use\n * {@link onHostThemeChange} or {@link useHostTheme} to react to changes.\n */\nexport const getHostTheme = (): HostTheme => channel.get().theme;\n\n/**\n * Subscribe to host theme polarity changes. The listener is invoked immediately\n * with the current polarity, then again on every change. Returns an unsubscribe fn.\n */\nexport const onHostThemeChange = (listener: (theme: HostTheme) => void): (() => void) =>\n channel.onChange((sel) => listener(sel.theme));\n\n/**\n * React hook returning the current host theme polarity, re-rendering when it\n * changes. The recommended way to implement an app's own `useTheme`: follow the\n * host, allow a local override.\n */\nexport const useHostTheme = (): HostTheme => channel.use().theme;\n\n/**\n * Returns the current full host theme selection — polarity, active theme key, and\n * resolved mode. Use {@link useHostThemeSelection} to react to changes.\n */\nexport const getHostThemeSelection = (): HostThemeSelection => channel.get();\n\n/**\n * Subscribe to full host theme selection changes. The listener is invoked\n * immediately with the current selection, then again on every change. Returns an\n * unsubscribe fn.\n */\nexport const onHostThemeSelectionChange = (listener: (selection: HostThemeSelection) => void): (() => void) =>\n channel.onChange(listener);\n\n/** React hook returning the current full host theme selection. */\nexport const useHostThemeSelection = (): HostThemeSelection => channel.use();\n\n/**\n * One entry of the theme catalogue: a selectable theme and its modes. The\n * catalogue is projected per grant — the baseline `theme:read` projection carries\n * NO source identities (no repo coordinates, no spaceIds), and labels are bounded.\n */\nexport interface ThemeCatalogEntry {\n themeKey: string;\n label: string;\n modes: { id: string; polarity: 'light' | 'dark' }[];\n}\n\n/**\n * The loaded-theme catalogue (HOST_THEMING_SPEC §9.2): every selectable theme, so\n * a theme-aware app can render a picker and match chrome. Pushed on\n * `theme-catalog` / polled with `request-theme-catalog`.\n */\nexport interface ThemeCatalog {\n themes: ThemeCatalogEntry[];\n}\n\nconst DEFAULT_CATALOG: ThemeCatalog = { themes: [] };\n\nconst catalogChannel = createPushChannel<ThemeCatalog>({\n pushType: THEME_CATALOG,\n requestType: REQUEST_THEME_CATALOG,\n initial: DEFAULT_CATALOG,\n parse: (msg) => {\n const themes = msg.themes;\n if (!Array.isArray(themes)) return undefined;\n const out: ThemeCatalogEntry[] = [];\n for (const t of themes as unknown[]) {\n if (!t || typeof t !== 'object') return undefined;\n const entry = t as { themeKey?: unknown; label?: unknown; modes?: unknown };\n if (typeof entry.themeKey !== 'string' || typeof entry.label !== 'string' || !Array.isArray(entry.modes)) {\n return undefined;\n }\n const modes: ThemeCatalogEntry['modes'] = [];\n for (const m of entry.modes) {\n if (!m || typeof m !== 'object') return undefined;\n const mode = m as { id?: unknown; polarity?: unknown };\n if (typeof mode.id !== 'string' || (mode.polarity !== 'light' && mode.polarity !== 'dark')) {\n return undefined;\n }\n modes.push({ id: mode.id, polarity: mode.polarity });\n }\n out.push({ themeKey: entry.themeKey, label: entry.label, modes });\n }\n return { themes: out };\n },\n});\n\n/**\n * Returns the current theme catalogue (themes + their modes). Use\n * {@link useThemeCatalog} to react to changes.\n */\nexport const getThemeCatalog = (): ThemeCatalog => catalogChannel.get();\n\n/**\n * Subscribe to theme catalogue changes. The listener is invoked immediately with\n * the current catalogue, then again on every change. Returns an unsubscribe fn.\n */\nexport const onThemeCatalogChange = (listener: (catalog: ThemeCatalog) => void): (() => void) =>\n catalogChannel.onChange(listener);\n\n/** React hook returning the current theme catalogue. */\nexport const useThemeCatalog = (): ThemeCatalog => catalogChannel.use();\n\n/**\n * A location the open-bundle picker returned — a repo or a space, with a\n * confined in-bundle path (OPEN_BUNDLE_SPEC §2). Carried to the host's\n * `theme:sources` `add-source` verb.\n */\nexport type ThemeBundleLocation =\n | { kind: 'repo'; repo: string; ref?: string; path: string }\n | { kind: 'space'; spaceId: string; path: string };\n\n/**\n * The canonical `theme:set` params (HOST_THEMING_SPEC §9.3). `theme` is the\n * registry key of the theme to select (or the legacy `'light' | 'dark'` polarity —\n * the host disambiguates by the reserved-id rule: legacy iff the value is\n * light/dark AND `mode` is absent). `mode` is one of that theme's modes or\n * `'system'`.\n */\nexport interface SetHostThemeSelectionParams {\n theme: string;\n mode?: string;\n}\n\n/** The one `set` call site, so the wire shape is fingerprint-stable. */\nconst setTheme = async (params: SetHostThemeSelectionParams): Promise<void> => {\n const res = (await protocolRequest(SCHEMES[PROTOCOL_THEME], 'set', [params])) as\n | { ok: true; data?: unknown }\n | { ok: false; code?: string; message?: string }\n | undefined;\n if (!res || res.ok !== true) {\n const err = new Error(res?.message ?? 'setHostTheme failed') as Error & {\n code?: string;\n };\n err.code = (res && 'code' in res ? res.code : undefined) ?? 'unknown';\n throw err;\n }\n};\n\n/**\n * Set the host theme selection — the ELEVATED `theme:set` action\n * (HOST_THEMING_SPEC §9.3). `theme` is the registry key of the theme to select,\n * `mode` is one of that theme's modes or `'system'`. The host applies it and\n * re-pushes the new selection to every `theme:read` iframe, so your own\n * {@link useHostThemeSelection} confirms the change (the loop closes with no\n * special case). Only a grant holding `theme:set` (e.g. the theme-toggle system\n * app) may call this; any other app is rejected host-side with a `forbidden`\n * {@link Error} (carrying `.code`), regardless of what the app claims.\n */\nexport const setHostThemeSelection = async (selection: { theme: string; mode: string }): Promise<void> => {\n await setTheme(selection);\n};\n\n/**\n * Set the host UI theme polarity — the LEGACY form of `theme:set` (§9.3). The host\n * applies that polarity to the CURRENT theme (never resets to the default), then\n * re-pushes. Keep this alias for old-SDK callers; new code should prefer\n * {@link setHostThemeSelection}.\n */\nexport const setHostTheme = async (theme: HostTheme): Promise<void> => {\n await setTheme({ theme });\n};\n\n/**\n * Add a theme source — the ELEVATED `theme:sources` `add-source` verb\n * (HOST_THEMING_SPEC §9.3). `location` must be a location the host journal saw a\n * RECENT open-bundle invocation OF THIS APP return (the picker-provenance rule —\n * \"the pick is the consent\", machine-checked); anything else is rejected with a\n * readable reason. The host fetches, gates, and registers the theme before\n * returning, so a rejected pick surfaces inline in the switcher. Only a grant\n * holding `theme:sources` (the theme switcher) may call this.\n */\nexport const addThemeSource = async (location: ThemeBundleLocation): Promise<void> => {\n const res = (await protocolRequest(SCHEMES[PROTOCOL_THEME], 'add-source', [{ location }])) as\n | { ok: true; data?: unknown }\n | { ok: false; code?: string; message?: string }\n | undefined;\n if (!res || res.ok !== true) {\n const err = new Error(res?.message ?? 'addThemeSource failed') as Error & {\n code?: string;\n };\n err.code = (res && 'code' in res ? res.code : undefined) ?? 'unknown';\n throw err;\n }\n};\n\n/**\n * Remove a theme source — the `theme:sources` `remove-source` verb (§9.3). If the\n * removed theme is the current selection, the host falls back to the default theme\n * (keeping the mode selection where it exists). The default theme is never\n * removable. Only a grant holding `theme:sources` may call this.\n */\nexport const removeThemeSource = async (themeKey: string): Promise<void> => {\n const res = (await protocolRequest(SCHEMES[PROTOCOL_THEME], 'remove-source', [{ themeKey }])) as\n | { ok: true; data?: unknown }\n | { ok: false; code?: string; message?: string }\n | undefined;\n if (!res || res.ok !== true) {\n const err = new Error(res?.message ?? 'removeThemeSource failed') as Error & {\n code?: string;\n };\n err.code = (res && 'code' in res ? res.code : undefined) ?? 'unknown';\n throw err;\n }\n};\n"],"mappings":"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","names":[]}
|
package/dist/version.cjs
CHANGED
|
@@ -21,7 +21,7 @@ __export(version_exports, {
|
|
|
21
21
|
SDK_VERSION: () => SDK_VERSION
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(version_exports);
|
|
24
|
-
const SDK_VERSION = "0.
|
|
24
|
+
const SDK_VERSION = "0.59.0";
|
|
25
25
|
// Annotate the CommonJS export names for ESM import in node:
|
|
26
26
|
0 && (module.exports = {
|
|
27
27
|
SDK_VERSION
|
package/dist/version.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/version.ts"],"sourcesContent":["// GENERATED by scripts/gen-version.mjs from package.json — do not edit by hand.\n// Regenerated on every build (prebuild); kept honest by version.test.ts.\n\n/** This SDK's package version, baked from package.json at build (SP2-6). */\nexport const SDK_VERSION = '0.
|
|
1
|
+
{"version":3,"sources":["../src/version.ts"],"sourcesContent":["// GENERATED by scripts/gen-version.mjs from package.json — do not edit by hand.\n// Regenerated on every build (prebuild); kept honest by version.test.ts.\n\n/** This SDK's package version, baked from package.json at build (SP2-6). */\nexport const SDK_VERSION = '0.59.0';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIO,MAAM,cAAc;","names":[]}
|
package/dist/version.d.cts
CHANGED
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/dist/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/version.ts"],"sourcesContent":["// GENERATED by scripts/gen-version.mjs from package.json — do not edit by hand.\n// Regenerated on every build (prebuild); kept honest by version.test.ts.\n\n/** This SDK's package version, baked from package.json at build (SP2-6). */\nexport const SDK_VERSION = '0.
|
|
1
|
+
{"version":3,"sources":["../src/version.ts"],"sourcesContent":["// GENERATED by scripts/gen-version.mjs from package.json — do not edit by hand.\n// Regenerated on every build (prebuild); kept honest by version.test.ts.\n\n/** This SDK's package version, baked from package.json at build (SP2-6). */\nexport const SDK_VERSION = '0.59.0';\n"],"mappings":";AAIO,MAAM,cAAc;","names":[]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var workspace_exports = {};
|
|
20
|
+
__export(workspace_exports, {
|
|
21
|
+
getWorkspace: () => getWorkspace,
|
|
22
|
+
onWorkspaceChange: () => onWorkspaceChange,
|
|
23
|
+
useWorkspace: () => useWorkspace
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(workspace_exports);
|
|
26
|
+
var import_pushChannel = require("./pushChannel");
|
|
27
|
+
var import_protocol = require("./generated/protocol");
|
|
28
|
+
const DEFAULT_WORKSPACE = null;
|
|
29
|
+
const isWorkspace = (v) => {
|
|
30
|
+
const w = v;
|
|
31
|
+
return !!w && typeof w === "object" && typeof w.provider === "string" && typeof w.namespace === "string" && typeof w.repository === "string" && typeof w.ref === "string" && typeof w.label === "string";
|
|
32
|
+
};
|
|
33
|
+
const channel = (0, import_pushChannel.createPushChannel)({
|
|
34
|
+
pushType: import_protocol.WORKSPACE,
|
|
35
|
+
requestType: import_protocol.REQUEST_WORKSPACE,
|
|
36
|
+
initial: DEFAULT_WORKSPACE,
|
|
37
|
+
parse: (msg) => {
|
|
38
|
+
if (msg.workspace === null) return null;
|
|
39
|
+
if (!isWorkspace(msg.workspace)) return void 0;
|
|
40
|
+
const { provider, namespace, repository, ref, label } = msg.workspace;
|
|
41
|
+
return { provider, namespace, repository, ref, label };
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
const getWorkspace = () => channel.get();
|
|
45
|
+
const onWorkspaceChange = (listener) => channel.onChange(listener);
|
|
46
|
+
const useWorkspace = () => channel.use();
|
|
47
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
48
|
+
0 && (module.exports = {
|
|
49
|
+
getWorkspace,
|
|
50
|
+
onWorkspaceChange,
|
|
51
|
+
useWorkspace
|
|
52
|
+
});
|
|
53
|
+
//# sourceMappingURL=workspace.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/workspace.ts"],"sourcesContent":["import { createPushChannel } from './pushChannel';\nimport { WORKSPACE, REQUEST_WORKSPACE } from './generated/protocol';\n\n/**\n * Which project the immediately.run workbench currently has open — the repository\n * the user is editing, not your app's own repository. `null` when your app is not\n * running inside an editing session at all (a standalone full-tab route, a task\n * overlay): that is a real answer, not a failure, and code here must handle it.\n *\n * ⚠ **`namespace` is not necessarily a GitHub owner.** A `local` session is\n * well-formed but not GitHub-shaped — `/edit/local/my-app-3fa9c2d1/my-app/live`\n * reads back as `{ provider: 'local', namespace: 'my-app-3fa9c2d1', repository:\n * 'my-app', ref: 'live' }`. Branch on `provider` before rendering a GitHub URL.\n *\n * Baseline capability `workspace:read` — every app may read it. It discloses\n * nothing that is not already in the session URL your app can read from\n * {@link onUrlChange} when it drives the host route; this channel exists for the\n * apps that *don't* — a self-routed panel keeps its own route, never receives\n * `urlchange`, and would otherwise have no way to learn which project it is in.\n *\n * There is deliberately no counterpart that lets an app *change* the workspace:\n * navigating the workbench stays a host action under the ordinary consent.\n *\n * ```ts\n * import { useWorkspace } from '@immediately-run/sdk';\n *\n * const workspace = useWorkspace();\n * // Scope your app's stored data to the project it belongs to.\n * const scope = workspace?.label ?? null;\n * ```\n */\nexport interface Workspace {\n /** Loader provider — `'github'`, `'local'`, … Branch on this, never assume. */\n provider: string;\n /** Owner/namespace segment. See the warning above: NOT always a GitHub owner. */\n namespace: string;\n /** Repository/project segment. */\n repository: string;\n /** The branch, tag, or ref-shaped segment of the session. */\n ref: string;\n /**\n * The session's display identity, `` `${namespace}/${repository}` `` — e.g.\n * `neumark-family/recipes`.\n *\n * This is the string to key durable per-project data on. It is the SAME value the\n * host labels the working-tree mount with, so an app that already scopes by that\n * mount's label needs no migration to move onto this channel.\n */\n label: string;\n}\n\n/**\n * Assumed before the host reports — and the value that stands forever on a host too\n * old to push this channel. `null` means \"no project here\", which is also the honest\n * answer outside an editing session, so an app written against it degrades to\n * unscoped rather than to wrong.\n */\nconst DEFAULT_WORKSPACE: Workspace | null = null;\n\nconst isWorkspace = (v: unknown): v is Workspace => {\n const w = v as Partial<Workspace> | null;\n return (\n !!w &&\n typeof w === 'object' &&\n typeof w.provider === 'string' &&\n typeof w.namespace === 'string' &&\n typeof w.repository === 'string' &&\n typeof w.ref === 'string' &&\n typeof w.label === 'string'\n );\n};\n\n// Read over the transport (SDK_PACKAGING_SPEC §4): the host pushes `workspace` and\n// answers `request-workspace` (wire format: site-main channelBridge.ts).\n//\n// `parse` must distinguish the host SAYING `null` from a message it cannot read.\n// `undefined` means \"not a value for this channel\" (createPushChannel ignores it and\n// keeps the last known workspace), while `null` is the host reporting \"no session\"\n// and MUST land — otherwise a frame that navigates out of a session would keep\n// reporting the project it used to be in.\n//\n// It REBUILDS the value field by field rather than passing the host's object through.\n// This channel is baseline-readable by every app, so \"it carries only the session's\n// coordinates\" has to be a property of this code, not of the host's good manners: a\n// host that pushed a token or a user id alongside them would otherwise get it into\n// app-visible memory by reference.\nconst channel = createPushChannel<Workspace | null>({\n pushType: WORKSPACE,\n requestType: REQUEST_WORKSPACE,\n initial: DEFAULT_WORKSPACE,\n parse: (msg) => {\n if (msg.workspace === null) return null;\n if (!isWorkspace(msg.workspace)) return undefined;\n const { provider, namespace, repository, ref, label } = msg.workspace;\n return { provider, namespace, repository, ref, label };\n },\n});\n\n/** Returns the current workspace, or `null` outside an editing session. */\nexport const getWorkspace = (): Workspace | null => channel.get();\n\n/**\n * Subscribe to workspace changes. The listener is invoked immediately with the\n * current value, then again on every change. Returns an unsubscribe fn.\n */\nexport const onWorkspaceChange = (listener: (workspace: Workspace | null) => void): (() => void) =>\n channel.onChange(listener);\n\n/** React hook returning the current workspace, re-rendering on change. */\nexport const useWorkspace = (): Workspace | null => channel.use();\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAkC;AAClC,sBAA6C;AAwD7C,MAAM,oBAAsC;AAE5C,MAAM,cAAc,CAAC,MAA+B;AAClD,QAAM,IAAI;AACV,SACE,CAAC,CAAC,KACF,OAAO,MAAM,YACb,OAAO,EAAE,aAAa,YACtB,OAAO,EAAE,cAAc,YACvB,OAAO,EAAE,eAAe,YACxB,OAAO,EAAE,QAAQ,YACjB,OAAO,EAAE,UAAU;AAEvB;AAgBA,MAAM,cAAU,sCAAoC;AAAA,EAClD,UAAU;AAAA,EACV,aAAa;AAAA,EACb,SAAS;AAAA,EACT,OAAO,CAAC,QAAQ;AACd,QAAI,IAAI,cAAc,KAAM,QAAO;AACnC,QAAI,CAAC,YAAY,IAAI,SAAS,EAAG,QAAO;AACxC,UAAM,EAAE,UAAU,WAAW,YAAY,KAAK,MAAM,IAAI,IAAI;AAC5D,WAAO,EAAE,UAAU,WAAW,YAAY,KAAK,MAAM;AAAA,EACvD;AACF,CAAC;AAGM,MAAM,eAAe,MAAwB,QAAQ,IAAI;AAMzD,MAAM,oBAAoB,CAAC,aAChC,QAAQ,SAAS,QAAQ;AAGpB,MAAM,eAAe,MAAwB,QAAQ,IAAI;","names":[]}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which project the immediately.run workbench currently has open — the repository
|
|
3
|
+
* the user is editing, not your app's own repository. `null` when your app is not
|
|
4
|
+
* running inside an editing session at all (a standalone full-tab route, a task
|
|
5
|
+
* overlay): that is a real answer, not a failure, and code here must handle it.
|
|
6
|
+
*
|
|
7
|
+
* ⚠ **`namespace` is not necessarily a GitHub owner.** A `local` session is
|
|
8
|
+
* well-formed but not GitHub-shaped — `/edit/local/my-app-3fa9c2d1/my-app/live`
|
|
9
|
+
* reads back as `{ provider: 'local', namespace: 'my-app-3fa9c2d1', repository:
|
|
10
|
+
* 'my-app', ref: 'live' }`. Branch on `provider` before rendering a GitHub URL.
|
|
11
|
+
*
|
|
12
|
+
* Baseline capability `workspace:read` — every app may read it. It discloses
|
|
13
|
+
* nothing that is not already in the session URL your app can read from
|
|
14
|
+
* {@link onUrlChange} when it drives the host route; this channel exists for the
|
|
15
|
+
* apps that *don't* — a self-routed panel keeps its own route, never receives
|
|
16
|
+
* `urlchange`, and would otherwise have no way to learn which project it is in.
|
|
17
|
+
*
|
|
18
|
+
* There is deliberately no counterpart that lets an app *change* the workspace:
|
|
19
|
+
* navigating the workbench stays a host action under the ordinary consent.
|
|
20
|
+
*
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { useWorkspace } from '@immediately-run/sdk';
|
|
23
|
+
*
|
|
24
|
+
* const workspace = useWorkspace();
|
|
25
|
+
* // Scope your app's stored data to the project it belongs to.
|
|
26
|
+
* const scope = workspace?.label ?? null;
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
interface Workspace {
|
|
30
|
+
/** Loader provider — `'github'`, `'local'`, … Branch on this, never assume. */
|
|
31
|
+
provider: string;
|
|
32
|
+
/** Owner/namespace segment. See the warning above: NOT always a GitHub owner. */
|
|
33
|
+
namespace: string;
|
|
34
|
+
/** Repository/project segment. */
|
|
35
|
+
repository: string;
|
|
36
|
+
/** The branch, tag, or ref-shaped segment of the session. */
|
|
37
|
+
ref: string;
|
|
38
|
+
/**
|
|
39
|
+
* The session's display identity, `` `${namespace}/${repository}` `` — e.g.
|
|
40
|
+
* `neumark-family/recipes`.
|
|
41
|
+
*
|
|
42
|
+
* This is the string to key durable per-project data on. It is the SAME value the
|
|
43
|
+
* host labels the working-tree mount with, so an app that already scopes by that
|
|
44
|
+
* mount's label needs no migration to move onto this channel.
|
|
45
|
+
*/
|
|
46
|
+
label: string;
|
|
47
|
+
}
|
|
48
|
+
/** Returns the current workspace, or `null` outside an editing session. */
|
|
49
|
+
declare const getWorkspace: () => Workspace | null;
|
|
50
|
+
/**
|
|
51
|
+
* Subscribe to workspace changes. The listener is invoked immediately with the
|
|
52
|
+
* current value, then again on every change. Returns an unsubscribe fn.
|
|
53
|
+
*/
|
|
54
|
+
declare const onWorkspaceChange: (listener: (workspace: Workspace | null) => void) => (() => void);
|
|
55
|
+
/** React hook returning the current workspace, re-rendering on change. */
|
|
56
|
+
declare const useWorkspace: () => Workspace | null;
|
|
57
|
+
|
|
58
|
+
export { type Workspace, getWorkspace, onWorkspaceChange, useWorkspace };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which project the immediately.run workbench currently has open — the repository
|
|
3
|
+
* the user is editing, not your app's own repository. `null` when your app is not
|
|
4
|
+
* running inside an editing session at all (a standalone full-tab route, a task
|
|
5
|
+
* overlay): that is a real answer, not a failure, and code here must handle it.
|
|
6
|
+
*
|
|
7
|
+
* ⚠ **`namespace` is not necessarily a GitHub owner.** A `local` session is
|
|
8
|
+
* well-formed but not GitHub-shaped — `/edit/local/my-app-3fa9c2d1/my-app/live`
|
|
9
|
+
* reads back as `{ provider: 'local', namespace: 'my-app-3fa9c2d1', repository:
|
|
10
|
+
* 'my-app', ref: 'live' }`. Branch on `provider` before rendering a GitHub URL.
|
|
11
|
+
*
|
|
12
|
+
* Baseline capability `workspace:read` — every app may read it. It discloses
|
|
13
|
+
* nothing that is not already in the session URL your app can read from
|
|
14
|
+
* {@link onUrlChange} when it drives the host route; this channel exists for the
|
|
15
|
+
* apps that *don't* — a self-routed panel keeps its own route, never receives
|
|
16
|
+
* `urlchange`, and would otherwise have no way to learn which project it is in.
|
|
17
|
+
*
|
|
18
|
+
* There is deliberately no counterpart that lets an app *change* the workspace:
|
|
19
|
+
* navigating the workbench stays a host action under the ordinary consent.
|
|
20
|
+
*
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { useWorkspace } from '@immediately-run/sdk';
|
|
23
|
+
*
|
|
24
|
+
* const workspace = useWorkspace();
|
|
25
|
+
* // Scope your app's stored data to the project it belongs to.
|
|
26
|
+
* const scope = workspace?.label ?? null;
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
interface Workspace {
|
|
30
|
+
/** Loader provider — `'github'`, `'local'`, … Branch on this, never assume. */
|
|
31
|
+
provider: string;
|
|
32
|
+
/** Owner/namespace segment. See the warning above: NOT always a GitHub owner. */
|
|
33
|
+
namespace: string;
|
|
34
|
+
/** Repository/project segment. */
|
|
35
|
+
repository: string;
|
|
36
|
+
/** The branch, tag, or ref-shaped segment of the session. */
|
|
37
|
+
ref: string;
|
|
38
|
+
/**
|
|
39
|
+
* The session's display identity, `` `${namespace}/${repository}` `` — e.g.
|
|
40
|
+
* `neumark-family/recipes`.
|
|
41
|
+
*
|
|
42
|
+
* This is the string to key durable per-project data on. It is the SAME value the
|
|
43
|
+
* host labels the working-tree mount with, so an app that already scopes by that
|
|
44
|
+
* mount's label needs no migration to move onto this channel.
|
|
45
|
+
*/
|
|
46
|
+
label: string;
|
|
47
|
+
}
|
|
48
|
+
/** Returns the current workspace, or `null` outside an editing session. */
|
|
49
|
+
declare const getWorkspace: () => Workspace | null;
|
|
50
|
+
/**
|
|
51
|
+
* Subscribe to workspace changes. The listener is invoked immediately with the
|
|
52
|
+
* current value, then again on every change. Returns an unsubscribe fn.
|
|
53
|
+
*/
|
|
54
|
+
declare const onWorkspaceChange: (listener: (workspace: Workspace | null) => void) => (() => void);
|
|
55
|
+
/** React hook returning the current workspace, re-rendering on change. */
|
|
56
|
+
declare const useWorkspace: () => Workspace | null;
|
|
57
|
+
|
|
58
|
+
export { type Workspace, getWorkspace, onWorkspaceChange, useWorkspace };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import "./chunk-VHAA22YE.js";
|
|
2
|
+
import { createPushChannel } from "./pushChannel";
|
|
3
|
+
import { WORKSPACE, REQUEST_WORKSPACE } from "./generated/protocol";
|
|
4
|
+
const DEFAULT_WORKSPACE = null;
|
|
5
|
+
const isWorkspace = (v) => {
|
|
6
|
+
const w = v;
|
|
7
|
+
return !!w && typeof w === "object" && typeof w.provider === "string" && typeof w.namespace === "string" && typeof w.repository === "string" && typeof w.ref === "string" && typeof w.label === "string";
|
|
8
|
+
};
|
|
9
|
+
const channel = createPushChannel({
|
|
10
|
+
pushType: WORKSPACE,
|
|
11
|
+
requestType: REQUEST_WORKSPACE,
|
|
12
|
+
initial: DEFAULT_WORKSPACE,
|
|
13
|
+
parse: (msg) => {
|
|
14
|
+
if (msg.workspace === null) return null;
|
|
15
|
+
if (!isWorkspace(msg.workspace)) return void 0;
|
|
16
|
+
const { provider, namespace, repository, ref, label } = msg.workspace;
|
|
17
|
+
return { provider, namespace, repository, ref, label };
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
const getWorkspace = () => channel.get();
|
|
21
|
+
const onWorkspaceChange = (listener) => channel.onChange(listener);
|
|
22
|
+
const useWorkspace = () => channel.use();
|
|
23
|
+
export {
|
|
24
|
+
getWorkspace,
|
|
25
|
+
onWorkspaceChange,
|
|
26
|
+
useWorkspace
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=workspace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/workspace.ts"],"sourcesContent":["import { createPushChannel } from './pushChannel';\nimport { WORKSPACE, REQUEST_WORKSPACE } from './generated/protocol';\n\n/**\n * Which project the immediately.run workbench currently has open — the repository\n * the user is editing, not your app's own repository. `null` when your app is not\n * running inside an editing session at all (a standalone full-tab route, a task\n * overlay): that is a real answer, not a failure, and code here must handle it.\n *\n * ⚠ **`namespace` is not necessarily a GitHub owner.** A `local` session is\n * well-formed but not GitHub-shaped — `/edit/local/my-app-3fa9c2d1/my-app/live`\n * reads back as `{ provider: 'local', namespace: 'my-app-3fa9c2d1', repository:\n * 'my-app', ref: 'live' }`. Branch on `provider` before rendering a GitHub URL.\n *\n * Baseline capability `workspace:read` — every app may read it. It discloses\n * nothing that is not already in the session URL your app can read from\n * {@link onUrlChange} when it drives the host route; this channel exists for the\n * apps that *don't* — a self-routed panel keeps its own route, never receives\n * `urlchange`, and would otherwise have no way to learn which project it is in.\n *\n * There is deliberately no counterpart that lets an app *change* the workspace:\n * navigating the workbench stays a host action under the ordinary consent.\n *\n * ```ts\n * import { useWorkspace } from '@immediately-run/sdk';\n *\n * const workspace = useWorkspace();\n * // Scope your app's stored data to the project it belongs to.\n * const scope = workspace?.label ?? null;\n * ```\n */\nexport interface Workspace {\n /** Loader provider — `'github'`, `'local'`, … Branch on this, never assume. */\n provider: string;\n /** Owner/namespace segment. See the warning above: NOT always a GitHub owner. */\n namespace: string;\n /** Repository/project segment. */\n repository: string;\n /** The branch, tag, or ref-shaped segment of the session. */\n ref: string;\n /**\n * The session's display identity, `` `${namespace}/${repository}` `` — e.g.\n * `neumark-family/recipes`.\n *\n * This is the string to key durable per-project data on. It is the SAME value the\n * host labels the working-tree mount with, so an app that already scopes by that\n * mount's label needs no migration to move onto this channel.\n */\n label: string;\n}\n\n/**\n * Assumed before the host reports — and the value that stands forever on a host too\n * old to push this channel. `null` means \"no project here\", which is also the honest\n * answer outside an editing session, so an app written against it degrades to\n * unscoped rather than to wrong.\n */\nconst DEFAULT_WORKSPACE: Workspace | null = null;\n\nconst isWorkspace = (v: unknown): v is Workspace => {\n const w = v as Partial<Workspace> | null;\n return (\n !!w &&\n typeof w === 'object' &&\n typeof w.provider === 'string' &&\n typeof w.namespace === 'string' &&\n typeof w.repository === 'string' &&\n typeof w.ref === 'string' &&\n typeof w.label === 'string'\n );\n};\n\n// Read over the transport (SDK_PACKAGING_SPEC §4): the host pushes `workspace` and\n// answers `request-workspace` (wire format: site-main channelBridge.ts).\n//\n// `parse` must distinguish the host SAYING `null` from a message it cannot read.\n// `undefined` means \"not a value for this channel\" (createPushChannel ignores it and\n// keeps the last known workspace), while `null` is the host reporting \"no session\"\n// and MUST land — otherwise a frame that navigates out of a session would keep\n// reporting the project it used to be in.\n//\n// It REBUILDS the value field by field rather than passing the host's object through.\n// This channel is baseline-readable by every app, so \"it carries only the session's\n// coordinates\" has to be a property of this code, not of the host's good manners: a\n// host that pushed a token or a user id alongside them would otherwise get it into\n// app-visible memory by reference.\nconst channel = createPushChannel<Workspace | null>({\n pushType: WORKSPACE,\n requestType: REQUEST_WORKSPACE,\n initial: DEFAULT_WORKSPACE,\n parse: (msg) => {\n if (msg.workspace === null) return null;\n if (!isWorkspace(msg.workspace)) return undefined;\n const { provider, namespace, repository, ref, label } = msg.workspace;\n return { provider, namespace, repository, ref, label };\n },\n});\n\n/** Returns the current workspace, or `null` outside an editing session. */\nexport const getWorkspace = (): Workspace | null => channel.get();\n\n/**\n * Subscribe to workspace changes. The listener is invoked immediately with the\n * current value, then again on every change. Returns an unsubscribe fn.\n */\nexport const onWorkspaceChange = (listener: (workspace: Workspace | null) => void): (() => void) =>\n channel.onChange(listener);\n\n/** React hook returning the current workspace, re-rendering on change. */\nexport const useWorkspace = (): Workspace | null => channel.use();\n"],"mappings":";AAAA,SAAS,yBAAyB;AAClC,SAAS,WAAW,yBAAyB;AAwD7C,MAAM,oBAAsC;AAE5C,MAAM,cAAc,CAAC,MAA+B;AAClD,QAAM,IAAI;AACV,SACE,CAAC,CAAC,KACF,OAAO,MAAM,YACb,OAAO,EAAE,aAAa,YACtB,OAAO,EAAE,cAAc,YACvB,OAAO,EAAE,eAAe,YACxB,OAAO,EAAE,QAAQ,YACjB,OAAO,EAAE,UAAU;AAEvB;AAgBA,MAAM,UAAU,kBAAoC;AAAA,EAClD,UAAU;AAAA,EACV,aAAa;AAAA,EACb,SAAS;AAAA,EACT,OAAO,CAAC,QAAQ;AACd,QAAI,IAAI,cAAc,KAAM,QAAO;AACnC,QAAI,CAAC,YAAY,IAAI,SAAS,EAAG,QAAO;AACxC,UAAM,EAAE,UAAU,WAAW,YAAY,KAAK,MAAM,IAAI,IAAI;AAC5D,WAAO,EAAE,UAAU,WAAW,YAAY,KAAK,MAAM;AAAA,EACvD;AACF,CAAC;AAGM,MAAM,eAAe,MAAwB,QAAQ,IAAI;AAMzD,MAAM,oBAAoB,CAAC,aAChC,QAAQ,SAAS,QAAQ;AAGpB,MAAM,eAAe,MAAwB,QAAQ,IAAI;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@immediately-run/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.59.0",
|
|
4
4
|
"description": "Runtime SDK for code executing inside an immediately.run sandbox.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "github:immediately-run/immediately-run-sdk",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"@immediately-run/mdx-plugins": "0.5.0",
|
|
65
65
|
"@immediately-run/platform-constants": "0.2.0",
|
|
66
66
|
"@immediately-run/safe-content": "0.1.0",
|
|
67
|
-
"@immediately-run/sandbox-protocol": "0.
|
|
67
|
+
"@immediately-run/sandbox-protocol": "0.8.2",
|
|
68
68
|
"react-error-boundary": "^6.0.0"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|