@immediately-run/sdk 0.1.1 → 0.1.3
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/README.md +4 -0
- package/dist/auth.cjs +46 -0
- package/dist/auth.cjs.map +1 -0
- package/dist/auth.d.cts +33 -0
- package/dist/auth.d.ts +33 -0
- package/dist/auth.js +20 -0
- package/dist/auth.js.map +1 -0
- package/dist/components/MainContent.cjs +1 -6
- package/dist/components/MainContent.cjs.map +1 -1
- package/dist/components/MainContent.js +1 -6
- package/dist/components/MainContent.js.map +1 -1
- package/dist/index.cjs +2 -0
- 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/urlUtils.cjs +6 -2
- package/dist/urlUtils.cjs.map +1 -1
- package/dist/urlUtils.d.cts +1 -0
- package/dist/urlUtils.d.ts +1 -0
- package/dist/urlUtils.js +6 -2
- package/dist/urlUtils.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,6 +22,10 @@ also reachable via subpaths (`@immediately-run/sdk/boot`, `@immediately-run/sdk/
|
|
|
22
22
|
- `Include` (`components/Include`) — render another file's exported component inline.
|
|
23
23
|
- `MDXComponents` (`Link`, …) — MDX component overrides.
|
|
24
24
|
- `useMetadataQuery`, `useFileMetadata` (`hooks`) — query files by frontmatter metadata.
|
|
25
|
+
- `getAuthState`, `onAuthChange`, `useAuth` (`auth`) — read or subscribe to the user's
|
|
26
|
+
login / account state (`{ status, user: { login } }`). Poll with `getAuthState()`,
|
|
27
|
+
subscribe with `onAuthChange(listener)` (the listener is called immediately with the
|
|
28
|
+
current state), or use the `useAuth()` React hook.
|
|
25
29
|
- routing helpers (`Router`, `SandboxRouter`, …).
|
|
26
30
|
- `MDXProvider` — the MDX context provider used by transformed `.mdx` files.
|
|
27
31
|
- `sandboxTypes` — shared TypeScript types for the sandbox runtime.
|
package/dist/auth.cjs
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
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 auth_exports = {};
|
|
20
|
+
__export(auth_exports, {
|
|
21
|
+
getAuthState: () => getAuthState,
|
|
22
|
+
onAuthChange: () => onAuthChange,
|
|
23
|
+
useAuth: () => useAuth
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(auth_exports);
|
|
26
|
+
var import_react = require("react");
|
|
27
|
+
const authService = () => {
|
|
28
|
+
return module.evaluation.module.bundler.auth;
|
|
29
|
+
};
|
|
30
|
+
const getAuthState = () => authService().getState();
|
|
31
|
+
const onAuthChange = (listener) => {
|
|
32
|
+
const disposable = authService().onChange(listener);
|
|
33
|
+
return () => disposable.dispose();
|
|
34
|
+
};
|
|
35
|
+
const useAuth = () => {
|
|
36
|
+
const [state, setState] = (0, import_react.useState)(getAuthState);
|
|
37
|
+
(0, import_react.useEffect)(() => onAuthChange(setState), []);
|
|
38
|
+
return state;
|
|
39
|
+
};
|
|
40
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
41
|
+
0 && (module.exports = {
|
|
42
|
+
getAuthState,
|
|
43
|
+
onAuthChange,
|
|
44
|
+
useAuth
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=auth.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/auth.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\n/**\n * Login / account state of the immediately.run user, mirrored from the host\n * window into the sandbox.\n *\n * `status` is `'unknown'` until the host has reported a value (use it to\n * distinguish \"still loading\" from a confirmed signed-out session).\n */\nexport type AuthStatus = 'unknown' | 'signed-in' | 'signed-out';\n\nexport interface SandboxUser {\n /** GitHub login (handle) of the signed-in user. */\n login: string;\n}\n\nexport interface AuthState {\n status: AuthStatus;\n user: SandboxUser | null;\n}\n\ninterface AuthService {\n getState(): AuthState;\n onChange(listener: (state: AuthState) => void): { dispose(): void };\n}\n\n// `module.evaluation.module.bundler` is the sandbox bundler injected into the\n// evaluation context (same path the other SDK helpers reach for `messageBus`).\nconst authService = (): AuthService => {\n // @ts-ignore - injected by the sandbox runtime\n return module.evaluation.module.bundler.auth;\n};\n\n/**\n * Returns the current login / account state. Poll this whenever you need a\n * one-off read; use {@link onAuthChange} or {@link useAuth} to react to changes.\n */\nexport const getAuthState = (): AuthState => authService().getState();\n\n/**\n * Subscribe to login / logout changes. The listener is invoked immediately with\n * the current state, then again on every change. Returns an unsubscribe fn.\n */\nexport const onAuthChange = (listener: (state: AuthState) => void): (() => void) => {\n const disposable = authService().onChange(listener);\n return () => disposable.dispose();\n};\n\n/**\n * React hook returning the current login / account state, re-rendering on\n * login / logout.\n */\nexport const useAuth = (): AuthState => {\n const [state, setState] = useState<AuthState>(getAuthState);\n useEffect(() => onAuthChange(setState), []);\n return state;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAoC;AA4BpC,MAAM,cAAc,MAAmB;AAErC,SAAO,OAAO,WAAW,OAAO,QAAQ;AAC1C;AAMO,MAAM,eAAe,MAAiB,YAAY,EAAE,SAAS;AAM7D,MAAM,eAAe,CAAC,aAAuD;AAClF,QAAM,aAAa,YAAY,EAAE,SAAS,QAAQ;AAClD,SAAO,MAAM,WAAW,QAAQ;AAClC;AAMO,MAAM,UAAU,MAAiB;AACtC,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAoB,YAAY;AAC1D,8BAAU,MAAM,aAAa,QAAQ,GAAG,CAAC,CAAC;AAC1C,SAAO;AACT;","names":[]}
|
package/dist/auth.d.cts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Login / account state of the immediately.run user, mirrored from the host
|
|
3
|
+
* window into the sandbox.
|
|
4
|
+
*
|
|
5
|
+
* `status` is `'unknown'` until the host has reported a value (use it to
|
|
6
|
+
* distinguish "still loading" from a confirmed signed-out session).
|
|
7
|
+
*/
|
|
8
|
+
type AuthStatus = 'unknown' | 'signed-in' | 'signed-out';
|
|
9
|
+
interface SandboxUser {
|
|
10
|
+
/** GitHub login (handle) of the signed-in user. */
|
|
11
|
+
login: string;
|
|
12
|
+
}
|
|
13
|
+
interface AuthState {
|
|
14
|
+
status: AuthStatus;
|
|
15
|
+
user: SandboxUser | null;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Returns the current login / account state. Poll this whenever you need a
|
|
19
|
+
* one-off read; use {@link onAuthChange} or {@link useAuth} to react to changes.
|
|
20
|
+
*/
|
|
21
|
+
declare const getAuthState: () => AuthState;
|
|
22
|
+
/**
|
|
23
|
+
* Subscribe to login / logout changes. The listener is invoked immediately with
|
|
24
|
+
* the current state, then again on every change. Returns an unsubscribe fn.
|
|
25
|
+
*/
|
|
26
|
+
declare const onAuthChange: (listener: (state: AuthState) => void) => (() => void);
|
|
27
|
+
/**
|
|
28
|
+
* React hook returning the current login / account state, re-rendering on
|
|
29
|
+
* login / logout.
|
|
30
|
+
*/
|
|
31
|
+
declare const useAuth: () => AuthState;
|
|
32
|
+
|
|
33
|
+
export { type AuthState, type AuthStatus, type SandboxUser, getAuthState, onAuthChange, useAuth };
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Login / account state of the immediately.run user, mirrored from the host
|
|
3
|
+
* window into the sandbox.
|
|
4
|
+
*
|
|
5
|
+
* `status` is `'unknown'` until the host has reported a value (use it to
|
|
6
|
+
* distinguish "still loading" from a confirmed signed-out session).
|
|
7
|
+
*/
|
|
8
|
+
type AuthStatus = 'unknown' | 'signed-in' | 'signed-out';
|
|
9
|
+
interface SandboxUser {
|
|
10
|
+
/** GitHub login (handle) of the signed-in user. */
|
|
11
|
+
login: string;
|
|
12
|
+
}
|
|
13
|
+
interface AuthState {
|
|
14
|
+
status: AuthStatus;
|
|
15
|
+
user: SandboxUser | null;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Returns the current login / account state. Poll this whenever you need a
|
|
19
|
+
* one-off read; use {@link onAuthChange} or {@link useAuth} to react to changes.
|
|
20
|
+
*/
|
|
21
|
+
declare const getAuthState: () => AuthState;
|
|
22
|
+
/**
|
|
23
|
+
* Subscribe to login / logout changes. The listener is invoked immediately with
|
|
24
|
+
* the current state, then again on every change. Returns an unsubscribe fn.
|
|
25
|
+
*/
|
|
26
|
+
declare const onAuthChange: (listener: (state: AuthState) => void) => (() => void);
|
|
27
|
+
/**
|
|
28
|
+
* React hook returning the current login / account state, re-rendering on
|
|
29
|
+
* login / logout.
|
|
30
|
+
*/
|
|
31
|
+
declare const useAuth: () => AuthState;
|
|
32
|
+
|
|
33
|
+
export { type AuthState, type AuthStatus, type SandboxUser, getAuthState, onAuthChange, useAuth };
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
const authService = () => {
|
|
3
|
+
return module.evaluation.module.bundler.auth;
|
|
4
|
+
};
|
|
5
|
+
const getAuthState = () => authService().getState();
|
|
6
|
+
const onAuthChange = (listener) => {
|
|
7
|
+
const disposable = authService().onChange(listener);
|
|
8
|
+
return () => disposable.dispose();
|
|
9
|
+
};
|
|
10
|
+
const useAuth = () => {
|
|
11
|
+
const [state, setState] = useState(getAuthState);
|
|
12
|
+
useEffect(() => onAuthChange(setState), []);
|
|
13
|
+
return state;
|
|
14
|
+
};
|
|
15
|
+
export {
|
|
16
|
+
getAuthState,
|
|
17
|
+
onAuthChange,
|
|
18
|
+
useAuth
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/auth.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\n/**\n * Login / account state of the immediately.run user, mirrored from the host\n * window into the sandbox.\n *\n * `status` is `'unknown'` until the host has reported a value (use it to\n * distinguish \"still loading\" from a confirmed signed-out session).\n */\nexport type AuthStatus = 'unknown' | 'signed-in' | 'signed-out';\n\nexport interface SandboxUser {\n /** GitHub login (handle) of the signed-in user. */\n login: string;\n}\n\nexport interface AuthState {\n status: AuthStatus;\n user: SandboxUser | null;\n}\n\ninterface AuthService {\n getState(): AuthState;\n onChange(listener: (state: AuthState) => void): { dispose(): void };\n}\n\n// `module.evaluation.module.bundler` is the sandbox bundler injected into the\n// evaluation context (same path the other SDK helpers reach for `messageBus`).\nconst authService = (): AuthService => {\n // @ts-ignore - injected by the sandbox runtime\n return module.evaluation.module.bundler.auth;\n};\n\n/**\n * Returns the current login / account state. Poll this whenever you need a\n * one-off read; use {@link onAuthChange} or {@link useAuth} to react to changes.\n */\nexport const getAuthState = (): AuthState => authService().getState();\n\n/**\n * Subscribe to login / logout changes. The listener is invoked immediately with\n * the current state, then again on every change. Returns an unsubscribe fn.\n */\nexport const onAuthChange = (listener: (state: AuthState) => void): (() => void) => {\n const disposable = authService().onChange(listener);\n return () => disposable.dispose();\n};\n\n/**\n * React hook returning the current login / account state, re-rendering on\n * login / logout.\n */\nexport const useAuth = (): AuthState => {\n const [state, setState] = useState<AuthState>(getAuthState);\n useEffect(() => onAuthChange(setState), []);\n return state;\n};\n"],"mappings":"AAAA,SAAS,WAAW,gBAAgB;AA4BpC,MAAM,cAAc,MAAmB;AAErC,SAAO,OAAO,WAAW,OAAO,QAAQ;AAC1C;AAMO,MAAM,eAAe,MAAiB,YAAY,EAAE,SAAS;AAM7D,MAAM,eAAe,CAAC,aAAuD;AAClF,QAAM,aAAa,YAAY,EAAE,SAAS,QAAQ;AAClD,SAAO,MAAM,WAAW,QAAQ;AAClC;AAMO,MAAM,UAAU,MAAiB;AACtC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAoB,YAAY;AAC1D,YAAU,MAAM,aAAa,QAAQ,GAAG,CAAC,CAAC;AAC1C,SAAO;AACT;","names":[]}
|
|
@@ -29,12 +29,7 @@ var import_react_error_boundary = require("react-error-boundary");
|
|
|
29
29
|
var import_routing = require("../routing");
|
|
30
30
|
var import_urlUtils = require("../urlUtils");
|
|
31
31
|
var import_defaults = require("./defaults");
|
|
32
|
-
const
|
|
33
|
-
const basenames = ["App", "landing", "main", "README"];
|
|
34
|
-
const extensions = [".js", ".jsx", ".mjs", ".cjs", ".ts", ".tsx", ".mdx", ".md"];
|
|
35
|
-
const candidates = directories.flatMap(
|
|
36
|
-
(dir) => basenames.flatMap((basename) => extensions.map((ext) => `${dir}${basename}${ext}`))
|
|
37
|
-
);
|
|
32
|
+
const candidates = ["/src/App.tsx", "/src/App.ts", "/src/App.js", "/App.tsx", "/App.ts", "/App.js", "/README.md", "/README.mdx", "/README.html"];
|
|
38
33
|
const fileExists = async (path) => {
|
|
39
34
|
const bundler = module.evaluation.module.bundler;
|
|
40
35
|
const exists = await bundler.fs.isFile.async(path);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/MainContent.tsx"],"sourcesContent":["import { Suspense, use, useMemo } from 'react';\nimport { ErrorBoundary } from 'react-error-boundary';\nimport { navigate, useTinkerableLink } from '../routing';\nimport { FILES_PREFIX } from '../urlUtils';\n\nimport { defaultErrorComponent, defaultLoadingComponent } from './defaults';\n\nconst
|
|
1
|
+
{"version":3,"sources":["../../src/components/MainContent.tsx"],"sourcesContent":["import { Suspense, use, useMemo } from 'react';\nimport { ErrorBoundary } from 'react-error-boundary';\nimport { navigate, useTinkerableLink } from '../routing';\nimport { FILES_PREFIX } from '../urlUtils';\n\nimport { defaultErrorComponent, defaultLoadingComponent } from './defaults';\n\nconst candidates = ['/src/App.tsx', '/src/App.ts', '/src/App.js', '/App.tsx', '/App.ts', '/App.js', '/README.md', '/README.mdx', '/README.html'];\n\nconst fileExists = async (path: string): Promise<[string, boolean]> => {\n // @ts-ignore\n const bundler = module.evaluation.module.bundler;\n const exists = await bundler.fs.isFile.async(path);\n return [path, exists];\n};\n\nexport const MainContentRedirect = ({filename}:{filename:string}) => {\n const url = useTinkerableLink(filename);\n navigate(url);\n return <>Redirecting to {filename}</>;\n}\n\nexport const MainContentInner = ({\n candidatesExistPromise,\n}: {\n candidatesExistPromise: Promise<[string, boolean][]>;\n}) => {\n const candidatesExist = use(candidatesExistPromise);\n const filename = candidatesExist.find(([_, exists]) => exists)?.[0];\n if (!filename) {\n // todo: show file list\n throw new Error(`No main content file present`);\n }\n return <MainContentRedirect filename={FILES_PREFIX + filename}/>;\n};\n\nexport const MainContent = ({\n LoadingComponent = defaultLoadingComponent,\n ErrorComponent = defaultErrorComponent,\n}: {\n LoadingComponent?: typeof defaultLoadingComponent;\n ErrorComponent?: typeof defaultErrorComponent;\n} = {}) => {\n // TODO: when to invalidate?\n const candidatesExistPromise = useMemo(() => Promise.all(candidates.map(fileExists)), []);\n return (\n <ErrorBoundary fallbackRender={ErrorComponent}>\n <Suspense fallback={<LoadingComponent />}>\n <MainContentInner candidatesExistPromise={candidatesExistPromise} />\n </Suspense>\n </ErrorBoundary>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBS;AAnBT,mBAAuC;AACvC,kCAA8B;AAC9B,qBAA4C;AAC5C,sBAA6B;AAE7B,sBAA+D;AAE/D,MAAM,aAAa,CAAC,gBAAgB,eAAe,eAAe,YAAY,WAAW,WAAW,cAAc,eAAe,cAAc;AAE/I,MAAM,aAAa,OAAO,SAA6C;AAErE,QAAM,UAAU,OAAO,WAAW,OAAO;AACzC,QAAM,SAAS,MAAM,QAAQ,GAAG,OAAO,MAAM,IAAI;AACjD,SAAO,CAAC,MAAM,MAAM;AACtB;AAEO,MAAM,sBAAsB,CAAC,EAAC,SAAQ,MAAwB;AACnE,QAAM,UAAM,kCAAkB,QAAQ;AACtC,+BAAS,GAAG;AACZ,SAAO,4EAAE;AAAA;AAAA,IAAgB;AAAA,KAAS;AACpC;AAEO,MAAM,mBAAmB,CAAC;AAAA,EAC/B;AACF,MAEM;AACJ,QAAM,sBAAkB,kBAAI,sBAAsB;AAClD,QAAM,WAAW,gBAAgB,KAAK,CAAC,CAAC,GAAG,MAAM,MAAM,MAAM,IAAI,CAAC;AAClE,MAAI,CAAC,UAAU;AAEb,UAAM,IAAI,MAAM,8BAA8B;AAAA,EAChD;AACA,SAAO,4CAAC,uBAAoB,UAAU,+BAAe,UAAS;AAChE;AAEO,MAAM,cAAc,CAAC;AAAA,EAC1B,mBAAmB;AAAA,EACnB,iBAAiB;AACnB,IAGI,CAAC,MAAM;AAET,QAAM,6BAAyB,sBAAQ,MAAM,QAAQ,IAAI,WAAW,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;AACxF,SACE,4CAAC,6CAAc,gBAAgB,gBAC7B,sDAAC,yBAAS,UAAU,4CAAC,oBAAiB,GACpC,sDAAC,oBAAiB,wBAAgD,GACpE,GACF;AAEJ;","names":[]}
|
|
@@ -4,12 +4,7 @@ import { ErrorBoundary } from "react-error-boundary";
|
|
|
4
4
|
import { navigate, useTinkerableLink } from "../routing";
|
|
5
5
|
import { FILES_PREFIX } from "../urlUtils";
|
|
6
6
|
import { defaultErrorComponent, defaultLoadingComponent } from "./defaults";
|
|
7
|
-
const
|
|
8
|
-
const basenames = ["App", "landing", "main", "README"];
|
|
9
|
-
const extensions = [".js", ".jsx", ".mjs", ".cjs", ".ts", ".tsx", ".mdx", ".md"];
|
|
10
|
-
const candidates = directories.flatMap(
|
|
11
|
-
(dir) => basenames.flatMap((basename) => extensions.map((ext) => `${dir}${basename}${ext}`))
|
|
12
|
-
);
|
|
7
|
+
const candidates = ["/src/App.tsx", "/src/App.ts", "/src/App.js", "/App.tsx", "/App.ts", "/App.js", "/README.md", "/README.mdx", "/README.html"];
|
|
13
8
|
const fileExists = async (path) => {
|
|
14
9
|
const bundler = module.evaluation.module.bundler;
|
|
15
10
|
const exists = await bundler.fs.isFile.async(path);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/MainContent.tsx"],"sourcesContent":["import { Suspense, use, useMemo } from 'react';\nimport { ErrorBoundary } from 'react-error-boundary';\nimport { navigate, useTinkerableLink } from '../routing';\nimport { FILES_PREFIX } from '../urlUtils';\n\nimport { defaultErrorComponent, defaultLoadingComponent } from './defaults';\n\nconst
|
|
1
|
+
{"version":3,"sources":["../../src/components/MainContent.tsx"],"sourcesContent":["import { Suspense, use, useMemo } from 'react';\nimport { ErrorBoundary } from 'react-error-boundary';\nimport { navigate, useTinkerableLink } from '../routing';\nimport { FILES_PREFIX } from '../urlUtils';\n\nimport { defaultErrorComponent, defaultLoadingComponent } from './defaults';\n\nconst candidates = ['/src/App.tsx', '/src/App.ts', '/src/App.js', '/App.tsx', '/App.ts', '/App.js', '/README.md', '/README.mdx', '/README.html'];\n\nconst fileExists = async (path: string): Promise<[string, boolean]> => {\n // @ts-ignore\n const bundler = module.evaluation.module.bundler;\n const exists = await bundler.fs.isFile.async(path);\n return [path, exists];\n};\n\nexport const MainContentRedirect = ({filename}:{filename:string}) => {\n const url = useTinkerableLink(filename);\n navigate(url);\n return <>Redirecting to {filename}</>;\n}\n\nexport const MainContentInner = ({\n candidatesExistPromise,\n}: {\n candidatesExistPromise: Promise<[string, boolean][]>;\n}) => {\n const candidatesExist = use(candidatesExistPromise);\n const filename = candidatesExist.find(([_, exists]) => exists)?.[0];\n if (!filename) {\n // todo: show file list\n throw new Error(`No main content file present`);\n }\n return <MainContentRedirect filename={FILES_PREFIX + filename}/>;\n};\n\nexport const MainContent = ({\n LoadingComponent = defaultLoadingComponent,\n ErrorComponent = defaultErrorComponent,\n}: {\n LoadingComponent?: typeof defaultLoadingComponent;\n ErrorComponent?: typeof defaultErrorComponent;\n} = {}) => {\n // TODO: when to invalidate?\n const candidatesExistPromise = useMemo(() => Promise.all(candidates.map(fileExists)), []);\n return (\n <ErrorBoundary fallbackRender={ErrorComponent}>\n <Suspense fallback={<LoadingComponent />}>\n <MainContentInner candidatesExistPromise={candidatesExistPromise} />\n </Suspense>\n </ErrorBoundary>\n );\n};\n"],"mappings":"AAmBS,mBAcA,KAdA;AAnBT,SAAS,UAAU,KAAK,eAAe;AACvC,SAAS,qBAAqB;AAC9B,SAAS,UAAU,yBAAyB;AAC5C,SAAS,oBAAoB;AAE7B,SAAS,uBAAuB,+BAA+B;AAE/D,MAAM,aAAa,CAAC,gBAAgB,eAAe,eAAe,YAAY,WAAW,WAAW,cAAc,eAAe,cAAc;AAE/I,MAAM,aAAa,OAAO,SAA6C;AAErE,QAAM,UAAU,OAAO,WAAW,OAAO;AACzC,QAAM,SAAS,MAAM,QAAQ,GAAG,OAAO,MAAM,IAAI;AACjD,SAAO,CAAC,MAAM,MAAM;AACtB;AAEO,MAAM,sBAAsB,CAAC,EAAC,SAAQ,MAAwB;AACnE,QAAM,MAAM,kBAAkB,QAAQ;AACtC,WAAS,GAAG;AACZ,SAAO,iCAAE;AAAA;AAAA,IAAgB;AAAA,KAAS;AACpC;AAEO,MAAM,mBAAmB,CAAC;AAAA,EAC/B;AACF,MAEM;AACJ,QAAM,kBAAkB,IAAI,sBAAsB;AAClD,QAAM,WAAW,gBAAgB,KAAK,CAAC,CAAC,GAAG,MAAM,MAAM,MAAM,IAAI,CAAC;AAClE,MAAI,CAAC,UAAU;AAEb,UAAM,IAAI,MAAM,8BAA8B;AAAA,EAChD;AACA,SAAO,oBAAC,uBAAoB,UAAU,eAAe,UAAS;AAChE;AAEO,MAAM,cAAc,CAAC;AAAA,EAC1B,mBAAmB;AAAA,EACnB,iBAAiB;AACnB,IAGI,CAAC,MAAM;AAET,QAAM,yBAAyB,QAAQ,MAAM,QAAQ,IAAI,WAAW,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;AACxF,SACE,oBAAC,iBAAc,gBAAgB,gBAC7B,8BAAC,YAAS,UAAU,oBAAC,oBAAiB,GACpC,8BAAC,oBAAiB,wBAAgD,GACpE,GACF;AAEJ;","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -21,6 +21,7 @@ __reExport(index_exports, require("./boot"), module.exports);
|
|
|
21
21
|
__reExport(index_exports, require("./components/Include"), module.exports);
|
|
22
22
|
__reExport(index_exports, require("./components/MDXComponents"), module.exports);
|
|
23
23
|
__reExport(index_exports, require("./hooks"), module.exports);
|
|
24
|
+
__reExport(index_exports, require("./auth"), module.exports);
|
|
24
25
|
__reExport(index_exports, require("./sandboxTypes"), module.exports);
|
|
25
26
|
// Annotate the CommonJS export names for ESM import in node:
|
|
26
27
|
0 && (module.exports = {
|
|
@@ -30,6 +31,7 @@ __reExport(index_exports, require("./sandboxTypes"), module.exports);
|
|
|
30
31
|
...require("./components/Include"),
|
|
31
32
|
...require("./components/MDXComponents"),
|
|
32
33
|
...require("./hooks"),
|
|
34
|
+
...require("./auth"),
|
|
33
35
|
...require("./sandboxTypes")
|
|
34
36
|
});
|
|
35
37
|
//# 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';\nexport * from './components/MDXComponents';\nexport * from './hooks'\nexport * from './sandboxTypes';\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AAAA;AAAA,0BAAc,0BAAd;AACA,0BAAc,sBADd;AAEA,0BAAc,mBAFd;AAGA,0BAAc,iCAHd;AAIA,0BAAc,uCAJd;AAKA,0BAAc,oBALd;AAMA,0BAAc,
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from \"./MDXProvider\";\nexport * from \"./routing\";\nexport * from \"./boot\";\nexport * from './components/Include';\nexport * from './components/MDXComponents';\nexport * from './hooks'\nexport * from './auth';\nexport * from './sandboxTypes';\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AAAA;AAAA,0BAAc,0BAAd;AACA,0BAAc,sBADd;AAEA,0BAAc,mBAFd;AAGA,0BAAc,iCAHd;AAIA,0BAAc,uCAJd;AAKA,0BAAc,oBALd;AAMA,0BAAc,mBANd;AAOA,0BAAc,2BAPd;","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -4,6 +4,7 @@ export { BootProps, DEFAULT_ROUTING_SPEC, TinkerableApp, boot } from './boot.cjs
|
|
|
4
4
|
export { Include, RenderExportedComponent, RenderExportedComponentContext, RenderFileContextType } from './components/Include.cjs';
|
|
5
5
|
export { DEFAULT_MDX_COMPONENTS, InternalLink, Link } from './components/MDXComponents.cjs';
|
|
6
6
|
export { useFileMetadata, useMetadataQuery } from './hooks.cjs';
|
|
7
|
+
export { AuthState, AuthStatus, SandboxUser, getAuthState, onAuthChange, useAuth } from './auth.cjs';
|
|
7
8
|
export { EvaluationContext, FileQueryResult, FilesMetadata, Metadata, MetadataQueryFunction, MetadataQueryResult, ModuleExports } from './sandboxTypes.cjs';
|
|
8
9
|
import 'react';
|
|
9
10
|
import './TinkerableContext.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export { BootProps, DEFAULT_ROUTING_SPEC, TinkerableApp, boot } from './boot.js'
|
|
|
4
4
|
export { Include, RenderExportedComponent, RenderExportedComponentContext, RenderFileContextType } from './components/Include.js';
|
|
5
5
|
export { DEFAULT_MDX_COMPONENTS, InternalLink, Link } from './components/MDXComponents.js';
|
|
6
6
|
export { useFileMetadata, useMetadataQuery } from './hooks.js';
|
|
7
|
+
export { AuthState, AuthStatus, SandboxUser, getAuthState, onAuthChange, useAuth } from './auth.js';
|
|
7
8
|
export { EvaluationContext, FileQueryResult, FilesMetadata, Metadata, MetadataQueryFunction, MetadataQueryResult, ModuleExports } from './sandboxTypes.js';
|
|
8
9
|
import 'react';
|
|
9
10
|
import './TinkerableContext.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';\nexport * from './components/MDXComponents';\nexport * from './hooks'\nexport * from './sandboxTypes';\n"],"mappings":"AAAA,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';\nexport * from './components/MDXComponents';\nexport * from './hooks'\nexport * from './auth';\nexport * from './sandboxTypes';\n"],"mappings":"AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
|
package/dist/urlUtils.cjs
CHANGED
|
@@ -97,9 +97,13 @@ const PATH_SEGMENTS = [
|
|
|
97
97
|
{ name: "namespace", pattern: "[a-zA-Z0-9-_]+" },
|
|
98
98
|
{ name: "repository", pattern: "[a-zA-Z0-9-_]+" },
|
|
99
99
|
{ name: "ref", pattern: "[a-zA-Z0-9-_]+" },
|
|
100
|
-
{ name: "sandboxPath", pattern: ".*", transform: (s) => `/${s}
|
|
100
|
+
{ name: "sandboxPath", pattern: ".*", transform: (s) => `/${s}`, optionalLeadingSlash: true }
|
|
101
101
|
];
|
|
102
|
-
const OUTER_HREF_REGEXP = new RegExp(
|
|
102
|
+
const OUTER_HREF_REGEXP = new RegExp(
|
|
103
|
+
"^" + PATH_SEGMENTS.map(
|
|
104
|
+
({ name, pattern, optionalLeadingSlash }) => optionalLeadingSlash ? `(?:/(?<${name}>${pattern}))?` : `/(?<${name}>${pattern})`
|
|
105
|
+
).join("") + "$"
|
|
106
|
+
);
|
|
103
107
|
const parsePath = (pathname) => {
|
|
104
108
|
const matchResults = pathname.match(OUTER_HREF_REGEXP)?.groups ?? {};
|
|
105
109
|
return PATH_SEGMENTS.reduce((acc, { name, transform }) => {
|
package/dist/urlUtils.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/urlUtils.ts"],"sourcesContent":["import { joinPaths } from \"./pathUtils\";\nimport { NavigationState, PathState } from \"./TinkerableContext\";\n\nexport const FILES_PREFIX = '/files';\n\nexport const getOuterHostname = (outerHref:string) => {\n const url = new URL(outerHref);\n return `${url.protocol}//${url.hostname}`;\n}\n\nexport const getSearchParams = (search?: string): Record<string, string> => Object.fromEntries(\n [...(new URLSearchParams(search ?? window.location.search).entries())]);\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\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\nexport const repositoryPrefixURL = (outerHref:string, navigationState: NavigationState) => constructUrl(outerHref, {\n ...navigationState,\n sandboxPath: ''\n });\n\nexport const constructOuterUrl = (previousOuterHref:string, sandboxTarget:string, navigationState: NavigationState, addFilesPrefix=true):string => {\n if (isAbsolutePath(sandboxTarget)) {\n return constructUrl(\n previousOuterHref,\n {\n ...navigationState,\n sandboxPath: addFilesPrefix ? joinPaths(FILES_PREFIX, sandboxTarget) : sandboxTarget\n })\n }\n return (\n new URL(\n sandboxTarget,\n constructUrl(\n previousOuterHref,\n navigationState\n )\n )\n ).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}\n\nconst PATH_SEGMENTS: PathSegment[] = [\n { name: 'mode', pattern: '\\\\w+' },\n { name: 'provider', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'namespace', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'repository', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'ref', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'sandboxPath', pattern: '.*', transform: s => `/${s}
|
|
1
|
+
{"version":3,"sources":["../src/urlUtils.ts"],"sourcesContent":["import { joinPaths } from \"./pathUtils\";\nimport { NavigationState, PathState } from \"./TinkerableContext\";\n\nexport const FILES_PREFIX = '/files';\n\nexport const getOuterHostname = (outerHref:string) => {\n const url = new URL(outerHref);\n return `${url.protocol}//${url.hostname}`;\n}\n\nexport const getSearchParams = (search?: string): Record<string, string> => Object.fromEntries(\n [...(new URLSearchParams(search ?? window.location.search).entries())]);\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\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\nexport const repositoryPrefixURL = (outerHref:string, navigationState: NavigationState) => constructUrl(outerHref, {\n ...navigationState,\n sandboxPath: ''\n });\n\nexport const constructOuterUrl = (previousOuterHref:string, sandboxTarget:string, navigationState: NavigationState, addFilesPrefix=true):string => {\n if (isAbsolutePath(sandboxTarget)) {\n return constructUrl(\n previousOuterHref,\n {\n ...navigationState,\n sandboxPath: addFilesPrefix ? joinPaths(FILES_PREFIX, sandboxTarget) : sandboxTarget\n })\n }\n return (\n new URL(\n sandboxTarget,\n constructUrl(\n previousOuterHref,\n navigationState\n )\n )\n ).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}\n\nconst PATH_SEGMENTS: PathSegment[] = [\n { name: 'mode', pattern: '\\\\w+' },\n { name: 'provider', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'namespace', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'repository', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'ref', pattern: '[a-zA-Z0-9-_]+' },\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\n ? `(?:\\/(?<${name}>${pattern}))?`\n : `\\/(?<${name}>${pattern})`\n ).join('') +\n \"$\"\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 }) => {\n let value = navigationState[name];\n return stripSlashPrefix(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
|
@@ -16,6 +16,7 @@ type PathSegment = {
|
|
|
16
16
|
name: string;
|
|
17
17
|
pattern: string;
|
|
18
18
|
transform?: (pathSegment: string) => string;
|
|
19
|
+
optionalLeadingSlash?: boolean;
|
|
19
20
|
};
|
|
20
21
|
declare const parsePath: (pathname: string) => PathState;
|
|
21
22
|
declare const parseHref: (href: string) => NavigationState;
|
package/dist/urlUtils.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ type PathSegment = {
|
|
|
16
16
|
name: string;
|
|
17
17
|
pattern: string;
|
|
18
18
|
transform?: (pathSegment: string) => string;
|
|
19
|
+
optionalLeadingSlash?: boolean;
|
|
19
20
|
};
|
|
20
21
|
declare const parsePath: (pathname: string) => PathState;
|
|
21
22
|
declare const parseHref: (href: string) => NavigationState;
|
package/dist/urlUtils.js
CHANGED
|
@@ -63,9 +63,13 @@ const PATH_SEGMENTS = [
|
|
|
63
63
|
{ name: "namespace", pattern: "[a-zA-Z0-9-_]+" },
|
|
64
64
|
{ name: "repository", pattern: "[a-zA-Z0-9-_]+" },
|
|
65
65
|
{ name: "ref", pattern: "[a-zA-Z0-9-_]+" },
|
|
66
|
-
{ name: "sandboxPath", pattern: ".*", transform: (s) => `/${s}
|
|
66
|
+
{ name: "sandboxPath", pattern: ".*", transform: (s) => `/${s}`, optionalLeadingSlash: true }
|
|
67
67
|
];
|
|
68
|
-
const OUTER_HREF_REGEXP = new RegExp(
|
|
68
|
+
const OUTER_HREF_REGEXP = new RegExp(
|
|
69
|
+
"^" + PATH_SEGMENTS.map(
|
|
70
|
+
({ name, pattern, optionalLeadingSlash }) => optionalLeadingSlash ? `(?:/(?<${name}>${pattern}))?` : `/(?<${name}>${pattern})`
|
|
71
|
+
).join("") + "$"
|
|
72
|
+
);
|
|
69
73
|
const parsePath = (pathname) => {
|
|
70
74
|
const matchResults = pathname.match(OUTER_HREF_REGEXP)?.groups ?? {};
|
|
71
75
|
return PATH_SEGMENTS.reduce((acc, { name, transform }) => {
|
package/dist/urlUtils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/urlUtils.ts"],"sourcesContent":["import { joinPaths } from \"./pathUtils\";\nimport { NavigationState, PathState } from \"./TinkerableContext\";\n\nexport const FILES_PREFIX = '/files';\n\nexport const getOuterHostname = (outerHref:string) => {\n const url = new URL(outerHref);\n return `${url.protocol}//${url.hostname}`;\n}\n\nexport const getSearchParams = (search?: string): Record<string, string> => Object.fromEntries(\n [...(new URLSearchParams(search ?? window.location.search).entries())]);\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\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\nexport const repositoryPrefixURL = (outerHref:string, navigationState: NavigationState) => constructUrl(outerHref, {\n ...navigationState,\n sandboxPath: ''\n });\n\nexport const constructOuterUrl = (previousOuterHref:string, sandboxTarget:string, navigationState: NavigationState, addFilesPrefix=true):string => {\n if (isAbsolutePath(sandboxTarget)) {\n return constructUrl(\n previousOuterHref,\n {\n ...navigationState,\n sandboxPath: addFilesPrefix ? joinPaths(FILES_PREFIX, sandboxTarget) : sandboxTarget\n })\n }\n return (\n new URL(\n sandboxTarget,\n constructUrl(\n previousOuterHref,\n navigationState\n )\n )\n ).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}\n\nconst PATH_SEGMENTS: PathSegment[] = [\n { name: 'mode', pattern: '\\\\w+' },\n { name: 'provider', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'namespace', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'repository', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'ref', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'sandboxPath', pattern: '.*', transform: s => `/${s}
|
|
1
|
+
{"version":3,"sources":["../src/urlUtils.ts"],"sourcesContent":["import { joinPaths } from \"./pathUtils\";\nimport { NavigationState, PathState } from \"./TinkerableContext\";\n\nexport const FILES_PREFIX = '/files';\n\nexport const getOuterHostname = (outerHref:string) => {\n const url = new URL(outerHref);\n return `${url.protocol}//${url.hostname}`;\n}\n\nexport const getSearchParams = (search?: string): Record<string, string> => Object.fromEntries(\n [...(new URLSearchParams(search ?? window.location.search).entries())]);\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\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\nexport const repositoryPrefixURL = (outerHref:string, navigationState: NavigationState) => constructUrl(outerHref, {\n ...navigationState,\n sandboxPath: ''\n });\n\nexport const constructOuterUrl = (previousOuterHref:string, sandboxTarget:string, navigationState: NavigationState, addFilesPrefix=true):string => {\n if (isAbsolutePath(sandboxTarget)) {\n return constructUrl(\n previousOuterHref,\n {\n ...navigationState,\n sandboxPath: addFilesPrefix ? joinPaths(FILES_PREFIX, sandboxTarget) : sandboxTarget\n })\n }\n return (\n new URL(\n sandboxTarget,\n constructUrl(\n previousOuterHref,\n navigationState\n )\n )\n ).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}\n\nconst PATH_SEGMENTS: PathSegment[] = [\n { name: 'mode', pattern: '\\\\w+' },\n { name: 'provider', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'namespace', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'repository', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'ref', pattern: '[a-zA-Z0-9-_]+' },\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\n ? `(?:\\/(?<${name}>${pattern}))?`\n : `\\/(?<${name}>${pattern})`\n ).join('') +\n \"$\"\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 }) => {\n let value = navigationState[name];\n return stripSlashPrefix(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/package.json
CHANGED