stitchkit 0.90.5 → 0.90.6

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.
Files changed (41) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +2 -0
  3. package/dist/agent-runtime-coding-tools.js +2 -1
  4. package/dist/agent-runtime-harness.js +2 -1
  5. package/dist/agent-runtime-sandbox.js +2 -1
  6. package/dist/agent-runtime.js +2 -1
  7. package/dist/application/grammy.d.ts.map +1 -1
  8. package/dist/application-grammy.js +4 -1
  9. package/dist/cli.js +2 -1
  10. package/dist/contract/index.js +2 -1
  11. package/dist/google.d.ts +56 -0
  12. package/dist/google.d.ts.map +1 -0
  13. package/dist/google.js +175 -0
  14. package/dist/{index-ra6txecz.js → index-640tz39q.js} +2 -2
  15. package/dist/{index-z78bjcxj.js → index-aj9geeez.js} +1 -1
  16. package/dist/{index-bg8ypxzn.js → index-bva395we.js} +6 -7
  17. package/dist/index-hr4tzbwq.js +11 -0
  18. package/dist/{index-kazec06k.js → index-nrqg8tks.js} +5 -19
  19. package/dist/index-rxfy4cq7.js +17 -0
  20. package/dist/{index-6q3zjwaz.js → index-vy2nxwg8.js} +1 -1
  21. package/dist/index.js +3 -2
  22. package/dist/internal/pkce.d.ts +3 -0
  23. package/dist/internal/pkce.d.ts.map +1 -0
  24. package/dist/node.js +4 -3
  25. package/dist/oauth.d.ts +57 -0
  26. package/dist/oauth.d.ts.map +1 -0
  27. package/dist/oauth.js +170 -0
  28. package/dist/observability/index.js +2 -1
  29. package/dist/primitives.js +2 -1
  30. package/dist/remote.js +3 -2
  31. package/dist/server/bun.d.ts.map +1 -1
  32. package/dist/server/index.js +9 -6
  33. package/dist/server/middleware/pkce.d.ts +1 -2
  34. package/dist/server/middleware/pkce.d.ts.map +1 -1
  35. package/dist/testing.js +3 -2
  36. package/dist/tool-invoker.js +2 -1
  37. package/dist/tools.js +5 -3
  38. package/dist/tracking.js +2 -1
  39. package/llms-full.txt +146 -0
  40. package/llms.txt +1 -0
  41. package/package.json +36 -22
package/dist/oauth.js ADDED
@@ -0,0 +1,170 @@
1
+ import {
2
+ deriveCodeChallenge
3
+ } from "./index-hr4tzbwq.js";
4
+ import {
5
+ bytesToBase64Url
6
+ } from "./index-rxfy4cq7.js";
7
+
8
+ // src/oauth.ts
9
+ var TRANSACTION_VERSION = 1;
10
+ var RESERVED_PARAMETERS = new Set([
11
+ "response_type",
12
+ "client_id",
13
+ "redirect_uri",
14
+ "scope",
15
+ "state",
16
+ "nonce",
17
+ "code_challenge",
18
+ "code_challenge_method"
19
+ ]);
20
+ var ERROR_MESSAGES = {
21
+ INVALID_CONFIGURATION: "The OAuth client configuration is invalid.",
22
+ RESERVED_PARAMETER: "A provider parameter conflicts with the OAuth protocol.",
23
+ INVALID_CONTEXT: "The OAuth transaction context is invalid.",
24
+ STORAGE_FAILURE: "The OAuth transaction store is unavailable.",
25
+ MISSING_TRANSACTION: "The OAuth transaction is missing or was already consumed.",
26
+ MALFORMED_TRANSACTION: "The OAuth transaction is malformed.",
27
+ UNSUPPORTED_TRANSACTION_VERSION: "The OAuth transaction version is unsupported.",
28
+ STATE_MISMATCH: "The OAuth response state does not match the pending transaction."
29
+ };
30
+
31
+ class AuthorizationCodeClientError extends Error {
32
+ code;
33
+ constructor(code, options) {
34
+ super(ERROR_MESSAGES[code], options);
35
+ this.name = "AuthorizationCodeClientError";
36
+ this.code = code;
37
+ }
38
+ }
39
+ function recordOf(value) {
40
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? Object.fromEntries(Object.entries(value)) : null;
41
+ }
42
+ function randomToken(crypto) {
43
+ return bytesToBase64Url(crypto.getRandomValues(new Uint8Array(32)));
44
+ }
45
+ function runtimeCrypto() {
46
+ const runtime = globalThis.crypto;
47
+ if (!runtime?.subtle || typeof runtime.getRandomValues !== "function") {
48
+ throw new AuthorizationCodeClientError("INVALID_CONFIGURATION");
49
+ }
50
+ return {
51
+ getRandomValues: (bytes) => runtime.getRandomValues(bytes),
52
+ subtle: runtime.subtle
53
+ };
54
+ }
55
+ function parseTransaction(raw, contextSchema) {
56
+ let decoded;
57
+ try {
58
+ decoded = JSON.parse(raw);
59
+ } catch {
60
+ throw new AuthorizationCodeClientError("MALFORMED_TRANSACTION");
61
+ }
62
+ const record = recordOf(decoded);
63
+ if (!record)
64
+ throw new AuthorizationCodeClientError("MALFORMED_TRANSACTION");
65
+ if (record.version !== TRANSACTION_VERSION) {
66
+ throw new AuthorizationCodeClientError("UNSUPPORTED_TRANSACTION_VERSION");
67
+ }
68
+ const context = contextSchema.safeParse(record.context);
69
+ if (!context.success)
70
+ throw new AuthorizationCodeClientError("INVALID_CONTEXT");
71
+ if (typeof record.state !== "string" || typeof record.nonce !== "string" || typeof record.codeVerifier !== "string" || typeof record.redirectUri !== "string") {
72
+ throw new AuthorizationCodeClientError("MALFORMED_TRANSACTION");
73
+ }
74
+ return {
75
+ version: TRANSACTION_VERSION,
76
+ state: record.state,
77
+ nonce: record.nonce,
78
+ codeVerifier: record.codeVerifier,
79
+ redirectUri: record.redirectUri,
80
+ context: context.data
81
+ };
82
+ }
83
+ function createAuthorizationCodeClient(config) {
84
+ if (!config.authorizationEndpoint || !config.clientId || !config.redirectUri || !config.storageKey || config.scopes.length === 0 || config.scopes.some((scope) => !scope)) {
85
+ throw new AuthorizationCodeClientError("INVALID_CONFIGURATION");
86
+ }
87
+ for (const parameter of Object.keys(config.authorizationParameters ?? {})) {
88
+ if (RESERVED_PARAMETERS.has(parameter)) {
89
+ throw new AuthorizationCodeClientError("RESERVED_PARAMETER");
90
+ }
91
+ }
92
+ return {
93
+ async begin({ context }) {
94
+ const parsedContext = config.contextSchema.safeParse(context);
95
+ if (!parsedContext.success)
96
+ throw new AuthorizationCodeClientError("INVALID_CONTEXT");
97
+ const crypto = config.crypto ?? runtimeCrypto();
98
+ const state = randomToken(crypto);
99
+ const nonce = randomToken(crypto);
100
+ const codeVerifier = randomToken(crypto);
101
+ const codeChallenge = await deriveCodeChallenge(codeVerifier, crypto.subtle);
102
+ let url;
103
+ try {
104
+ url = new URL(config.authorizationEndpoint);
105
+ } catch {
106
+ throw new AuthorizationCodeClientError("INVALID_CONFIGURATION");
107
+ }
108
+ for (const [name, value] of Object.entries(config.authorizationParameters ?? {})) {
109
+ url.searchParams.set(name, value);
110
+ }
111
+ url.searchParams.set("response_type", "code");
112
+ url.searchParams.set("client_id", config.clientId);
113
+ url.searchParams.set("redirect_uri", config.redirectUri);
114
+ url.searchParams.set("scope", config.scopes.join(" "));
115
+ url.searchParams.set("state", state);
116
+ url.searchParams.set("nonce", nonce);
117
+ url.searchParams.set("code_challenge", codeChallenge);
118
+ url.searchParams.set("code_challenge_method", "S256");
119
+ const transaction = {
120
+ version: TRANSACTION_VERSION,
121
+ state,
122
+ nonce,
123
+ codeVerifier,
124
+ redirectUri: config.redirectUri,
125
+ context: parsedContext.data
126
+ };
127
+ try {
128
+ config.storage.setItem(config.storageKey, JSON.stringify(transaction));
129
+ } catch {
130
+ throw new AuthorizationCodeClientError("STORAGE_FAILURE");
131
+ }
132
+ return { authorizationUrl: url.toString() };
133
+ },
134
+ consume({ state }) {
135
+ let raw;
136
+ try {
137
+ raw = config.storage.getItem(config.storageKey);
138
+ config.storage.removeItem(config.storageKey);
139
+ } catch {
140
+ throw new AuthorizationCodeClientError("STORAGE_FAILURE");
141
+ }
142
+ if (raw === null)
143
+ throw new AuthorizationCodeClientError("MISSING_TRANSACTION");
144
+ const transaction = parseTransaction(raw, config.contextSchema);
145
+ if (transaction.state !== state)
146
+ throw new AuthorizationCodeClientError("STATE_MISMATCH");
147
+ return {
148
+ codeVerifier: transaction.codeVerifier,
149
+ nonce: transaction.nonce,
150
+ redirectUri: transaction.redirectUri,
151
+ context: transaction.context
152
+ };
153
+ }
154
+ };
155
+ }
156
+ function safeInternalReturnPath(candidate, fallback) {
157
+ const hasAsciiControl = [...candidate ?? ""].some((character) => {
158
+ const code = character.charCodeAt(0);
159
+ return code <= 31 || code === 127;
160
+ });
161
+ if (!candidate?.startsWith("/") || candidate.startsWith("//") || candidate.includes("\\") || hasAsciiControl) {
162
+ return fallback;
163
+ }
164
+ return candidate;
165
+ }
166
+ export {
167
+ safeInternalReturnPath,
168
+ createAuthorizationCodeClient,
169
+ AuthorizationCodeClientError
170
+ };
@@ -28,7 +28,8 @@ import"../index-f9mb610r.js";
28
28
  import {
29
29
  recordedErrorMessage
30
30
  } from "../index-2hryh65w.js";
31
- import"../index-kazec06k.js";
31
+ import"../index-nrqg8tks.js";
32
+ import"../index-rxfy4cq7.js";
32
33
  import"../index-6k1937bx.js";
33
34
  import {
34
35
  childSpan,
@@ -1,4 +1,5 @@
1
- import"./index-kazec06k.js";
1
+ import"./index-nrqg8tks.js";
2
+ import"./index-rxfy4cq7.js";
2
3
  import {
3
4
  ManagedFileRefSchema
4
5
  } from "./index-6k1937bx.js";
package/dist/remote.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createClient
3
- } from "./index-6q3zjwaz.js";
3
+ } from "./index-vy2nxwg8.js";
4
4
  import"./index-1txvygak.js";
5
5
  import {
6
6
  ApiError
@@ -9,7 +9,8 @@ import"./index-2hryh65w.js";
9
9
  import {
10
10
  mergeMeta,
11
11
  resolveRouteParamsSchema
12
- } from "./index-kazec06k.js";
12
+ } from "./index-nrqg8tks.js";
13
+ import"./index-rxfy4cq7.js";
13
14
  import"./index-6k1937bx.js";
14
15
  import"./index-zcgf3gqf.js";
15
16
  import {
@@ -1 +1 @@
1
- {"version":3,"file":"bun.d.ts","sourceRoot":"","sources":["../../src/server/bun.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,mBAAmB,EAEzB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,eAAe,EAChB,MAAM,SAAS,CAAC;AAEjB,yEAAyE;AACzE,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC;AACrD,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;AAC9C,MAAM,MAAM,kBAAkB,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;AAC5D,MAAM,MAAM,eAAe,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;AACtD,MAAM,MAAM,mBAAmB,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;AAC9D,MAAM,MAAM,gBAAgB,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;AAExD,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,KAAK,oBAAoB,GAAG,GAAG,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;AAC1D,KAAK,qBAAqB,GAAG,eAAe,SAAS;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,CAAC,GAAG,KAAK,CAAC;AAE3F,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAClC,eAAe,EACf,OAAO,GAAG,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,WAAW,GAAG,aAAa,CAChF,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAExE,8EAA8E;AAC9E,MAAM,WAAW,eAAgB,SAAQ,gBAAgB,EAAE,mBAAmB;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,SAAS,CAAC,EAAE,oBAAoB,CAAC;IACjC,iGAAiG;IACjG,MAAM,CAAC,EAAE,uBAAuB,CAAC;IACjC,WAAW,CAAC,EAAE,qBAAqB,CAAC;IACpC,GAAG,CAAC,EAAE,iBAAiB,CAAC;CACzB;AAED,MAAM,MAAM,eAAe,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;AAyD7D,qDAAqD;AACrD,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,eAAe,CA+NrE"}
1
+ {"version":3,"file":"bun.d.ts","sourceRoot":"","sources":["../../src/server/bun.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,mBAAmB,EAEzB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,eAAe,EAChB,MAAM,SAAS,CAAC;AAEjB,yEAAyE;AACzE,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC;AACrD,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;AAC9C,MAAM,MAAM,kBAAkB,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;AAC5D,MAAM,MAAM,eAAe,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;AACtD,MAAM,MAAM,mBAAmB,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;AAC9D,MAAM,MAAM,gBAAgB,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;AAExD,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,KAAK,oBAAoB,GAAG,GAAG,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;AAC1D,KAAK,qBAAqB,GAAG,eAAe,SAAS;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,CAAC,GAAG,KAAK,CAAC;AAE3F,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAClC,eAAe,EACf,OAAO,GAAG,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,WAAW,GAAG,aAAa,CAChF,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAExE,8EAA8E;AAC9E,MAAM,WAAW,eAAgB,SAAQ,gBAAgB,EAAE,mBAAmB;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,SAAS,CAAC,EAAE,oBAAoB,CAAC;IACjC,iGAAiG;IACjG,MAAM,CAAC,EAAE,uBAAuB,CAAC;IACjC,WAAW,CAAC,EAAE,qBAAqB,CAAC;IACpC,GAAG,CAAC,EAAE,iBAAiB,CAAC;CACzB;AAED,MAAM,MAAM,eAAe,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;AAyD7D,qDAAqD;AACrD,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,eAAe,CAiOrE"}
@@ -13,7 +13,7 @@ import {
13
13
  sseRoute,
14
14
  streamingRoute,
15
15
  webSocketLane
16
- } from "../index-ra6txecz.js";
16
+ } from "../index-640tz39q.js";
17
17
  import"../index-y91ry9h2.js";
18
18
  import {
19
19
  withDeadline
@@ -37,7 +37,6 @@ import {
37
37
  createAuthHook,
38
38
  createBearerResolver,
39
39
  defineCookie,
40
- deriveCodeChallenge,
41
40
  extractToken,
42
41
  parseCookieHeader,
43
42
  parseCookies,
@@ -45,7 +44,10 @@ import {
45
44
  signJwt,
46
45
  verifyJwt,
47
46
  verifyPkce
48
- } from "../index-bg8ypxzn.js";
47
+ } from "../index-bva395we.js";
48
+ import {
49
+ deriveCodeChallenge
50
+ } from "../index-hr4tzbwq.js";
49
51
  import {
50
52
  DEFAULT_CORS_ALLOW_HEADERS,
51
53
  DEFAULT_CORS_EXPOSE_HEADERS,
@@ -59,7 +61,7 @@ import {
59
61
  defineMultipartStream,
60
62
  implement,
61
63
  implementRegistry
62
- } from "../index-z78bjcxj.js";
64
+ } from "../index-aj9geeez.js";
63
65
  import {
64
66
  isWithinDir,
65
67
  realPathWithinDir
@@ -85,7 +87,8 @@ import {
85
87
  DEFAULT_CONTRACT_STREAM_FRAME_BYTES,
86
88
  joinRoutePath,
87
89
  parseTrailingWildcard
88
- } from "../index-kazec06k.js";
90
+ } from "../index-nrqg8tks.js";
91
+ import"../index-rxfy4cq7.js";
89
92
  import"../index-6k1937bx.js";
90
93
  import"../index-zcgf3gqf.js";
91
94
  import {
@@ -491,7 +494,7 @@ function createServer(config) {
491
494
  };
492
495
  if (unixPath !== undefined) {
493
496
  reclaimStaleUnixSocket(unixPath);
494
- const { reusePort, ipv6Only, http3, http1, idleTimeout, ...unixExtra } = bunExtra ?? {};
497
+ const { reusePort, ipv6Only, http3, http2, http1, idleTimeout, ...unixExtra } = bunExtra ?? {};
495
498
  runtime = trackedWebSocket ? Bun.serve({
496
499
  ...unixExtra,
497
500
  ...development && { development },
@@ -1,7 +1,6 @@
1
+ export { deriveCodeChallenge } from '../../internal/pkce.js';
1
2
  /** The only PKCE method OAuth 2.1 permits for public clients. */
2
3
  export type PkceMethod = 'S256';
3
- /** Derive the S256 `code_challenge` from a `code_verifier`. */
4
- export declare function deriveCodeChallenge(verifier: string): Promise<string>;
5
4
  /**
6
5
  * Verify a `code_verifier` against the stored S256 `code_challenge`. S256 is the
7
6
  * only method OAuth 2.1 permits for public clients — `plain` is intentionally
@@ -1 +1 @@
1
- {"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../../../src/server/middleware/pkce.ts"],"names":[],"mappings":"AAQA,iEAAiE;AACjE,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAEhC,+DAA+D;AAC/D,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG3E;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAItF"}
1
+ {"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../../../src/server/middleware/pkce.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,iEAAiE;AACjE,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAEhC;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAItF"}
package/dist/testing.js CHANGED
@@ -28,7 +28,7 @@ import {
28
28
  import {
29
29
  createClient,
30
30
  createClients
31
- } from "./index-6q3zjwaz.js";
31
+ } from "./index-vy2nxwg8.js";
32
32
  import {
33
33
  RealtimeRequestDisconnectedError,
34
34
  RealtimeRequestInvalidAcknowledgementError,
@@ -39,7 +39,8 @@ import"./index-3xwxfj4z.js";
39
39
  import"./index-2hryh65w.js";
40
40
  import {
41
41
  joinRoutePath
42
- } from "./index-kazec06k.js";
42
+ } from "./index-nrqg8tks.js";
43
+ import"./index-rxfy4cq7.js";
43
44
  import"./index-6k1937bx.js";
44
45
  import"./index-zcgf3gqf.js";
45
46
  import {
@@ -6,7 +6,8 @@ import"./index-8pjqv3zh.js";
6
6
  import"./index-vsbzgd7b.js";
7
7
  import"./index-f9mb610r.js";
8
8
  import"./index-2hryh65w.js";
9
- import"./index-kazec06k.js";
9
+ import"./index-nrqg8tks.js";
10
+ import"./index-rxfy4cq7.js";
10
11
  import"./index-6k1937bx.js";
11
12
  import"./index-zcgf3gqf.js";
12
13
  import"./index-7zbps32p.js";
package/dist/tools.js CHANGED
@@ -4,7 +4,8 @@ import {
4
4
  import {
5
5
  signJwt,
6
6
  verifyPkce
7
- } from "./index-bg8ypxzn.js";
7
+ } from "./index-bva395we.js";
8
+ import"./index-hr4tzbwq.js";
8
9
  import {
9
10
  DEFAULT_CORS_ALLOW_HEADERS,
10
11
  DEFAULT_PROCESS_SIGNALS,
@@ -13,7 +14,7 @@ import {
13
14
  guardSignalCallback,
14
15
  mediaTypeEssence,
15
16
  reportSignalError
16
- } from "./index-z78bjcxj.js";
17
+ } from "./index-aj9geeez.js";
17
18
  import {
18
19
  redact
19
20
  } from "./index-xbppf54a.js";
@@ -73,7 +74,8 @@ import {
73
74
  } from "./index-2hryh65w.js";
74
75
  import {
75
76
  defineContract
76
- } from "./index-kazec06k.js";
77
+ } from "./index-nrqg8tks.js";
78
+ import"./index-rxfy4cq7.js";
77
79
  import {
78
80
  ManagedFilePathSchema,
79
81
  ManagedFileRefSchema
package/dist/tracking.js CHANGED
@@ -3,7 +3,8 @@ import {
3
3
  } from "./index-3xwxfj4z.js";
4
4
  import {
5
5
  defineContract
6
- } from "./index-kazec06k.js";
6
+ } from "./index-nrqg8tks.js";
7
+ import"./index-rxfy4cq7.js";
7
8
  import"./index-6k1937bx.js";
8
9
  import"./index-zcgf3gqf.js";
9
10
  import"./index-scs3f1eg.js";
package/llms-full.txt CHANGED
@@ -64,6 +64,8 @@ own, recorded as an ADR.
64
64
  | `stitchkit/tracking/server` | server (Bun or Node) | evolving | the decisions a tracking backend makes — dispositions, visit lease over an application-owned store, active intervals, presence; no database |
65
65
  | `stitchkit/release` | browser **and** server | evolving | a page follows the release it was built for — `createReleaseMarker` on the server, `createReleaseWatcher` in the browser, the `X-Build-Id` header and a socket event between them |
66
66
  | `stitchkit/geo` | server (Bun or Node) | evolving | managed GeoIP reader generations, last-known-good reload and the optional MaxMind adapter |
67
+ | `stitchkit/oauth` | browser **and** server | evolving | provider-neutral Authorization Code + PKCE request and one-shot callback transaction mechanics |
68
+ | `stitchkit/google` | server (Bun or Node) | evolving | optional Google code exchange and verified OIDC identity adapter |
67
69
  | `stitchkit/observability` | server | stable<br>_redefined in 1 of the 35 minors since 0.56.2, most recently 0.83.0_ | request/tool event projections — `createObservability`, trace context, sanitisation |
68
70
  | `stitchkit/testing` | tests on Bun or Node | stable | in-process generated clients over a real Fetch handler, plus the store and managed-resource conformance kits |
69
71
  | `stitchkit/declaration` | browser + build and deployment tooling (Bun or Node) | evolving | `ProjectDeclarationSchema` — the one machine-readable statement a repository makes about itself |
@@ -190,6 +192,8 @@ map — feature → packages:
190
192
  | MCP Apps UI widgets | `@modelcontextprotocol/ext-apps` |
191
193
  | React data layer (`stitchkit/react`) | `@tanstack/react-query` `react-query-kit` |
192
194
  | MaxMind GeoIP (`stitchkit/geo`) | `maxmind` |
195
+ | Browser OAuth client (`stitchkit/oauth`) | — |
196
+ | Google OIDC verifier (`stitchkit/google`) | `google-auth-library` |
193
197
  | **Socket.IO server on Bun** | `socket.io` `@socket.io/bun-engine` |
194
198
  | **Socket.IO server on Node** | `socket.io` |
195
199
  | Socket.IO client | `socket.io-client` (runtime peer; unrelated root declarations remain peer-free) |
@@ -226,6 +230,7 @@ package. MCP hosts and client E2E additionally install
226
230
  - [MCP & agents](./mcp-and-agents.md) — contracts as AI tools.
227
231
  - [Realtime](./realtime.md) — Socket.IO and the cache bridge.
228
232
  - [Auth & errors](./auth-and-errors.md) — scopes, auth hooks, the error model.
233
+ - [Browser OAuth and Google OIDC](./oauth.md) — PKCE transaction and verified provider identity.
229
234
  - [Testing & deployment](./testing-and-deployment.md).
230
235
  - [API reference](../api/reference.md) — every export, by entrypoint.
231
236
 
@@ -10098,6 +10103,118 @@ onError: (ctx, err) => {
10098
10103
  ```
10099
10104
 
10100
10105
 
10106
+ ==============================================================================
10107
+ # Guide: OAuth & OpenID Connect (docs/guide/oauth.md)
10108
+ ==============================================================================
10109
+
10110
+ # Browser OAuth and Google OIDC
10111
+
10112
+ Stitchkit separates the browser's Authorization Code + PKCE transaction from the server's
10113
+ provider credential verification. The application still owns navigation, users, account matching
10114
+ and merge policy, persistence, sessions, roles, unlink policy and UI.
10115
+
10116
+ ## Supported profile
10117
+
10118
+ The current Google adapter supports one explicit profile: **web OpenID Connect Authorization Code
10119
+ with PKCE**. A browser performs a top-level redirect, an application backend exchanges the
10120
+ one-time code, and Stitchkit returns a verified identity. It is the redirect-based sign-in path;
10121
+ it is not a generic name for every Google identity or authorization mechanism.
10122
+
10123
+ Keep adjacent Google capabilities separate because their credentials, lifecycle and trust
10124
+ boundaries differ:
10125
+
10126
+ | Capability | Credential/result | Stitchkit support |
10127
+ | --- | --- | --- |
10128
+ | Web OIDC Authorization Code + PKCE | verified user identity | `stitchkit/oauth` + `stitchkit/google` |
10129
+ | Google Identity Services button, One Tap or FedCM | browser-delivered ID credential | not implemented |
10130
+ | Incremental authorization for Drive, Calendar or other Google APIs | access/refresh tokens and granted scopes | not implemented |
10131
+ | Installed Android, iOS or desktop application | platform client and system-browser callback | not implemented |
10132
+ | Limited-input/device authorization | device/user codes and polling lifecycle | not implemented |
10133
+ | Service account or workload identity | application identity, possibly domain-wide delegation | not implemented |
10134
+
10135
+ Do not add these as mode flags to `GoogleOidcClient`. Each future capability gets its own adapter
10136
+ and result type, while the provider-neutral PKCE transaction can be reused where its protocol
10137
+ actually applies. In particular, authentication establishes the person; authorization to Google
10138
+ APIs is requested later, in product context, and owns refresh-token persistence and revocation.
10139
+
10140
+ ## Browser transaction
10141
+
10142
+ `stitchkit/oauth` is browser-safe and provider-neutral. It creates independent 32-byte `state`,
10143
+ `nonce` and PKCE verifier values, writes one versioned transaction to caller-provided storage and
10144
+ returns the authorization URL without navigating:
10145
+
10146
+ ```ts
10147
+ import { createAuthorizationCodeClient, safeInternalReturnPath } from 'stitchkit/oauth'
10148
+ import { z } from 'zod'
10149
+
10150
+ const oauth = createAuthorizationCodeClient({
10151
+ authorizationEndpoint: 'https://accounts.google.com/o/oauth2/v2/auth',
10152
+ clientId,
10153
+ redirectUri: `${window.location.origin}/auth/google/callback`,
10154
+ scopes: ['openid', 'email', 'profile'],
10155
+ storage: window.sessionStorage,
10156
+ storageKey: 'app:google:oauth',
10157
+ contextSchema: z.object({ mode: z.enum(['login', 'link']), returnTo: z.string() }),
10158
+ authorizationParameters: { prompt: 'select_account' },
10159
+ })
10160
+
10161
+ const { authorizationUrl } = await oauth.begin({
10162
+ context: { mode: 'login', returnTo: '/account' },
10163
+ })
10164
+ window.location.assign(authorizationUrl)
10165
+
10166
+ // In the callback route. Reading is one-shot even when validation fails.
10167
+ const pending = oauth.consume({ state: new URL(location.href).searchParams.get('state') ?? '' })
10168
+ const returnTo = safeInternalReturnPath(pending.context.returnTo, '/')
10169
+ ```
10170
+
10171
+ Provider parameters cannot replace protocol-owned fields. `consume` removes the pending value
10172
+ before parsing, version checking, context validation or state comparison, so a malformed callback
10173
+ and a React Strict Mode replay cannot reuse it. Errors expose a stable
10174
+ `AuthorizationCodeClientError.code` and never include transaction contents.
10175
+
10176
+ Token exchange, ID-token verification, credential persistence and application identity do not
10177
+ belong to this browser entrypoint.
10178
+
10179
+ ## Google server adapter
10180
+
10181
+ Install the optional peer only in an application that imports `stitchkit/google`:
10182
+
10183
+ ```bash
10184
+ bun add google-auth-library
10185
+ ```
10186
+
10187
+ ```ts
10188
+ import { createGoogleOidcClient } from 'stitchkit/google'
10189
+
10190
+ const google = createGoogleOidcClient({
10191
+ clientId: env.GOOGLE_CLIENT_ID,
10192
+ clientSecret: env.GOOGLE_CLIENT_SECRET,
10193
+ allowedRedirectUris: [env.GOOGLE_WEB_CALLBACK, env.GOOGLE_LOOPBACK_CALLBACK],
10194
+ timeoutMs: 10_000,
10195
+ })
10196
+
10197
+ const identity = await google.exchangeAuthorizationCode({
10198
+ code,
10199
+ codeVerifier: pending.codeVerifier,
10200
+ redirectUri: pending.redirectUri,
10201
+ nonce: pending.nonce,
10202
+ })
10203
+ // { subject, email, name?, picture? }
10204
+ ```
10205
+
10206
+ The redirect must match the immutable allowlist exactly before any outbound call. The token
10207
+ exchange is bounded by an abort deadline; `google-auth-library` verifies the ID-token signature,
10208
+ issuer, audience and expiry. Stitchkit additionally requires `sub`, a valid verified email and an
10209
+ exact nonce. Access, refresh and raw ID tokens never leave the adapter.
10210
+
10211
+ `GoogleOidcError.code` distinguishes `MISCONFIGURED`, `INVALID_CREDENTIAL` and
10212
+ `UPSTREAM_UNAVAILABLE` with fixed safe messages. Endpoints compose their own rate limiter and then
10213
+ map the verified identity into application-owned user/session policy. Offline access, Google API
10214
+ scopes, database writes, user lookup or merging, session rotation, roles and UI remain outside the
10215
+ adapter.
10216
+
10217
+
10101
10218
  ==============================================================================
10102
10219
  # Guide: Observability (docs/guide/observability.md)
10103
10220
  ==============================================================================
@@ -17163,6 +17280,35 @@ adapter is used.
17163
17280
 
17164
17281
  ---
17165
17282
 
17283
+ ## `stitchkit/oauth`
17284
+
17285
+ Browser-safe, provider-neutral Authorization Code + PKCE transaction mechanics. Navigation,
17286
+ token exchange, identity and sessions remain application-owned. See the [OAuth guide](../guide/oauth.md).
17287
+
17288
+ | Export | Kind | Summary |
17289
+ |--------|------|---------|
17290
+ | `createAuthorizationCodeClient` / `AuthorizationCodeClient` / `AuthorizationCodeClientConfig` | function / _type_ | begin one S256 authorization request and consume its versioned pending transaction exactly once |
17291
+ | `BeginAuthorizationCodeInput` / `BeginAuthorizationCodeResult` / `ConsumeAuthorizationCodeInput` / `ConsumedAuthorizationCode` | _type_ | inputs and safe protocol result around caller-validated context |
17292
+ | `AuthorizationCodeStorage` / `AuthorizationCodeCrypto` | _type_ | injected browser capabilities; neither is read at module initialisation |
17293
+ | `AuthorizationCodeClientError` / `AuthorizationCodeClientErrorCode` | class / _type_ | fixed safe failure codes for configuration, context, storage, transaction and state failures |
17294
+ | `safeInternalReturnPath` | function | accept only a single-slash current-origin path without backslashes or ASCII controls |
17295
+
17296
+ ---
17297
+
17298
+ ## `stitchkit/google`
17299
+
17300
+ Server-only Google code exchange and verified OIDC identity. This entry requires the optional
17301
+ `google-auth-library` peer. See the [OAuth guide](../guide/oauth.md).
17302
+
17303
+ | Export | Kind | Summary |
17304
+ |--------|------|---------|
17305
+ | `createGoogleOidcClient` / `GoogleOidcClient` / `GoogleOidcClientConfig` | function / _type_ | exact-redirect, deadline-bounded code exchange and verified identity projection |
17306
+ | `ExchangeGoogleAuthorizationCodeInput` / `GoogleOidcIdentity` / `GoogleOidcClaims` | _type_ | callback input, provider-neutral result and verifier seam claims |
17307
+ | `GoogleOidcExchangeInput` / `GoogleOidcTokenTransport` / `GoogleOidcIdTokenVerifier` | _type_ | injectable transport and verifier boundaries used by production and deterministic tests |
17308
+ | `GoogleOidcError` / `GoogleOidcErrorCode` | class / _type_ | safe `MISCONFIGURED`, `INVALID_CREDENTIAL` or retryable `UPSTREAM_UNAVAILABLE` failure |
17309
+
17310
+ ---
17311
+
17166
17312
  ## `stitchkit/declaration`
17167
17313
 
17168
17314
  Zod-only, dependency-free. The **project declaration**: the single
package/llms.txt CHANGED
@@ -21,6 +21,7 @@ Build with stitchkit: define a contract once, then `implement` it and serve it (
21
21
  - [Realtime](https://github.com/max-listov/stitchkit/blob/master/docs/guide/realtime.md): Socket.IO server/client wrappers, handshake auth, the cache bridge, a raw WebSocket lane
22
22
  - [Live data](https://github.com/max-listov/stitchkit/blob/master/docs/guide/live.md): defineEvents beside the contract, watched reads shared by every subscriber, keyspaces with authoritative memory, and the trust fence
23
23
  - [Auth & errors](https://github.com/max-listov/stitchkit/blob/master/docs/guide/auth-and-errors.md): scopes, createAuthHook, JWT/cookies, the AppError model, the stitch error-code registry
24
+ - [OAuth & OpenID Connect](https://github.com/max-listov/stitchkit/blob/master/docs/guide/oauth.md): browser Authorization Code + PKCE transactions and the optional Google OIDC server adapter
24
25
  - [Observability](https://github.com/max-listov/stitchkit/blob/master/docs/guide/observability.md): request and tool-call observability, W3C trace context, createObservability
25
26
  - [Testing & deployment](https://github.com/max-listov/stitchkit/blob/master/docs/guide/testing-and-deployment.md): in-process testing; deploying on Bun and on Node (serveNode)
26
27
  - [Multi-tenant](https://github.com/max-listov/stitchkit/blob/master/docs/guide/multi-tenant.md): a /tenants/:id/… scenario end-to-end — scopePrefixes, scoped client, extend