@kortix/sdk 0.13.5 → 0.13.9
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 +69 -6
- package/dist/browser/session-sync/server-transcript-mirror.d.ts +82 -0
- package/dist/browser/session-sync/server-transcript-mirror.d.ts.map +1 -0
- package/dist/browser/session-sync/server-transcript-mirror.js +143 -0
- package/dist/browser/session-sync/server-transcript-mirror.js.map +1 -0
- package/dist/browser/session-sync/session-sync-registry.d.ts +11 -21
- package/dist/browser/session-sync/session-sync-registry.d.ts.map +1 -1
- package/dist/browser/session-sync/session-sync-registry.js +48 -3
- package/dist/browser/session-sync/session-sync-registry.js.map +1 -1
- package/dist/browser/stores/sandbox-connection-store.d.ts +13 -1
- package/dist/browser/stores/sandbox-connection-store.d.ts.map +1 -1
- package/dist/browser/stores/sandbox-connection-store.js +5 -2
- package/dist/browser/stores/sandbox-connection-store.js.map +1 -1
- package/dist/browser/stores/session-working-store.d.ts +10 -5
- package/dist/browser/stores/session-working-store.d.ts.map +1 -1
- package/dist/browser/stores/session-working-store.js +32 -8
- package/dist/browser/stores/session-working-store.js.map +1 -1
- package/dist/browser/stores/sync-store.d.ts +29 -1
- package/dist/browser/stores/sync-store.d.ts.map +1 -1
- package/dist/browser/stores/sync-store.js +516 -393
- package/dist/browser/stores/sync-store.js.map +1 -1
- package/dist/core/auth/app-viewer.d.ts +57 -0
- package/dist/core/auth/app-viewer.d.ts.map +1 -0
- package/dist/core/auth/app-viewer.js +82 -0
- package/dist/core/auth/app-viewer.js.map +1 -0
- package/dist/core/auth/session.d.ts +45 -0
- package/dist/core/auth/session.d.ts.map +1 -0
- package/dist/core/auth/session.js +113 -0
- package/dist/core/auth/session.js.map +1 -0
- package/dist/core/client/kortix.d.ts +37 -18
- package/dist/core/client/kortix.d.ts.map +1 -1
- package/dist/core/client/kortix.js +47 -0
- package/dist/core/client/kortix.js.map +1 -1
- package/dist/core/http/config.d.ts +4 -2
- package/dist/core/http/config.d.ts.map +1 -1
- package/dist/core/http/config.js.map +1 -1
- package/dist/core/http/opencode-errors.d.ts +17 -0
- package/dist/core/http/opencode-errors.d.ts.map +1 -1
- package/dist/core/http/opencode-errors.js +25 -0
- package/dist/core/http/opencode-errors.js.map +1 -1
- package/dist/core/rest/platform-client/auth.d.ts +120 -0
- package/dist/core/rest/platform-client/auth.d.ts.map +1 -0
- package/dist/core/rest/platform-client/auth.js +98 -0
- package/dist/core/rest/platform-client/auth.js.map +1 -0
- package/dist/core/rest/platform-client/host-boundary.d.ts +5 -0
- package/dist/core/rest/platform-client/host-boundary.d.ts.map +1 -1
- package/dist/core/rest/platform-client/host-boundary.js.map +1 -1
- package/dist/core/rest/projects-client/accounts.d.ts +57 -0
- package/dist/core/rest/projects-client/accounts.d.ts.map +1 -1
- package/dist/core/rest/projects-client/accounts.js +31 -0
- package/dist/core/rest/projects-client/accounts.js.map +1 -1
- package/dist/core/rest/projects-client/apps.d.ts +9 -0
- package/dist/core/rest/projects-client/apps.d.ts.map +1 -1
- package/dist/core/rest/projects-client/apps.js.map +1 -1
- package/dist/core/rest/projects-client/billing.d.ts +2 -0
- package/dist/core/rest/projects-client/billing.d.ts.map +1 -1
- package/dist/core/rest/projects-client/billing.js.map +1 -1
- package/dist/core/rest/projects-client/connectors.d.ts +104 -19
- package/dist/core/rest/projects-client/connectors.d.ts.map +1 -1
- package/dist/core/rest/projects-client/connectors.js +56 -2
- package/dist/core/rest/projects-client/connectors.js.map +1 -1
- package/dist/core/rest/projects-client/index.d.ts +1 -0
- package/dist/core/rest/projects-client/index.d.ts.map +1 -1
- package/dist/core/rest/projects-client/index.js +1 -0
- package/dist/core/rest/projects-client/index.js.map +1 -1
- package/dist/core/rest/projects-client/oauth-clients.d.ts +47 -0
- package/dist/core/rest/projects-client/oauth-clients.d.ts.map +1 -0
- package/dist/core/rest/projects-client/oauth-clients.js +33 -0
- package/dist/core/rest/projects-client/oauth-clients.js.map +1 -0
- package/dist/core/rest/projects-client/projects.d.ts +23 -6
- package/dist/core/rest/projects-client/projects.d.ts.map +1 -1
- package/dist/core/rest/projects-client/projects.js +1 -0
- package/dist/core/rest/projects-client/projects.js.map +1 -1
- package/dist/core/rest/projects-client/session-sandbox.d.ts +52 -0
- package/dist/core/rest/projects-client/session-sandbox.d.ts.map +1 -1
- package/dist/core/rest/projects-client/session-sandbox.js.map +1 -1
- package/dist/core/rest/projects-client/sessions.d.ts +134 -1
- package/dist/core/rest/projects-client/sessions.d.ts.map +1 -1
- package/dist/core/rest/projects-client/sessions.js +47 -1
- package/dist/core/rest/projects-client/sessions.js.map +1 -1
- package/dist/core/session/index.d.ts +1 -0
- package/dist/core/session/index.d.ts.map +1 -1
- package/dist/core/session/index.js +1 -0
- package/dist/core/session/index.js.map +1 -1
- package/dist/core/session/open-bundle.d.ts +110 -0
- package/dist/core/session/open-bundle.d.ts.map +1 -0
- package/dist/core/session/open-bundle.js +183 -0
- package/dist/core/session/open-bundle.js.map +1 -0
- package/dist/core/session/poll-owner.d.ts +35 -0
- package/dist/core/session/poll-owner.d.ts.map +1 -0
- package/dist/core/session/poll-owner.js +90 -0
- package/dist/core/session/poll-owner.js.map +1 -0
- package/dist/core/session/static-file-preview.d.ts +50 -0
- package/dist/core/session/static-file-preview.d.ts.map +1 -0
- package/dist/core/session/static-file-preview.js +91 -0
- package/dist/core/session/static-file-preview.js.map +1 -0
- package/dist/core/session/wake-escalation.d.ts +188 -0
- package/dist/core/session/wake-escalation.d.ts.map +1 -0
- package/dist/core/session/wake-escalation.js +241 -0
- package/dist/core/session/wake-escalation.js.map +1 -0
- package/dist/core/session/working.d.ts +63 -2
- package/dist/core/session/working.d.ts.map +1 -1
- package/dist/core/session/working.js +66 -9
- package/dist/core/session/working.js.map +1 -1
- package/dist/core/session-sync/session-sync-controller.d.ts +34 -2
- package/dist/core/session-sync/session-sync-controller.d.ts.map +1 -1
- package/dist/core/session-sync/session-sync-controller.js +97 -11
- package/dist/core/session-sync/session-sync-controller.js.map +1 -1
- package/dist/core/stream/keepalive.d.ts +17 -0
- package/dist/core/stream/keepalive.d.ts.map +1 -0
- package/dist/core/stream/keepalive.js +19 -0
- package/dist/core/stream/keepalive.js.map +1 -0
- package/dist/core/turns/grouping.d.ts.map +1 -1
- package/dist/core/turns/grouping.js +13 -0
- package/dist/core/turns/grouping.js.map +1 -1
- package/dist/core/turns/types.d.ts +5 -0
- package/dist/core/turns/types.d.ts.map +1 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -1
- package/dist/kortix.esm.min.js +25 -25
- package/dist/kortix.global.js +25 -25
- package/dist/node/app-viewer.d.ts +41 -0
- package/dist/node/app-viewer.d.ts.map +1 -0
- package/dist/node/app-viewer.js +150 -0
- package/dist/node/app-viewer.js.map +1 -0
- package/dist/node/auth.d.ts +84 -0
- package/dist/node/auth.d.ts.map +1 -0
- package/dist/node/auth.js +414 -0
- package/dist/node/auth.js.map +1 -0
- package/dist/node/server.d.ts +19 -0
- package/dist/node/server.d.ts.map +1 -1
- package/dist/node/server.js +13 -1
- package/dist/node/server.js.map +1 -1
- package/dist/react/bedrock-invokable.d.ts +58 -0
- package/dist/react/bedrock-invokable.d.ts.map +1 -0
- package/dist/react/bedrock-invokable.js +83 -0
- package/dist/react/bedrock-invokable.js.map +1 -0
- package/dist/react/index.d.ts +3 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +7 -0
- package/dist/react/index.js.map +1 -1
- package/dist/react/model-flatten.d.ts +14 -1
- package/dist/react/model-flatten.d.ts.map +1 -1
- package/dist/react/model-flatten.js +3 -4
- package/dist/react/model-flatten.js.map +1 -1
- package/dist/react/opencode.d.ts +2 -1
- package/dist/react/opencode.d.ts.map +1 -1
- package/dist/react/opencode.js +2 -1
- package/dist/react/opencode.js.map +1 -1
- package/dist/react/provider-selection.d.ts +58 -0
- package/dist/react/provider-selection.d.ts.map +1 -1
- package/dist/react/provider-selection.js +253 -2
- package/dist/react/provider-selection.js.map +1 -1
- package/dist/react/session-start-giveup.d.ts +12 -0
- package/dist/react/session-start-giveup.d.ts.map +1 -0
- package/dist/react/session-start-giveup.js +13 -0
- package/dist/react/session-start-giveup.js.map +1 -0
- package/dist/react/session-title-sync.d.ts.map +1 -1
- package/dist/react/session-title-sync.js +15 -5
- package/dist/react/session-title-sync.js.map +1 -1
- package/dist/react/sign-in-with-kortix.d.ts +346 -0
- package/dist/react/sign-in-with-kortix.d.ts.map +1 -0
- package/dist/react/sign-in-with-kortix.js +65 -0
- package/dist/react/sign-in-with-kortix.js.map +1 -0
- package/dist/react/use-admin-accounts.d.ts +1 -1
- package/dist/react/use-admin-accounts.d.ts.map +1 -1
- package/dist/react/use-admin-accounts.js +1 -0
- package/dist/react/use-admin-accounts.js.map +1 -1
- package/dist/react/use-gateway-routing-policy.d.ts +1 -0
- package/dist/react/use-gateway-routing-policy.d.ts.map +1 -1
- package/dist/react/use-gateway-routing-policy.js +12 -1
- package/dist/react/use-gateway-routing-policy.js.map +1 -1
- package/dist/react/use-kortix-app-viewer.d.ts +13 -0
- package/dist/react/use-kortix-app-viewer.d.ts.map +1 -0
- package/dist/react/use-kortix-app-viewer.js +29 -0
- package/dist/react/use-kortix-app-viewer.js.map +1 -0
- package/dist/react/use-model-defaults.d.ts +7 -0
- package/dist/react/use-model-defaults.d.ts.map +1 -1
- package/dist/react/use-model-defaults.js +7 -1
- package/dist/react/use-model-defaults.js.map +1 -1
- package/dist/react/use-model-enablement.d.ts.map +1 -1
- package/dist/react/use-model-enablement.js +5 -1
- package/dist/react/use-model-enablement.js.map +1 -1
- package/dist/react/use-model-store.d.ts +31 -0
- package/dist/react/use-model-store.d.ts.map +1 -1
- package/dist/react/use-model-store.js +31 -2
- package/dist/react/use-model-store.js.map +1 -1
- package/dist/react/use-opencode-events/helpers.d.ts +49 -5
- package/dist/react/use-opencode-events/helpers.d.ts.map +1 -1
- package/dist/react/use-opencode-events/helpers.js +54 -6
- package/dist/react/use-opencode-events/helpers.js.map +1 -1
- package/dist/react/use-opencode-events/index.d.ts.map +1 -1
- package/dist/react/use-opencode-events/index.js +22 -3
- package/dist/react/use-opencode-events/index.js.map +1 -1
- package/dist/react/use-opencode-events/use-event-stream-refs.d.ts.map +1 -1
- package/dist/react/use-opencode-events/use-event-stream-refs.js +14 -2
- package/dist/react/use-opencode-events/use-event-stream-refs.js.map +1 -1
- package/dist/react/use-opencode-local.d.ts.map +1 -1
- package/dist/react/use-opencode-local.js +27 -8
- package/dist/react/use-opencode-local.js.map +1 -1
- package/dist/react/use-opencode-sessions/providers.d.ts.map +1 -1
- package/dist/react/use-opencode-sessions/providers.js +44 -3
- package/dist/react/use-opencode-sessions/providers.js.map +1 -1
- package/dist/react/use-poll-owner.d.ts +14 -0
- package/dist/react/use-poll-owner.d.ts.map +1 -0
- package/dist/react/use-poll-owner.js +32 -0
- package/dist/react/use-poll-owner.js.map +1 -0
- package/dist/react/use-project-llm-gateway.d.ts +27 -0
- package/dist/react/use-project-llm-gateway.d.ts.map +1 -0
- package/dist/react/use-project-llm-gateway.js +41 -0
- package/dist/react/use-project-llm-gateway.js.map +1 -0
- package/dist/react/use-project-models.d.ts +9 -0
- package/dist/react/use-project-models.d.ts.map +1 -1
- package/dist/react/use-project-models.js +24 -1
- package/dist/react/use-project-models.js.map +1 -1
- package/dist/react/use-runtime-reconnect.d.ts +11 -0
- package/dist/react/use-runtime-reconnect.d.ts.map +1 -1
- package/dist/react/use-runtime-reconnect.js +34 -3
- package/dist/react/use-runtime-reconnect.js.map +1 -1
- package/dist/react/use-session-prompts.d.ts +16 -1
- package/dist/react/use-session-prompts.d.ts.map +1 -1
- package/dist/react/use-session-prompts.js +76 -11
- package/dist/react/use-session-prompts.js.map +1 -1
- package/dist/react/use-session-send.d.ts.map +1 -1
- package/dist/react/use-session-send.js +14 -1
- package/dist/react/use-session-send.js.map +1 -1
- package/dist/react/use-session-start-give-up.d.ts +20 -0
- package/dist/react/use-session-start-give-up.d.ts.map +1 -0
- package/dist/react/use-session-start-give-up.js +60 -0
- package/dist/react/use-session-start-give-up.js.map +1 -0
- package/dist/react/use-session-sync.d.ts +22 -0
- package/dist/react/use-session-sync.d.ts.map +1 -1
- package/dist/react/use-session-sync.js +61 -5
- package/dist/react/use-session-sync.js.map +1 -1
- package/dist/react/use-session-working.d.ts +38 -0
- package/dist/react/use-session-working.d.ts.map +1 -1
- package/dist/react/use-session-working.js +81 -10
- package/dist/react/use-session-working.js.map +1 -1
- package/dist/react/use-session.d.ts +13 -13
- package/dist/react/use-session.d.ts.map +1 -1
- package/dist/react/use-session.js +74 -53
- package/dist/react/use-session.js.map +1 -1
- package/dist/react/use-static-file-preview.d.ts +12 -0
- package/dist/react/use-static-file-preview.d.ts.map +1 -0
- package/dist/react/use-static-file-preview.js +119 -0
- package/dist/react/use-static-file-preview.js.map +1 -0
- package/dist/react/use-wake-escalation.d.ts +51 -0
- package/dist/react/use-wake-escalation.d.ts.map +1 -0
- package/dist/react/use-wake-escalation.js +62 -0
- package/dist/react/use-wake-escalation.js.map +1 -0
- package/package.json +6 -4
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Kortix } from '../core/client/kortix.js';
|
|
2
|
+
export declare const APP_VIEWER_HEADER = "x-kortix-app-viewer";
|
|
3
|
+
export declare const APP_VIEWER_TOKEN_HEADER = "x-kortix-app-viewer-token";
|
|
4
|
+
export declare const APP_VIEWER_SECRET_ENV = "KORTIX_APP_VIEWER_SECRET";
|
|
5
|
+
export interface KortixAppViewer {
|
|
6
|
+
userId: string;
|
|
7
|
+
email: string | null;
|
|
8
|
+
groupIds: string[];
|
|
9
|
+
accountId: string;
|
|
10
|
+
appId: string;
|
|
11
|
+
/** The App's access mode when the gate authorized this request. */
|
|
12
|
+
accessMode: string;
|
|
13
|
+
/** The viewer's App-scoped Kortix bearer, or null for an identity-only App. */
|
|
14
|
+
token: string | null;
|
|
15
|
+
/** When the signed identity expires (the gate re-signs on every request). */
|
|
16
|
+
expiresAt: Date;
|
|
17
|
+
}
|
|
18
|
+
export interface ReadAppViewerOptions {
|
|
19
|
+
/** Defaults to `process.env.KORTIX_APP_VIEWER_SECRET`. */
|
|
20
|
+
secret?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The verified Kortix viewer behind this request, or `null` when there is none
|
|
24
|
+
* (a public App, a signed-out visitor, or no secret configured).
|
|
25
|
+
*/
|
|
26
|
+
export declare function readAppViewer(request: Request, options?: ReadAppViewerOptions): Promise<KortixAppViewer | null>;
|
|
27
|
+
export declare class AppViewerUnavailableError extends Error {
|
|
28
|
+
readonly code: 'no_viewer' | 'identity_only';
|
|
29
|
+
constructor(code: 'no_viewer' | 'identity_only', message: string);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A request-scoped Kortix client acting AS this App's viewer.
|
|
33
|
+
*
|
|
34
|
+
* Needs the App to be API-scoped (`viewer_token_scope: 'api'` — Kortix web:
|
|
35
|
+
* the App's Access panel). Throws `AppViewerUnavailableError` otherwise, so a
|
|
36
|
+
* misconfigured App fails loudly instead of quietly acting as nobody.
|
|
37
|
+
*/
|
|
38
|
+
export declare function createAppViewerKortix(request: Request, options: {
|
|
39
|
+
backendUrl: string;
|
|
40
|
+
} & ReadAppViewerOptions): Promise<Kortix>;
|
|
41
|
+
//# sourceMappingURL=app-viewer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-viewer.d.ts","sourceRoot":"","sources":["../../src/node/app-viewer.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAEpD,eAAO,MAAM,iBAAiB,wBAAwB,CAAC;AACvD,eAAO,MAAM,uBAAuB,8BAA8B,CAAC;AACnE,eAAO,MAAM,qBAAqB,6BAA6B,CAAC;AAEhE,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,6EAA6E;IAC7E,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAyCD;;;GAGG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAwDjC;AAED,qBAAa,yBAA0B,SAAQ,KAAK;aAEhC,IAAI,EAAE,WAAW,GAAG,eAAe;gBAAnC,IAAI,EAAE,WAAW,GAAG,eAAe,EACnD,OAAO,EAAE,MAAM;CAKlB;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,oBAAoB,GACrD,OAAO,CAAC,MAAM,CAAC,CAiBjB"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kortix Apps — the viewer, on the App's server.
|
|
3
|
+
*
|
|
4
|
+
* The Apps gate signs an identity into every proxied request
|
|
5
|
+
* (`x-kortix-app-viewer`) and, for an API-scoped App, the viewer's token
|
|
6
|
+
* alongside it (`x-kortix-app-viewer-token`). An App verifies the first with
|
|
7
|
+
* the per-App secret Kortix injects at deploy (`KORTIX_APP_VIEWER_SECRET`) and
|
|
8
|
+
* knows exactly who is looking — with no login of its own and no round trip:
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* const viewer = await readAppViewer(request);
|
|
12
|
+
* if (!viewer) return new Response('Not found', { status: 404 });
|
|
13
|
+
* const dashboards = await listFor(viewer.userId, viewer.groupIds);
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* and, when the App may act as them on the Kortix API:
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* const kortix = await createAppViewerKortix(request, { backendUrl });
|
|
20
|
+
* await kortix.projects.list(); // as the viewer, with the viewer's role
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* A forged header cannot survive: the gate deletes any client-supplied copy
|
|
24
|
+
* before forwarding, and this function refuses anything the App's own secret
|
|
25
|
+
* does not sign. With no secret configured it returns `null` — an App never
|
|
26
|
+
* trusts an unverified identity.
|
|
27
|
+
*/
|
|
28
|
+
import { createScopedKortix } from './server.js';
|
|
29
|
+
export const APP_VIEWER_HEADER = 'x-kortix-app-viewer';
|
|
30
|
+
export const APP_VIEWER_TOKEN_HEADER = 'x-kortix-app-viewer-token';
|
|
31
|
+
export const APP_VIEWER_SECRET_ENV = 'KORTIX_APP_VIEWER_SECRET';
|
|
32
|
+
function envSecret() {
|
|
33
|
+
const env = globalThis.process?.env;
|
|
34
|
+
return env?.[APP_VIEWER_SECRET_ENV];
|
|
35
|
+
}
|
|
36
|
+
function fromB64url(value) {
|
|
37
|
+
const padded = value.replace(/-/g, '+').replace(/_/g, '/') + '='.repeat((4 - (value.length % 4)) % 4);
|
|
38
|
+
const bin = atob(padded);
|
|
39
|
+
const out = new Uint8Array(bin.length);
|
|
40
|
+
for (let i = 0; i < bin.length; i += 1)
|
|
41
|
+
out[i] = bin.charCodeAt(i);
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
44
|
+
function b64url(bytes) {
|
|
45
|
+
let s = '';
|
|
46
|
+
for (const b of bytes)
|
|
47
|
+
s += String.fromCharCode(b);
|
|
48
|
+
return btoa(s).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
49
|
+
}
|
|
50
|
+
/** Length-independent compare — never returns early on the first differing byte. */
|
|
51
|
+
function equal(a, b) {
|
|
52
|
+
if (a.length !== b.length)
|
|
53
|
+
return false;
|
|
54
|
+
let diff = 0;
|
|
55
|
+
for (let i = 0; i < a.length; i += 1)
|
|
56
|
+
diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
57
|
+
return diff === 0;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The verified Kortix viewer behind this request, or `null` when there is none
|
|
61
|
+
* (a public App, a signed-out visitor, or no secret configured).
|
|
62
|
+
*/
|
|
63
|
+
export async function readAppViewer(request, options = {}) {
|
|
64
|
+
const secret = options.secret ?? envSecret();
|
|
65
|
+
if (!secret)
|
|
66
|
+
return null;
|
|
67
|
+
const raw = request.headers.get(APP_VIEWER_HEADER);
|
|
68
|
+
if (!raw)
|
|
69
|
+
return null;
|
|
70
|
+
const [payloadB64, sig, extra] = raw.split('.');
|
|
71
|
+
if (!payloadB64 || !sig || extra)
|
|
72
|
+
return null;
|
|
73
|
+
const key = await crypto.subtle.importKey('raw', new TextEncoder().encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
|
|
74
|
+
const message = new TextEncoder().encode(`kortix-app-viewer:v1\0${payloadB64}`);
|
|
75
|
+
const expected = b64url(new Uint8Array(await crypto.subtle.sign('HMAC', key, message)));
|
|
76
|
+
if (!equal(sig, expected))
|
|
77
|
+
return null;
|
|
78
|
+
let payload;
|
|
79
|
+
try {
|
|
80
|
+
payload = JSON.parse(new TextDecoder().decode(fromB64url(payloadB64)));
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
if (payload.v !== 1 || typeof payload.userId !== 'string' || !payload.userId)
|
|
86
|
+
return null;
|
|
87
|
+
if (typeof payload.exp !== 'number' || payload.exp * 1000 <= Date.now())
|
|
88
|
+
return null;
|
|
89
|
+
/*
|
|
90
|
+
* A malformed field is refused, never coerced.
|
|
91
|
+
*
|
|
92
|
+
* Reading a non-array `groupIds` as `[]` would hand the App a viewer with
|
|
93
|
+
* their group memberships silently missing — which reads to the App as "this
|
|
94
|
+
* person is in no groups" and quietly removes whatever group grants gave
|
|
95
|
+
* them. No viewer at all is the honest answer, and the one an App is already
|
|
96
|
+
* written to handle. (Found from the consumer side: essentia-dashboards
|
|
97
|
+
* asserts that a signed payload which is not a statement about a person is
|
|
98
|
+
* refused.)
|
|
99
|
+
*/
|
|
100
|
+
if (payload.groupIds !== undefined) {
|
|
101
|
+
if (!Array.isArray(payload.groupIds))
|
|
102
|
+
return null;
|
|
103
|
+
if (payload.groupIds.some((id) => typeof id !== 'string'))
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
if (payload.email !== undefined && payload.email !== null && typeof payload.email !== 'string') {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
userId: payload.userId,
|
|
111
|
+
email: payload.email ?? null,
|
|
112
|
+
groupIds: payload.groupIds ?? [],
|
|
113
|
+
accountId: payload.accountId,
|
|
114
|
+
appId: payload.appId,
|
|
115
|
+
accessMode: payload.accessMode,
|
|
116
|
+
token: request.headers.get(APP_VIEWER_TOKEN_HEADER),
|
|
117
|
+
expiresAt: new Date(payload.exp * 1000),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
export class AppViewerUnavailableError extends Error {
|
|
121
|
+
code;
|
|
122
|
+
constructor(code, message) {
|
|
123
|
+
super(message);
|
|
124
|
+
this.code = code;
|
|
125
|
+
this.name = 'AppViewerUnavailableError';
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* A request-scoped Kortix client acting AS this App's viewer.
|
|
130
|
+
*
|
|
131
|
+
* Needs the App to be API-scoped (`viewer_token_scope: 'api'` — Kortix web:
|
|
132
|
+
* the App's Access panel). Throws `AppViewerUnavailableError` otherwise, so a
|
|
133
|
+
* misconfigured App fails loudly instead of quietly acting as nobody.
|
|
134
|
+
*/
|
|
135
|
+
export async function createAppViewerKortix(request, options) {
|
|
136
|
+
const viewer = await readAppViewer(request, options);
|
|
137
|
+
if (!viewer) {
|
|
138
|
+
throw new AppViewerUnavailableError('no_viewer', 'No verified Kortix viewer on this request');
|
|
139
|
+
}
|
|
140
|
+
if (!viewer.token) {
|
|
141
|
+
throw new AppViewerUnavailableError('identity_only', "This App carries viewer identity but no API token — set its access policy to viewer_token_scope: 'api' to act as the viewer.");
|
|
142
|
+
}
|
|
143
|
+
const token = viewer.token;
|
|
144
|
+
return createScopedKortix({
|
|
145
|
+
backendUrl: options.backendUrl,
|
|
146
|
+
getToken: async () => token,
|
|
147
|
+
clientSource: 'web',
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=app-viewer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-viewer.js","sourceRoot":"","sources":["../../src/node/app-viewer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { Kortix } from '../core/client/kortix.js';
|
|
2
|
+
import type { AccountIdentity } from '../core/rest/projects-client/accounts.js';
|
|
3
|
+
/** The subset of `fetch` the kit needs — assignable from any fetch-shaped function. */
|
|
4
|
+
export type KortixFetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
5
|
+
export interface KortixAuthOptions {
|
|
6
|
+
/** Kortix API base incl. version prefix, e.g. `https://api.kortix.com/v1`. */
|
|
7
|
+
backendUrl: string;
|
|
8
|
+
/** The OAuth client id from Account → Tokens → OAuth apps. */
|
|
9
|
+
clientId: string;
|
|
10
|
+
/** The client secret. Omit for a `public` client (PKCE only). */
|
|
11
|
+
clientSecret?: string;
|
|
12
|
+
/** Absolute callback URL, byte-identical to one registered on the client. */
|
|
13
|
+
redirectUri: string;
|
|
14
|
+
/** ≥ 32 characters. Encrypts the session cookie (AES-256-GCM, key = SHA-256 of this). */
|
|
15
|
+
cookieSecret: string;
|
|
16
|
+
/** Scopes to request. Default: `profile email kortix` (`kortix` = act as the user on the API). */
|
|
17
|
+
scopes?: string[];
|
|
18
|
+
/** Mount path of `handler()`. Default: the redirect URI's path minus `/callback`. */
|
|
19
|
+
basePath?: string;
|
|
20
|
+
/** How long a signed-in session may live without a fresh sign-in. Default 30 days (the refresh-token lifetime). */
|
|
21
|
+
sessionTtlSeconds?: number;
|
|
22
|
+
/** Custom `fetch` (tests, edge adapters). */
|
|
23
|
+
fetch?: KortixFetch;
|
|
24
|
+
/** Clock, for tests. */
|
|
25
|
+
now?: () => number;
|
|
26
|
+
}
|
|
27
|
+
export interface KortixViewer {
|
|
28
|
+
userId: string;
|
|
29
|
+
email: string;
|
|
30
|
+
accounts: AccountIdentity['accounts'];
|
|
31
|
+
/** Scopes the user granted this app. */
|
|
32
|
+
scopes: string[];
|
|
33
|
+
/** The viewer's access token — pass it to `createScopedKortix` or send it as a bearer. */
|
|
34
|
+
token: string;
|
|
35
|
+
/** Epoch milliseconds when `token` expires. */
|
|
36
|
+
expiresAt: number;
|
|
37
|
+
}
|
|
38
|
+
export type RequireViewerResult = {
|
|
39
|
+
viewer: KortixViewer;
|
|
40
|
+
response?: undefined;
|
|
41
|
+
} | {
|
|
42
|
+
viewer?: undefined;
|
|
43
|
+
response: Response;
|
|
44
|
+
};
|
|
45
|
+
export interface KortixAuth {
|
|
46
|
+
/** The mount path every link and cookie assumes (e.g. `/api/kortix/auth`). */
|
|
47
|
+
readonly basePath: string;
|
|
48
|
+
/**
|
|
49
|
+
* The one route. Mount it as a catch-all under `basePath` for every method:
|
|
50
|
+
* `/signin`, `/callback`, `/refresh`, `/signout`, `/me`, `/proxy/*`.
|
|
51
|
+
*/
|
|
52
|
+
handler(request: Request): Promise<Response>;
|
|
53
|
+
/** The signed-in viewer, or `null`. Read-only: never rotates a refresh token. */
|
|
54
|
+
viewer(request: Request): Promise<KortixViewer | null>;
|
|
55
|
+
/** The viewer, or the redirect (`/refresh` when refreshable, else `/signin`) to return from middleware. */
|
|
56
|
+
requireViewer(request: Request): Promise<RequireViewerResult>;
|
|
57
|
+
/** A request-scoped SDK client acting as the viewer. Throws `KortixAuthError` when signed out. */
|
|
58
|
+
kortix(request: Request): Promise<Kortix>;
|
|
59
|
+
/** Link target that starts sign-in and returns to `returnTo` (a same-origin path). */
|
|
60
|
+
signInUrl(returnTo?: string): string;
|
|
61
|
+
/** Link target that signs out and lands on `returnTo`. */
|
|
62
|
+
signOutUrl(returnTo?: string): string;
|
|
63
|
+
/**
|
|
64
|
+
* `createKortix` config for the browser: `backendUrl` is this app's
|
|
65
|
+
* `/proxy`, and `getToken` yields a sentinel the proxy swaps for the
|
|
66
|
+
* viewer's real token. `origin` defaults to `window.location.origin`.
|
|
67
|
+
*/
|
|
68
|
+
clientConfig(origin?: string): {
|
|
69
|
+
backendUrl: string;
|
|
70
|
+
getToken: () => Promise<string>;
|
|
71
|
+
};
|
|
72
|
+
/** @internal test seam */
|
|
73
|
+
__setNow(now: () => number): void;
|
|
74
|
+
}
|
|
75
|
+
export declare class KortixAuthError extends Error {
|
|
76
|
+
readonly code: 'invalid_options' | 'unauthenticated' | 'state_mismatch' | 'token_exchange_failed' | 'refresh_failed';
|
|
77
|
+
constructor(code: 'invalid_options' | 'unauthenticated' | 'state_mismatch' | 'token_exchange_failed' | 'refresh_failed', message: string);
|
|
78
|
+
}
|
|
79
|
+
/** The bearer the browser sends; `/proxy` replaces it with the viewer's token. */
|
|
80
|
+
export declare const KORTIX_SESSION_SENTINEL = "kortix-session";
|
|
81
|
+
/** Only a same-origin path may be a post-auth destination. */
|
|
82
|
+
export declare function safeReturnTo(value: string | null | undefined): string;
|
|
83
|
+
export declare function createKortixAuth(options: KortixAuthOptions): KortixAuth;
|
|
84
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/node/auth.ts"],"names":[],"mappings":"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"}
|