@monkeyplus/flow 6.0.17 → 6.0.18

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 (101) hide show
  1. package/README.md +2 -0
  2. package/cms/server/database/schema.d.ts +648 -0
  3. package/cms/server/database/schema.mjs +43 -0
  4. package/cms/server/routes/api/auth/[...auth].d.ts +2 -0
  5. package/cms/server/routes/api/auth/[...auth].mjs +5 -0
  6. package/cms/server/routes/api/draft.d.ts +3 -0
  7. package/cms/server/routes/api/draft.mjs +26 -0
  8. package/cms/server/routes/api/repos/remote/[repo]/blobs/[file]/index.d.ts +2 -0
  9. package/cms/server/routes/api/repos/remote/[repo]/blobs/[file]/index.mjs +20 -0
  10. package/cms/server/routes/api/repos/remote/[repo]/blobs/index.post.d.ts +2 -0
  11. package/cms/server/routes/api/repos/remote/[repo]/blobs/index.post.mjs +8 -0
  12. package/cms/server/routes/api/repos/remote/[repo]/branches/[branch]/index.d.ts +2 -0
  13. package/cms/server/routes/api/repos/remote/[repo]/branches/[branch]/index.mjs +8 -0
  14. package/cms/server/routes/api/repos/remote/[repo]/commits/index.post.d.ts +2 -0
  15. package/cms/server/routes/api/repos/remote/[repo]/commits/index.post.mjs +8 -0
  16. package/cms/server/routes/api/repos/remote/[repo]/files/[branch]/index.d.ts +2 -0
  17. package/cms/server/routes/api/repos/remote/[repo]/files/[branch]/index.mjs +38 -0
  18. package/cms/server/routes/api/repos/remote/[repo]/files/index.post.d.ts +2 -0
  19. package/cms/server/routes/api/repos/remote/[repo]/files/index.post.mjs +8 -0
  20. package/cms/server/routes/api/repos/remote/[repo]/refs/heads/[branch]/index.patch.d.ts +2 -0
  21. package/cms/server/routes/api/repos/remote/[repo]/refs/heads/[branch]/index.patch.mjs +9 -0
  22. package/cms/server/utils/auth.d.ts +3 -0
  23. package/cms/server/utils/auth.mjs +16 -0
  24. package/cms/server/utils/db.d.ts +3 -0
  25. package/cms/server/utils/db.mjs +5 -0
  26. package/cms/server/utils/github.d.ts +15 -0
  27. package/cms/server/utils/github.mjs +160 -0
  28. package/cms/server/utils/github_token.d.ts +71 -0
  29. package/cms/server/utils/github_token.mjs +377 -0
  30. package/modules/cms/module.d.ts +11 -0
  31. package/modules/cms/module.mjs +163 -0
  32. package/modules/cms/server/api/admin.d.ts +2 -0
  33. package/modules/cms/server/api/admin.mjs +18 -0
  34. package/modules/cms/server/api/config.d.ts +2 -0
  35. package/modules/cms/server/api/config.mjs +88 -0
  36. package/modules/cms/server/api/localFs.d.ts +2 -0
  37. package/modules/cms/server/api/localFs.mjs +88 -0
  38. package/modules/cms/server/api/meta.d.ts +2 -0
  39. package/modules/cms/server/api/meta.mjs +12 -0
  40. package/modules/cms/server/lib/composables.d.ts +116 -0
  41. package/modules/cms/server/lib/composables.mjs +82 -0
  42. package/modules/cms/server/lib/fs.d.ts +1 -0
  43. package/modules/cms/server/lib/fs.mjs +18 -0
  44. package/modules/cms/server/lib/helpers.d.ts +14 -0
  45. package/modules/cms/server/lib/helpers.mjs +78 -0
  46. package/modules/cms/server/lib/types.d.ts +120 -0
  47. package/modules/cms/server/lib/types.mjs +0 -0
  48. package/modules/cms/server/lib/widgets.d.ts +82 -0
  49. package/modules/cms/server/lib/widgets.mjs +200 -0
  50. package/modules/cms/server/trial.d.ts +2 -0
  51. package/modules/cms/server/trial.mjs +8 -0
  52. package/modules/content/query.mjs +31 -3
  53. package/modules/images/ipx.mjs +4 -2
  54. package/modules/images/module.d.ts +0 -1
  55. package/modules/images/module.mjs +5 -3
  56. package/modules/images/runtime/build.mjs +12 -0
  57. package/modules/images/runtime/image.mjs +4 -3
  58. package/modules/images/runtime/renames.mjs +59 -8
  59. package/modules/images/runtime/types.d.ts +27 -4
  60. package/modules/images/watermark.d.ts +1 -0
  61. package/modules/images/watermark.mjs +113 -0
  62. package/modules/netlify-cms/handler.mjs +2 -1
  63. package/modules/netlify-cms/module.mjs +1 -1
  64. package/modules/netlify-cms/server/api/config.mjs +25 -1
  65. package/modules/netlify-cms/server/api/local-fs.d.ts +51 -0
  66. package/modules/netlify-cms/server/api/local-fs.mjs +81 -77
  67. package/modules/netlify-cms/server/lib/cms/handler.d.ts +1 -1
  68. package/modules/netlify-cms/server/lib/cms/handlerV1.d.ts +1 -1
  69. package/modules/netlify-cms/server/lib/composables.d.ts +8 -0
  70. package/modules/netlify-cms/server/lib/composables.mjs +2 -1
  71. package/package.json +2 -2
  72. package/server/lib/context.d.ts +3 -0
  73. package/server/lib/context.mjs +5 -0
  74. package/server/lib/handler.mjs +58 -23
  75. package/server/lib/pages.d.ts +2 -2
  76. package/server/lib/pages.mjs +8 -6
  77. package/server/lib/render.mjs +20 -4
  78. package/server/plugins/00.lifecycle.mjs +2 -1
  79. package/src/public/index.d.ts +1 -0
  80. package/src/public/index.mjs +1 -0
  81. package/src/public/nitro.mjs +2 -0
  82. package/src/public/query-content.mjs +9 -2
  83. package/src/public/shared.d.ts +1 -0
  84. package/src/public/shared.mjs +3 -0
  85. package/src/public/vite.mjs +63 -8
  86. package/src/runtime/components/FlowIsland.mjs +31 -4
  87. package/src/runtime/components/MkImage.d.ts +100 -22
  88. package/src/runtime/components/MkImage.mjs +20 -12
  89. package/src/runtime/components/MkLink.d.ts +8 -5
  90. package/src/runtime/components/MkLink.mjs +9 -3
  91. package/src/runtime/components/MkPicture.d.ts +92 -7
  92. package/src/runtime/components/MkPicture.mjs +8 -2
  93. package/src/runtime/components/image-shared.d.ts +0 -1
  94. package/src/runtime/components/image-shared.mjs +9 -18
  95. package/src/runtime/config.d.ts +6 -15
  96. package/src/runtime/head.d.ts +2 -1
  97. package/src/runtime/head.mjs +5 -2
  98. package/src/runtime/islands.mjs +20 -2
  99. package/src/runtime/page-discovery.mjs +9 -1
  100. package/src/runtime/pages.d.ts +14 -13
  101. package/src/runtime/virtual-pages.mjs +2 -2
@@ -0,0 +1,5 @@
1
+ import { defineEventHandler } from "nitro/h3";
2
+ import { auth } from "#cms-utils/auth";
3
+ export default defineEventHandler(async (event) => {
4
+ return auth.handler(event.req);
5
+ });
@@ -0,0 +1,3 @@
1
+ import type { H3Event } from 'nitro';
2
+ declare const _default: (event: H3Event) => Promise<any>;
3
+ export default _default;
@@ -0,0 +1,26 @@
1
+ import { getQuery, HTTPError, readBody } from "nitro/h3";
2
+ import { useStorage } from "nitro/storage";
3
+ export default async (event) => {
4
+ const query = getQuery(event);
5
+ if (event.req.method === "GET") {
6
+ const file = query.file;
7
+ if (!file) {
8
+ return new HTTPError({
9
+ statusCode: 400,
10
+ statusMessage: "File is required",
11
+ message: "File is required"
12
+ });
13
+ }
14
+ const data = await useStorage("draft").getItem(file);
15
+ return data || {};
16
+ }
17
+ if (event.req.method === "DELETE") {
18
+ return {};
19
+ }
20
+ const body = await readBody(event);
21
+ if (!body?.file || !body?.data) {
22
+ throw new Error("Missing file or data");
23
+ }
24
+ await useStorage("draft").setItem(body.file, body.data);
25
+ return "world";
26
+ };
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,20 @@
1
+ import { defineHandler, defineRouteMeta } from "nitro";
2
+ import { ghRepoBlob } from "#cms-utils/github";
3
+ defineRouteMeta({
4
+ openAPI: {
5
+ description: "(disabled - redirects to raw.githubusercontent.com)",
6
+ tags: ["hidden"]
7
+ }
8
+ });
9
+ export default defineHandler(async (event) => {
10
+ const repo = `${event.context.params.repo}`;
11
+ const fileSha = event.context.params.file;
12
+ const res = await ghRepoBlob(repo, fileSha);
13
+ const file = res;
14
+ return {
15
+ meta: {
16
+ sha: res.sha
17
+ },
18
+ file
19
+ };
20
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<any>>;
2
+ export default _default;
@@ -0,0 +1,8 @@
1
+ import { defineEventHandler, readBody } from "h3";
2
+ import { ghCreateBlob } from "#cms-utils/github";
3
+ export default defineEventHandler(async (event) => {
4
+ const repo = event.context.params.repo;
5
+ const body = await readBody(event);
6
+ const res = await ghCreateBlob(repo, body);
7
+ return res;
8
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<any>>;
2
+ export default _default;
@@ -0,0 +1,8 @@
1
+ import { defineEventHandler } from "h3";
2
+ import { ghGetBranch } from "#cms-utils/github";
3
+ export default defineEventHandler(async (event) => {
4
+ const repo = event.context.params.repo;
5
+ const branch = event.context.params.branch;
6
+ const res = await ghGetBranch(repo, branch);
7
+ return res;
8
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<any>>;
2
+ export default _default;
@@ -0,0 +1,8 @@
1
+ import { defineEventHandler, readBody } from "h3";
2
+ import { ghCreateCommit } from "#cms-utils/github";
3
+ export default defineEventHandler(async (event) => {
4
+ const repo = event.context.params.repo;
5
+ const body = await readBody(event);
6
+ const res = await ghCreateCommit(repo, body);
7
+ return res;
8
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,38 @@
1
+ import { defineHandler, defineRouteMeta } from "nitro";
2
+ import { getQuery, HTTPError } from "nitro/h3";
3
+ import { ghRepoFile, ghRepoFiles } from "#cms-utils/github";
4
+ defineRouteMeta({
5
+ openAPI: {
6
+ description: "(disabled - redirects to raw.githubusercontent.com)",
7
+ tags: ["hidden"]
8
+ }
9
+ });
10
+ export default defineHandler(async (event) => {
11
+ const repo = `${event.context.params.repo}`;
12
+ const branch = event.context.params.branch;
13
+ const query = getQuery(event);
14
+ if (query.file) {
15
+ return await ghRepoFile(repo, query.file, branch);
16
+ }
17
+ if (!query.folder) {
18
+ return new HTTPError({
19
+ message: "No folder provided",
20
+ statusCode: 400
21
+ });
22
+ }
23
+ const res = await ghRepoFiles(repo, `${branch}:${query.folder}`);
24
+ const files = res.tree.filter((i) => i.type === "blob").map(
25
+ (i) => ({
26
+ path: i.path,
27
+ mode: i.mode,
28
+ sha: i.sha,
29
+ size: i.size
30
+ })
31
+ );
32
+ return {
33
+ meta: {
34
+ sha: res.sha
35
+ },
36
+ files
37
+ };
38
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<any>>;
2
+ export default _default;
@@ -0,0 +1,8 @@
1
+ import { defineEventHandler, readBody } from "h3";
2
+ import { ghCreateTree } from "#cms-utils/github";
3
+ export default defineEventHandler(async (event) => {
4
+ const repo = event.context.params.repo;
5
+ const body = await readBody(event);
6
+ const res = await ghCreateTree(repo, body);
7
+ return res;
8
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<any>>;
2
+ export default _default;
@@ -0,0 +1,9 @@
1
+ import { defineEventHandler, readBody } from "h3";
2
+ import { ghUpdateRef } from "#cms-utils/github";
3
+ export default defineEventHandler(async (event) => {
4
+ const repo = event.context.params.repo;
5
+ const branch = event.context.params.branch;
6
+ const body = await readBody(event);
7
+ const res = await ghUpdateRef(repo, branch, body);
8
+ return res;
9
+ });
@@ -0,0 +1,3 @@
1
+ export declare const auth: import("better-auth/*").Auth<{
2
+ database: (options: import("better-auth/*").BetterAuthOptions) => import("better-auth/*").DBAdapter<import("better-auth/*").BetterAuthOptions>;
3
+ }>;
@@ -0,0 +1,16 @@
1
+ import { betterAuth } from "better-auth";
2
+ import { drizzleAdapter } from "better-auth/adapters/drizzle";
3
+ import * as schema from "../database/schema.mjs";
4
+ import { db } from "./db.mjs";
5
+ export const auth = betterAuth({
6
+ database: drizzleAdapter(db, {
7
+ provider: "sqlite",
8
+ schema
9
+ })
10
+ // socialProviders: {
11
+ // github: {
12
+ // clientId: process.env.GITHUB_CLIENT_ID as string,
13
+ // clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
14
+ // },
15
+ // },
16
+ });
@@ -0,0 +1,3 @@
1
+ export declare const db: import("drizzle-orm/libsql").LibSQLDatabase<Record<string, never>> & {
2
+ $client: import("@libsql/client/.").Client;
3
+ };
@@ -0,0 +1,5 @@
1
+ import process from "node:process";
2
+ import { createClient } from "@libsql/client";
3
+ import { drizzle } from "drizzle-orm/libsql";
4
+ const client = createClient({ url: process.env.DATABASE_URL || "file:local.db" });
5
+ export const db = drizzle(client);
@@ -0,0 +1,15 @@
1
+ import type { CacheOptions } from 'nitro/types';
2
+ export declare const commonCacheOptions: CacheOptions;
3
+ export declare const ghFetch: any;
4
+ export declare function ghFetchNoCache<T = any>(url: string, opts?: RequestInit): Promise<T>;
5
+ export declare const ghRepo: any;
6
+ export declare const ghRepoContributors: any;
7
+ export declare const ghRepoFiles: any;
8
+ export declare const ghRepoFile: any;
9
+ export declare const ghRepoBlob: any;
10
+ export declare const ghMarkdown: any;
11
+ export declare function ghCreateBlob(repo: string, body: any): Promise<any>;
12
+ export declare function ghCreateTree(repo: string, body: any): Promise<any>;
13
+ export declare function ghCreateCommit(repo: string, body: any): Promise<any>;
14
+ export declare function ghUpdateRef(repo: string, branch: string, body: any): Promise<any>;
15
+ export declare function ghGetBranch(repo: string, branch: string): Promise<any>;
@@ -0,0 +1,160 @@
1
+ import process from "node:process";
2
+ import { defineCachedFunction } from "nitro/cache";
3
+ import { HTTPError } from "nitro/h3";
4
+ import { joinURL } from "ufo";
5
+ import { acquireGHToken, formatDuration, ghTokens, retryAfterSeconds } from "#cms-utils/github_token";
6
+ const OWNER = process.env.GH_OWNER;
7
+ console.log(OWNER);
8
+ export const commonCacheOptions = {
9
+ group: "gh",
10
+ maxAge: 60 * 60 * 24,
11
+ // 24 hours
12
+ staleMaxAge: 60 * 60 * 48,
13
+ // 48 hours
14
+ // base: ["/cache", "/redis"],
15
+ base: ["/cache"]
16
+ };
17
+ function cacheOptions(name) {
18
+ return {
19
+ ...commonCacheOptions,
20
+ name
21
+ };
22
+ }
23
+ export const ghFetch = defineCachedFunction(
24
+ async (url, opts = {}) => {
25
+ const token = await acquireGHToken();
26
+ if (!token) {
27
+ const soonestReset = ghTokens.filter((t) => t.valid && t.reset).sort((a, b) => (a.reset || 0) - (b.reset || 0))[0];
28
+ const resetInfo = soonestReset?.reset ? ` Rate limit resets in ${formatDuration(soonestReset.reset - Date.now())}.` : "";
29
+ const invalidCount = ghTokens.filter((t) => t.valid === false).length;
30
+ const exhaustedCount = ghTokens.filter((t) => t.valid && (t.remaining || 0) === 0).length;
31
+ const retryAfter = retryAfterSeconds(soonestReset?.reset);
32
+ throw new HTTPError({
33
+ message: `No valid GitHub token available (${ghTokens.length} configured: ${invalidCount} invalid, ${exhaustedCount} rate-limited).${resetInfo} You can help by installing the GitHub App: https://github.com/apps/ungh-app`,
34
+ statusCode: 429,
35
+ headers: { "Retry-After": String(retryAfter) }
36
+ });
37
+ }
38
+ const fullUrl = url.startsWith("/") ? url : `/${url}`;
39
+ console.log("URL", fullUrl);
40
+ const res = await fetch(`https://api.github.com${fullUrl}`, {
41
+ ...opts,
42
+ method: (opts.method || "GET").toUpperCase(),
43
+ headers: {
44
+ "User-Agent": "fetch",
45
+ "Authorization": `token ${token.token}`,
46
+ ...opts.headers
47
+ }
48
+ });
49
+ token.updateStatus(res);
50
+ if (!res.ok) {
51
+ throw new HTTPError({
52
+ message: `GitHub API error: ${res.status} ${res.statusText}`,
53
+ statusCode: res.status
54
+ });
55
+ }
56
+ const contentType = res.headers.get("content-type") || "";
57
+ return contentType.includes("application/json") ? await res.json() : await res.text();
58
+ },
59
+ {
60
+ ...cacheOptions("api"),
61
+ integrity: "v1",
62
+ validate(entry) {
63
+ if (!entry.value || isEmptyArray(entry.value) || entry.value?.total_count === 0 || isEmptyArray(entry.value?.items)) {
64
+ return false;
65
+ }
66
+ return true;
67
+ }
68
+ }
69
+ );
70
+ export async function ghFetchNoCache(url, opts = {}) {
71
+ const token = await acquireGHToken();
72
+ if (!token) {
73
+ throw new HTTPError({
74
+ message: "No valid GitHub token available",
75
+ statusCode: 429
76
+ });
77
+ }
78
+ const fullUrl = url.startsWith("/") ? url : `/${url}`;
79
+ const res = await fetch(`https://api.github.com${fullUrl}`, {
80
+ ...opts,
81
+ method: (opts.method || "GET").toUpperCase(),
82
+ headers: {
83
+ "User-Agent": "fetch",
84
+ "Authorization": `token ${token.token}`,
85
+ "Accept": "application/vnd.github+json",
86
+ ...opts.headers
87
+ }
88
+ });
89
+ token.updateStatus(res);
90
+ if (!res.ok) {
91
+ throw new HTTPError({
92
+ message: `GitHub API error: ${res.status} ${res.statusText}`,
93
+ statusCode: res.status
94
+ });
95
+ }
96
+ const contentType = res.headers.get("content-type") || "";
97
+ return contentType.includes("application/json") ? await res.json() : await res.text();
98
+ }
99
+ export const ghRepo = defineCachedFunction((repo) => {
100
+ return ghFetch(`/repos/${repo}`);
101
+ }, cacheOptions("repo"));
102
+ export const ghRepoContributors = defineCachedFunction((repo) => {
103
+ return ghFetch(`/repos/${repo}/contributors`);
104
+ }, cacheOptions("contributors"));
105
+ export const ghRepoFiles = defineCachedFunction((repo, ref) => {
106
+ repo = joinURL(OWNER, repo);
107
+ return ghFetch(`/repos/${repo}/git/trees/${ref}?recursive=1`);
108
+ }, cacheOptions("files"));
109
+ export const ghRepoFile = defineCachedFunction((repo, ref, branch) => {
110
+ repo = joinURL(OWNER, repo);
111
+ return ghFetch(`/repos/${repo}/contents/${ref}?branch=${branch}`);
112
+ }, cacheOptions("file"));
113
+ export const ghRepoBlob = defineCachedFunction((repo, sha) => {
114
+ repo = joinURL(OWNER, repo);
115
+ return ghFetch(`/repos/${repo}/git/blobs/${sha}`);
116
+ }, cacheOptions("blobs"));
117
+ export const ghMarkdown = defineCachedFunction(
118
+ (markdown, repo, _id) => {
119
+ if (!markdown) {
120
+ return "";
121
+ }
122
+ return ghFetch("/markdown", {
123
+ method: "POST",
124
+ headers: {
125
+ accept: "application/vnd.github+json"
126
+ },
127
+ body: JSON.stringify({
128
+ text: markdown,
129
+ context: repo
130
+ })
131
+ });
132
+ },
133
+ {
134
+ ...cacheOptions("markdown"),
135
+ getKey: (_markdown, repo, id) => `${repo}/${id}`
136
+ }
137
+ );
138
+ function isEmptyArray(val) {
139
+ return Array.isArray(val) && val.length === 0;
140
+ }
141
+ export async function ghCreateBlob(repo, body) {
142
+ repo = joinURL(OWNER, repo);
143
+ return ghFetchNoCache(`/repos/${repo}/git/blobs`, { method: "POST", body: JSON.stringify(body) });
144
+ }
145
+ export async function ghCreateTree(repo, body) {
146
+ repo = joinURL(OWNER, repo);
147
+ return ghFetchNoCache(`/repos/${repo}/git/trees`, { method: "POST", body: JSON.stringify(body) });
148
+ }
149
+ export async function ghCreateCommit(repo, body) {
150
+ repo = joinURL(OWNER, repo);
151
+ return ghFetchNoCache(`/repos/${repo}/git/commits`, { method: "POST", body: JSON.stringify(body) });
152
+ }
153
+ export async function ghUpdateRef(repo, branch, body) {
154
+ repo = joinURL(OWNER, repo);
155
+ return ghFetchNoCache(`/repos/${repo}/git/refs/heads/${branch}`, { method: "PATCH", body: JSON.stringify(body) });
156
+ }
157
+ export async function ghGetBranch(repo, branch) {
158
+ repo = joinURL(OWNER, repo);
159
+ return ghFetchNoCache(`/repos/${repo}/git/refs/heads/${branch}`);
160
+ }
@@ -0,0 +1,71 @@
1
+ /** Represents a GitHub API token with rate limit tracking and validation. */
2
+ export declare class GHToken {
3
+ token: string;
4
+ valid?: boolean;
5
+ remaining?: number;
6
+ limit?: number;
7
+ reset?: number;
8
+ _lastValidated?: number;
9
+ _app?: boolean;
10
+ _appInstallationId?: string;
11
+ constructor(token: string, opts?: {
12
+ app?: boolean;
13
+ appInstallationId?: string;
14
+ });
15
+ get maskedToken(): string;
16
+ toJSON(): {
17
+ token: string;
18
+ valid: boolean | undefined;
19
+ remaining: number | undefined;
20
+ limit: number | undefined;
21
+ reset: number | undefined;
22
+ };
23
+ toString(): string;
24
+ updateStatus(res: Response): void;
25
+ /** NOTE: Each call consumes one API request to fetch rate limit info. */
26
+ validate(): Promise<void>;
27
+ /** Returns true if this token needs revalidation */
28
+ isStale(now?: number): boolean;
29
+ /** Clears expired rate limit state */
30
+ clearExpiredLimits(now?: number): void;
31
+ /** Whether this token is usable for requests */
32
+ get available(): boolean | undefined;
33
+ }
34
+ /** All registered GitHub tokens (PAT and App-generated). */
35
+ export declare const ghTokens: GHToken[];
36
+ /** Bootstraps all App tokens (once), then re-validates all tokens. Use for status page. */
37
+ export declare function ensureAllTokensValidated(): Promise<void>;
38
+ /** Validates tokens until one is available, then continues the rest in background. Idempotent (once). */
39
+ export declare const ensureTokensValidated: (() => Promise<void>) & {
40
+ reset: () => void;
41
+ };
42
+ /**
43
+ * Revalidates only tokens that haven't been validated in the last minute.
44
+ * Concurrent callers share the same in-flight promise (coalesced, not once).
45
+ * Returns true if any tokens were revalidated.
46
+ */
47
+ export declare const revalidateGHTokens: (() => Promise<boolean>) & {
48
+ reset: () => void;
49
+ };
50
+ /** Returns the best available token (highest remaining quota), or `undefined` if none available. */
51
+ export declare function getGHToken(): GHToken | undefined;
52
+ /** Ensures tokens are validated and returns the best available one. Revalidates if needed. */
53
+ export declare function acquireGHToken(): Promise<GHToken | undefined>;
54
+ /** Returns aggregate rate limit stats across all tokens. */
55
+ export declare function getAggregateRateLimit(): {
56
+ remaining: number;
57
+ limit: number;
58
+ reset: number | undefined;
59
+ };
60
+ /** Computes a Retry-After value in seconds from a reset timestamp, with ~0-30 min random jitter. */
61
+ export declare function retryAfterSeconds(resetMs: number | undefined, fallback?: number): number;
62
+ /** Formats a duration in milliseconds to a human-readable string (e.g. `"5m"`, `"1h30m"`). */
63
+ export declare function formatDuration(ms: number): string;
64
+ /** Bootstraps GitHub App installation tokens (samples up to 5 random installations). Coalesced (not once). */
65
+ export declare const ensureAppToken: (() => Promise<void>) & {
66
+ reset: () => void;
67
+ };
68
+ /** Creates an RS256-signed JWT for GitHub App authentication. Exported for testing. */
69
+ export declare function _createAppJWT(appId: string, privateKey: string): Promise<string>;
70
+ /** Encodes a UTF-8 string to base64url. Exported for testing. */
71
+ export declare function _base64url(str: string): string;