@immediately-run/sdk 0.59.1 → 0.60.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 +3 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/platformLink.cjs +42 -0
- package/dist/platformLink.cjs.map +1 -0
- package/dist/platformLink.d.cts +30 -0
- package/dist/platformLink.d.ts +30 -0
- package/dist/platformLink.js +18 -0
- package/dist/platformLink.js.map +1 -0
- package/dist/urlUtils.cjs +13 -0
- package/dist/urlUtils.cjs.map +1 -1
- package/dist/urlUtils.d.cts +15 -1
- package/dist/urlUtils.d.ts +15 -1
- package/dist/urlUtils.js +12 -0
- package/dist/urlUtils.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/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -81,6 +81,7 @@ __reExport(index_exports, require("./metadataQueryTool"), module.exports);
|
|
|
81
81
|
__reExport(index_exports, require("./collectHeadings"), module.exports);
|
|
82
82
|
__reExport(index_exports, require("./agentContext"), module.exports);
|
|
83
83
|
__reExport(index_exports, require("./fence"), module.exports);
|
|
84
|
+
__reExport(index_exports, require("./platformLink"), module.exports);
|
|
84
85
|
// Annotate the CommonJS export names for ESM import in node:
|
|
85
86
|
0 && (module.exports = {
|
|
86
87
|
SafeInclude,
|
|
@@ -140,6 +141,7 @@ __reExport(index_exports, require("./fence"), module.exports);
|
|
|
140
141
|
...require("./metadataQueryTool"),
|
|
141
142
|
...require("./collectHeadings"),
|
|
142
143
|
...require("./agentContext"),
|
|
143
|
-
...require("./fence")
|
|
144
|
+
...require("./fence"),
|
|
145
|
+
...require("./platformLink")
|
|
144
146
|
});
|
|
145
147
|
//# sourceMappingURL=index.cjs.map
|
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 './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":[]}
|
|
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';\nexport * from './platformLink';\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;AAsEA,0BAAc,2BAtEd;","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -54,6 +54,7 @@ export { HeadingSummary, METADATA_HEADINGS_KEY, METADATA_QUERY_TOOL_DESCRIPTOR,
|
|
|
54
54
|
export { collectHeadings } from './collectHeadings.cjs';
|
|
55
55
|
export { AgentContextAppFields, AgentContextBlock, renderAgentContext, useAgentContext } from './agentContext.cjs';
|
|
56
56
|
export { fenceUntrusted } from './fence.cjs';
|
|
57
|
+
export { PlatformLink, PlatformLinkProps, usePlatformHref } from './platformLink.cjs';
|
|
57
58
|
export { Admonition, AdmonitionType } from './components/Admonition.cjs';
|
|
58
59
|
export { FS_PREFIX, LinkSpace, ResolvedLinkTarget, normalizeAbsolute, resolveLinkTarget } from '@immediately-run/mdx-plugins';
|
|
59
60
|
export { GrantRecord, Member, ResolvedUser, Role, SpaceInfo, getSpaceMembers, inviteToSpace, listAllSpaces, listGrants, listSpaces, lookupUser, revokeGrant, setSpaceRole, unshareSpace } from './generated/spaces.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -54,6 +54,7 @@ export { HeadingSummary, METADATA_HEADINGS_KEY, METADATA_QUERY_TOOL_DESCRIPTOR,
|
|
|
54
54
|
export { collectHeadings } from './collectHeadings.js';
|
|
55
55
|
export { AgentContextAppFields, AgentContextBlock, renderAgentContext, useAgentContext } from './agentContext.js';
|
|
56
56
|
export { fenceUntrusted } from './fence.js';
|
|
57
|
+
export { PlatformLink, PlatformLinkProps, usePlatformHref } from './platformLink.js';
|
|
57
58
|
export { Admonition, AdmonitionType } from './components/Admonition.js';
|
|
58
59
|
export { FS_PREFIX, LinkSpace, ResolvedLinkTarget, normalizeAbsolute, resolveLinkTarget } from '@immediately-run/mdx-plugins';
|
|
59
60
|
export { GrantRecord, Member, ResolvedUser, Role, SpaceInfo, getSpaceMembers, inviteToSpace, listAllSpaces, listGrants, listSpaces, lookupUser, revokeGrant, setSpaceRole, unshareSpace } from './generated/spaces.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 './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":[]}
|
|
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';\nexport * from './platformLink';\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;AACd,cAAc;","names":[]}
|
|
@@ -0,0 +1,42 @@
|
|
|
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 platformLink_exports = {};
|
|
20
|
+
__export(platformLink_exports, {
|
|
21
|
+
PlatformLink: () => PlatformLink,
|
|
22
|
+
usePlatformHref: () => usePlatformHref
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(platformLink_exports);
|
|
25
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
26
|
+
var import_react = require("react");
|
|
27
|
+
var import_TinkerableContext = require("./TinkerableContext");
|
|
28
|
+
var import_urlUtils = require("./urlUtils");
|
|
29
|
+
const usePlatformHref = () => {
|
|
30
|
+
const { outerHref } = (0, import_react.use)(import_TinkerableContext.TinkerableContext);
|
|
31
|
+
return (path) => (0, import_urlUtils.platformHref)(outerHref, path);
|
|
32
|
+
};
|
|
33
|
+
function PlatformLink({ path, children, ...rest }) {
|
|
34
|
+
const platform = usePlatformHref();
|
|
35
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { ...rest, href: platform(path), target: "_top", children });
|
|
36
|
+
}
|
|
37
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
38
|
+
0 && (module.exports = {
|
|
39
|
+
PlatformLink,
|
|
40
|
+
usePlatformHref
|
|
41
|
+
});
|
|
42
|
+
//# sourceMappingURL=platformLink.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/platformLink.tsx"],"sourcesContent":["import type { AnchorHTMLAttributes, ReactNode } from 'react';\nimport { use } from 'react';\n\nimport { TinkerableContext } from './TinkerableContext';\nimport { platformHref } from './urlUtils';\n\n/**\n * Build a PLATFORM-space href (`/present/…`, `/edit/github/…`, `/home`) in the host's URL\n * space, reading `outerHref` from {@link TinkerableContext} the way `useTinkerableLink` does.\n * The returned closure is fresh each render (its output is pure, so identity churn is\n * harmless); an empty context (no host, `vite dev`) yields the path unchanged.\n *\n * Render the result through {@link PlatformLink}, which also carries `target=\"_top\"` —\n * a root-relative href inside the sandboxed frame would resolve against the SANDBOX origin\n * and land nowhere, and an anchor without `target=\"_top\"` navigates the frame instead of\n * the page.\n */\nexport const usePlatformHref = (): ((path: string) => string) => {\n const { outerHref } = use(TinkerableContext);\n return (path: string) => platformHref(outerHref, path);\n};\n\nexport interface PlatformLinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> {\n /** A root-relative platform path, e.g. `/present/github/acme/todo`. */\n path: string;\n children?: ReactNode;\n}\n\n/**\n * The ONE way to render an anchor to a PLATFORM route: it builds the href with\n * {@link platformHref} (resolving against the host's outer origin) and always carries\n * `target=\"_top\"`, because an anchor inside the sandboxed frame otherwise navigates the\n * frame instead of the host document. External URLs (`https://…`) are not platform routes\n * and should stay plain `<a target=\"_blank\">` anchors.\n */\nexport function PlatformLink({ path, children, ...rest }: PlatformLinkProps) {\n const platform = usePlatformHref();\n return (\n <a {...rest} href={platform(path)} target=\"_top\">\n {children}\n </a>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsCI;AArCJ,mBAAoB;AAEpB,+BAAkC;AAClC,sBAA6B;AAatB,MAAM,kBAAkB,MAAkC;AAC/D,QAAM,EAAE,UAAU,QAAI,kBAAI,0CAAiB;AAC3C,SAAO,CAAC,aAAiB,8BAAa,WAAW,IAAI;AACvD;AAeO,SAAS,aAAa,EAAE,MAAM,UAAU,GAAG,KAAK,GAAsB;AAC3E,QAAM,WAAW,gBAAgB;AACjC,SACE,4CAAC,OAAG,GAAG,MAAM,MAAM,SAAS,IAAI,GAAG,QAAO,QACvC,UACH;AAEJ;","names":[]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { AnchorHTMLAttributes, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Build a PLATFORM-space href (`/present/…`, `/edit/github/…`, `/home`) in the host's URL
|
|
6
|
+
* space, reading `outerHref` from {@link TinkerableContext} the way `useTinkerableLink` does.
|
|
7
|
+
* The returned closure is fresh each render (its output is pure, so identity churn is
|
|
8
|
+
* harmless); an empty context (no host, `vite dev`) yields the path unchanged.
|
|
9
|
+
*
|
|
10
|
+
* Render the result through {@link PlatformLink}, which also carries `target="_top"` —
|
|
11
|
+
* a root-relative href inside the sandboxed frame would resolve against the SANDBOX origin
|
|
12
|
+
* and land nowhere, and an anchor without `target="_top"` navigates the frame instead of
|
|
13
|
+
* the page.
|
|
14
|
+
*/
|
|
15
|
+
declare const usePlatformHref: () => ((path: string) => string);
|
|
16
|
+
interface PlatformLinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> {
|
|
17
|
+
/** A root-relative platform path, e.g. `/present/github/acme/todo`. */
|
|
18
|
+
path: string;
|
|
19
|
+
children?: ReactNode;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The ONE way to render an anchor to a PLATFORM route: it builds the href with
|
|
23
|
+
* {@link platformHref} (resolving against the host's outer origin) and always carries
|
|
24
|
+
* `target="_top"`, because an anchor inside the sandboxed frame otherwise navigates the
|
|
25
|
+
* frame instead of the host document. External URLs (`https://…`) are not platform routes
|
|
26
|
+
* and should stay plain `<a target="_blank">` anchors.
|
|
27
|
+
*/
|
|
28
|
+
declare function PlatformLink({ path, children, ...rest }: PlatformLinkProps): react.JSX.Element;
|
|
29
|
+
|
|
30
|
+
export { PlatformLink, type PlatformLinkProps, usePlatformHref };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { AnchorHTMLAttributes, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Build a PLATFORM-space href (`/present/…`, `/edit/github/…`, `/home`) in the host's URL
|
|
6
|
+
* space, reading `outerHref` from {@link TinkerableContext} the way `useTinkerableLink` does.
|
|
7
|
+
* The returned closure is fresh each render (its output is pure, so identity churn is
|
|
8
|
+
* harmless); an empty context (no host, `vite dev`) yields the path unchanged.
|
|
9
|
+
*
|
|
10
|
+
* Render the result through {@link PlatformLink}, which also carries `target="_top"` —
|
|
11
|
+
* a root-relative href inside the sandboxed frame would resolve against the SANDBOX origin
|
|
12
|
+
* and land nowhere, and an anchor without `target="_top"` navigates the frame instead of
|
|
13
|
+
* the page.
|
|
14
|
+
*/
|
|
15
|
+
declare const usePlatformHref: () => ((path: string) => string);
|
|
16
|
+
interface PlatformLinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> {
|
|
17
|
+
/** A root-relative platform path, e.g. `/present/github/acme/todo`. */
|
|
18
|
+
path: string;
|
|
19
|
+
children?: ReactNode;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The ONE way to render an anchor to a PLATFORM route: it builds the href with
|
|
23
|
+
* {@link platformHref} (resolving against the host's outer origin) and always carries
|
|
24
|
+
* `target="_top"`, because an anchor inside the sandboxed frame otherwise navigates the
|
|
25
|
+
* frame instead of the host document. External URLs (`https://…`) are not platform routes
|
|
26
|
+
* and should stay plain `<a target="_blank">` anchors.
|
|
27
|
+
*/
|
|
28
|
+
declare function PlatformLink({ path, children, ...rest }: PlatformLinkProps): react.JSX.Element;
|
|
29
|
+
|
|
30
|
+
export { PlatformLink, type PlatformLinkProps, usePlatformHref };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import "./chunk-VHAA22YE.js";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { use } from "react";
|
|
4
|
+
import { TinkerableContext } from "./TinkerableContext";
|
|
5
|
+
import { platformHref } from "./urlUtils";
|
|
6
|
+
const usePlatformHref = () => {
|
|
7
|
+
const { outerHref } = use(TinkerableContext);
|
|
8
|
+
return (path) => platformHref(outerHref, path);
|
|
9
|
+
};
|
|
10
|
+
function PlatformLink({ path, children, ...rest }) {
|
|
11
|
+
const platform = usePlatformHref();
|
|
12
|
+
return /* @__PURE__ */ jsx("a", { ...rest, href: platform(path), target: "_top", children });
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
PlatformLink,
|
|
16
|
+
usePlatformHref
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=platformLink.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/platformLink.tsx"],"sourcesContent":["import type { AnchorHTMLAttributes, ReactNode } from 'react';\nimport { use } from 'react';\n\nimport { TinkerableContext } from './TinkerableContext';\nimport { platformHref } from './urlUtils';\n\n/**\n * Build a PLATFORM-space href (`/present/…`, `/edit/github/…`, `/home`) in the host's URL\n * space, reading `outerHref` from {@link TinkerableContext} the way `useTinkerableLink` does.\n * The returned closure is fresh each render (its output is pure, so identity churn is\n * harmless); an empty context (no host, `vite dev`) yields the path unchanged.\n *\n * Render the result through {@link PlatformLink}, which also carries `target=\"_top\"` —\n * a root-relative href inside the sandboxed frame would resolve against the SANDBOX origin\n * and land nowhere, and an anchor without `target=\"_top\"` navigates the frame instead of\n * the page.\n */\nexport const usePlatformHref = (): ((path: string) => string) => {\n const { outerHref } = use(TinkerableContext);\n return (path: string) => platformHref(outerHref, path);\n};\n\nexport interface PlatformLinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> {\n /** A root-relative platform path, e.g. `/present/github/acme/todo`. */\n path: string;\n children?: ReactNode;\n}\n\n/**\n * The ONE way to render an anchor to a PLATFORM route: it builds the href with\n * {@link platformHref} (resolving against the host's outer origin) and always carries\n * `target=\"_top\"`, because an anchor inside the sandboxed frame otherwise navigates the\n * frame instead of the host document. External URLs (`https://…`) are not platform routes\n * and should stay plain `<a target=\"_blank\">` anchors.\n */\nexport function PlatformLink({ path, children, ...rest }: PlatformLinkProps) {\n const platform = usePlatformHref();\n return (\n <a {...rest} href={platform(path)} target=\"_top\">\n {children}\n </a>\n );\n}\n"],"mappings":";AAsCI;AArCJ,SAAS,WAAW;AAEpB,SAAS,yBAAyB;AAClC,SAAS,oBAAoB;AAatB,MAAM,kBAAkB,MAAkC;AAC/D,QAAM,EAAE,UAAU,IAAI,IAAI,iBAAiB;AAC3C,SAAO,CAAC,SAAiB,aAAa,WAAW,IAAI;AACvD;AAeO,SAAS,aAAa,EAAE,MAAM,UAAU,GAAG,KAAK,GAAsB;AAC3E,QAAM,WAAW,gBAAgB;AACjC,SACE,oBAAC,OAAG,GAAG,MAAM,MAAM,SAAS,IAAI,GAAG,QAAO,QACvC,UACH;AAEJ;","names":[]}
|
package/dist/urlUtils.cjs
CHANGED
|
@@ -30,6 +30,7 @@ __export(urlUtils_exports, {
|
|
|
30
30
|
parseHref: () => parseHref,
|
|
31
31
|
parsePath: () => parsePath,
|
|
32
32
|
parseTarget: () => parseTarget,
|
|
33
|
+
platformHref: () => platformHref,
|
|
33
34
|
repositoryPrefixURL: () => repositoryPrefixURL,
|
|
34
35
|
splitHash: () => splitHash,
|
|
35
36
|
underAppRoot: () => import_platform_constants.underAppRoot
|
|
@@ -92,6 +93,17 @@ const isInternalHref = (outerHref, target, navigationState) => {
|
|
|
92
93
|
}
|
|
93
94
|
return true;
|
|
94
95
|
};
|
|
96
|
+
const platformHref = (outerHref, path) => {
|
|
97
|
+
if (typeof path !== "string") {
|
|
98
|
+
throw new TypeError(`platformHref: path must be a string, got ${typeof path}`);
|
|
99
|
+
}
|
|
100
|
+
if (!outerHref) return path;
|
|
101
|
+
try {
|
|
102
|
+
return new URL(path, outerHref).toString();
|
|
103
|
+
} catch {
|
|
104
|
+
return path;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
95
107
|
const decodeSegment = (value) => {
|
|
96
108
|
try {
|
|
97
109
|
return decodeURIComponent(value);
|
|
@@ -170,6 +182,7 @@ const constructUrl = (outerHref, navigationState) => {
|
|
|
170
182
|
parseHref,
|
|
171
183
|
parsePath,
|
|
172
184
|
parseTarget,
|
|
185
|
+
platformHref,
|
|
173
186
|
repositoryPrefixURL,
|
|
174
187
|
splitHash,
|
|
175
188
|
underAppRoot
|
package/dist/urlUtils.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/urlUtils.ts"],"sourcesContent":["import { APP_ROOT, underAppRoot } from '@immediately-run/platform-constants';\n\nimport { joinPaths } from './pathUtils';\nimport { NavigationState, PathState } from './TinkerableContext';\n\nexport const FILES_PREFIX = '/files';\n\n/**\n * Mount point of the Git repository inside the sandbox filesystem, and the join\n * into it — both now defined ONCE in `@immediately-run/platform-constants` (R3-275)\n * and re-exported here so every import site is unchanged.\n *\n * They were declared here AND in `sandbox/src/fsLayout.ts`, with two different\n * implementations of the join (this one over `joinPaths`, the sandbox's hand-rolled).\n * The two agreed; nothing made them agree — and the metadata key space is derived\n * from this constant on both sides, so a drift would have split that key space\n * silently. The package's tests replicate BOTH implementations, quirks included.\n *\n * The sandbox fs is rooted at `/` (so apps can reach dynamic mounts like\n * `/firestore`), with the repo mounted at `APP_ROOT`. URL subpaths are\n * repo-relative, so the file router resolves them under it.\n */\nexport { APP_ROOT, underAppRoot };\n\n/**\n * The origin every outer URL is rebuilt on — `protocol//host`, **port included**.\n *\n * `url.hostname` drops the port; `url.host` keeps it (and still omits it for the default\n * 80/443, so a production URL is byte-identical either way). Using `hostname` here was\n * invisible on `https://immediately.run` and broke every routed link under local dev on any\n * port but 80: `http://localhost:3100/edit/…` was rebuilt as `http://localhost/edit/…`.\n *\n * Worse than a wrong link, it silently changed link BEHAVIOUR. `repositoryPrefixURL` is\n * built from this, and `isInternalHref` decides by prefix-matching against it — so an\n * absolute in-app URL failed the match, was classified EXTERNAL, and rendered as a plain\n * `<a>`. Clicking it performed a real navigation out of the sandboxed frame instead of\n * routing: the app appeared to \"reload\" on an ordinary internal link.\n */\nexport const getOuterHostname = (outerHref: string) => {\n const url = new URL(outerHref);\n return `${url.protocol}//${url.host}`;\n};\n\nexport const getSearchParams = (search?: string): Record<string, string> =>\n Object.fromEntries([...new URLSearchParams(search ?? window.location.search).entries()]);\n\n/**\n * Split a link target into its path part and its `#fragment` (the `#` dropped),\n * e.g. `\"FOO.mdx#sec-8-9\"` → `[\"FOO.mdx\", \"sec-8-9\"]`, `\"#sec-3\"` → `[\"\", \"sec-3\"]`,\n * `\"FOO.mdx\"` → `[\"FOO.mdx\", \"\"]`. Only the **first** `#` splits — a fragment never\n * contains another `#`. The seam between wiki-links (§13) and heading ids (§15):\n * existence is resolved on the path part, the fragment is threaded to navigation.\n * MARKDOWN_SYNTAX_SPEC §13.5.\n */\nexport const splitHash = (target: string): [string, string] => {\n const i = target.indexOf('#');\n return i === -1 ? [target, ''] : [target.slice(0, i), target.slice(i + 1)];\n};\n\nexport const parseTarget = (target: string, navigation: NavigationState): NavigationState => {\n const newNavigation = { ...navigation };\n let [prehash, hash] = target.split('#');\n if (prehash) {\n let [path, search] = prehash.split('?');\n if (path) {\n newNavigation.sandboxPath = path;\n }\n newNavigation.search = search ? search : '';\n }\n newNavigation.hash = hash ? hash : '';\n return newNavigation;\n};\n\nexport const maybeParseUrl = (str: string): URL | null => {\n try {\n return new URL(str);\n } catch (_) {\n return null;\n }\n};\n\nexport const isAbsolutePath = (sandboxPath: string) => sandboxPath.startsWith('/');\n\n/**\n * The origin+repo prefix every same-app URL starts with — used by {@link isInternalHref} to\n * decide whether an absolute href is \"this app\" or somewhere else.\n *\n * `hash` and `search` are cleared, not just `sandboxPath`. They belong to the CURRENT page,\n * and leaving them in put them on the end of a *prefix*: from a page carrying `#sec-8-9`,\n * the prefix became `…/main/#sec-8-9`, no same-app URL could start with it, every absolute\n * in-app link was classified EXTERNAL, and clicking one navigated the sandboxed frame away\n * instead of routing. A page with a fragment quietly broke its own links.\n */\nexport const repositoryPrefixURL = (outerHref: string, navigationState: NavigationState) =>\n constructUrl(outerHref, {\n ...navigationState,\n sandboxPath: '',\n hash: '',\n search: '',\n });\n\nexport const constructOuterUrl = (\n previousOuterHref: string,\n sandboxTarget: string,\n navigationState: NavigationState,\n addFilesPrefix = true,\n): string => {\n if (isAbsolutePath(sandboxTarget)) {\n // Split a trailing `#fragment` off before the target is folded into the\n // sandboxPath, and carry it in `hash` instead — a fragment addresses a section,\n // not a file, so it must not leak into the path (MARKDOWN_SYNTAX_SPEC §13.5). An\n // absolute target with no fragment clears any stale hash from the prior state.\n const [pathPart, hash] = splitHash(sandboxTarget);\n return constructUrl(previousOuterHref, {\n ...navigationState,\n sandboxPath: addFilesPrefix ? joinPaths(FILES_PREFIX, pathPart) : pathPart,\n hash,\n });\n }\n return new URL(sandboxTarget, constructUrl(previousOuterHref, navigationState)).toString();\n};\n\nexport const isInternalHref = (outerHref: string, target: string, navigationState: NavigationState) => {\n const parsedUrl = maybeParseUrl(target);\n if (parsedUrl) {\n return target.startsWith(repositoryPrefixURL(outerHref, navigationState));\n }\n // if target is not a valid URL, then assume it's relative.\n return true;\n};\n\nexport type PathSegment = {\n name: string;\n pattern: string;\n transform?: (pathSegment: string) => string;\n // When true, the leading slash that delimits this segment is optional, so the\n // whole `/segment` group can be absent. Used for the trailing sandboxPath:\n // an outer href of `/mode/provider/namespace/repository/ref` (no trailing\n // slash, no sub-path) must still parse, otherwise the regex matches nothing\n // and every segment comes back empty.\n optionalLeadingSlash?: boolean;\n // Inverse of `transform`, applied when BUILDING a url (`constructUrl`). Without it a\n // decoded ref would be written back raw and split into two segments again.\n encode?: (value: string) => string;\n};\n\n// One URL path segment is \"anything but a slash\". The previous patterns instead\n// ENUMERATED the allowed characters (`[a-zA-Z0-9-_]+`), which silently rejected three\n// real shapes — and rejection here is not an error, it is a whole-match failure that\n// makes `parsePath` return every field EMPTY, so the app's navigation state just goes\n// blank with nothing logged:\n//\n// /…/repo/v1.2.3/… a semver TAG (dot)\n// /…/foo.js/main/… a dotted REPOSITORY name (dot — very common)\n// /…/repo/claude%2Fx/… a `/`-containing REF, percent-encoded as one segment\n//\n// The third is the one that motivated this (a ref may contain `/`; the host now encodes\n// it — see site-main `encodeRef`), but the first two were already broken and are the\n// same mistake. `[^/]+` is both the fix and the accurate description of a segment.\n/** Percent-decode one path segment, tolerating a malformed escape: this is untrusted\n * URL input, and `decodeURIComponent('%zz')` throws. A bad ref must not blank out the\n * whole navigation state. */\nconst decodeSegment = (value: string): string => {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n};\n\nconst PATH_SEGMENTS: PathSegment[] = [\n { name: 'mode', pattern: '\\\\w+' },\n { name: 'provider', pattern: '[^/]+' },\n { name: 'namespace', pattern: '[^/]+' },\n { name: 'repository', pattern: '[^/]+' },\n // The ref is percent-encoded by the host so a `/` inside it stays ONE segment; decode\n // on the way in and re-encode on the way out (`encode`), so app code always sees the\n // real ref (`claude/x`) and never the wire form.\n { name: 'ref', pattern: '[^/]+', transform: decodeSegment, encode: encodeURIComponent },\n { name: 'sandboxPath', pattern: '.*', transform: (s) => `/${s}`, optionalLeadingSlash: true },\n];\n\nconst OUTER_HREF_REGEXP = new RegExp(\n '^' +\n PATH_SEGMENTS.map(({ name, pattern, optionalLeadingSlash }) =>\n optionalLeadingSlash ? `(?:\\/(?<${name}>${pattern}))?` : `\\/(?<${name}>${pattern})`,\n ).join('') +\n '$',\n);\n\nexport const parsePath = (pathname: string): PathState => {\n const matchResults = pathname.match(OUTER_HREF_REGEXP)?.groups ?? {};\n return PATH_SEGMENTS.reduce((acc: Partial<PathState>, { name, transform }: PathSegment) => {\n let value: string | undefined = undefined;\n if (name in matchResults) {\n value = matchResults[name];\n }\n if (!value) {\n // fall back to default value if var not present in\n value = '';\n }\n if (typeof value === 'string') {\n acc[name] = transform ? transform(value) : value;\n }\n return acc;\n }, {}) as PathState;\n};\n\nexport const parseHref = (href: string): NavigationState => {\n const parsedUrl = new URL(href);\n const pathnameState = parsePath(parsedUrl.pathname);\n return {\n ...pathnameState,\n search: parsedUrl.search.substring(1),\n hash: parsedUrl.hash.substring(1),\n } as NavigationState;\n};\n\nconst stripSlashPrefix = (s: string): string => (s.startsWith('/') ? s.substring(1) : s);\n\nexport const constructUrl = (outerHref: string, navigationState: NavigationState): string => {\n const path = PATH_SEGMENTS.map(({ name, encode }) => {\n const value = stripSlashPrefix(navigationState[name] ?? '');\n // Encode AFTER stripping the delimiter slash: `encode` is per-segment, and the\n // sandboxPath (which has no `encode`) keeps its own internal slashes.\n return encode ? encode(value) : value;\n }).join('/');\n const host = getOuterHostname(outerHref);\n let url = `${host}/${path}`;\n if (navigationState.search) {\n url += '?' + navigationState.search;\n }\n if (navigationState.hash) {\n url += '#' + navigationState.hash;\n }\n return url;\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/urlUtils.ts"],"sourcesContent":["import { APP_ROOT, underAppRoot } from '@immediately-run/platform-constants';\n\nimport { joinPaths } from './pathUtils';\nimport { NavigationState, PathState } from './TinkerableContext';\n\nexport const FILES_PREFIX = '/files';\n\n/**\n * Mount point of the Git repository inside the sandbox filesystem, and the join\n * into it — both now defined ONCE in `@immediately-run/platform-constants` (R3-275)\n * and re-exported here so every import site is unchanged.\n *\n * They were declared here AND in `sandbox/src/fsLayout.ts`, with two different\n * implementations of the join (this one over `joinPaths`, the sandbox's hand-rolled).\n * The two agreed; nothing made them agree — and the metadata key space is derived\n * from this constant on both sides, so a drift would have split that key space\n * silently. The package's tests replicate BOTH implementations, quirks included.\n *\n * The sandbox fs is rooted at `/` (so apps can reach dynamic mounts like\n * `/firestore`), with the repo mounted at `APP_ROOT`. URL subpaths are\n * repo-relative, so the file router resolves them under it.\n */\nexport { APP_ROOT, underAppRoot };\n\n/**\n * The origin every outer URL is rebuilt on — `protocol//host`, **port included**.\n *\n * `url.hostname` drops the port; `url.host` keeps it (and still omits it for the default\n * 80/443, so a production URL is byte-identical either way). Using `hostname` here was\n * invisible on `https://immediately.run` and broke every routed link under local dev on any\n * port but 80: `http://localhost:3100/edit/…` was rebuilt as `http://localhost/edit/…`.\n *\n * Worse than a wrong link, it silently changed link BEHAVIOUR. `repositoryPrefixURL` is\n * built from this, and `isInternalHref` decides by prefix-matching against it — so an\n * absolute in-app URL failed the match, was classified EXTERNAL, and rendered as a plain\n * `<a>`. Clicking it performed a real navigation out of the sandboxed frame instead of\n * routing: the app appeared to \"reload\" on an ordinary internal link.\n */\nexport const getOuterHostname = (outerHref: string) => {\n const url = new URL(outerHref);\n return `${url.protocol}//${url.host}`;\n};\n\nexport const getSearchParams = (search?: string): Record<string, string> =>\n Object.fromEntries([...new URLSearchParams(search ?? window.location.search).entries()]);\n\n/**\n * Split a link target into its path part and its `#fragment` (the `#` dropped),\n * e.g. `\"FOO.mdx#sec-8-9\"` → `[\"FOO.mdx\", \"sec-8-9\"]`, `\"#sec-3\"` → `[\"\", \"sec-3\"]`,\n * `\"FOO.mdx\"` → `[\"FOO.mdx\", \"\"]`. Only the **first** `#` splits — a fragment never\n * contains another `#`. The seam between wiki-links (§13) and heading ids (§15):\n * existence is resolved on the path part, the fragment is threaded to navigation.\n * MARKDOWN_SYNTAX_SPEC §13.5.\n */\nexport const splitHash = (target: string): [string, string] => {\n const i = target.indexOf('#');\n return i === -1 ? [target, ''] : [target.slice(0, i), target.slice(i + 1)];\n};\n\nexport const parseTarget = (target: string, navigation: NavigationState): NavigationState => {\n const newNavigation = { ...navigation };\n let [prehash, hash] = target.split('#');\n if (prehash) {\n let [path, search] = prehash.split('?');\n if (path) {\n newNavigation.sandboxPath = path;\n }\n newNavigation.search = search ? search : '';\n }\n newNavigation.hash = hash ? hash : '';\n return newNavigation;\n};\n\nexport const maybeParseUrl = (str: string): URL | null => {\n try {\n return new URL(str);\n } catch (_) {\n return null;\n }\n};\n\nexport const isAbsolutePath = (sandboxPath: string) => sandboxPath.startsWith('/');\n\n/**\n * The origin+repo prefix every same-app URL starts with — used by {@link isInternalHref} to\n * decide whether an absolute href is \"this app\" or somewhere else.\n *\n * `hash` and `search` are cleared, not just `sandboxPath`. They belong to the CURRENT page,\n * and leaving them in put them on the end of a *prefix*: from a page carrying `#sec-8-9`,\n * the prefix became `…/main/#sec-8-9`, no same-app URL could start with it, every absolute\n * in-app link was classified EXTERNAL, and clicking one navigated the sandboxed frame away\n * instead of routing. A page with a fragment quietly broke its own links.\n */\nexport const repositoryPrefixURL = (outerHref: string, navigationState: NavigationState) =>\n constructUrl(outerHref, {\n ...navigationState,\n sandboxPath: '',\n hash: '',\n search: '',\n });\n\nexport const constructOuterUrl = (\n previousOuterHref: string,\n sandboxTarget: string,\n navigationState: NavigationState,\n addFilesPrefix = true,\n): string => {\n if (isAbsolutePath(sandboxTarget)) {\n // Split a trailing `#fragment` off before the target is folded into the\n // sandboxPath, and carry it in `hash` instead — a fragment addresses a section,\n // not a file, so it must not leak into the path (MARKDOWN_SYNTAX_SPEC §13.5). An\n // absolute target with no fragment clears any stale hash from the prior state.\n const [pathPart, hash] = splitHash(sandboxTarget);\n return constructUrl(previousOuterHref, {\n ...navigationState,\n sandboxPath: addFilesPrefix ? joinPaths(FILES_PREFIX, pathPart) : pathPart,\n hash,\n });\n }\n return new URL(sandboxTarget, constructUrl(previousOuterHref, navigationState)).toString();\n};\n\nexport const isInternalHref = (outerHref: string, target: string, navigationState: NavigationState) => {\n const parsedUrl = maybeParseUrl(target);\n if (parsedUrl) {\n return target.startsWith(repositoryPrefixURL(outerHref, navigationState));\n }\n // if target is not a valid URL, then assume it's relative.\n return true;\n};\n\n/**\n * The href to render for a PLATFORM-space path — `/present/github/…`, `/edit/github/…`,\n * `/home`, `/settings/language-model`. These are the HOST's URLs, not this app's: inside the\n * sandboxed frame a root-relative `href` resolves against the SANDBOX origin, which serves no\n * such page, so the path is resolved against the OUTER origin (`outerHref`) instead. An\n * absolute `path` (`https://…`) is returned as-is, which `new URL` already does. With no host\n * (`vite dev`, an empty `outerHref`) or an unresolvable pair, `path` is returned unchanged so\n * the local dev server keeps working. A non-string `path` throws: a caller passing one has a\n * bug worth surfacing, not silently rendering.\n *\n * Render the result through `PlatformLink` (`./platformLink`), which also carries\n * `target=\"_top\"` — an anchor inside the sandboxed frame otherwise navigates the frame.\n */\nexport const platformHref = (outerHref: string, path: string): string => {\n if (typeof path !== 'string') {\n throw new TypeError(`platformHref: path must be a string, got ${typeof path}`);\n }\n if (!outerHref) return path;\n try {\n return new URL(path, outerHref).toString();\n } catch {\n return path;\n }\n};\n\nexport type PathSegment = {\n name: string;\n pattern: string;\n transform?: (pathSegment: string) => string;\n // When true, the leading slash that delimits this segment is optional, so the\n // whole `/segment` group can be absent. Used for the trailing sandboxPath:\n // an outer href of `/mode/provider/namespace/repository/ref` (no trailing\n // slash, no sub-path) must still parse, otherwise the regex matches nothing\n // and every segment comes back empty.\n optionalLeadingSlash?: boolean;\n // Inverse of `transform`, applied when BUILDING a url (`constructUrl`). Without it a\n // decoded ref would be written back raw and split into two segments again.\n encode?: (value: string) => string;\n};\n\n// One URL path segment is \"anything but a slash\". The previous patterns instead\n// ENUMERATED the allowed characters (`[a-zA-Z0-9-_]+`), which silently rejected three\n// real shapes — and rejection here is not an error, it is a whole-match failure that\n// makes `parsePath` return every field EMPTY, so the app's navigation state just goes\n// blank with nothing logged:\n//\n// /…/repo/v1.2.3/… a semver TAG (dot)\n// /…/foo.js/main/… a dotted REPOSITORY name (dot — very common)\n// /…/repo/claude%2Fx/… a `/`-containing REF, percent-encoded as one segment\n//\n// The third is the one that motivated this (a ref may contain `/`; the host now encodes\n// it — see site-main `encodeRef`), but the first two were already broken and are the\n// same mistake. `[^/]+` is both the fix and the accurate description of a segment.\n/** Percent-decode one path segment, tolerating a malformed escape: this is untrusted\n * URL input, and `decodeURIComponent('%zz')` throws. A bad ref must not blank out the\n * whole navigation state. */\nconst decodeSegment = (value: string): string => {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n};\n\nconst PATH_SEGMENTS: PathSegment[] = [\n { name: 'mode', pattern: '\\\\w+' },\n { name: 'provider', pattern: '[^/]+' },\n { name: 'namespace', pattern: '[^/]+' },\n { name: 'repository', pattern: '[^/]+' },\n // The ref is percent-encoded by the host so a `/` inside it stays ONE segment; decode\n // on the way in and re-encode on the way out (`encode`), so app code always sees the\n // real ref (`claude/x`) and never the wire form.\n { name: 'ref', pattern: '[^/]+', transform: decodeSegment, encode: encodeURIComponent },\n { name: 'sandboxPath', pattern: '.*', transform: (s) => `/${s}`, optionalLeadingSlash: true },\n];\n\nconst OUTER_HREF_REGEXP = new RegExp(\n '^' +\n PATH_SEGMENTS.map(({ name, pattern, optionalLeadingSlash }) =>\n optionalLeadingSlash ? `(?:\\/(?<${name}>${pattern}))?` : `\\/(?<${name}>${pattern})`,\n ).join('') +\n '$',\n);\n\nexport const parsePath = (pathname: string): PathState => {\n const matchResults = pathname.match(OUTER_HREF_REGEXP)?.groups ?? {};\n return PATH_SEGMENTS.reduce((acc: Partial<PathState>, { name, transform }: PathSegment) => {\n let value: string | undefined = undefined;\n if (name in matchResults) {\n value = matchResults[name];\n }\n if (!value) {\n // fall back to default value if var not present in\n value = '';\n }\n if (typeof value === 'string') {\n acc[name] = transform ? transform(value) : value;\n }\n return acc;\n }, {}) as PathState;\n};\n\nexport const parseHref = (href: string): NavigationState => {\n const parsedUrl = new URL(href);\n const pathnameState = parsePath(parsedUrl.pathname);\n return {\n ...pathnameState,\n search: parsedUrl.search.substring(1),\n hash: parsedUrl.hash.substring(1),\n } as NavigationState;\n};\n\nconst stripSlashPrefix = (s: string): string => (s.startsWith('/') ? s.substring(1) : s);\n\nexport const constructUrl = (outerHref: string, navigationState: NavigationState): string => {\n const path = PATH_SEGMENTS.map(({ name, encode }) => {\n const value = stripSlashPrefix(navigationState[name] ?? '');\n // Encode AFTER stripping the delimiter slash: `encode` is per-segment, and the\n // sandboxPath (which has no `encode`) keeps its own internal slashes.\n return encode ? encode(value) : value;\n }).join('/');\n const host = getOuterHostname(outerHref);\n let url = `${host}/${path}`;\n if (navigationState.search) {\n url += '?' + navigationState.search;\n }\n if (navigationState.hash) {\n url += '#' + navigationState.hash;\n }\n return url;\n};\n"],"mappings":"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","names":[]}
|
package/dist/urlUtils.d.cts
CHANGED
|
@@ -47,6 +47,20 @@ declare const isAbsolutePath: (sandboxPath: string) => boolean;
|
|
|
47
47
|
declare const repositoryPrefixURL: (outerHref: string, navigationState: NavigationState) => string;
|
|
48
48
|
declare const constructOuterUrl: (previousOuterHref: string, sandboxTarget: string, navigationState: NavigationState, addFilesPrefix?: boolean) => string;
|
|
49
49
|
declare const isInternalHref: (outerHref: string, target: string, navigationState: NavigationState) => boolean;
|
|
50
|
+
/**
|
|
51
|
+
* The href to render for a PLATFORM-space path — `/present/github/…`, `/edit/github/…`,
|
|
52
|
+
* `/home`, `/settings/language-model`. These are the HOST's URLs, not this app's: inside the
|
|
53
|
+
* sandboxed frame a root-relative `href` resolves against the SANDBOX origin, which serves no
|
|
54
|
+
* such page, so the path is resolved against the OUTER origin (`outerHref`) instead. An
|
|
55
|
+
* absolute `path` (`https://…`) is returned as-is, which `new URL` already does. With no host
|
|
56
|
+
* (`vite dev`, an empty `outerHref`) or an unresolvable pair, `path` is returned unchanged so
|
|
57
|
+
* the local dev server keeps working. A non-string `path` throws: a caller passing one has a
|
|
58
|
+
* bug worth surfacing, not silently rendering.
|
|
59
|
+
*
|
|
60
|
+
* Render the result through `PlatformLink` (`./platformLink`), which also carries
|
|
61
|
+
* `target="_top"` — an anchor inside the sandboxed frame otherwise navigates the frame.
|
|
62
|
+
*/
|
|
63
|
+
declare const platformHref: (outerHref: string, path: string) => string;
|
|
50
64
|
type PathSegment = {
|
|
51
65
|
name: string;
|
|
52
66
|
pattern: string;
|
|
@@ -58,4 +72,4 @@ declare const parsePath: (pathname: string) => PathState;
|
|
|
58
72
|
declare const parseHref: (href: string) => NavigationState;
|
|
59
73
|
declare const constructUrl: (outerHref: string, navigationState: NavigationState) => string;
|
|
60
74
|
|
|
61
|
-
export { FILES_PREFIX, type PathSegment, constructOuterUrl, constructUrl, getOuterHostname, getSearchParams, isAbsolutePath, isInternalHref, maybeParseUrl, parseHref, parsePath, parseTarget, repositoryPrefixURL, splitHash };
|
|
75
|
+
export { FILES_PREFIX, type PathSegment, constructOuterUrl, constructUrl, getOuterHostname, getSearchParams, isAbsolutePath, isInternalHref, maybeParseUrl, parseHref, parsePath, parseTarget, platformHref, repositoryPrefixURL, splitHash };
|
package/dist/urlUtils.d.ts
CHANGED
|
@@ -47,6 +47,20 @@ declare const isAbsolutePath: (sandboxPath: string) => boolean;
|
|
|
47
47
|
declare const repositoryPrefixURL: (outerHref: string, navigationState: NavigationState) => string;
|
|
48
48
|
declare const constructOuterUrl: (previousOuterHref: string, sandboxTarget: string, navigationState: NavigationState, addFilesPrefix?: boolean) => string;
|
|
49
49
|
declare const isInternalHref: (outerHref: string, target: string, navigationState: NavigationState) => boolean;
|
|
50
|
+
/**
|
|
51
|
+
* The href to render for a PLATFORM-space path — `/present/github/…`, `/edit/github/…`,
|
|
52
|
+
* `/home`, `/settings/language-model`. These are the HOST's URLs, not this app's: inside the
|
|
53
|
+
* sandboxed frame a root-relative `href` resolves against the SANDBOX origin, which serves no
|
|
54
|
+
* such page, so the path is resolved against the OUTER origin (`outerHref`) instead. An
|
|
55
|
+
* absolute `path` (`https://…`) is returned as-is, which `new URL` already does. With no host
|
|
56
|
+
* (`vite dev`, an empty `outerHref`) or an unresolvable pair, `path` is returned unchanged so
|
|
57
|
+
* the local dev server keeps working. A non-string `path` throws: a caller passing one has a
|
|
58
|
+
* bug worth surfacing, not silently rendering.
|
|
59
|
+
*
|
|
60
|
+
* Render the result through `PlatformLink` (`./platformLink`), which also carries
|
|
61
|
+
* `target="_top"` — an anchor inside the sandboxed frame otherwise navigates the frame.
|
|
62
|
+
*/
|
|
63
|
+
declare const platformHref: (outerHref: string, path: string) => string;
|
|
50
64
|
type PathSegment = {
|
|
51
65
|
name: string;
|
|
52
66
|
pattern: string;
|
|
@@ -58,4 +72,4 @@ declare const parsePath: (pathname: string) => PathState;
|
|
|
58
72
|
declare const parseHref: (href: string) => NavigationState;
|
|
59
73
|
declare const constructUrl: (outerHref: string, navigationState: NavigationState) => string;
|
|
60
74
|
|
|
61
|
-
export { FILES_PREFIX, type PathSegment, constructOuterUrl, constructUrl, getOuterHostname, getSearchParams, isAbsolutePath, isInternalHref, maybeParseUrl, parseHref, parsePath, parseTarget, repositoryPrefixURL, splitHash };
|
|
75
|
+
export { FILES_PREFIX, type PathSegment, constructOuterUrl, constructUrl, getOuterHostname, getSearchParams, isAbsolutePath, isInternalHref, maybeParseUrl, parseHref, parsePath, parseTarget, platformHref, repositoryPrefixURL, splitHash };
|
package/dist/urlUtils.js
CHANGED
|
@@ -56,6 +56,17 @@ const isInternalHref = (outerHref, target, navigationState) => {
|
|
|
56
56
|
}
|
|
57
57
|
return true;
|
|
58
58
|
};
|
|
59
|
+
const platformHref = (outerHref, path) => {
|
|
60
|
+
if (typeof path !== "string") {
|
|
61
|
+
throw new TypeError(`platformHref: path must be a string, got ${typeof path}`);
|
|
62
|
+
}
|
|
63
|
+
if (!outerHref) return path;
|
|
64
|
+
try {
|
|
65
|
+
return new URL(path, outerHref).toString();
|
|
66
|
+
} catch {
|
|
67
|
+
return path;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
59
70
|
const decodeSegment = (value) => {
|
|
60
71
|
try {
|
|
61
72
|
return decodeURIComponent(value);
|
|
@@ -133,6 +144,7 @@ export {
|
|
|
133
144
|
parseHref,
|
|
134
145
|
parsePath,
|
|
135
146
|
parseTarget,
|
|
147
|
+
platformHref,
|
|
136
148
|
repositoryPrefixURL,
|
|
137
149
|
splitHash,
|
|
138
150
|
underAppRoot
|
package/dist/urlUtils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/urlUtils.ts"],"sourcesContent":["import { APP_ROOT, underAppRoot } from '@immediately-run/platform-constants';\n\nimport { joinPaths } from './pathUtils';\nimport { NavigationState, PathState } from './TinkerableContext';\n\nexport const FILES_PREFIX = '/files';\n\n/**\n * Mount point of the Git repository inside the sandbox filesystem, and the join\n * into it — both now defined ONCE in `@immediately-run/platform-constants` (R3-275)\n * and re-exported here so every import site is unchanged.\n *\n * They were declared here AND in `sandbox/src/fsLayout.ts`, with two different\n * implementations of the join (this one over `joinPaths`, the sandbox's hand-rolled).\n * The two agreed; nothing made them agree — and the metadata key space is derived\n * from this constant on both sides, so a drift would have split that key space\n * silently. The package's tests replicate BOTH implementations, quirks included.\n *\n * The sandbox fs is rooted at `/` (so apps can reach dynamic mounts like\n * `/firestore`), with the repo mounted at `APP_ROOT`. URL subpaths are\n * repo-relative, so the file router resolves them under it.\n */\nexport { APP_ROOT, underAppRoot };\n\n/**\n * The origin every outer URL is rebuilt on — `protocol//host`, **port included**.\n *\n * `url.hostname` drops the port; `url.host` keeps it (and still omits it for the default\n * 80/443, so a production URL is byte-identical either way). Using `hostname` here was\n * invisible on `https://immediately.run` and broke every routed link under local dev on any\n * port but 80: `http://localhost:3100/edit/…` was rebuilt as `http://localhost/edit/…`.\n *\n * Worse than a wrong link, it silently changed link BEHAVIOUR. `repositoryPrefixURL` is\n * built from this, and `isInternalHref` decides by prefix-matching against it — so an\n * absolute in-app URL failed the match, was classified EXTERNAL, and rendered as a plain\n * `<a>`. Clicking it performed a real navigation out of the sandboxed frame instead of\n * routing: the app appeared to \"reload\" on an ordinary internal link.\n */\nexport const getOuterHostname = (outerHref: string) => {\n const url = new URL(outerHref);\n return `${url.protocol}//${url.host}`;\n};\n\nexport const getSearchParams = (search?: string): Record<string, string> =>\n Object.fromEntries([...new URLSearchParams(search ?? window.location.search).entries()]);\n\n/**\n * Split a link target into its path part and its `#fragment` (the `#` dropped),\n * e.g. `\"FOO.mdx#sec-8-9\"` → `[\"FOO.mdx\", \"sec-8-9\"]`, `\"#sec-3\"` → `[\"\", \"sec-3\"]`,\n * `\"FOO.mdx\"` → `[\"FOO.mdx\", \"\"]`. Only the **first** `#` splits — a fragment never\n * contains another `#`. The seam between wiki-links (§13) and heading ids (§15):\n * existence is resolved on the path part, the fragment is threaded to navigation.\n * MARKDOWN_SYNTAX_SPEC §13.5.\n */\nexport const splitHash = (target: string): [string, string] => {\n const i = target.indexOf('#');\n return i === -1 ? [target, ''] : [target.slice(0, i), target.slice(i + 1)];\n};\n\nexport const parseTarget = (target: string, navigation: NavigationState): NavigationState => {\n const newNavigation = { ...navigation };\n let [prehash, hash] = target.split('#');\n if (prehash) {\n let [path, search] = prehash.split('?');\n if (path) {\n newNavigation.sandboxPath = path;\n }\n newNavigation.search = search ? search : '';\n }\n newNavigation.hash = hash ? hash : '';\n return newNavigation;\n};\n\nexport const maybeParseUrl = (str: string): URL | null => {\n try {\n return new URL(str);\n } catch (_) {\n return null;\n }\n};\n\nexport const isAbsolutePath = (sandboxPath: string) => sandboxPath.startsWith('/');\n\n/**\n * The origin+repo prefix every same-app URL starts with — used by {@link isInternalHref} to\n * decide whether an absolute href is \"this app\" or somewhere else.\n *\n * `hash` and `search` are cleared, not just `sandboxPath`. They belong to the CURRENT page,\n * and leaving them in put them on the end of a *prefix*: from a page carrying `#sec-8-9`,\n * the prefix became `…/main/#sec-8-9`, no same-app URL could start with it, every absolute\n * in-app link was classified EXTERNAL, and clicking one navigated the sandboxed frame away\n * instead of routing. A page with a fragment quietly broke its own links.\n */\nexport const repositoryPrefixURL = (outerHref: string, navigationState: NavigationState) =>\n constructUrl(outerHref, {\n ...navigationState,\n sandboxPath: '',\n hash: '',\n search: '',\n });\n\nexport const constructOuterUrl = (\n previousOuterHref: string,\n sandboxTarget: string,\n navigationState: NavigationState,\n addFilesPrefix = true,\n): string => {\n if (isAbsolutePath(sandboxTarget)) {\n // Split a trailing `#fragment` off before the target is folded into the\n // sandboxPath, and carry it in `hash` instead — a fragment addresses a section,\n // not a file, so it must not leak into the path (MARKDOWN_SYNTAX_SPEC §13.5). An\n // absolute target with no fragment clears any stale hash from the prior state.\n const [pathPart, hash] = splitHash(sandboxTarget);\n return constructUrl(previousOuterHref, {\n ...navigationState,\n sandboxPath: addFilesPrefix ? joinPaths(FILES_PREFIX, pathPart) : pathPart,\n hash,\n });\n }\n return new URL(sandboxTarget, constructUrl(previousOuterHref, navigationState)).toString();\n};\n\nexport const isInternalHref = (outerHref: string, target: string, navigationState: NavigationState) => {\n const parsedUrl = maybeParseUrl(target);\n if (parsedUrl) {\n return target.startsWith(repositoryPrefixURL(outerHref, navigationState));\n }\n // if target is not a valid URL, then assume it's relative.\n return true;\n};\n\nexport type PathSegment = {\n name: string;\n pattern: string;\n transform?: (pathSegment: string) => string;\n // When true, the leading slash that delimits this segment is optional, so the\n // whole `/segment` group can be absent. Used for the trailing sandboxPath:\n // an outer href of `/mode/provider/namespace/repository/ref` (no trailing\n // slash, no sub-path) must still parse, otherwise the regex matches nothing\n // and every segment comes back empty.\n optionalLeadingSlash?: boolean;\n // Inverse of `transform`, applied when BUILDING a url (`constructUrl`). Without it a\n // decoded ref would be written back raw and split into two segments again.\n encode?: (value: string) => string;\n};\n\n// One URL path segment is \"anything but a slash\". The previous patterns instead\n// ENUMERATED the allowed characters (`[a-zA-Z0-9-_]+`), which silently rejected three\n// real shapes — and rejection here is not an error, it is a whole-match failure that\n// makes `parsePath` return every field EMPTY, so the app's navigation state just goes\n// blank with nothing logged:\n//\n// /…/repo/v1.2.3/… a semver TAG (dot)\n// /…/foo.js/main/… a dotted REPOSITORY name (dot — very common)\n// /…/repo/claude%2Fx/… a `/`-containing REF, percent-encoded as one segment\n//\n// The third is the one that motivated this (a ref may contain `/`; the host now encodes\n// it — see site-main `encodeRef`), but the first two were already broken and are the\n// same mistake. `[^/]+` is both the fix and the accurate description of a segment.\n/** Percent-decode one path segment, tolerating a malformed escape: this is untrusted\n * URL input, and `decodeURIComponent('%zz')` throws. A bad ref must not blank out the\n * whole navigation state. */\nconst decodeSegment = (value: string): string => {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n};\n\nconst PATH_SEGMENTS: PathSegment[] = [\n { name: 'mode', pattern: '\\\\w+' },\n { name: 'provider', pattern: '[^/]+' },\n { name: 'namespace', pattern: '[^/]+' },\n { name: 'repository', pattern: '[^/]+' },\n // The ref is percent-encoded by the host so a `/` inside it stays ONE segment; decode\n // on the way in and re-encode on the way out (`encode`), so app code always sees the\n // real ref (`claude/x`) and never the wire form.\n { name: 'ref', pattern: '[^/]+', transform: decodeSegment, encode: encodeURIComponent },\n { name: 'sandboxPath', pattern: '.*', transform: (s) => `/${s}`, optionalLeadingSlash: true },\n];\n\nconst OUTER_HREF_REGEXP = new RegExp(\n '^' +\n PATH_SEGMENTS.map(({ name, pattern, optionalLeadingSlash }) =>\n optionalLeadingSlash ? `(?:\\/(?<${name}>${pattern}))?` : `\\/(?<${name}>${pattern})`,\n ).join('') +\n '$',\n);\n\nexport const parsePath = (pathname: string): PathState => {\n const matchResults = pathname.match(OUTER_HREF_REGEXP)?.groups ?? {};\n return PATH_SEGMENTS.reduce((acc: Partial<PathState>, { name, transform }: PathSegment) => {\n let value: string | undefined = undefined;\n if (name in matchResults) {\n value = matchResults[name];\n }\n if (!value) {\n // fall back to default value if var not present in\n value = '';\n }\n if (typeof value === 'string') {\n acc[name] = transform ? transform(value) : value;\n }\n return acc;\n }, {}) as PathState;\n};\n\nexport const parseHref = (href: string): NavigationState => {\n const parsedUrl = new URL(href);\n const pathnameState = parsePath(parsedUrl.pathname);\n return {\n ...pathnameState,\n search: parsedUrl.search.substring(1),\n hash: parsedUrl.hash.substring(1),\n } as NavigationState;\n};\n\nconst stripSlashPrefix = (s: string): string => (s.startsWith('/') ? s.substring(1) : s);\n\nexport const constructUrl = (outerHref: string, navigationState: NavigationState): string => {\n const path = PATH_SEGMENTS.map(({ name, encode }) => {\n const value = stripSlashPrefix(navigationState[name] ?? '');\n // Encode AFTER stripping the delimiter slash: `encode` is per-segment, and the\n // sandboxPath (which has no `encode`) keeps its own internal slashes.\n return encode ? encode(value) : value;\n }).join('/');\n const host = getOuterHostname(outerHref);\n let url = `${host}/${path}`;\n if (navigationState.search) {\n url += '?' + navigationState.search;\n }\n if (navigationState.hash) {\n url += '#' + navigationState.hash;\n }\n return url;\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/urlUtils.ts"],"sourcesContent":["import { APP_ROOT, underAppRoot } from '@immediately-run/platform-constants';\n\nimport { joinPaths } from './pathUtils';\nimport { NavigationState, PathState } from './TinkerableContext';\n\nexport const FILES_PREFIX = '/files';\n\n/**\n * Mount point of the Git repository inside the sandbox filesystem, and the join\n * into it — both now defined ONCE in `@immediately-run/platform-constants` (R3-275)\n * and re-exported here so every import site is unchanged.\n *\n * They were declared here AND in `sandbox/src/fsLayout.ts`, with two different\n * implementations of the join (this one over `joinPaths`, the sandbox's hand-rolled).\n * The two agreed; nothing made them agree — and the metadata key space is derived\n * from this constant on both sides, so a drift would have split that key space\n * silently. The package's tests replicate BOTH implementations, quirks included.\n *\n * The sandbox fs is rooted at `/` (so apps can reach dynamic mounts like\n * `/firestore`), with the repo mounted at `APP_ROOT`. URL subpaths are\n * repo-relative, so the file router resolves them under it.\n */\nexport { APP_ROOT, underAppRoot };\n\n/**\n * The origin every outer URL is rebuilt on — `protocol//host`, **port included**.\n *\n * `url.hostname` drops the port; `url.host` keeps it (and still omits it for the default\n * 80/443, so a production URL is byte-identical either way). Using `hostname` here was\n * invisible on `https://immediately.run` and broke every routed link under local dev on any\n * port but 80: `http://localhost:3100/edit/…` was rebuilt as `http://localhost/edit/…`.\n *\n * Worse than a wrong link, it silently changed link BEHAVIOUR. `repositoryPrefixURL` is\n * built from this, and `isInternalHref` decides by prefix-matching against it — so an\n * absolute in-app URL failed the match, was classified EXTERNAL, and rendered as a plain\n * `<a>`. Clicking it performed a real navigation out of the sandboxed frame instead of\n * routing: the app appeared to \"reload\" on an ordinary internal link.\n */\nexport const getOuterHostname = (outerHref: string) => {\n const url = new URL(outerHref);\n return `${url.protocol}//${url.host}`;\n};\n\nexport const getSearchParams = (search?: string): Record<string, string> =>\n Object.fromEntries([...new URLSearchParams(search ?? window.location.search).entries()]);\n\n/**\n * Split a link target into its path part and its `#fragment` (the `#` dropped),\n * e.g. `\"FOO.mdx#sec-8-9\"` → `[\"FOO.mdx\", \"sec-8-9\"]`, `\"#sec-3\"` → `[\"\", \"sec-3\"]`,\n * `\"FOO.mdx\"` → `[\"FOO.mdx\", \"\"]`. Only the **first** `#` splits — a fragment never\n * contains another `#`. The seam between wiki-links (§13) and heading ids (§15):\n * existence is resolved on the path part, the fragment is threaded to navigation.\n * MARKDOWN_SYNTAX_SPEC §13.5.\n */\nexport const splitHash = (target: string): [string, string] => {\n const i = target.indexOf('#');\n return i === -1 ? [target, ''] : [target.slice(0, i), target.slice(i + 1)];\n};\n\nexport const parseTarget = (target: string, navigation: NavigationState): NavigationState => {\n const newNavigation = { ...navigation };\n let [prehash, hash] = target.split('#');\n if (prehash) {\n let [path, search] = prehash.split('?');\n if (path) {\n newNavigation.sandboxPath = path;\n }\n newNavigation.search = search ? search : '';\n }\n newNavigation.hash = hash ? hash : '';\n return newNavigation;\n};\n\nexport const maybeParseUrl = (str: string): URL | null => {\n try {\n return new URL(str);\n } catch (_) {\n return null;\n }\n};\n\nexport const isAbsolutePath = (sandboxPath: string) => sandboxPath.startsWith('/');\n\n/**\n * The origin+repo prefix every same-app URL starts with — used by {@link isInternalHref} to\n * decide whether an absolute href is \"this app\" or somewhere else.\n *\n * `hash` and `search` are cleared, not just `sandboxPath`. They belong to the CURRENT page,\n * and leaving them in put them on the end of a *prefix*: from a page carrying `#sec-8-9`,\n * the prefix became `…/main/#sec-8-9`, no same-app URL could start with it, every absolute\n * in-app link was classified EXTERNAL, and clicking one navigated the sandboxed frame away\n * instead of routing. A page with a fragment quietly broke its own links.\n */\nexport const repositoryPrefixURL = (outerHref: string, navigationState: NavigationState) =>\n constructUrl(outerHref, {\n ...navigationState,\n sandboxPath: '',\n hash: '',\n search: '',\n });\n\nexport const constructOuterUrl = (\n previousOuterHref: string,\n sandboxTarget: string,\n navigationState: NavigationState,\n addFilesPrefix = true,\n): string => {\n if (isAbsolutePath(sandboxTarget)) {\n // Split a trailing `#fragment` off before the target is folded into the\n // sandboxPath, and carry it in `hash` instead — a fragment addresses a section,\n // not a file, so it must not leak into the path (MARKDOWN_SYNTAX_SPEC §13.5). An\n // absolute target with no fragment clears any stale hash from the prior state.\n const [pathPart, hash] = splitHash(sandboxTarget);\n return constructUrl(previousOuterHref, {\n ...navigationState,\n sandboxPath: addFilesPrefix ? joinPaths(FILES_PREFIX, pathPart) : pathPart,\n hash,\n });\n }\n return new URL(sandboxTarget, constructUrl(previousOuterHref, navigationState)).toString();\n};\n\nexport const isInternalHref = (outerHref: string, target: string, navigationState: NavigationState) => {\n const parsedUrl = maybeParseUrl(target);\n if (parsedUrl) {\n return target.startsWith(repositoryPrefixURL(outerHref, navigationState));\n }\n // if target is not a valid URL, then assume it's relative.\n return true;\n};\n\n/**\n * The href to render for a PLATFORM-space path — `/present/github/…`, `/edit/github/…`,\n * `/home`, `/settings/language-model`. These are the HOST's URLs, not this app's: inside the\n * sandboxed frame a root-relative `href` resolves against the SANDBOX origin, which serves no\n * such page, so the path is resolved against the OUTER origin (`outerHref`) instead. An\n * absolute `path` (`https://…`) is returned as-is, which `new URL` already does. With no host\n * (`vite dev`, an empty `outerHref`) or an unresolvable pair, `path` is returned unchanged so\n * the local dev server keeps working. A non-string `path` throws: a caller passing one has a\n * bug worth surfacing, not silently rendering.\n *\n * Render the result through `PlatformLink` (`./platformLink`), which also carries\n * `target=\"_top\"` — an anchor inside the sandboxed frame otherwise navigates the frame.\n */\nexport const platformHref = (outerHref: string, path: string): string => {\n if (typeof path !== 'string') {\n throw new TypeError(`platformHref: path must be a string, got ${typeof path}`);\n }\n if (!outerHref) return path;\n try {\n return new URL(path, outerHref).toString();\n } catch {\n return path;\n }\n};\n\nexport type PathSegment = {\n name: string;\n pattern: string;\n transform?: (pathSegment: string) => string;\n // When true, the leading slash that delimits this segment is optional, so the\n // whole `/segment` group can be absent. Used for the trailing sandboxPath:\n // an outer href of `/mode/provider/namespace/repository/ref` (no trailing\n // slash, no sub-path) must still parse, otherwise the regex matches nothing\n // and every segment comes back empty.\n optionalLeadingSlash?: boolean;\n // Inverse of `transform`, applied when BUILDING a url (`constructUrl`). Without it a\n // decoded ref would be written back raw and split into two segments again.\n encode?: (value: string) => string;\n};\n\n// One URL path segment is \"anything but a slash\". The previous patterns instead\n// ENUMERATED the allowed characters (`[a-zA-Z0-9-_]+`), which silently rejected three\n// real shapes — and rejection here is not an error, it is a whole-match failure that\n// makes `parsePath` return every field EMPTY, so the app's navigation state just goes\n// blank with nothing logged:\n//\n// /…/repo/v1.2.3/… a semver TAG (dot)\n// /…/foo.js/main/… a dotted REPOSITORY name (dot — very common)\n// /…/repo/claude%2Fx/… a `/`-containing REF, percent-encoded as one segment\n//\n// The third is the one that motivated this (a ref may contain `/`; the host now encodes\n// it — see site-main `encodeRef`), but the first two were already broken and are the\n// same mistake. `[^/]+` is both the fix and the accurate description of a segment.\n/** Percent-decode one path segment, tolerating a malformed escape: this is untrusted\n * URL input, and `decodeURIComponent('%zz')` throws. A bad ref must not blank out the\n * whole navigation state. */\nconst decodeSegment = (value: string): string => {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n};\n\nconst PATH_SEGMENTS: PathSegment[] = [\n { name: 'mode', pattern: '\\\\w+' },\n { name: 'provider', pattern: '[^/]+' },\n { name: 'namespace', pattern: '[^/]+' },\n { name: 'repository', pattern: '[^/]+' },\n // The ref is percent-encoded by the host so a `/` inside it stays ONE segment; decode\n // on the way in and re-encode on the way out (`encode`), so app code always sees the\n // real ref (`claude/x`) and never the wire form.\n { name: 'ref', pattern: '[^/]+', transform: decodeSegment, encode: encodeURIComponent },\n { name: 'sandboxPath', pattern: '.*', transform: (s) => `/${s}`, optionalLeadingSlash: true },\n];\n\nconst OUTER_HREF_REGEXP = new RegExp(\n '^' +\n PATH_SEGMENTS.map(({ name, pattern, optionalLeadingSlash }) =>\n optionalLeadingSlash ? `(?:\\/(?<${name}>${pattern}))?` : `\\/(?<${name}>${pattern})`,\n ).join('') +\n '$',\n);\n\nexport const parsePath = (pathname: string): PathState => {\n const matchResults = pathname.match(OUTER_HREF_REGEXP)?.groups ?? {};\n return PATH_SEGMENTS.reduce((acc: Partial<PathState>, { name, transform }: PathSegment) => {\n let value: string | undefined = undefined;\n if (name in matchResults) {\n value = matchResults[name];\n }\n if (!value) {\n // fall back to default value if var not present in\n value = '';\n }\n if (typeof value === 'string') {\n acc[name] = transform ? transform(value) : value;\n }\n return acc;\n }, {}) as PathState;\n};\n\nexport const parseHref = (href: string): NavigationState => {\n const parsedUrl = new URL(href);\n const pathnameState = parsePath(parsedUrl.pathname);\n return {\n ...pathnameState,\n search: parsedUrl.search.substring(1),\n hash: parsedUrl.hash.substring(1),\n } as NavigationState;\n};\n\nconst stripSlashPrefix = (s: string): string => (s.startsWith('/') ? s.substring(1) : s);\n\nexport const constructUrl = (outerHref: string, navigationState: NavigationState): string => {\n const path = PATH_SEGMENTS.map(({ name, encode }) => {\n const value = stripSlashPrefix(navigationState[name] ?? '');\n // Encode AFTER stripping the delimiter slash: `encode` is per-segment, and the\n // sandboxPath (which has no `encode`) keeps its own internal slashes.\n return encode ? encode(value) : value;\n }).join('/');\n const host = getOuterHostname(outerHref);\n let url = `${host}/${path}`;\n if (navigationState.search) {\n url += '?' + navigationState.search;\n }\n if (navigationState.hash) {\n url += '#' + navigationState.hash;\n }\n return url;\n};\n"],"mappings":";AAAA,SAAS,UAAU,oBAAoB;AAEvC,SAAS,iBAAiB;AAGnB,MAAM,eAAe;AAiCrB,MAAM,mBAAmB,CAAC,cAAsB;AACrD,QAAM,MAAM,IAAI,IAAI,SAAS;AAC7B,SAAO,GAAG,IAAI,QAAQ,KAAK,IAAI,IAAI;AACrC;AAEO,MAAM,kBAAkB,CAAC,WAC9B,OAAO,YAAY,CAAC,GAAG,IAAI,gBAAgB,UAAU,OAAO,SAAS,MAAM,EAAE,QAAQ,CAAC,CAAC;AAUlF,MAAM,YAAY,CAAC,WAAqC;AAC7D,QAAM,IAAI,OAAO,QAAQ,GAAG;AAC5B,SAAO,MAAM,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,MAAM,GAAG,CAAC,GAAG,OAAO,MAAM,IAAI,CAAC,CAAC;AAC3E;AAEO,MAAM,cAAc,CAAC,QAAgB,eAAiD;AAC3F,QAAM,gBAAgB,EAAE,GAAG,WAAW;AACtC,MAAI,CAAC,SAAS,IAAI,IAAI,OAAO,MAAM,GAAG;AACtC,MAAI,SAAS;AACX,QAAI,CAAC,MAAM,MAAM,IAAI,QAAQ,MAAM,GAAG;AACtC,QAAI,MAAM;AACR,oBAAc,cAAc;AAAA,IAC9B;AACA,kBAAc,SAAS,SAAS,SAAS;AAAA,EAC3C;AACA,gBAAc,OAAO,OAAO,OAAO;AACnC,SAAO;AACT;AAEO,MAAM,gBAAgB,CAAC,QAA4B;AACxD,MAAI;AACF,WAAO,IAAI,IAAI,GAAG;AAAA,EACpB,SAAS,GAAG;AACV,WAAO;AAAA,EACT;AACF;AAEO,MAAM,iBAAiB,CAAC,gBAAwB,YAAY,WAAW,GAAG;AAY1E,MAAM,sBAAsB,CAAC,WAAmB,oBACrD,aAAa,WAAW;AAAA,EACtB,GAAG;AAAA,EACH,aAAa;AAAA,EACb,MAAM;AAAA,EACN,QAAQ;AACV,CAAC;AAEI,MAAM,oBAAoB,CAC/B,mBACA,eACA,iBACA,iBAAiB,SACN;AACX,MAAI,eAAe,aAAa,GAAG;AAKjC,UAAM,CAAC,UAAU,IAAI,IAAI,UAAU,aAAa;AAChD,WAAO,aAAa,mBAAmB;AAAA,MACrC,GAAG;AAAA,MACH,aAAa,iBAAiB,UAAU,cAAc,QAAQ,IAAI;AAAA,MAClE;AAAA,IACF,CAAC;AAAA,EACH;AACA,SAAO,IAAI,IAAI,eAAe,aAAa,mBAAmB,eAAe,CAAC,EAAE,SAAS;AAC3F;AAEO,MAAM,iBAAiB,CAAC,WAAmB,QAAgB,oBAAqC;AACrG,QAAM,YAAY,cAAc,MAAM;AACtC,MAAI,WAAW;AACb,WAAO,OAAO,WAAW,oBAAoB,WAAW,eAAe,CAAC;AAAA,EAC1E;AAEA,SAAO;AACT;AAeO,MAAM,eAAe,CAAC,WAAmB,SAAyB;AACvE,MAAI,OAAO,SAAS,UAAU;AAC5B,UAAM,IAAI,UAAU,4CAA4C,OAAO,IAAI,EAAE;AAAA,EAC/E;AACA,MAAI,CAAC,UAAW,QAAO;AACvB,MAAI;AACF,WAAO,IAAI,IAAI,MAAM,SAAS,EAAE,SAAS;AAAA,EAC3C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAiCA,MAAM,gBAAgB,CAAC,UAA0B;AAC/C,MAAI;AACF,WAAO,mBAAmB,KAAK;AAAA,EACjC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,MAAM,gBAA+B;AAAA,EACnC,EAAE,MAAM,QAAQ,SAAS,OAAO;AAAA,EAChC,EAAE,MAAM,YAAY,SAAS,QAAQ;AAAA,EACrC,EAAE,MAAM,aAAa,SAAS,QAAQ;AAAA,EACtC,EAAE,MAAM,cAAc,SAAS,QAAQ;AAAA;AAAA;AAAA;AAAA,EAIvC,EAAE,MAAM,OAAO,SAAS,SAAS,WAAW,eAAe,QAAQ,mBAAmB;AAAA,EACtF,EAAE,MAAM,eAAe,SAAS,MAAM,WAAW,CAAC,MAAM,IAAI,CAAC,IAAI,sBAAsB,KAAK;AAC9F;AAEA,MAAM,oBAAoB,IAAI;AAAA,EAC5B,MACE,cAAc;AAAA,IAAI,CAAC,EAAE,MAAM,SAAS,qBAAqB,MACvD,uBAAuB,UAAW,IAAI,IAAI,OAAO,QAAQ,OAAQ,IAAI,IAAI,OAAO;AAAA,EAClF,EAAE,KAAK,EAAE,IACT;AACJ;AAEO,MAAM,YAAY,CAAC,aAAgC;AACxD,QAAM,eAAe,SAAS,MAAM,iBAAiB,GAAG,UAAU,CAAC;AACnE,SAAO,cAAc,OAAO,CAAC,KAAyB,EAAE,MAAM,UAAU,MAAmB;AACzF,QAAI,QAA4B;AAChC,QAAI,QAAQ,cAAc;AACxB,cAAQ,aAAa,IAAI;AAAA,IAC3B;AACA,QAAI,CAAC,OAAO;AAEV,cAAQ;AAAA,IACV;AACA,QAAI,OAAO,UAAU,UAAU;AAC7B,UAAI,IAAI,IAAI,YAAY,UAAU,KAAK,IAAI;AAAA,IAC7C;AACA,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AACP;AAEO,MAAM,YAAY,CAAC,SAAkC;AAC1D,QAAM,YAAY,IAAI,IAAI,IAAI;AAC9B,QAAM,gBAAgB,UAAU,UAAU,QAAQ;AAClD,SAAO;AAAA,IACL,GAAG;AAAA,IACH,QAAQ,UAAU,OAAO,UAAU,CAAC;AAAA,IACpC,MAAM,UAAU,KAAK,UAAU,CAAC;AAAA,EAClC;AACF;AAEA,MAAM,mBAAmB,CAAC,MAAuB,EAAE,WAAW,GAAG,IAAI,EAAE,UAAU,CAAC,IAAI;AAE/E,MAAM,eAAe,CAAC,WAAmB,oBAA6C;AAC3F,QAAM,OAAO,cAAc,IAAI,CAAC,EAAE,MAAM,OAAO,MAAM;AACnD,UAAM,QAAQ,iBAAiB,gBAAgB,IAAI,KAAK,EAAE;AAG1D,WAAO,SAAS,OAAO,KAAK,IAAI;AAAA,EAClC,CAAC,EAAE,KAAK,GAAG;AACX,QAAM,OAAO,iBAAiB,SAAS;AACvC,MAAI,MAAM,GAAG,IAAI,IAAI,IAAI;AACzB,MAAI,gBAAgB,QAAQ;AAC1B,WAAO,MAAM,gBAAgB;AAAA,EAC/B;AACA,MAAI,gBAAgB,MAAM;AACxB,WAAO,MAAM,gBAAgB;AAAA,EAC/B;AACA,SAAO;AACT;","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.60.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.60.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.60.0';\n"],"mappings":";AAIO,MAAM,cAAc;","names":[]}
|
package/package.json
CHANGED