@maudecode/kanvil 0.4.0 → 0.4.1
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/apps/server/.env.example +2 -0
- package/apps/server/dist/{auth-Cuo7ECLh.mjs → auth-DAqfvUJm.mjs} +2 -1
- package/apps/server/dist/{config-DtNfVSnB.mjs → config-BFzcAs8u.mjs} +1 -0
- package/apps/server/dist/index.mjs +3 -3
- package/apps/server/dist/migrate.mjs +1 -1
- package/apps/server/dist/recover.mjs +2 -2
- package/compose.yml +1 -0
- package/docs/api.md +1 -1
- package/docs/self-hosting.md +3 -1
- package/package.json +1 -1
package/apps/server/.env.example
CHANGED
|
@@ -10,6 +10,8 @@ PORT=5180
|
|
|
10
10
|
KANVIL_TRUSTED_ORIGINS=http://localhost:5173
|
|
11
11
|
# Write requests per minute allowed for one signed-in account before 429 responses.
|
|
12
12
|
KANVIL_SESSION_WRITE_LIMIT=120
|
|
13
|
+
# Set false to disable rate limiting for all API keys, including existing keys.
|
|
14
|
+
KANVIL_API_KEY_RATE_LIMIT_ENABLED=true
|
|
13
15
|
# Configure all three OIDC values together. Omit them to use local login only.
|
|
14
16
|
# OIDC_DISCOVERY_URL=https://identity.example.com/.well-known/openid-configuration
|
|
15
17
|
# OIDC_CLIENT_ID=
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as auth_schema_exports, c as oauthConsent, d as user, i as apikey, l as oauthRefreshToken, o as oauthAccessToken, r as account, s as oauthClient, u as session } from "./config-
|
|
1
|
+
import { a as auth_schema_exports, c as oauthConsent, d as user, i as apikey, l as oauthRefreshToken, o as oauthAccessToken, r as account, s as oauthClient, u as session } from "./config-BFzcAs8u.mjs";
|
|
2
2
|
import { c as searchAuthentication, i as instanceUpdateSchema, l as searchSettingsSchema, n as authenticationPolicySchema, r as brokerSettingsSchema, s as s3SettingsSchema } from "./instance-CCeXRJ6m.mjs";
|
|
3
3
|
import { $ as permissions, C as eventLabels, Ct as ticketFilter, D as formatEvent, Dt as workflowOrder, E as filterList, Et as ticketSchema, J as parseCustomFieldFilter, K as operationPermission, L as isSeededRole, M as invitationStatuses, N as isHexColor, O as hasAdminRole, Ot as workspaceSchema, Q as permissionScope, S as eventCategories, St as ticketExportFormat, T as filterKey, Tt as ticketPredicates, X as parsePublicOutput, Y as parseOutput, Z as permissionLabels, _ as deliverySettingsSchema, _t as snapshotSchema, at as remoteKinds, b as difficulties, bt as states, c as credentialProjectsSchema, ct as repositorySecretFields, d as customFieldValue, dt as roleLabels, et as priorities, f as customFieldValueSchema, ft as roles, g as deliverySecretFields, gt as signInMethodLabels, h as deletedAccountName, ht as seededPermissions, i as channelRouteAllows, j as importSecretFields, l as customFieldFilterTokens, lt as resourceProvider, m as defaultWorkflow, mt as searchResultTypes, n as attachmentLimit, nt as projectSchema, o as closedStates, ot as repositoryProviderDefinitions, p as defaultOrder, pt as scopes, q as operations, r as channelKinds, rt as publicOperations, st as repositoryProviders, t as ApiError, tt as priorityLabels, u as customFieldSchema, ut as roleCategory, v as destinationEventKeys, vt as stagedUploadLifetime, w as eventSchema, wt as ticketImportSchema, y as destinationKinds, yt as stateLabels, z as mentionScheme } from "./src-tQ82UI8k.mjs";
|
|
4
4
|
import { and, asc, count, desc, eq, getTableColumns, gt, ilike, inArray, isNotNull, isNull, lt, lte, ne, notInArray, or, sql } from "drizzle-orm";
|
|
@@ -7711,6 +7711,7 @@ function createAuth(database, config) {
|
|
|
7711
7711
|
defaultPrefix: "kv_",
|
|
7712
7712
|
enableMetadata: true,
|
|
7713
7713
|
maximumNameLength: 100,
|
|
7714
|
+
rateLimit: { enabled: config.KANVIL_API_KEY_RATE_LIMIT_ENABLED },
|
|
7714
7715
|
keyExpiration: {
|
|
7715
7716
|
minExpiresIn: 1 / 24,
|
|
7716
7717
|
maxExpiresIn: 365
|
|
@@ -395,6 +395,7 @@ const envSchema = z.object({
|
|
|
395
395
|
DISCORD_CLIENT_ID: optionalEnv(z.string().min(1)),
|
|
396
396
|
DISCORD_CLIENT_SECRET: optionalEnv(z.string().min(1)),
|
|
397
397
|
KANVIL_SESSION_WRITE_LIMIT: z.coerce.number().int().min(1).max(1e5).default(120),
|
|
398
|
+
KANVIL_API_KEY_RATE_LIMIT_ENABLED: z.enum(["true", "false"]).default("true").transform((value) => value === "true"),
|
|
398
399
|
KANVIL_PUSH_ENABLED: z.enum(["true", "false"]).default("false").transform((value) => value === "true"),
|
|
399
400
|
EXPO_ACCESS_TOKEN: optionalEnv(z.string().min(1)),
|
|
400
401
|
SMTP_URL: optionalEnv(z.url({ protocol: /^smtps?$/ })),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { a as auth_schema_exports, d as user$1, i as apikey, n as createDatabase, r as account, t as readConfig, u as session } from "./config-
|
|
1
|
+
import { a as auth_schema_exports, d as user$1, i as apikey, n as createDatabase, r as account, t as readConfig, u as session } from "./config-BFzcAs8u.mjs";
|
|
2
2
|
import { a as photoInputSchema, i as instanceUpdateSchema, l as searchSettingsSchema, o as photoResultSchema, r as brokerSettingsSchema, s as s3SettingsSchema, t as adminInstanceSchema } from "./instance-CCeXRJ6m.mjs";
|
|
3
3
|
import { t as migrateDatabase } from "./migrate-C9f4ozB4.mjs";
|
|
4
|
-
import { $ as subscriptions, A as createTicketSearch, B as blobObjects, C as DeliveryError, D as requireInstanceAdmin, E as createWriteLimiter, F as stagedUploadCutoff, G as members, H as eventClock, I as createObjectStore, J as profilePhotos, K as notificationPreferences, L as createPollingJob, M as createBlobStorage, N as decodeImage, O as requireSession, P as imageResponse, Q as storageBackends, R as attachmentContent, S as deliverBatch, T as createAccess, U as events, V as deliveryCheckpoints, X as pushDevices, Y as projects, Z as stagedUploads, _ as recipientColumns, a as deliverySecrets, b as receiveRepositoryWebhook, c as ownerBlocker, d as createDomain, et as tickets, f as fail, g as reachable, h as one, i as createInstance, j as createTicketIndex, k as readCalendarFeed, l as appendEvents, m as notify, n as emailCodesAvailable, nt as workspaces, o as otherActiveAdministrator, p as json, q as notifications, r as signInProviders, rt as matchesOIDCBinding, s as ownedWorkspaces, t as createAuth, tt as workspaceMembers, u as assertVersion, v as requireRow, w as createHttpSender, x as defaultSenders, y as processImports, z as attachments } from "./auth-
|
|
4
|
+
import { $ as subscriptions, A as createTicketSearch, B as blobObjects, C as DeliveryError, D as requireInstanceAdmin, E as createWriteLimiter, F as stagedUploadCutoff, G as members, H as eventClock, I as createObjectStore, J as profilePhotos, K as notificationPreferences, L as createPollingJob, M as createBlobStorage, N as decodeImage, O as requireSession, P as imageResponse, Q as storageBackends, R as attachmentContent, S as deliverBatch, T as createAccess, U as events, V as deliveryCheckpoints, X as pushDevices, Y as projects, Z as stagedUploads, _ as recipientColumns, a as deliverySecrets, b as receiveRepositoryWebhook, c as ownerBlocker, d as createDomain, et as tickets, f as fail, g as reachable, h as one, i as createInstance, j as createTicketIndex, k as readCalendarFeed, l as appendEvents, m as notify, n as emailCodesAvailable, nt as workspaces, o as otherActiveAdministrator, p as json, q as notifications, r as signInProviders, rt as matchesOIDCBinding, s as ownedWorkspaces, t as createAuth, tt as workspaceMembers, u as assertVersion, v as requireRow, w as createHttpSender, x as defaultSenders, y as processImports, z as attachments } from "./auth-DAqfvUJm.mjs";
|
|
5
5
|
import { A as importProviderDefinitions, B as notificationIdsInput, F as isPresetColor, G as okSchema, H as notificationPreferencesSchema, I as isPublicOperation, O as hasAdminRole, P as isOperation, R as memberSchema, St as ticketExportFormat, U as notificationReadInput, V as notificationPreferencesInput, ft as roles, it as pushDeviceInput, k as importLimits, m as defaultWorkflow, o as closedStates, pt as scopes, q as operations, rt as publicOperations, s as credentialInput, t as ApiError, x as errorSchema, yt as stateLabels } from "./src-tQ82UI8k.mjs";
|
|
6
6
|
import { serve } from "@hono/node-server";
|
|
7
7
|
import pg from "pg";
|
|
@@ -326,7 +326,7 @@ function createAccountAdministration(database, auth, config) {
|
|
|
326
326
|
}
|
|
327
327
|
//#endregion
|
|
328
328
|
//#region src/version.ts
|
|
329
|
-
const applicationVersion = "0.4.
|
|
329
|
+
const applicationVersion = "0.4.1";
|
|
330
330
|
//#endregion
|
|
331
331
|
//#region src/realtime.ts
|
|
332
332
|
async function createRealtime(config) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as createDatabase, t as readConfig } from "./config-
|
|
1
|
+
import { n as createDatabase, t as readConfig } from "./config-BFzcAs8u.mjs";
|
|
2
2
|
import { t as migrateDatabase } from "./migrate-C9f4ozB4.mjs";
|
|
3
3
|
//#region src/cli/migrate.ts
|
|
4
4
|
const database = createDatabase(readConfig().DATABASE_URL);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { d as user, n as createDatabase, r as account, t as readConfig, u as session } from "./config-
|
|
2
|
-
import { W as instanceSettings, f as fail, t as createAuth } from "./auth-
|
|
1
|
+
import { d as user, n as createDatabase, r as account, t as readConfig, u as session } from "./config-BFzcAs8u.mjs";
|
|
2
|
+
import { W as instanceSettings, f as fail, t as createAuth } from "./auth-DAqfvUJm.mjs";
|
|
3
3
|
import { O as hasAdminRole } from "./src-tQ82UI8k.mjs";
|
|
4
4
|
import { and, eq, isNull, sql } from "drizzle-orm";
|
|
5
5
|
import { z } from "zod";
|
package/compose.yml
CHANGED
|
@@ -12,6 +12,7 @@ services:
|
|
|
12
12
|
KANVIL_SETUP_TOKEN: ${KANVIL_SETUP_TOKEN:-}
|
|
13
13
|
KANVIL_URL: ${KANVIL_URL:?Set your public HTTPS URL}
|
|
14
14
|
KANVIL_TRUSTED_ORIGINS: ${KANVIL_TRUSTED_ORIGINS:-}
|
|
15
|
+
KANVIL_API_KEY_RATE_LIMIT_ENABLED: ${KANVIL_API_KEY_RATE_LIMIT_ENABLED:-true}
|
|
15
16
|
OIDC_DISCOVERY_URL: ${OIDC_DISCOVERY_URL:-}
|
|
16
17
|
OIDC_CLIENT_ID: ${OIDC_CLIENT_ID:-}
|
|
17
18
|
OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET:-}
|
package/docs/api.md
CHANGED
|
@@ -16,7 +16,7 @@ Use the ticket's current `version` as `expectedVersion` for updates. A stale ver
|
|
|
16
16
|
|
|
17
17
|
Reuse the same UUID `requestId` when retrying a write. Reusing it with a different operation or payload returns `409 idempotency_conflict`. Bulk edits either all commit or all roll back, and publish one `ticket.updated` event per ticket with consecutive IDs in a single batch.
|
|
18
18
|
|
|
19
|
-
Signed-in sessions may make `KANVIL_SESSION_WRITE_LIMIT` write requests per minute (120 by default) to `/api/v1`, and MCP OAuth clients get the same budget for write tools; exceeding it returns `429 rate_limited` with a `Retry-After` header. API keys
|
|
19
|
+
Signed-in sessions may make `KANVIL_SESSION_WRITE_LIMIT` write requests per minute (120 by default) to `/api/v1`, and MCP OAuth clients get the same budget for write tools; exceeding it returns `429 rate_limited` with a `Retry-After` header. This counter is per application process. API keys have a separate limit of 600 requests per minute per key across HTTP and MCP. An instance operator can set `KANVIL_API_KEY_RATE_LIMIT_ENABLED=false` and restart the server to disable that limit for existing and new keys. The default is `true`; restoring it enforces the limit again. Session, MCP OAuth, and sign-in limits are unchanged, as are key expiration, revocation, scopes, and account permissions.
|
|
20
20
|
|
|
21
21
|
Claims require an eligible ticket and current version. Successful claiming moves it to In progress. Renew an unexpired claim using its ID and the same credential. Once a ticket has been claimed, machine ticket updates and evidence submissions always require a current matching claim ID, including after release or recovery. Submit completion and evidence before releasing ownership. Human sessions can edit and reschedule work without a machine claim. Release unexpired ownership after the worker stops or completes. The ticket response exposes `canReleaseClaim` for the exact credential or client identity; sharing an account does not confer ownership. An expired claim remains blocking until a project administrator confirms the old worker stopped and explicitly recovers it; recovery does not automatically reschedule work.
|
|
22
22
|
|
package/docs/self-hosting.md
CHANGED
|
@@ -91,7 +91,9 @@ location / {
|
|
|
91
91
|
|
|
92
92
|
Keep `KANVIL_URL` equal to the public HTTPS origin. Add `KANVIL_TRUSTED_ORIGINS` only for additional browser clients you explicitly operate. Web, API, MCP, login, consent, and realtime use the same application origin. No separate message broker or search service is required.
|
|
93
93
|
|
|
94
|
-
Signed-in sessions and MCP OAuth clients may make `KANVIL_SESSION_WRITE_LIMIT` write requests per minute (120 by default) before receiving `429 rate_limited
|
|
94
|
+
Signed-in sessions and MCP OAuth clients may make `KANVIL_SESSION_WRITE_LIMIT` write requests per minute (120 by default) before receiving `429 rate_limited`. This counter is per application process.
|
|
95
|
+
|
|
96
|
+
API keys have a separate limit of 600 requests per minute per key across HTTP and MCP. Set `KANVIL_API_KEY_RATE_LIMIT_ENABLED=false` in `.env` and restart the server (with Compose, `docker compose up -d app`) to disable that limit for every existing and new API key. Restore `true` to enforce it again. This setting does not change session, MCP OAuth, or sign-in limits, and key expiration, revocation, scopes, and account permissions still apply.
|
|
95
97
|
|
|
96
98
|
## PocketID / OIDC
|
|
97
99
|
|