@ghostly-solutions/auth 0.2.2 → 0.2.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 +2 -8
- package/dist/extension.d.ts +5 -2
- package/dist/extension.js +47 -5
- package/dist/extension.js.map +1 -1
- package/docs/integration-guide.md +4 -4
- package/extension.js +1 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -232,16 +232,10 @@ import { createExtensionAuthClient } from "@ghostly-solutions/auth/extension";
|
|
|
232
232
|
const auth = createExtensionAuthClient({
|
|
233
233
|
apiOrigin: "https://api.ghostlysolutions.com",
|
|
234
234
|
application: "ghostguard-extension",
|
|
235
|
-
openAuthorizePage: async ({ authorizeUrl }) => {
|
|
236
|
-
await chrome.tabs.create({ url: authorizeUrl });
|
|
237
|
-
},
|
|
238
|
-
launchWebAuthFlow: async ({ authorizeUrl }) => {
|
|
239
|
-
await openAuthWindow(authorizeUrl);
|
|
240
|
-
},
|
|
241
235
|
});
|
|
242
236
|
|
|
243
|
-
await auth.
|
|
244
|
-
returnTo: "/
|
|
237
|
+
await auth.login({
|
|
238
|
+
returnTo: "/",
|
|
245
239
|
});
|
|
246
240
|
```
|
|
247
241
|
|
package/dist/extension.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ interface ExtensionStoredAccessToken extends ExtensionAccessToken {
|
|
|
24
24
|
interface ExtensionAuthClientOptions {
|
|
25
25
|
apiOrigin: string;
|
|
26
26
|
application?: string;
|
|
27
|
+
defaultReturnToPath?: string;
|
|
27
28
|
clearSessionId?: () => Promise<void> | void;
|
|
28
29
|
launchWebAuthFlow?: (payload: LaunchWebAuthFlowPayload) => Promise<void>;
|
|
29
30
|
openAuthorizePage?: (payload: OpenAuthorizePagePayload) => Promise<void>;
|
|
@@ -36,7 +37,7 @@ interface ExtensionAuthClient extends AuthClient {
|
|
|
36
37
|
loginWithTabFlow(options?: LoginOptions): Promise<void>;
|
|
37
38
|
loginWithWebAuthFlow(options?: LoginOptions): Promise<void>;
|
|
38
39
|
}
|
|
39
|
-
declare function
|
|
40
|
+
declare function createCustomExtensionAuthClient(options: ExtensionAuthClientOptions): ExtensionAuthClient;
|
|
40
41
|
|
|
41
42
|
interface ChromeExtensionAuthClientOptions extends Omit<ExtensionAuthClientOptions, "clearSessionId" | "openAuthorizePage" | "persistAccessToken" | "resolveSessionId" | "restoreAccessToken"> {
|
|
42
43
|
accessTokenStorageKey?: string;
|
|
@@ -46,4 +47,6 @@ interface ChromeExtensionAuthClientOptions extends Omit<ExtensionAuthClientOptio
|
|
|
46
47
|
}
|
|
47
48
|
declare function createChromeExtensionAuthClient(options: ChromeExtensionAuthClientOptions): ExtensionAuthClient;
|
|
48
49
|
|
|
49
|
-
|
|
50
|
+
declare function createExtensionAuthClient(options: ExtensionAuthClientOptions | ChromeExtensionAuthClientOptions): ExtensionAuthClient;
|
|
51
|
+
|
|
52
|
+
export { type ChromeExtensionAuthClientOptions, type ExtensionAccessToken, type ExtensionAccessTokenRequestOptions, type ExtensionAuthClient, type ExtensionAuthClientOptions, type ExtensionStoredAccessToken, createChromeExtensionAuthClient, createCustomExtensionAuthClient, createExtensionAuthClient };
|
package/dist/extension.js
CHANGED
|
@@ -304,6 +304,15 @@ function buildAuthorizeUrl(apiOrigin, returnTo, application) {
|
|
|
304
304
|
}
|
|
305
305
|
return authorizeUrl.toString();
|
|
306
306
|
}
|
|
307
|
+
function resolveExtensionReturnToPath(requestedReturnTo, defaultReturnToPath) {
|
|
308
|
+
if (requestedReturnTo?.trim()) {
|
|
309
|
+
return resolveReturnToPath(requestedReturnTo);
|
|
310
|
+
}
|
|
311
|
+
if (defaultReturnToPath?.trim()) {
|
|
312
|
+
return resolveReturnToPath(defaultReturnToPath);
|
|
313
|
+
}
|
|
314
|
+
return resolveReturnToPath(requestedReturnTo);
|
|
315
|
+
}
|
|
307
316
|
function parseErrorPayload(payload) {
|
|
308
317
|
if (!isObjectRecord(payload)) {
|
|
309
318
|
return {
|
|
@@ -454,7 +463,7 @@ function createLogout(request, sessionStore, publishSession, options) {
|
|
|
454
463
|
await options.persistAccessToken?.(null);
|
|
455
464
|
};
|
|
456
465
|
}
|
|
457
|
-
function
|
|
466
|
+
function createCustomExtensionAuthClient(options) {
|
|
458
467
|
const sessionStore = new SessionStore();
|
|
459
468
|
const broadcastSync = createSafeBroadcastSync((session) => {
|
|
460
469
|
sessionStore.setSession(session);
|
|
@@ -494,7 +503,10 @@ function createExtensionAuthClient(options) {
|
|
|
494
503
|
if (!options.openAuthorizePage) {
|
|
495
504
|
throw new Error("Extension auth client requires openAuthorizePage for tab login flow.");
|
|
496
505
|
}
|
|
497
|
-
const returnTo =
|
|
506
|
+
const returnTo = resolveExtensionReturnToPath(
|
|
507
|
+
loginOptions?.returnTo,
|
|
508
|
+
options.defaultReturnToPath
|
|
509
|
+
);
|
|
498
510
|
const authorizeUrl = buildAuthorizeUrl(
|
|
499
511
|
options.apiOrigin,
|
|
500
512
|
returnTo,
|
|
@@ -508,7 +520,10 @@ function createExtensionAuthClient(options) {
|
|
|
508
520
|
if (!options.launchWebAuthFlow) {
|
|
509
521
|
throw new Error("Extension auth client requires launchWebAuthFlow for web auth flow.");
|
|
510
522
|
}
|
|
511
|
-
const returnTo =
|
|
523
|
+
const returnTo = resolveExtensionReturnToPath(
|
|
524
|
+
loginOptions?.returnTo,
|
|
525
|
+
options.defaultReturnToPath
|
|
526
|
+
);
|
|
512
527
|
const authorizeUrl = buildAuthorizeUrl(
|
|
513
528
|
options.apiOrigin,
|
|
514
529
|
returnTo,
|
|
@@ -542,10 +557,15 @@ function createExtensionAuthClient(options) {
|
|
|
542
557
|
}
|
|
543
558
|
|
|
544
559
|
// src/adapters/extension/chrome-auth-client.ts
|
|
560
|
+
function hasChromeExtensionRuntime() {
|
|
561
|
+
const chrome = getChromeRuntime();
|
|
562
|
+
return Boolean(chrome.cookies && chrome.storage?.local && chrome.tabs);
|
|
563
|
+
}
|
|
545
564
|
var defaultSessionCookieName = "gs_auth_session";
|
|
546
565
|
var defaultAccessTokenStorageKey = "authToken";
|
|
547
566
|
var defaultTokenExpiresAtStorageKey = "authTokenExpiresAt";
|
|
548
567
|
var defaultSessionStorageKey = "authSession";
|
|
568
|
+
var defaultExtensionReturnToPath = "/oauth/complete";
|
|
549
569
|
function getChromeRuntime() {
|
|
550
570
|
return globalThis.chrome ?? {};
|
|
551
571
|
}
|
|
@@ -619,8 +639,9 @@ function createChromeExtensionAuthClient(options) {
|
|
|
619
639
|
}
|
|
620
640
|
await tabs.create({ active: true, url: authorizeUrl });
|
|
621
641
|
};
|
|
622
|
-
return
|
|
642
|
+
return createCustomExtensionAuthClient({
|
|
623
643
|
...options,
|
|
644
|
+
defaultReturnToPath: options.defaultReturnToPath?.trim() || defaultExtensionReturnToPath,
|
|
624
645
|
clearSessionId,
|
|
625
646
|
openAuthorizePage,
|
|
626
647
|
persistAccessToken,
|
|
@@ -629,6 +650,27 @@ function createChromeExtensionAuthClient(options) {
|
|
|
629
650
|
});
|
|
630
651
|
}
|
|
631
652
|
|
|
632
|
-
|
|
653
|
+
// src/extension.ts
|
|
654
|
+
function hasCustomExtensionHooks(options) {
|
|
655
|
+
return Boolean(
|
|
656
|
+
options.clearSessionId || options.launchWebAuthFlow || options.openAuthorizePage || options.persistAccessToken || options.resolveSessionId || options.restoreAccessToken
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
function createExtensionAuthClient(options) {
|
|
660
|
+
if (hasChromeExtensionRuntime()) {
|
|
661
|
+
return createChromeExtensionAuthClient(options);
|
|
662
|
+
}
|
|
663
|
+
if (hasCustomExtensionHooks(options)) {
|
|
664
|
+
return createCustomExtensionAuthClient(options);
|
|
665
|
+
}
|
|
666
|
+
throw new AuthSdkError({
|
|
667
|
+
code: authErrorCode.apiError,
|
|
668
|
+
details: null,
|
|
669
|
+
message: "No supported extension runtime detected. Chromium browsers are supported automatically. Safari requires a dedicated adapter or explicit custom hooks.",
|
|
670
|
+
status: null
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
export { createChromeExtensionAuthClient, createCustomExtensionAuthClient, createExtensionAuthClient };
|
|
633
675
|
//# sourceMappingURL=extension.js.map
|
|
634
676
|
//# sourceMappingURL=extension.js.map
|
package/dist/extension.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/constants/auth-endpoints.ts","../src/constants/http-status.ts","../src/errors/auth-sdk-error.ts","../src/types/auth-error-code.ts","../src/core/api-origin.ts","../src/constants/auth-keys.ts","../src/core/object-guards.ts","../src/core/session-parser.ts","../src/core/broadcast-sync.ts","../src/core/runtime.ts","../src/core/return-to-storage.ts","../src/core/session-store.ts","../src/adapters/extension/auth-client.ts","../src/adapters/extension/chrome-auth-client.ts"],"names":[],"mappings":"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","file":"extension.js","sourcesContent":["const authApiPrefix = \"/oauth\";\n\nexport const authEndpoints = {\n authorize: `${authApiPrefix}/authorize`,\n extensionToken: `${authApiPrefix}/extension/token`,\n providerCallback: `${authApiPrefix}/callback/provider`,\n session: `${authApiPrefix}/session`,\n refresh: `${authApiPrefix}/refresh`,\n logout: `${authApiPrefix}/logout`,\n} as const;\n","export const httpStatus = {\n ok: 200,\n found: 302,\n noContent: 204,\n badRequest: 400,\n unauthorized: 401,\n} as const;\n","import type { AuthErrorCode } from \"../types/auth-error-code\";\n\nexport interface AuthSdkErrorPayload {\n code: AuthErrorCode;\n details: unknown;\n message: string;\n status: number | null;\n}\n\nexport class AuthSdkError extends Error {\n readonly code: AuthErrorCode;\n readonly details: unknown;\n readonly status: number | null;\n\n constructor(payload: AuthSdkErrorPayload) {\n super(payload.message);\n this.name = \"AuthSdkError\";\n this.code = payload.code;\n this.details = payload.details;\n this.status = payload.status;\n }\n}\n","export const authErrorCode = {\n unauthorized: \"unauthorized\",\n networkError: \"network_error\",\n apiError: \"api_error\",\n broadcastChannelUnsupported: \"broadcast_channel_unsupported\",\n serverOriginResolutionFailed: \"server_origin_resolution_failed\",\n} as const;\n\nexport type AuthErrorCode = (typeof authErrorCode)[keyof typeof authErrorCode];\n","import { AuthSdkError } from \"../errors/auth-sdk-error\";\nimport { authErrorCode } from \"../types/auth-error-code\";\n\nconst slash = \"/\";\n\nfunction normalizeApiOrigin(apiOrigin: string): string {\n const trimmed = apiOrigin.trim();\n\n if (!trimmed) {\n throw new AuthSdkError({\n code: authErrorCode.apiError,\n details: null,\n message: \"Auth API origin must be a non-empty absolute URL.\",\n status: null,\n });\n }\n\n let parsed: URL;\n\n try {\n parsed = new URL(trimmed);\n } catch (error) {\n throw new AuthSdkError({\n code: authErrorCode.apiError,\n details: error,\n message: \"Auth API origin must be a valid absolute URL.\",\n status: null,\n });\n }\n\n if (parsed.pathname !== slash || parsed.search || parsed.hash) {\n throw new AuthSdkError({\n code: authErrorCode.apiError,\n details: null,\n message: \"Auth API origin must not include path, query, or hash.\",\n status: null,\n });\n }\n\n return parsed.origin;\n}\n\nexport function resolveApiEndpoint(path: string, apiOrigin?: string): string {\n if (!apiOrigin) {\n return path;\n }\n\n return `${normalizeApiOrigin(apiOrigin)}${path}`;\n}\n","export const authBroadcast = {\n channelName: \"ghostly-auth-channel\",\n sessionUpdatedEvent: \"session-updated\",\n} as const;\n\nexport const authRoutes = {\n root: \"/\",\n} as const;\n","export function isObjectRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nexport function isStringValue(value: unknown): value is string {\n return typeof value === \"string\";\n}\n","import type { GhostlySession } from \"../types/ghostly-session\";\nimport { isObjectRecord, isStringValue } from \"./object-guards\";\n\nexport function isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every((entry) => isStringValue(entry));\n}\n\nexport function isGhostlySession(value: unknown): value is GhostlySession {\n if (!isObjectRecord(value)) {\n return false;\n }\n\n return (\n isStringValue(value.id) &&\n isStringValue(value.username) &&\n (value.firstName === null || isStringValue(value.firstName)) &&\n (value.lastName === null || isStringValue(value.lastName)) &&\n isStringValue(value.email) &&\n isStringValue(value.role) &&\n isStringArray(value.permissions)\n );\n}\n","import { authBroadcast } from \"../constants/auth-keys\";\nimport { AuthSdkError } from \"../errors/auth-sdk-error\";\nimport { authErrorCode } from \"../types/auth-error-code\";\nimport type { GhostlySession } from \"../types/ghostly-session\";\nimport { isObjectRecord, isStringValue } from \"./object-guards\";\nimport { isGhostlySession } from \"./session-parser\";\n\ninterface SessionUpdatedMessage {\n session: GhostlySession | null;\n type: typeof authBroadcast.sessionUpdatedEvent;\n}\n\nexport interface BroadcastSync {\n close(): void;\n publishSession(session: GhostlySession | null): void;\n}\n\ninterface CreateBroadcastSyncOptions {\n onSessionUpdated: (session: GhostlySession | null) => void;\n}\n\nfunction isSessionUpdatedMessage(value: unknown): value is SessionUpdatedMessage {\n if (!isObjectRecord(value)) {\n return false;\n }\n\n if (!isStringValue(value.type)) {\n return false;\n }\n\n if (value.type !== authBroadcast.sessionUpdatedEvent) {\n return false;\n }\n\n return value.session === null || isGhostlySession(value.session);\n}\n\nfunction createUnsupportedBroadcastChannelError(): AuthSdkError {\n return new AuthSdkError({\n code: authErrorCode.broadcastChannelUnsupported,\n details: null,\n message: \"BroadcastChannel is unavailable in this runtime.\",\n status: null,\n });\n}\n\nexport function createBroadcastSync(options: CreateBroadcastSyncOptions): BroadcastSync {\n if (typeof BroadcastChannel === \"undefined\") {\n throw createUnsupportedBroadcastChannelError();\n }\n\n const channel = new BroadcastChannel(authBroadcast.channelName);\n\n const onMessage: EventListener = (event) => {\n const messageEvent = event as MessageEvent<unknown>;\n\n if (!isSessionUpdatedMessage(messageEvent.data)) {\n return;\n }\n\n options.onSessionUpdated(messageEvent.data.session);\n };\n\n channel.addEventListener(\"message\", onMessage);\n\n return {\n close() {\n channel.removeEventListener(\"message\", onMessage);\n channel.close();\n },\n publishSession(session) {\n const payload: SessionUpdatedMessage = {\n session,\n type: authBroadcast.sessionUpdatedEvent,\n };\n\n channel.postMessage(payload);\n },\n };\n}\n","import { AuthSdkError } from \"../errors/auth-sdk-error\";\nimport { authErrorCode } from \"../types/auth-error-code\";\n\nconst browserRuntimeErrorMessage = \"Browser runtime is required for this auth operation.\";\n\nexport function isBrowserRuntime(): boolean {\n return typeof window !== \"undefined\";\n}\n\nexport function assertBrowserRuntime(): void {\n if (isBrowserRuntime()) {\n return;\n }\n\n throw new AuthSdkError({\n code: authErrorCode.apiError,\n details: null,\n message: browserRuntimeErrorMessage,\n status: null,\n });\n}\n","import { authRoutes } from \"../constants/auth-keys\";\nimport { assertBrowserRuntime } from \"./runtime\";\n\nfunction sanitizeReturnTo(value: string | null | undefined): string {\n if (!value) {\n return authRoutes.root;\n }\n\n if (!value.startsWith(authRoutes.root)) {\n return authRoutes.root;\n }\n\n const protocolRelativePrefix = \"//\";\n\n if (value.startsWith(protocolRelativePrefix)) {\n return authRoutes.root;\n }\n\n return value;\n}\n\nfunction getCurrentBrowserPath(): string {\n return `${window.location.pathname}${window.location.search}${window.location.hash}`;\n}\n\nexport function resolveReturnToPath(returnTo: string | undefined): string {\n assertBrowserRuntime();\n\n const fallbackPath = getCurrentBrowserPath();\n return sanitizeReturnTo(returnTo ?? fallbackPath);\n}\n","import type { SessionListener } from \"../types/auth-client\";\nimport type { GhostlySession } from \"../types/ghostly-session\";\n\ntype SessionResolveState = \"pending\" | \"resolved\";\n\nexport class SessionStore {\n private listeners = new Set<SessionListener>();\n private resolvedSession: GhostlySession | null = null;\n private resolveState: SessionResolveState = \"pending\";\n\n getSessionIfResolved(): GhostlySession | null {\n if (this.resolveState === \"pending\") {\n return null;\n }\n\n return this.resolvedSession;\n }\n\n hasResolvedSession(): boolean {\n return this.resolveState === \"resolved\";\n }\n\n setSession(session: GhostlySession | null): void {\n this.resolveState = \"resolved\";\n this.resolvedSession = session;\n\n for (const listener of this.listeners) {\n listener(session);\n }\n }\n\n subscribe(listener: SessionListener): () => void {\n this.listeners.add(listener);\n\n return () => {\n this.listeners.delete(listener);\n };\n }\n}\n","import { authEndpoints } from \"../../constants/auth-endpoints\";\nimport { httpStatus } from \"../../constants/http-status\";\nimport { resolveApiEndpoint } from \"../../core/api-origin\";\nimport type { BroadcastSync } from \"../../core/broadcast-sync\";\nimport { createBroadcastSync } from \"../../core/broadcast-sync\";\nimport { isObjectRecord, isStringValue } from \"../../core/object-guards\";\nimport { resolveReturnToPath } from \"../../core/return-to-storage\";\nimport { isGhostlySession } from \"../../core/session-parser\";\nimport { SessionStore } from \"../../core/session-store\";\nimport { AuthSdkError } from \"../../errors/auth-sdk-error\";\nimport type {\n AuthClient,\n AuthInitOptions,\n AuthInitResult,\n LoginOptions,\n SessionListener,\n SessionRequestOptions,\n} from \"../../types/auth-client\";\nimport { authErrorCode } from \"../../types/auth-error-code\";\nimport type { GhostlySession } from \"../../types/ghostly-session\";\n\ninterface LaunchWebAuthFlowPayload {\n authorizeUrl: string;\n}\n\ninterface OpenAuthorizePagePayload {\n authorizeUrl: string;\n}\n\ninterface RequestOptions {\n expectedStatus?: number;\n method: \"GET\" | \"POST\";\n path: string;\n}\n\ntype PersistAccessToken = (token: ExtensionStoredAccessToken | null) => Promise<void> | void;\ntype ResolveSessionId = () => Promise<string | null>;\ntype RestoreAccessToken =\n | (() => Promise<ExtensionStoredAccessToken | null>)\n | (() => ExtensionStoredAccessToken | null);\n\nexport interface ExtensionAccessToken {\n accessToken: string;\n application: string;\n expiresAt: string | null;\n session: GhostlySession | null;\n tokenType: string;\n}\n\nexport interface ExtensionAccessTokenRequestOptions {\n forceRefresh?: boolean;\n}\n\nexport interface ExtensionStoredAccessToken extends ExtensionAccessToken {}\n\nexport interface ExtensionAuthClientOptions {\n apiOrigin: string;\n application?: string;\n clearSessionId?: () => Promise<void> | void;\n launchWebAuthFlow?: (payload: LaunchWebAuthFlowPayload) => Promise<void>;\n openAuthorizePage?: (payload: OpenAuthorizePagePayload) => Promise<void>;\n persistAccessToken?: PersistAccessToken;\n resolveSessionId?: ResolveSessionId;\n restoreAccessToken?: RestoreAccessToken;\n}\n\nexport interface ExtensionAuthClient extends AuthClient {\n getAccessToken(\n options?: ExtensionAccessTokenRequestOptions,\n ): Promise<ExtensionAccessToken | null>;\n loginWithTabFlow(options?: LoginOptions): Promise<void>;\n loginWithWebAuthFlow(options?: LoginOptions): Promise<void>;\n}\n\nconst extensionSessionHeader = \"X-Ghostly-Session-Id\";\nconst includeCredentials: RequestCredentials = \"include\";\nconst noStoreCache: RequestCache = \"no-store\";\nconst tokenFreshnessLeewayMs = 60_000;\n\nfunction createNoopBroadcastSync(): BroadcastSync {\n return {\n close() {},\n publishSession() {},\n };\n}\n\nfunction createSafeBroadcastSync(\n onSessionUpdated: (session: GhostlySession | null) => void,\n): BroadcastSync {\n try {\n return createBroadcastSync({\n onSessionUpdated,\n });\n } catch (error) {\n if (error instanceof AuthSdkError && error.code === authErrorCode.broadcastChannelUnsupported) {\n return createNoopBroadcastSync();\n }\n\n throw error;\n }\n}\n\nfunction buildApiErrorMessage(method: RequestOptions[\"method\"], path: string): string {\n return `Auth API request failed: ${method} ${path}`;\n}\n\nfunction buildNetworkErrorMessage(method: RequestOptions[\"method\"], path: string): string {\n return `Auth API network failure: ${method} ${path}`;\n}\n\nfunction createInvalidSessionPayloadError(path: string): AuthSdkError {\n return new AuthSdkError({\n code: authErrorCode.apiError,\n details: null,\n message: `Auth API response has invalid session shape: ${path}`,\n status: null,\n });\n}\n\nfunction toInitResult(session: GhostlySession | null): AuthInitResult {\n return {\n session,\n status: session ? \"authenticated\" : \"unauthenticated\",\n };\n}\n\nfunction parseSessionPayload(payload: unknown, path: string): GhostlySession | null {\n if (payload === null) {\n return null;\n }\n if (!isGhostlySession(payload)) {\n throw createInvalidSessionPayloadError(path);\n }\n return payload;\n}\n\nfunction isExtensionAccessToken(value: unknown): value is ExtensionAccessToken {\n if (!isObjectRecord(value)) {\n return false;\n }\n\n return (\n isStringValue(value.accessToken) &&\n isStringValue(value.application) &&\n (value.expiresAt === null || isStringValue(value.expiresAt)) &&\n (value.session === null || isGhostlySession(value.session)) &&\n isStringValue(value.tokenType)\n );\n}\n\nfunction isStoredTokenFresh(\n token: ExtensionStoredAccessToken | null,\n): token is ExtensionStoredAccessToken {\n if (!token || !token.accessToken.trim()) {\n return false;\n }\n\n if (!token.expiresAt) {\n return true;\n }\n\n const expiresAt = Date.parse(token.expiresAt);\n if (Number.isNaN(expiresAt)) {\n return false;\n }\n\n return expiresAt - Date.now() > tokenFreshnessLeewayMs;\n}\n\nfunction buildAuthorizeUrl(apiOrigin: string, returnTo: string, application?: string): string {\n const authorizeEndpoint = resolveApiEndpoint(authEndpoints.authorize, apiOrigin);\n const authorizeUrl = new URL(authorizeEndpoint, window.location.origin);\n authorizeUrl.searchParams.set(\"return_to\", returnTo);\n if (application?.trim()) {\n authorizeUrl.searchParams.set(\"app\", application.trim());\n }\n return authorizeUrl.toString();\n}\n\nfunction parseErrorPayload(payload: unknown): { details: unknown; message: string | null } {\n if (!isObjectRecord(payload)) {\n return {\n details: null,\n message: null,\n };\n }\n\n return {\n details: \"details\" in payload ? payload.details : null,\n message: isStringValue(payload.message)\n ? payload.message\n : isStringValue(payload.error)\n ? payload.error\n : null,\n };\n}\n\nfunction createRequest(\n options: ExtensionAuthClientOptions,\n): <TResponse>(requestOptions: RequestOptions) => Promise<TResponse> {\n const resolveEndpoint = (path: string): string => resolveApiEndpoint(path, options.apiOrigin);\n\n return async function request<TResponse>(requestOptions: RequestOptions): Promise<TResponse> {\n const expectedStatus = requestOptions.expectedStatus ?? httpStatus.ok;\n const headers = new Headers();\n const sessionId = (await options.resolveSessionId?.())?.trim() || \"\";\n\n if (sessionId) {\n headers.set(extensionSessionHeader, sessionId);\n }\n\n let response: Response;\n try {\n response = await fetch(resolveEndpoint(requestOptions.path), {\n cache: noStoreCache,\n credentials: includeCredentials,\n headers,\n method: requestOptions.method,\n });\n } catch (error) {\n throw new AuthSdkError({\n code: authErrorCode.networkError,\n details: error,\n message: buildNetworkErrorMessage(requestOptions.method, requestOptions.path),\n status: null,\n });\n }\n\n if (response.status !== expectedStatus) {\n let parsedPayload: unknown = null;\n try {\n parsedPayload = await response.json();\n } catch {\n parsedPayload = null;\n }\n\n const parsed = parseErrorPayload(parsedPayload);\n throw new AuthSdkError({\n code:\n response.status === httpStatus.unauthorized\n ? authErrorCode.unauthorized\n : authErrorCode.apiError,\n details: parsed.details,\n message: parsed.message ?? buildApiErrorMessage(requestOptions.method, requestOptions.path),\n status: response.status,\n });\n }\n\n if (response.status === httpStatus.noContent) {\n return null as TResponse;\n }\n\n return (await response.json()) as TResponse;\n };\n}\n\nfunction createLoadSession(\n request: <TResponse>(requestOptions: RequestOptions) => Promise<TResponse>,\n): () => Promise<GhostlySession | null> {\n return async () => {\n const payload = await request<unknown>({\n method: \"GET\",\n path: authEndpoints.session,\n });\n return parseSessionPayload(payload, authEndpoints.session);\n };\n}\n\nfunction createInit(\n sessionStore: SessionStore,\n loadSession: () => Promise<GhostlySession | null>,\n publishSession: (session: GhostlySession | null) => void,\n): (initOptions?: AuthInitOptions) => Promise<AuthInitResult> {\n let initPromise: Promise<AuthInitResult> | null = null;\n\n return async (initOptions?: AuthInitOptions): Promise<AuthInitResult> => {\n const forceRefresh = initOptions?.forceRefresh ?? false;\n\n if (sessionStore.hasResolvedSession() && !forceRefresh) {\n return toInitResult(sessionStore.getSessionIfResolved());\n }\n\n if (initPromise) {\n return initPromise;\n }\n\n initPromise = (async () => {\n const session = await loadSession();\n sessionStore.setSession(session);\n publishSession(session);\n return toInitResult(session);\n })();\n\n try {\n return await initPromise;\n } finally {\n initPromise = null;\n }\n };\n}\n\nfunction createRefresh(\n request: <TResponse>(requestOptions: RequestOptions) => Promise<TResponse>,\n sessionStore: SessionStore,\n publishSession: (session: GhostlySession | null) => void,\n): () => Promise<GhostlySession | null> {\n return async () => {\n const payload = await request<unknown>({\n method: \"POST\",\n path: authEndpoints.refresh,\n });\n const session = parseSessionPayload(payload, authEndpoints.refresh);\n sessionStore.setSession(session);\n publishSession(session);\n return session;\n };\n}\n\nfunction createGetAccessToken(\n request: <TResponse>(requestOptions: RequestOptions) => Promise<TResponse>,\n sessionStore: SessionStore,\n publishSession: (session: GhostlySession | null) => void,\n persistAccessToken?: PersistAccessToken,\n restoreAccessToken?: RestoreAccessToken,\n): (requestOptions?: ExtensionAccessTokenRequestOptions) => Promise<ExtensionAccessToken | null> {\n return async (requestOptions?: ExtensionAccessTokenRequestOptions) => {\n const forceRefresh = requestOptions?.forceRefresh ?? false;\n const stored = (await restoreAccessToken?.()) ?? null;\n if (!forceRefresh && isStoredTokenFresh(stored)) {\n if (stored.session) {\n sessionStore.setSession(stored.session);\n }\n return stored;\n }\n\n const payload = await request<unknown>({\n method: \"GET\",\n path: authEndpoints.extensionToken,\n });\n\n if (!isExtensionAccessToken(payload)) {\n throw new AuthSdkError({\n code: authErrorCode.apiError,\n details: null,\n message: `Auth API response has invalid extension token shape: ${authEndpoints.extensionToken}`,\n status: null,\n });\n }\n\n const nextToken: ExtensionStoredAccessToken = {\n accessToken: payload.accessToken,\n application: payload.application,\n expiresAt: payload.expiresAt,\n session: payload.session,\n tokenType: payload.tokenType,\n };\n\n sessionStore.setSession(nextToken.session);\n publishSession(nextToken.session);\n await persistAccessToken?.(nextToken);\n return nextToken;\n };\n}\n\nfunction createLogout(\n request: <TResponse>(requestOptions: RequestOptions) => Promise<TResponse>,\n sessionStore: SessionStore,\n publishSession: (session: GhostlySession | null) => void,\n options: ExtensionAuthClientOptions,\n): () => Promise<void> {\n return async () => {\n await request<null>({\n expectedStatus: httpStatus.noContent,\n method: \"POST\",\n path: authEndpoints.logout,\n });\n await options.clearSessionId?.();\n sessionStore.setSession(null);\n publishSession(null);\n await options.persistAccessToken?.(null);\n };\n}\n\nexport function createExtensionAuthClient(\n options: ExtensionAuthClientOptions,\n): ExtensionAuthClient {\n const sessionStore = new SessionStore();\n const broadcastSync = createSafeBroadcastSync((session) => {\n sessionStore.setSession(session);\n });\n const publishSession = broadcastSync.publishSession.bind(broadcastSync);\n const request = createRequest(options);\n const loadSession = createLoadSession(request);\n const init = createInit(sessionStore, loadSession, publishSession);\n const refresh = createRefresh(request, sessionStore, publishSession);\n const getAccessToken = createGetAccessToken(\n request,\n sessionStore,\n publishSession,\n options.persistAccessToken,\n options.restoreAccessToken,\n );\n const logout = createLogout(request, sessionStore, publishSession, options);\n\n const getSession = async (\n requestOptions?: SessionRequestOptions,\n ): Promise<GhostlySession | null> => {\n const result = await init({\n forceRefresh: requestOptions?.forceRefresh ?? false,\n });\n return result.session;\n };\n\n const requireSession = async (): Promise<GhostlySession> => {\n const session = await getSession();\n if (session) {\n return session;\n }\n\n throw new AuthSdkError({\n code: authErrorCode.unauthorized,\n details: null,\n message: \"Authenticated session is required.\",\n status: httpStatus.unauthorized,\n });\n };\n\n const loginWithTabFlow = async (loginOptions?: LoginOptions): Promise<void> => {\n if (!options.openAuthorizePage) {\n throw new Error(\"Extension auth client requires openAuthorizePage for tab login flow.\");\n }\n\n const returnTo = resolveReturnToPath(loginOptions?.returnTo);\n const authorizeUrl = buildAuthorizeUrl(\n options.apiOrigin,\n returnTo,\n loginOptions?.application ?? options.application,\n );\n\n await options.openAuthorizePage({\n authorizeUrl,\n });\n };\n\n const loginWithWebAuthFlow = async (loginOptions?: LoginOptions): Promise<void> => {\n if (!options.launchWebAuthFlow) {\n throw new Error(\"Extension auth client requires launchWebAuthFlow for web auth flow.\");\n }\n\n const returnTo = resolveReturnToPath(loginOptions?.returnTo);\n const authorizeUrl = buildAuthorizeUrl(\n options.apiOrigin,\n returnTo,\n loginOptions?.application ?? options.application,\n );\n\n await options.launchWebAuthFlow({\n authorizeUrl,\n });\n await refresh();\n };\n\n return {\n init,\n getSession,\n login(loginOptions?: LoginOptions) {\n if (options.openAuthorizePage) {\n void loginWithTabFlow(loginOptions);\n return;\n }\n\n void loginWithWebAuthFlow(loginOptions);\n },\n logout,\n refresh,\n requireSession,\n subscribe(listener: SessionListener) {\n return sessionStore.subscribe(listener);\n },\n getAccessToken,\n loginWithTabFlow,\n loginWithWebAuthFlow,\n };\n}\n","import {\n createExtensionAuthClient,\n type ExtensionAuthClient,\n type ExtensionAuthClientOptions,\n type ExtensionStoredAccessToken,\n} from \"./auth-client\";\n\ninterface ChromeCookiesApi {\n get(details: { name: string; url: string }): Promise<{ value?: string } | null>;\n remove(details: { name: string; url: string }): Promise<unknown>;\n}\n\ninterface ChromeStorageAreaApi {\n get(keys: string[]): Promise<Record<string, unknown>>;\n remove(keys: string[]): Promise<void>;\n set(items: Record<string, unknown>): Promise<void>;\n}\n\ninterface ChromeTabsApi {\n create(details: { active?: boolean; url: string }): Promise<unknown>;\n}\n\ninterface ChromeRuntimeLike {\n cookies?: ChromeCookiesApi;\n storage?: {\n local?: ChromeStorageAreaApi;\n };\n tabs?: ChromeTabsApi;\n}\n\nexport interface ChromeExtensionAuthClientOptions\n extends Omit<\n ExtensionAuthClientOptions,\n | \"clearSessionId\"\n | \"openAuthorizePage\"\n | \"persistAccessToken\"\n | \"resolveSessionId\"\n | \"restoreAccessToken\"\n > {\n accessTokenStorageKey?: string;\n sessionCookieName?: string;\n sessionStorageKey?: string;\n tokenExpiresAtStorageKey?: string;\n}\n\nconst defaultSessionCookieName = \"gs_auth_session\";\nconst defaultAccessTokenStorageKey = \"authToken\";\nconst defaultTokenExpiresAtStorageKey = \"authTokenExpiresAt\";\nconst defaultSessionStorageKey = \"authSession\";\n\nfunction getChromeRuntime(): ChromeRuntimeLike {\n return (globalThis as { chrome?: ChromeRuntimeLike }).chrome ?? {};\n}\n\nexport function createChromeExtensionAuthClient(\n options: ChromeExtensionAuthClientOptions,\n): ExtensionAuthClient {\n const sessionCookieName = options.sessionCookieName?.trim() || defaultSessionCookieName;\n const accessTokenStorageKey =\n options.accessTokenStorageKey?.trim() || defaultAccessTokenStorageKey;\n const tokenExpiresAtStorageKey =\n options.tokenExpiresAtStorageKey?.trim() || defaultTokenExpiresAtStorageKey;\n const sessionStorageKey = options.sessionStorageKey?.trim() || defaultSessionStorageKey;\n\n const resolveSessionId = async (): Promise<string | null> => {\n const cookies = getChromeRuntime().cookies;\n if (!cookies) {\n return null;\n }\n\n const cookie = await cookies.get({\n name: sessionCookieName,\n url: `${options.apiOrigin}/`,\n });\n return cookie?.value?.trim() || null;\n };\n\n const clearSessionId = async (): Promise<void> => {\n const cookies = getChromeRuntime().cookies;\n if (!cookies) {\n return;\n }\n await cookies.remove({\n name: sessionCookieName,\n url: `${options.apiOrigin}/`,\n });\n };\n\n const persistAccessToken = async (token: ExtensionStoredAccessToken | null): Promise<void> => {\n const storage = getChromeRuntime().storage?.local;\n if (!storage) {\n return;\n }\n\n if (!token) {\n await storage.remove([accessTokenStorageKey, tokenExpiresAtStorageKey, sessionStorageKey]);\n return;\n }\n\n await storage.set({\n [accessTokenStorageKey]: token.accessToken,\n [tokenExpiresAtStorageKey]: token.expiresAt || null,\n [sessionStorageKey]: token.session || null,\n });\n };\n\n const restoreAccessToken = async (): Promise<ExtensionStoredAccessToken | null> => {\n const storage = getChromeRuntime().storage?.local;\n if (!storage) {\n return null;\n }\n\n const stored = await storage.get([\n accessTokenStorageKey,\n tokenExpiresAtStorageKey,\n sessionStorageKey,\n ]);\n\n const rawAccessToken = stored[accessTokenStorageKey];\n if (typeof rawAccessToken !== \"string\" || rawAccessToken.trim() === \"\") {\n return null;\n }\n\n return {\n accessToken: rawAccessToken,\n application: options.application?.trim() || \"\",\n expiresAt:\n typeof stored[tokenExpiresAtStorageKey] === \"string\"\n ? stored[tokenExpiresAtStorageKey]\n : null,\n session: (stored[sessionStorageKey] as ExtensionStoredAccessToken[\"session\"]) ?? null,\n tokenType: \"Bearer\",\n };\n };\n\n const openAuthorizePage = async ({ authorizeUrl }: { authorizeUrl: string }): Promise<void> => {\n const tabs = getChromeRuntime().tabs;\n if (!tabs) {\n throw new Error(\"Chrome tabs API is unavailable.\");\n }\n await tabs.create({ active: true, url: authorizeUrl });\n };\n\n return createExtensionAuthClient({\n ...options,\n clearSessionId,\n openAuthorizePage,\n persistAccessToken,\n resolveSessionId,\n restoreAccessToken,\n });\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/constants/auth-endpoints.ts","../src/constants/http-status.ts","../src/errors/auth-sdk-error.ts","../src/types/auth-error-code.ts","../src/core/api-origin.ts","../src/constants/auth-keys.ts","../src/core/object-guards.ts","../src/core/session-parser.ts","../src/core/broadcast-sync.ts","../src/core/runtime.ts","../src/core/return-to-storage.ts","../src/core/session-store.ts","../src/adapters/extension/auth-client.ts","../src/adapters/extension/chrome-auth-client.ts","../src/extension.ts"],"names":[],"mappings":"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","file":"extension.js","sourcesContent":["const authApiPrefix = \"/oauth\";\n\nexport const authEndpoints = {\n authorize: `${authApiPrefix}/authorize`,\n extensionToken: `${authApiPrefix}/extension/token`,\n providerCallback: `${authApiPrefix}/callback/provider`,\n session: `${authApiPrefix}/session`,\n refresh: `${authApiPrefix}/refresh`,\n logout: `${authApiPrefix}/logout`,\n} as const;\n","export const httpStatus = {\n ok: 200,\n found: 302,\n noContent: 204,\n badRequest: 400,\n unauthorized: 401,\n} as const;\n","import type { AuthErrorCode } from \"../types/auth-error-code\";\n\nexport interface AuthSdkErrorPayload {\n code: AuthErrorCode;\n details: unknown;\n message: string;\n status: number | null;\n}\n\nexport class AuthSdkError extends Error {\n readonly code: AuthErrorCode;\n readonly details: unknown;\n readonly status: number | null;\n\n constructor(payload: AuthSdkErrorPayload) {\n super(payload.message);\n this.name = \"AuthSdkError\";\n this.code = payload.code;\n this.details = payload.details;\n this.status = payload.status;\n }\n}\n","export const authErrorCode = {\n unauthorized: \"unauthorized\",\n networkError: \"network_error\",\n apiError: \"api_error\",\n broadcastChannelUnsupported: \"broadcast_channel_unsupported\",\n serverOriginResolutionFailed: \"server_origin_resolution_failed\",\n} as const;\n\nexport type AuthErrorCode = (typeof authErrorCode)[keyof typeof authErrorCode];\n","import { AuthSdkError } from \"../errors/auth-sdk-error\";\nimport { authErrorCode } from \"../types/auth-error-code\";\n\nconst slash = \"/\";\n\nfunction normalizeApiOrigin(apiOrigin: string): string {\n const trimmed = apiOrigin.trim();\n\n if (!trimmed) {\n throw new AuthSdkError({\n code: authErrorCode.apiError,\n details: null,\n message: \"Auth API origin must be a non-empty absolute URL.\",\n status: null,\n });\n }\n\n let parsed: URL;\n\n try {\n parsed = new URL(trimmed);\n } catch (error) {\n throw new AuthSdkError({\n code: authErrorCode.apiError,\n details: error,\n message: \"Auth API origin must be a valid absolute URL.\",\n status: null,\n });\n }\n\n if (parsed.pathname !== slash || parsed.search || parsed.hash) {\n throw new AuthSdkError({\n code: authErrorCode.apiError,\n details: null,\n message: \"Auth API origin must not include path, query, or hash.\",\n status: null,\n });\n }\n\n return parsed.origin;\n}\n\nexport function resolveApiEndpoint(path: string, apiOrigin?: string): string {\n if (!apiOrigin) {\n return path;\n }\n\n return `${normalizeApiOrigin(apiOrigin)}${path}`;\n}\n","export const authBroadcast = {\n channelName: \"ghostly-auth-channel\",\n sessionUpdatedEvent: \"session-updated\",\n} as const;\n\nexport const authRoutes = {\n root: \"/\",\n} as const;\n","export function isObjectRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nexport function isStringValue(value: unknown): value is string {\n return typeof value === \"string\";\n}\n","import type { GhostlySession } from \"../types/ghostly-session\";\nimport { isObjectRecord, isStringValue } from \"./object-guards\";\n\nexport function isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every((entry) => isStringValue(entry));\n}\n\nexport function isGhostlySession(value: unknown): value is GhostlySession {\n if (!isObjectRecord(value)) {\n return false;\n }\n\n return (\n isStringValue(value.id) &&\n isStringValue(value.username) &&\n (value.firstName === null || isStringValue(value.firstName)) &&\n (value.lastName === null || isStringValue(value.lastName)) &&\n isStringValue(value.email) &&\n isStringValue(value.role) &&\n isStringArray(value.permissions)\n );\n}\n","import { authBroadcast } from \"../constants/auth-keys\";\nimport { AuthSdkError } from \"../errors/auth-sdk-error\";\nimport { authErrorCode } from \"../types/auth-error-code\";\nimport type { GhostlySession } from \"../types/ghostly-session\";\nimport { isObjectRecord, isStringValue } from \"./object-guards\";\nimport { isGhostlySession } from \"./session-parser\";\n\ninterface SessionUpdatedMessage {\n session: GhostlySession | null;\n type: typeof authBroadcast.sessionUpdatedEvent;\n}\n\nexport interface BroadcastSync {\n close(): void;\n publishSession(session: GhostlySession | null): void;\n}\n\ninterface CreateBroadcastSyncOptions {\n onSessionUpdated: (session: GhostlySession | null) => void;\n}\n\nfunction isSessionUpdatedMessage(value: unknown): value is SessionUpdatedMessage {\n if (!isObjectRecord(value)) {\n return false;\n }\n\n if (!isStringValue(value.type)) {\n return false;\n }\n\n if (value.type !== authBroadcast.sessionUpdatedEvent) {\n return false;\n }\n\n return value.session === null || isGhostlySession(value.session);\n}\n\nfunction createUnsupportedBroadcastChannelError(): AuthSdkError {\n return new AuthSdkError({\n code: authErrorCode.broadcastChannelUnsupported,\n details: null,\n message: \"BroadcastChannel is unavailable in this runtime.\",\n status: null,\n });\n}\n\nexport function createBroadcastSync(options: CreateBroadcastSyncOptions): BroadcastSync {\n if (typeof BroadcastChannel === \"undefined\") {\n throw createUnsupportedBroadcastChannelError();\n }\n\n const channel = new BroadcastChannel(authBroadcast.channelName);\n\n const onMessage: EventListener = (event) => {\n const messageEvent = event as MessageEvent<unknown>;\n\n if (!isSessionUpdatedMessage(messageEvent.data)) {\n return;\n }\n\n options.onSessionUpdated(messageEvent.data.session);\n };\n\n channel.addEventListener(\"message\", onMessage);\n\n return {\n close() {\n channel.removeEventListener(\"message\", onMessage);\n channel.close();\n },\n publishSession(session) {\n const payload: SessionUpdatedMessage = {\n session,\n type: authBroadcast.sessionUpdatedEvent,\n };\n\n channel.postMessage(payload);\n },\n };\n}\n","import { AuthSdkError } from \"../errors/auth-sdk-error\";\nimport { authErrorCode } from \"../types/auth-error-code\";\n\nconst browserRuntimeErrorMessage = \"Browser runtime is required for this auth operation.\";\n\nexport function isBrowserRuntime(): boolean {\n return typeof window !== \"undefined\";\n}\n\nexport function assertBrowserRuntime(): void {\n if (isBrowserRuntime()) {\n return;\n }\n\n throw new AuthSdkError({\n code: authErrorCode.apiError,\n details: null,\n message: browserRuntimeErrorMessage,\n status: null,\n });\n}\n","import { authRoutes } from \"../constants/auth-keys\";\nimport { assertBrowserRuntime } from \"./runtime\";\n\nfunction sanitizeReturnTo(value: string | null | undefined): string {\n if (!value) {\n return authRoutes.root;\n }\n\n if (!value.startsWith(authRoutes.root)) {\n return authRoutes.root;\n }\n\n const protocolRelativePrefix = \"//\";\n\n if (value.startsWith(protocolRelativePrefix)) {\n return authRoutes.root;\n }\n\n return value;\n}\n\nfunction getCurrentBrowserPath(): string {\n return `${window.location.pathname}${window.location.search}${window.location.hash}`;\n}\n\nexport function resolveReturnToPath(returnTo: string | undefined): string {\n assertBrowserRuntime();\n\n const fallbackPath = getCurrentBrowserPath();\n return sanitizeReturnTo(returnTo ?? fallbackPath);\n}\n","import type { SessionListener } from \"../types/auth-client\";\nimport type { GhostlySession } from \"../types/ghostly-session\";\n\ntype SessionResolveState = \"pending\" | \"resolved\";\n\nexport class SessionStore {\n private listeners = new Set<SessionListener>();\n private resolvedSession: GhostlySession | null = null;\n private resolveState: SessionResolveState = \"pending\";\n\n getSessionIfResolved(): GhostlySession | null {\n if (this.resolveState === \"pending\") {\n return null;\n }\n\n return this.resolvedSession;\n }\n\n hasResolvedSession(): boolean {\n return this.resolveState === \"resolved\";\n }\n\n setSession(session: GhostlySession | null): void {\n this.resolveState = \"resolved\";\n this.resolvedSession = session;\n\n for (const listener of this.listeners) {\n listener(session);\n }\n }\n\n subscribe(listener: SessionListener): () => void {\n this.listeners.add(listener);\n\n return () => {\n this.listeners.delete(listener);\n };\n }\n}\n","import { authEndpoints } from \"../../constants/auth-endpoints\";\nimport { httpStatus } from \"../../constants/http-status\";\nimport { resolveApiEndpoint } from \"../../core/api-origin\";\nimport type { BroadcastSync } from \"../../core/broadcast-sync\";\nimport { createBroadcastSync } from \"../../core/broadcast-sync\";\nimport { isObjectRecord, isStringValue } from \"../../core/object-guards\";\nimport { resolveReturnToPath } from \"../../core/return-to-storage\";\nimport { isGhostlySession } from \"../../core/session-parser\";\nimport { SessionStore } from \"../../core/session-store\";\nimport { AuthSdkError } from \"../../errors/auth-sdk-error\";\nimport type {\n AuthClient,\n AuthInitOptions,\n AuthInitResult,\n LoginOptions,\n SessionListener,\n SessionRequestOptions,\n} from \"../../types/auth-client\";\nimport { authErrorCode } from \"../../types/auth-error-code\";\nimport type { GhostlySession } from \"../../types/ghostly-session\";\n\ninterface LaunchWebAuthFlowPayload {\n authorizeUrl: string;\n}\n\ninterface OpenAuthorizePagePayload {\n authorizeUrl: string;\n}\n\ninterface RequestOptions {\n expectedStatus?: number;\n method: \"GET\" | \"POST\";\n path: string;\n}\n\ntype PersistAccessToken = (token: ExtensionStoredAccessToken | null) => Promise<void> | void;\ntype ResolveSessionId = () => Promise<string | null>;\ntype RestoreAccessToken =\n | (() => Promise<ExtensionStoredAccessToken | null>)\n | (() => ExtensionStoredAccessToken | null);\n\nexport interface ExtensionAccessToken {\n accessToken: string;\n application: string;\n expiresAt: string | null;\n session: GhostlySession | null;\n tokenType: string;\n}\n\nexport interface ExtensionAccessTokenRequestOptions {\n forceRefresh?: boolean;\n}\n\nexport interface ExtensionStoredAccessToken extends ExtensionAccessToken {}\n\nexport interface ExtensionAuthClientOptions {\n apiOrigin: string;\n application?: string;\n defaultReturnToPath?: string;\n clearSessionId?: () => Promise<void> | void;\n launchWebAuthFlow?: (payload: LaunchWebAuthFlowPayload) => Promise<void>;\n openAuthorizePage?: (payload: OpenAuthorizePagePayload) => Promise<void>;\n persistAccessToken?: PersistAccessToken;\n resolveSessionId?: ResolveSessionId;\n restoreAccessToken?: RestoreAccessToken;\n}\n\nexport interface ExtensionAuthClient extends AuthClient {\n getAccessToken(\n options?: ExtensionAccessTokenRequestOptions,\n ): Promise<ExtensionAccessToken | null>;\n loginWithTabFlow(options?: LoginOptions): Promise<void>;\n loginWithWebAuthFlow(options?: LoginOptions): Promise<void>;\n}\n\nconst extensionSessionHeader = \"X-Ghostly-Session-Id\";\nconst includeCredentials: RequestCredentials = \"include\";\nconst noStoreCache: RequestCache = \"no-store\";\nconst tokenFreshnessLeewayMs = 60_000;\n\nfunction createNoopBroadcastSync(): BroadcastSync {\n return {\n close() {},\n publishSession() {},\n };\n}\n\nfunction createSafeBroadcastSync(\n onSessionUpdated: (session: GhostlySession | null) => void,\n): BroadcastSync {\n try {\n return createBroadcastSync({\n onSessionUpdated,\n });\n } catch (error) {\n if (error instanceof AuthSdkError && error.code === authErrorCode.broadcastChannelUnsupported) {\n return createNoopBroadcastSync();\n }\n\n throw error;\n }\n}\n\nfunction buildApiErrorMessage(method: RequestOptions[\"method\"], path: string): string {\n return `Auth API request failed: ${method} ${path}`;\n}\n\nfunction buildNetworkErrorMessage(method: RequestOptions[\"method\"], path: string): string {\n return `Auth API network failure: ${method} ${path}`;\n}\n\nfunction createInvalidSessionPayloadError(path: string): AuthSdkError {\n return new AuthSdkError({\n code: authErrorCode.apiError,\n details: null,\n message: `Auth API response has invalid session shape: ${path}`,\n status: null,\n });\n}\n\nfunction toInitResult(session: GhostlySession | null): AuthInitResult {\n return {\n session,\n status: session ? \"authenticated\" : \"unauthenticated\",\n };\n}\n\nfunction parseSessionPayload(payload: unknown, path: string): GhostlySession | null {\n if (payload === null) {\n return null;\n }\n if (!isGhostlySession(payload)) {\n throw createInvalidSessionPayloadError(path);\n }\n return payload;\n}\n\nfunction isExtensionAccessToken(value: unknown): value is ExtensionAccessToken {\n if (!isObjectRecord(value)) {\n return false;\n }\n\n return (\n isStringValue(value.accessToken) &&\n isStringValue(value.application) &&\n (value.expiresAt === null || isStringValue(value.expiresAt)) &&\n (value.session === null || isGhostlySession(value.session)) &&\n isStringValue(value.tokenType)\n );\n}\n\nfunction isStoredTokenFresh(\n token: ExtensionStoredAccessToken | null,\n): token is ExtensionStoredAccessToken {\n if (!token || !token.accessToken.trim()) {\n return false;\n }\n\n if (!token.expiresAt) {\n return true;\n }\n\n const expiresAt = Date.parse(token.expiresAt);\n if (Number.isNaN(expiresAt)) {\n return false;\n }\n\n return expiresAt - Date.now() > tokenFreshnessLeewayMs;\n}\n\nfunction buildAuthorizeUrl(apiOrigin: string, returnTo: string, application?: string): string {\n const authorizeEndpoint = resolveApiEndpoint(authEndpoints.authorize, apiOrigin);\n const authorizeUrl = new URL(authorizeEndpoint, window.location.origin);\n authorizeUrl.searchParams.set(\"return_to\", returnTo);\n if (application?.trim()) {\n authorizeUrl.searchParams.set(\"app\", application.trim());\n }\n return authorizeUrl.toString();\n}\n\nfunction resolveExtensionReturnToPath(\n requestedReturnTo: string | undefined,\n defaultReturnToPath?: string,\n): string {\n if (requestedReturnTo?.trim()) {\n return resolveReturnToPath(requestedReturnTo);\n }\n\n if (defaultReturnToPath?.trim()) {\n return resolveReturnToPath(defaultReturnToPath);\n }\n\n return resolveReturnToPath(requestedReturnTo);\n}\n\nfunction parseErrorPayload(payload: unknown): { details: unknown; message: string | null } {\n if (!isObjectRecord(payload)) {\n return {\n details: null,\n message: null,\n };\n }\n\n return {\n details: \"details\" in payload ? payload.details : null,\n message: isStringValue(payload.message)\n ? payload.message\n : isStringValue(payload.error)\n ? payload.error\n : null,\n };\n}\n\nfunction createRequest(\n options: ExtensionAuthClientOptions,\n): <TResponse>(requestOptions: RequestOptions) => Promise<TResponse> {\n const resolveEndpoint = (path: string): string => resolveApiEndpoint(path, options.apiOrigin);\n\n return async function request<TResponse>(requestOptions: RequestOptions): Promise<TResponse> {\n const expectedStatus = requestOptions.expectedStatus ?? httpStatus.ok;\n const headers = new Headers();\n const sessionId = (await options.resolveSessionId?.())?.trim() || \"\";\n\n if (sessionId) {\n headers.set(extensionSessionHeader, sessionId);\n }\n\n let response: Response;\n try {\n response = await fetch(resolveEndpoint(requestOptions.path), {\n cache: noStoreCache,\n credentials: includeCredentials,\n headers,\n method: requestOptions.method,\n });\n } catch (error) {\n throw new AuthSdkError({\n code: authErrorCode.networkError,\n details: error,\n message: buildNetworkErrorMessage(requestOptions.method, requestOptions.path),\n status: null,\n });\n }\n\n if (response.status !== expectedStatus) {\n let parsedPayload: unknown = null;\n try {\n parsedPayload = await response.json();\n } catch {\n parsedPayload = null;\n }\n\n const parsed = parseErrorPayload(parsedPayload);\n throw new AuthSdkError({\n code:\n response.status === httpStatus.unauthorized\n ? authErrorCode.unauthorized\n : authErrorCode.apiError,\n details: parsed.details,\n message: parsed.message ?? buildApiErrorMessage(requestOptions.method, requestOptions.path),\n status: response.status,\n });\n }\n\n if (response.status === httpStatus.noContent) {\n return null as TResponse;\n }\n\n return (await response.json()) as TResponse;\n };\n}\n\nfunction createLoadSession(\n request: <TResponse>(requestOptions: RequestOptions) => Promise<TResponse>,\n): () => Promise<GhostlySession | null> {\n return async () => {\n const payload = await request<unknown>({\n method: \"GET\",\n path: authEndpoints.session,\n });\n return parseSessionPayload(payload, authEndpoints.session);\n };\n}\n\nfunction createInit(\n sessionStore: SessionStore,\n loadSession: () => Promise<GhostlySession | null>,\n publishSession: (session: GhostlySession | null) => void,\n): (initOptions?: AuthInitOptions) => Promise<AuthInitResult> {\n let initPromise: Promise<AuthInitResult> | null = null;\n\n return async (initOptions?: AuthInitOptions): Promise<AuthInitResult> => {\n const forceRefresh = initOptions?.forceRefresh ?? false;\n\n if (sessionStore.hasResolvedSession() && !forceRefresh) {\n return toInitResult(sessionStore.getSessionIfResolved());\n }\n\n if (initPromise) {\n return initPromise;\n }\n\n initPromise = (async () => {\n const session = await loadSession();\n sessionStore.setSession(session);\n publishSession(session);\n return toInitResult(session);\n })();\n\n try {\n return await initPromise;\n } finally {\n initPromise = null;\n }\n };\n}\n\nfunction createRefresh(\n request: <TResponse>(requestOptions: RequestOptions) => Promise<TResponse>,\n sessionStore: SessionStore,\n publishSession: (session: GhostlySession | null) => void,\n): () => Promise<GhostlySession | null> {\n return async () => {\n const payload = await request<unknown>({\n method: \"POST\",\n path: authEndpoints.refresh,\n });\n const session = parseSessionPayload(payload, authEndpoints.refresh);\n sessionStore.setSession(session);\n publishSession(session);\n return session;\n };\n}\n\nfunction createGetAccessToken(\n request: <TResponse>(requestOptions: RequestOptions) => Promise<TResponse>,\n sessionStore: SessionStore,\n publishSession: (session: GhostlySession | null) => void,\n persistAccessToken?: PersistAccessToken,\n restoreAccessToken?: RestoreAccessToken,\n): (requestOptions?: ExtensionAccessTokenRequestOptions) => Promise<ExtensionAccessToken | null> {\n return async (requestOptions?: ExtensionAccessTokenRequestOptions) => {\n const forceRefresh = requestOptions?.forceRefresh ?? false;\n const stored = (await restoreAccessToken?.()) ?? null;\n if (!forceRefresh && isStoredTokenFresh(stored)) {\n if (stored.session) {\n sessionStore.setSession(stored.session);\n }\n return stored;\n }\n\n const payload = await request<unknown>({\n method: \"GET\",\n path: authEndpoints.extensionToken,\n });\n\n if (!isExtensionAccessToken(payload)) {\n throw new AuthSdkError({\n code: authErrorCode.apiError,\n details: null,\n message: `Auth API response has invalid extension token shape: ${authEndpoints.extensionToken}`,\n status: null,\n });\n }\n\n const nextToken: ExtensionStoredAccessToken = {\n accessToken: payload.accessToken,\n application: payload.application,\n expiresAt: payload.expiresAt,\n session: payload.session,\n tokenType: payload.tokenType,\n };\n\n sessionStore.setSession(nextToken.session);\n publishSession(nextToken.session);\n await persistAccessToken?.(nextToken);\n return nextToken;\n };\n}\n\nfunction createLogout(\n request: <TResponse>(requestOptions: RequestOptions) => Promise<TResponse>,\n sessionStore: SessionStore,\n publishSession: (session: GhostlySession | null) => void,\n options: ExtensionAuthClientOptions,\n): () => Promise<void> {\n return async () => {\n await request<null>({\n expectedStatus: httpStatus.noContent,\n method: \"POST\",\n path: authEndpoints.logout,\n });\n await options.clearSessionId?.();\n sessionStore.setSession(null);\n publishSession(null);\n await options.persistAccessToken?.(null);\n };\n}\n\nexport function createCustomExtensionAuthClient(\n options: ExtensionAuthClientOptions,\n): ExtensionAuthClient {\n const sessionStore = new SessionStore();\n const broadcastSync = createSafeBroadcastSync((session) => {\n sessionStore.setSession(session);\n });\n const publishSession = broadcastSync.publishSession.bind(broadcastSync);\n const request = createRequest(options);\n const loadSession = createLoadSession(request);\n const init = createInit(sessionStore, loadSession, publishSession);\n const refresh = createRefresh(request, sessionStore, publishSession);\n const getAccessToken = createGetAccessToken(\n request,\n sessionStore,\n publishSession,\n options.persistAccessToken,\n options.restoreAccessToken,\n );\n const logout = createLogout(request, sessionStore, publishSession, options);\n\n const getSession = async (\n requestOptions?: SessionRequestOptions,\n ): Promise<GhostlySession | null> => {\n const result = await init({\n forceRefresh: requestOptions?.forceRefresh ?? false,\n });\n return result.session;\n };\n\n const requireSession = async (): Promise<GhostlySession> => {\n const session = await getSession();\n if (session) {\n return session;\n }\n\n throw new AuthSdkError({\n code: authErrorCode.unauthorized,\n details: null,\n message: \"Authenticated session is required.\",\n status: httpStatus.unauthorized,\n });\n };\n\n const loginWithTabFlow = async (loginOptions?: LoginOptions): Promise<void> => {\n if (!options.openAuthorizePage) {\n throw new Error(\"Extension auth client requires openAuthorizePage for tab login flow.\");\n }\n\n const returnTo = resolveExtensionReturnToPath(\n loginOptions?.returnTo,\n options.defaultReturnToPath,\n );\n const authorizeUrl = buildAuthorizeUrl(\n options.apiOrigin,\n returnTo,\n loginOptions?.application ?? options.application,\n );\n\n await options.openAuthorizePage({\n authorizeUrl,\n });\n };\n\n const loginWithWebAuthFlow = async (loginOptions?: LoginOptions): Promise<void> => {\n if (!options.launchWebAuthFlow) {\n throw new Error(\"Extension auth client requires launchWebAuthFlow for web auth flow.\");\n }\n\n const returnTo = resolveExtensionReturnToPath(\n loginOptions?.returnTo,\n options.defaultReturnToPath,\n );\n const authorizeUrl = buildAuthorizeUrl(\n options.apiOrigin,\n returnTo,\n loginOptions?.application ?? options.application,\n );\n\n await options.launchWebAuthFlow({\n authorizeUrl,\n });\n await refresh();\n };\n\n return {\n init,\n getSession,\n login(loginOptions?: LoginOptions) {\n if (options.openAuthorizePage) {\n void loginWithTabFlow(loginOptions);\n return;\n }\n\n void loginWithWebAuthFlow(loginOptions);\n },\n logout,\n refresh,\n requireSession,\n subscribe(listener: SessionListener) {\n return sessionStore.subscribe(listener);\n },\n getAccessToken,\n loginWithTabFlow,\n loginWithWebAuthFlow,\n };\n}\n","import {\n createCustomExtensionAuthClient,\n type ExtensionAuthClient,\n type ExtensionAuthClientOptions,\n type ExtensionStoredAccessToken,\n} from \"./auth-client\";\n\ninterface ChromeCookiesApi {\n get(details: { name: string; url: string }): Promise<{ value?: string } | null>;\n remove(details: { name: string; url: string }): Promise<unknown>;\n}\n\ninterface ChromeStorageAreaApi {\n get(keys: string[]): Promise<Record<string, unknown>>;\n remove(keys: string[]): Promise<void>;\n set(items: Record<string, unknown>): Promise<void>;\n}\n\ninterface ChromeTabsApi {\n create(details: { active?: boolean; url: string }): Promise<unknown>;\n}\n\ninterface ChromeRuntimeLike {\n cookies?: ChromeCookiesApi;\n storage?: {\n local?: ChromeStorageAreaApi;\n };\n tabs?: ChromeTabsApi;\n}\n\nexport function hasChromeExtensionRuntime(): boolean {\n const chrome = getChromeRuntime();\n return Boolean(chrome.cookies && chrome.storage?.local && chrome.tabs);\n}\n\nexport interface ChromeExtensionAuthClientOptions\n extends Omit<\n ExtensionAuthClientOptions,\n | \"clearSessionId\"\n | \"openAuthorizePage\"\n | \"persistAccessToken\"\n | \"resolveSessionId\"\n | \"restoreAccessToken\"\n > {\n accessTokenStorageKey?: string;\n sessionCookieName?: string;\n sessionStorageKey?: string;\n tokenExpiresAtStorageKey?: string;\n}\n\nconst defaultSessionCookieName = \"gs_auth_session\";\nconst defaultAccessTokenStorageKey = \"authToken\";\nconst defaultTokenExpiresAtStorageKey = \"authTokenExpiresAt\";\nconst defaultSessionStorageKey = \"authSession\";\nconst defaultExtensionReturnToPath = \"/oauth/complete\";\n\nfunction getChromeRuntime(): ChromeRuntimeLike {\n return (globalThis as { chrome?: ChromeRuntimeLike }).chrome ?? {};\n}\n\nexport function createChromeExtensionAuthClient(\n options: ChromeExtensionAuthClientOptions,\n): ExtensionAuthClient {\n const sessionCookieName = options.sessionCookieName?.trim() || defaultSessionCookieName;\n const accessTokenStorageKey =\n options.accessTokenStorageKey?.trim() || defaultAccessTokenStorageKey;\n const tokenExpiresAtStorageKey =\n options.tokenExpiresAtStorageKey?.trim() || defaultTokenExpiresAtStorageKey;\n const sessionStorageKey = options.sessionStorageKey?.trim() || defaultSessionStorageKey;\n\n const resolveSessionId = async (): Promise<string | null> => {\n const cookies = getChromeRuntime().cookies;\n if (!cookies) {\n return null;\n }\n\n const cookie = await cookies.get({\n name: sessionCookieName,\n url: `${options.apiOrigin}/`,\n });\n return cookie?.value?.trim() || null;\n };\n\n const clearSessionId = async (): Promise<void> => {\n const cookies = getChromeRuntime().cookies;\n if (!cookies) {\n return;\n }\n await cookies.remove({\n name: sessionCookieName,\n url: `${options.apiOrigin}/`,\n });\n };\n\n const persistAccessToken = async (token: ExtensionStoredAccessToken | null): Promise<void> => {\n const storage = getChromeRuntime().storage?.local;\n if (!storage) {\n return;\n }\n\n if (!token) {\n await storage.remove([accessTokenStorageKey, tokenExpiresAtStorageKey, sessionStorageKey]);\n return;\n }\n\n await storage.set({\n [accessTokenStorageKey]: token.accessToken,\n [tokenExpiresAtStorageKey]: token.expiresAt || null,\n [sessionStorageKey]: token.session || null,\n });\n };\n\n const restoreAccessToken = async (): Promise<ExtensionStoredAccessToken | null> => {\n const storage = getChromeRuntime().storage?.local;\n if (!storage) {\n return null;\n }\n\n const stored = await storage.get([\n accessTokenStorageKey,\n tokenExpiresAtStorageKey,\n sessionStorageKey,\n ]);\n\n const rawAccessToken = stored[accessTokenStorageKey];\n if (typeof rawAccessToken !== \"string\" || rawAccessToken.trim() === \"\") {\n return null;\n }\n\n return {\n accessToken: rawAccessToken,\n application: options.application?.trim() || \"\",\n expiresAt:\n typeof stored[tokenExpiresAtStorageKey] === \"string\"\n ? stored[tokenExpiresAtStorageKey]\n : null,\n session: (stored[sessionStorageKey] as ExtensionStoredAccessToken[\"session\"]) ?? null,\n tokenType: \"Bearer\",\n };\n };\n\n const openAuthorizePage = async ({ authorizeUrl }: { authorizeUrl: string }): Promise<void> => {\n const tabs = getChromeRuntime().tabs;\n if (!tabs) {\n throw new Error(\"Chrome tabs API is unavailable.\");\n }\n await tabs.create({ active: true, url: authorizeUrl });\n };\n\n return createCustomExtensionAuthClient({\n ...options,\n defaultReturnToPath: options.defaultReturnToPath?.trim() || defaultExtensionReturnToPath,\n clearSessionId,\n openAuthorizePage,\n persistAccessToken,\n resolveSessionId,\n restoreAccessToken,\n });\n}\n","export type {\n ExtensionAccessToken,\n ExtensionAccessTokenRequestOptions,\n ExtensionAuthClient,\n ExtensionAuthClientOptions,\n ExtensionStoredAccessToken,\n} from \"./adapters/extension/auth-client\";\n\nimport {\n createCustomExtensionAuthClient,\n type ExtensionAuthClient,\n type ExtensionAuthClientOptions,\n} from \"./adapters/extension/auth-client\";\nimport {\n type ChromeExtensionAuthClientOptions,\n createChromeExtensionAuthClient,\n hasChromeExtensionRuntime,\n} from \"./adapters/extension/chrome-auth-client\";\nimport { AuthSdkError } from \"./errors/auth-sdk-error\";\nimport { authErrorCode } from \"./types/auth-error-code\";\n\nexport type { ChromeExtensionAuthClientOptions } from \"./adapters/extension/chrome-auth-client\";\nexport { createChromeExtensionAuthClient, createCustomExtensionAuthClient };\n\nfunction hasCustomExtensionHooks(options: ExtensionAuthClientOptions): boolean {\n return Boolean(\n options.clearSessionId ||\n options.launchWebAuthFlow ||\n options.openAuthorizePage ||\n options.persistAccessToken ||\n options.resolveSessionId ||\n options.restoreAccessToken,\n );\n}\n\nexport function createExtensionAuthClient(\n options: ExtensionAuthClientOptions | ChromeExtensionAuthClientOptions,\n): ExtensionAuthClient {\n if (hasChromeExtensionRuntime()) {\n return createChromeExtensionAuthClient(options);\n }\n\n if (hasCustomExtensionHooks(options)) {\n return createCustomExtensionAuthClient(options);\n }\n\n throw new AuthSdkError({\n code: authErrorCode.apiError,\n details: null,\n message:\n \"No supported extension runtime detected. Chromium browsers are supported automatically. Safari requires a dedicated adapter or explicit custom hooks.\",\n status: null,\n });\n}\n"]}
|
|
@@ -76,9 +76,9 @@ If session is missing, helper triggers `login()` and redirects browser.
|
|
|
76
76
|
## 6. Extension Integration
|
|
77
77
|
|
|
78
78
|
```ts
|
|
79
|
-
import {
|
|
79
|
+
import { createExtensionAuthClient } from "@ghostly-solutions/auth/extension";
|
|
80
80
|
|
|
81
|
-
const auth =
|
|
81
|
+
const auth = createExtensionAuthClient({
|
|
82
82
|
apiOrigin: "https://auth.ghostlysolutions.com",
|
|
83
83
|
application: "extension",
|
|
84
84
|
});
|
|
@@ -91,7 +91,7 @@ if (!session) {
|
|
|
91
91
|
}
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
-
`
|
|
94
|
+
`createExtensionAuthClient()` is the preferred extension entrypoint. In Chromium browsers like Chrome, Edge, Brave, and Opera it automatically manages:
|
|
95
95
|
|
|
96
96
|
- `chrome.tabs.create(...)` for login tab flow
|
|
97
97
|
- `chrome.cookies` access for `gs_auth_session`
|
|
@@ -99,7 +99,7 @@ if (!session) {
|
|
|
99
99
|
|
|
100
100
|
`loginWithTabFlow()` opens the authorize URL in a regular browser tab and relies on later `init()` / `getSession()` calls to observe the server-owned session.
|
|
101
101
|
|
|
102
|
-
`
|
|
102
|
+
If you need an explicit browser-specific override, `createChromeExtensionAuthClient()` remains available. For non-Chromium runtimes, `createCustomExtensionAuthClient()` can be used with explicit hooks such as `launchWebAuthFlow(...)`.
|
|
103
103
|
|
|
104
104
|
## 7. Error Handling
|
|
105
105
|
|
package/extension.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./dist/extension.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ghostly-solutions/auth",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Authentication SDK for Ghostly Solutions products using OAuth redirect and Ghostly Auth API session validation.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"sideEffects": false,
|
|
20
20
|
"files": [
|
|
21
21
|
"dist",
|
|
22
|
+
"extension.js",
|
|
22
23
|
"react-client.js",
|
|
23
24
|
"README.md",
|
|
24
25
|
"docs"
|
|
@@ -45,8 +46,8 @@
|
|
|
45
46
|
},
|
|
46
47
|
"./extension": {
|
|
47
48
|
"types": "./dist/extension.d.ts",
|
|
48
|
-
"import": "./
|
|
49
|
-
"default": "./
|
|
49
|
+
"import": "./extension.js",
|
|
50
|
+
"default": "./extension.js"
|
|
50
51
|
}
|
|
51
52
|
},
|
|
52
53
|
"publishConfig": {
|