@maudecode/kanvil 0.4.3 → 0.5.0
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 +5 -0
- package/apps/server/dist/{auth-CnAQzKyq.mjs → auth-Cs_whzgk.mjs} +382 -127
- package/apps/server/dist/client.mjs +4 -3
- package/apps/server/dist/{config-DOT1SDQO.mjs → config-DKuNQY5b.mjs} +15 -7
- package/apps/server/dist/index.mjs +105 -57
- package/apps/server/dist/migrate.mjs +2 -2
- package/apps/server/dist/recover.mjs +4 -4
- package/apps/server/dist/{src-VxR5jZiK.mjs → src-DptOUNRd.mjs} +67 -23
- package/apps/web/dist/assets/{CompositeItem-B5Qlh5m0.js → CompositeItem-CXqewtEL.js} +1 -1
- package/apps/web/dist/assets/{Trans-DxqBaUXP.js → Trans-B1rRlWca.js} +1 -1
- package/apps/web/dist/assets/{admin-settings-Bp7V2t1V.js → admin-settings-DE3MfBFE.js} +1 -1
- package/apps/web/dist/assets/{archive-restore-wsAzhqi-.js → archive-restore-76sStk8K.js} +1 -1
- package/apps/web/dist/assets/az-AZ-bFxpMMZN.js +1 -0
- package/apps/web/dist/assets/{az-C4KDjOOw.js → az-B7OgHoaE.js} +1 -1
- package/apps/web/dist/assets/{corner-left-up-arA2ipmM.js → corner-left-up-PD-73Nae.js} +1 -1
- package/apps/web/dist/assets/{de-Z599ZW7b.js → de-B-bv38Q0.js} +1 -1
- package/apps/web/dist/assets/de-DE-BeXI30Ll.js +1 -0
- package/apps/web/dist/assets/default-bQFGTwIp.js +56 -0
- package/apps/web/dist/assets/{delivery-settings-D5NKPlhN.js → delivery-settings-BvMeOsCS.js} +1 -1
- package/apps/web/dist/assets/{el-xsvq992p.js → el-BQHQHQgX.js} +1 -1
- package/apps/web/dist/assets/el-GR-SgRHlWhY.js +1 -0
- package/apps/web/dist/assets/{ellipsis-UOkL14vq.js → ellipsis-GF1HwTDb.js} +1 -1
- package/apps/web/dist/assets/es-ES-BF1J5vap.js +1 -0
- package/apps/web/dist/assets/{es-D3e9L5_i.js → es-f5Xr8ldr.js} +1 -1
- package/apps/web/dist/assets/{forms-BbWAl0BZ.js → forms-BlEL8C_P.js} +1 -1
- package/apps/web/dist/assets/{fr-CY35Bcpp.js → fr-DSR0htnl.js} +1 -1
- package/apps/web/dist/assets/fr-FR-D_sldwf6.js +1 -0
- package/apps/web/dist/assets/{hi-Cqfv-E5P.js → hi-BaAJEWuW.js} +1 -1
- package/apps/web/dist/assets/hi-IN-CfOw4TWf.js +1 -0
- package/apps/web/dist/assets/{highlight-Ds7xUUQv.js → highlight-DXT2xgt8.js} +1 -1
- package/apps/web/dist/assets/id-ID-CLKtHO7Q.js +1 -0
- package/apps/web/dist/assets/{id-CFBOVDUC.js → id-kxogWcip.js} +1 -1
- package/apps/web/dist/assets/{index-2V6MWx63.js → index-CYVrs22O.js} +5 -5
- package/apps/web/dist/assets/{invitations-BPk5fwwU.js → invitations-BPik3J_G.js} +1 -1
- package/apps/web/dist/assets/{it-DNLponcC.js → it-C_qk40U6.js} +1 -1
- package/apps/web/dist/assets/it-IT-eVZNW5qX.js +1 -0
- package/apps/web/dist/assets/{item-DED0Ikqi.js → item-TCHuZNK6.js} +1 -1
- package/apps/web/dist/assets/{ja-ZXGlS4WA.js → ja-Dn5h64V9.js} +1 -1
- package/apps/web/dist/assets/ja-JP-D96njn-P.js +1 -0
- package/apps/web/dist/assets/{ko-CSoj1hQM.js → ko-CjaoEPuG.js} +1 -1
- package/apps/web/dist/assets/ko-KR-Bash_ieA.js +1 -0
- package/apps/web/dist/assets/{label-settings-D12QOkDs.js → label-settings-DZTorNDm.js} +1 -1
- package/apps/web/dist/assets/{markdown-blocks-DbsqN1T2.js → markdown-blocks-BQLO-H_7.js} +1 -1
- package/apps/web/dist/assets/{member-directory-BRhEIYZ6.js → member-directory-Dx_jQYfI.js} +1 -1
- package/apps/web/dist/assets/mk-MK-BWQWGIRx.js +1 -0
- package/apps/web/dist/assets/{mk-D77vceoz.js → mk-jLeGD50T.js} +1 -1
- package/apps/web/dist/assets/{nl-Bew8-xmX.js → nl-AVtC5ygT.js} +1 -1
- package/apps/web/dist/assets/nl-NL-D1tvo0Gd.js +1 -0
- package/apps/web/dist/assets/{pl-CEBl_oa9.js → pl-Dup1h_Y1.js} +1 -1
- package/apps/web/dist/assets/pl-PL-DNgGUEcQ.js +1 -0
- package/apps/web/dist/assets/{project-lifecycle-DGHAmEB2.js → project-lifecycle-n1ZZbYfu.js} +1 -1
- package/apps/web/dist/assets/{project-settings-DY8Ossd-.js → project-settings-B_Ih5kiz.js} +1 -1
- package/apps/web/dist/assets/pt-BR-CZsUZQ6P.js +1 -0
- package/apps/web/dist/assets/{pt-BR-BDTQeKcp.js → pt-BR-Cm04EWM-.js} +1 -1
- package/apps/web/dist/assets/{public-project-BeXla8TL.js → public-project-BivDjU_a.js} +1 -1
- package/apps/web/dist/assets/{rotate-ccw-DGM890Fc.js → rotate-ccw-CSaKhZYt.js} +1 -1
- package/apps/web/dist/assets/{ru-BeH0eXQq.js → ru-IeycXsyE.js} +1 -1
- package/apps/web/dist/assets/ru-RU-4ew92YE_.js +1 -0
- package/apps/web/dist/assets/{search-B3-w3oCd.js → search-Ble6WSEU.js} +3 -3
- package/apps/web/dist/assets/{send-B9baaCnt.js → send-BLMZ8gQ0.js} +1 -1
- package/apps/web/dist/assets/settings-CH48qQK2.js +1 -0
- package/apps/web/dist/assets/{sliders-horizontal-yKgghk8h.js → sliders-horizontal-Db6kRvuw.js} +1 -1
- package/apps/web/dist/assets/{switch-ByOrazEW.js → switch-BeX-0Fwq.js} +1 -1
- package/apps/web/dist/assets/{table-Cm6NQXfq.js → table-UJp5S9yy.js} +1 -1
- package/apps/web/dist/assets/ticket-detail-C24opfNW.js +2 -0
- package/apps/web/dist/assets/{ticket-editor-CLDBUk0n.js → ticket-editor--d_bG9C1.js} +2 -2
- package/apps/web/dist/assets/{ticket-list-BC9acNl4.js → ticket-list-DRbZWYHf.js} +1 -1
- package/apps/web/dist/assets/{ticket-list-controls-CRQk5ghe.js → ticket-list-controls-fYBottFC.js} +1 -1
- package/apps/web/dist/assets/{tr-BNApk6Hc.js → tr-DtT_dKUK.js} +1 -1
- package/apps/web/dist/assets/tr-TR-CM381XCw.js +1 -0
- package/apps/web/dist/assets/{uk-CjShsgpN.js → uk-CsbeHSS6.js} +1 -1
- package/apps/web/dist/assets/uk-UA-AeOiWCVo.js +1 -0
- package/apps/web/dist/assets/{upload-BzLq4CMS.js → upload-DUEg04Nj.js} +1 -1
- package/apps/web/dist/assets/{useQueries-D64vLhM6.js → useQueries-5lW2C5Sb.js} +1 -1
- package/apps/web/dist/assets/vi-VN-td08xXv9.js +1 -0
- package/apps/web/dist/assets/{vi-s5Hfv1Y-.js → vi-rkf1BOLx.js} +1 -1
- package/apps/web/dist/assets/{visual-editor-KE96mwCg.js → visual-editor-DkFLjouD.js} +1 -1
- package/apps/web/dist/assets/{workspace-settings-C-Phmi9i.js → workspace-settings-Bcsp-VoJ.js} +1 -1
- package/apps/web/dist/assets/zh-CN-D3dhEYLS.js +1 -0
- package/apps/web/dist/assets/{zh-CN-BBnpHJ9R.js → zh-CN-Xo-QId5w.js} +1 -1
- package/apps/web/dist/assets/zh-TW-CfhOEFo8.js +1 -0
- package/apps/web/dist/assets/{zh-TW-sSWkqSLN.js → zh-TW-DEnTqjbn.js} +1 -1
- package/apps/web/dist/index.html +7 -7
- package/docs/api.md +27 -13
- package/docs/cli.md +9 -1
- package/docs/releasing.md +16 -2
- package/docs/self-hosting.md +8 -0
- package/package.json +1 -1
- package/apps/web/dist/assets/az-AZ-DlsPlUZi.js +0 -1
- package/apps/web/dist/assets/de-DE-DLCaqUUe.js +0 -1
- package/apps/web/dist/assets/default-6QIAyMq2.js +0 -56
- package/apps/web/dist/assets/el-GR-P2XcwrSU.js +0 -1
- package/apps/web/dist/assets/es-ES-CJoX8f3w.js +0 -1
- package/apps/web/dist/assets/fr-FR-yLkQdy6a.js +0 -1
- package/apps/web/dist/assets/hi-IN-y8dqej7z.js +0 -1
- package/apps/web/dist/assets/id-ID-DSvh8mGH.js +0 -1
- package/apps/web/dist/assets/it-IT-BUcfUqNo.js +0 -1
- package/apps/web/dist/assets/ja-JP-C-jLP_Ay.js +0 -1
- package/apps/web/dist/assets/ko-KR-C5Ozdm2E.js +0 -1
- package/apps/web/dist/assets/mk-MK-BdM_SsE8.js +0 -1
- package/apps/web/dist/assets/nl-NL-CwjB5sva.js +0 -1
- package/apps/web/dist/assets/pl-PL-6-PMhTBd.js +0 -1
- package/apps/web/dist/assets/pt-BR-TD_wt6Hr.js +0 -1
- package/apps/web/dist/assets/ru-RU-Bk1a6Oln.js +0 -1
- package/apps/web/dist/assets/settings-BKZfEkVk.js +0 -1
- package/apps/web/dist/assets/ticket-detail-Cd3_e2jz.js +0 -2
- package/apps/web/dist/assets/tr-TR-CUfBb7K9.js +0 -1
- package/apps/web/dist/assets/uk-UA-BDaXBsDP.js +0 -1
- package/apps/web/dist/assets/vi-VN-Bgb-L6mE.js +0 -1
- package/apps/web/dist/assets/zh-CN-BypkvBe6.js +0 -1
- package/apps/web/dist/assets/zh-TW-CgMsT_XS.js +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as errorSchema, Ct as streamErrorSchema, E as eventSchema, G as notificationReadInput, H as notificationIdsInput, K as notificationsSchema, Q as parsePublicOutput, U as notificationPreferencesInput, W as notificationPreferencesSchema, Y as operations, Z as parseOutput, a as checkpointSchema, at as publicOperations, q as okSchema, t as ApiError, yt as snapshotSchema } from "./src-
|
|
1
|
+
import { C as errorSchema, Ct as streamErrorSchema, E as eventSchema, G as notificationReadInput, H as notificationIdsInput, K as notificationsSchema, Q as parsePublicOutput, U as notificationPreferencesInput, W as notificationPreferencesSchema, Y as operations, Z as parseOutput, a as checkpointSchema, at as publicOperations, q as okSchema, t as ApiError, yt as snapshotSchema } from "./src-DptOUNRd.mjs";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { parseArgs } from "node:util";
|
|
4
4
|
import { constants } from "node:fs";
|
|
@@ -639,7 +639,8 @@ const commands = {
|
|
|
639
639
|
"comment add": "add_comment",
|
|
640
640
|
"claim acquire": "claim_ticket",
|
|
641
641
|
"claim renew": "renew_claim",
|
|
642
|
-
"claim release": "release_claim"
|
|
642
|
+
"claim release": "release_claim",
|
|
643
|
+
"claim recover": "recover_claim"
|
|
643
644
|
};
|
|
644
645
|
const clientHelp = `Usage: kanvil <namespace> <action> [ticket-key] [options]
|
|
645
646
|
${Object.keys(commands).join("\n")}
|
|
@@ -651,7 +652,7 @@ profile list | profile remove <name> --yes
|
|
|
651
652
|
--input <json|-> Operation input as a JSON object; - reads stdin
|
|
652
653
|
--title <text> Ticket title
|
|
653
654
|
--body <markdown> Comment body
|
|
654
|
-
--expected-version <n> Required version for update, delete and
|
|
655
|
+
--expected-version <n> Required version for update, delete, acquire and rescheduling recovery
|
|
655
656
|
--changes <json> Ticket update changes as a JSON object
|
|
656
657
|
--request-id <uuid> Reuse for a deliberate retry across invocations
|
|
657
658
|
--json Compact JSON output (default: indented JSON)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Bt as searchSettingsSchema, Pt as brokerSettingsSchema, Rt as s3SettingsSchema, m as defaultClaimMaxLeaseSeconds, o as claimLeaseSecondsSchema } from "./src-DptOUNRd.mjs";
|
|
2
2
|
import pg from "pg";
|
|
3
3
|
import { drizzle } from "drizzle-orm/node-postgres";
|
|
4
4
|
import { relations } from "drizzle-orm";
|
|
@@ -341,12 +341,17 @@ const oauthConsentRelations = relations(oauthConsent, ({ one }) => ({
|
|
|
341
341
|
}));
|
|
342
342
|
//#endregion
|
|
343
343
|
//#region src/database.ts
|
|
344
|
-
function
|
|
345
|
-
|
|
346
|
-
connectionString:
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
344
|
+
function poolOptions(config, role) {
|
|
345
|
+
return {
|
|
346
|
+
connectionString: config.DATABASE_URL,
|
|
347
|
+
application_name: role === "domain" ? "kanvil" : "kanvil-integration",
|
|
348
|
+
max: role === "domain" ? config.KANVIL_DATABASE_POOL_MAX : config.KANVIL_INTEGRATION_POOL_MAX,
|
|
349
|
+
idleTimeoutMillis: 3e4,
|
|
350
|
+
connectionTimeoutMillis: config.KANVIL_DATABASE_ACQUIRE_TIMEOUT_MS
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
function createDatabase(config, role = "domain") {
|
|
354
|
+
const pool = new pg.Pool(poolOptions(config, role));
|
|
350
355
|
pool.on("error", () => {
|
|
351
356
|
console.error("A PostgreSQL idle connection was lost; the pool will reconnect.");
|
|
352
357
|
});
|
|
@@ -360,6 +365,9 @@ function createDatabase(url) {
|
|
|
360
365
|
const optionalEnv = (schema) => z.preprocess((value) => value === "" ? void 0 : value, schema.optional());
|
|
361
366
|
const envSchema = z.object({
|
|
362
367
|
DATABASE_URL: z.url(),
|
|
368
|
+
KANVIL_DATABASE_POOL_MAX: z.coerce.number().int().min(2).max(1e3).default(10),
|
|
369
|
+
KANVIL_INTEGRATION_POOL_MAX: z.coerce.number().int().min(1).max(1e3).default(4),
|
|
370
|
+
KANVIL_DATABASE_ACQUIRE_TIMEOUT_MS: z.coerce.number().int().min(100).max(6e5).default(3e4),
|
|
363
371
|
KANVIL_STORAGE_PROVIDER: optionalEnv(z.enum(["local", "s3"])),
|
|
364
372
|
S3_ENDPOINT: optionalEnv(s3SettingsSchema.shape.endpoint),
|
|
365
373
|
S3_REGION: s3SettingsSchema.shape.region,
|
|
@@ -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-
|
|
2
|
-
import { A as hasAdminRole, B as memberSchema, C as errorSchema, Ft as
|
|
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-DKuNQY5b.mjs";
|
|
2
|
+
import { A as hasAdminRole, B as memberSchema, Bt as searchSettingsSchema, C as errorSchema, Ft as instanceUpdateSchema, G as notificationReadInput, H as notificationIdsInput, I as isOperation, It as photoInputSchema, L as isPresetColor, Lt as photoResultSchema, M as importProviderDefinitions, Mt as adminInstanceSchema, Pt as brokerSettingsSchema, R as isPublicOperation, Rt as s3SettingsSchema, U as notificationPreferencesInput, W as notificationPreferencesSchema, Y as operations, at as publicOperations, c as credentialInput, g as defaultWorkflow, ht as scopes, j as importLimits, mt as roles, ot as pushDeviceInput, q as okSchema, s as closedStates, t as ApiError, wt as ticketExportFormat, xt as stateLabels } from "./src-DptOUNRd.mjs";
|
|
3
3
|
import { t as migrateDatabase } from "./migrate-C9f4ozB4.mjs";
|
|
4
|
-
import { $ as
|
|
4
|
+
import { $ as stagedUploads, A as requireSession, B as attachmentContent, C as defaultSenders, D as createAccess, E as createHttpSender, F as decodeImage, G as events, H as blobObjects, I as imageResponse, J as notificationPreferences, L as stagedUploadCutoff, M as createTicketSearch, N as createTicketIndex, O as createWriteLimiter, P as createBlobStorage, Q as pushDevices, R as createObjectStore, S as receiveRepositoryWebhook, T as DeliveryError, U as deliveryCheckpoints, V as attachments, W as eventClock, X as profilePhotos, Y as notifications, Z as projects, _ as one, a as deliverySecrets, at as matchesOIDCBinding, b as requireRow, c as ownerBlocker, d as createDomain, et as storageBackends, f as errorEnvelope, g as notify, h as json, i as createInstance, it as workspaces, j as readCalendarFeed, k as requireInstanceAdmin, l as appendEvents, m as intakeOnly, n as emailCodesAvailable, nt as tickets, o as otherActiveAdministrator, p as fail, q as members, r as signInProviders, rt as workspaceMembers, s as ownedWorkspaces, t as createAuth, tt as subscriptions, u as assertVersion, v as reachable, w as deliverBatch, x as processImports, y as recipientColumns, z as createPollingJob } from "./auth-Cs_whzgk.mjs";
|
|
5
5
|
import { serve } from "@hono/node-server";
|
|
6
6
|
import pg from "pg";
|
|
7
7
|
import { drizzle } from "drizzle-orm/node-postgres";
|
|
@@ -324,8 +324,42 @@ function createAccountAdministration(database, auth, config) {
|
|
|
324
324
|
};
|
|
325
325
|
}
|
|
326
326
|
//#endregion
|
|
327
|
+
//#region src/cleanup.ts
|
|
328
|
+
function createCleanup() {
|
|
329
|
+
const resources = [];
|
|
330
|
+
let closing;
|
|
331
|
+
function close() {
|
|
332
|
+
return closing ??= Promise.resolve().then(async () => {
|
|
333
|
+
const failures = [];
|
|
334
|
+
for (const resource of resources.toReversed()) try {
|
|
335
|
+
await resource.close();
|
|
336
|
+
} catch {
|
|
337
|
+
failures.push(/* @__PURE__ */ new Error(`Could not close ${resource.name}.`));
|
|
338
|
+
}
|
|
339
|
+
if (failures.length) throw new AggregateError(failures, "Resource cleanup failed.");
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
return {
|
|
343
|
+
add(name, release) {
|
|
344
|
+
resources.push({
|
|
345
|
+
name,
|
|
346
|
+
close: release
|
|
347
|
+
});
|
|
348
|
+
},
|
|
349
|
+
close,
|
|
350
|
+
async fail(error) {
|
|
351
|
+
try {
|
|
352
|
+
await close();
|
|
353
|
+
} catch (cleanupError) {
|
|
354
|
+
console.error("Startup cleanup failed.", cleanupError);
|
|
355
|
+
}
|
|
356
|
+
throw error;
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
//#endregion
|
|
327
361
|
//#region src/version.ts
|
|
328
|
-
const applicationVersion = "0.
|
|
362
|
+
const applicationVersion = "0.5.0";
|
|
329
363
|
//#endregion
|
|
330
364
|
//#region src/realtime.ts
|
|
331
365
|
async function createRealtime(config) {
|
|
@@ -334,7 +368,10 @@ async function createRealtime(config) {
|
|
|
334
368
|
let client, closed = false, retry;
|
|
335
369
|
async function connect() {
|
|
336
370
|
if (closed) return;
|
|
337
|
-
const connection = new pg.Client({
|
|
371
|
+
const connection = new pg.Client({
|
|
372
|
+
connectionString: config.DATABASE_URL,
|
|
373
|
+
application_name: "kanvil-realtime"
|
|
374
|
+
});
|
|
338
375
|
client = connection;
|
|
339
376
|
const disconnected = () => {
|
|
340
377
|
if (client !== connection || closed) return;
|
|
@@ -497,8 +534,25 @@ function brokerEndpoint(settings) {
|
|
|
497
534
|
return `${url.protocol}//${url.host}${url.pathname}`;
|
|
498
535
|
}
|
|
499
536
|
async function createEventDelivery(config, instance, database, factory = createWakeupBus) {
|
|
500
|
-
const
|
|
537
|
+
const cleanup = createCleanup();
|
|
538
|
+
try {
|
|
539
|
+
const postgres = await createRealtime(config);
|
|
540
|
+
cleanup.add("PostgreSQL realtime client", () => postgres.close());
|
|
541
|
+
return await initializeEventDelivery(instance, database, factory, postgres, cleanup);
|
|
542
|
+
} catch (error) {
|
|
543
|
+
return cleanup.fail(error);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
async function initializeEventDelivery(instance, database, factory, postgres, cleanup) {
|
|
547
|
+
const emitter = new EventEmitter();
|
|
501
548
|
emitter.setMaxListeners(0);
|
|
549
|
+
cleanup.add("realtime listeners", () => {
|
|
550
|
+
try {
|
|
551
|
+
emitter.emit("close");
|
|
552
|
+
} finally {
|
|
553
|
+
emitter.removeAllListeners();
|
|
554
|
+
}
|
|
555
|
+
});
|
|
502
556
|
const identity = (await instance.read()).identity;
|
|
503
557
|
let bus, fingerprint = "", destination = "", closed = false, pending, dirty = false, error = null;
|
|
504
558
|
const wake = () => emitter.emit("change");
|
|
@@ -580,11 +634,23 @@ async function createEventDelivery(config, instance, database, factory = createW
|
|
|
580
634
|
if (!bus?.ready() || error) wake();
|
|
581
635
|
trigger();
|
|
582
636
|
});
|
|
637
|
+
cleanup.add("broker connection", async () => {
|
|
638
|
+
await bus?.close();
|
|
639
|
+
});
|
|
640
|
+
cleanup.add("broker worker", async () => {
|
|
641
|
+
closed = true;
|
|
642
|
+
await pending;
|
|
643
|
+
});
|
|
644
|
+
cleanup.add("PostgreSQL subscription", unsubscribe);
|
|
583
645
|
const timer = setInterval(() => {
|
|
584
646
|
if (error) wake();
|
|
585
647
|
trigger();
|
|
586
648
|
}, 1e3);
|
|
587
649
|
timer.unref();
|
|
650
|
+
cleanup.add("broker timer", () => {
|
|
651
|
+
closed = true;
|
|
652
|
+
clearInterval(timer);
|
|
653
|
+
});
|
|
588
654
|
trigger();
|
|
589
655
|
return {
|
|
590
656
|
subscribe(listener) {
|
|
@@ -631,16 +697,7 @@ async function createEventDelivery(config, instance, database, factory = createW
|
|
|
631
697
|
await probe.close().catch(() => {});
|
|
632
698
|
}
|
|
633
699
|
},
|
|
634
|
-
|
|
635
|
-
closed = true;
|
|
636
|
-
clearInterval(timer);
|
|
637
|
-
unsubscribe();
|
|
638
|
-
await pending;
|
|
639
|
-
await bus?.close().catch(() => {});
|
|
640
|
-
emitter.emit("close");
|
|
641
|
-
emitter.removeAllListeners();
|
|
642
|
-
await postgres.close();
|
|
643
|
-
}
|
|
700
|
+
close: cleanup.close
|
|
644
701
|
};
|
|
645
702
|
}
|
|
646
703
|
//#endregion
|
|
@@ -3095,12 +3152,11 @@ function createMcp(auth, domain, access, config, limitWrite) {
|
|
|
3095
3152
|
structuredContent: { result }
|
|
3096
3153
|
};
|
|
3097
3154
|
} catch (error) {
|
|
3098
|
-
if (!(error instanceof ApiError) && !(error instanceof z.ZodError)) throw error;
|
|
3099
3155
|
return {
|
|
3100
3156
|
isError: true,
|
|
3101
3157
|
content: [{
|
|
3102
3158
|
type: "text",
|
|
3103
|
-
text:
|
|
3159
|
+
text: JSON.stringify(errorEnvelope(error).body)
|
|
3104
3160
|
}]
|
|
3105
3161
|
};
|
|
3106
3162
|
}
|
|
@@ -3205,11 +3261,28 @@ const toPreferences = (row) => notificationPreferencesSchema.parse(row ? {
|
|
|
3205
3261
|
} : {});
|
|
3206
3262
|
const digest = (value) => createHash("sha256").update(value).digest();
|
|
3207
3263
|
async function createApplication(database, config, overrides = {}) {
|
|
3264
|
+
const cleanup = createCleanup();
|
|
3208
3265
|
const adapters = {
|
|
3209
3266
|
...defaultAdapters,
|
|
3210
3267
|
...overrides
|
|
3211
3268
|
};
|
|
3212
|
-
const
|
|
3269
|
+
const jobs = (name, interval, run) => {
|
|
3270
|
+
const job = adapters.jobs(name, interval, run);
|
|
3271
|
+
cleanup.add(name, () => job.close());
|
|
3272
|
+
return job;
|
|
3273
|
+
};
|
|
3274
|
+
try {
|
|
3275
|
+
return await initializeApplication(database, config, {
|
|
3276
|
+
...adapters,
|
|
3277
|
+
jobs
|
|
3278
|
+
}, cleanup);
|
|
3279
|
+
} catch (error) {
|
|
3280
|
+
return cleanup.fail(error);
|
|
3281
|
+
}
|
|
3282
|
+
}
|
|
3283
|
+
async function initializeApplication(database, config, adapters, cleanup) {
|
|
3284
|
+
const integrationDatabase = createDatabase(config, "integration");
|
|
3285
|
+
cleanup.add("integration database", () => integrationDatabase.pool.end());
|
|
3213
3286
|
const instance = createInstance(integrationDatabase, config);
|
|
3214
3287
|
await instance.read();
|
|
3215
3288
|
const blobs = createBlobStorage(integrationDatabase, instance, adapters.objectStore, adapters.jobs), search = createTicketSearch(integrationDatabase, instance, adapters.ticketIndex, adapters.jobs);
|
|
@@ -3223,12 +3296,14 @@ async function createApplication(database, config, overrides = {}) {
|
|
|
3223
3296
|
sources: adapters.importSources(config),
|
|
3224
3297
|
claimMaxLeaseSeconds: config.KANVIL_CLAIM_MAX_LEASE_SECONDS
|
|
3225
3298
|
}), access = createAccess(auth, domain, config, database), realtime = await adapters.realtime(config, instance, integrationDatabase);
|
|
3299
|
+
cleanup.add("realtime", () => realtime.close());
|
|
3226
3300
|
const unsubscribeJobs = realtime.subscribe(() => {
|
|
3227
3301
|
blobs.sync().catch(() => {});
|
|
3228
3302
|
search.sync().catch(() => {});
|
|
3229
3303
|
});
|
|
3230
|
-
|
|
3231
|
-
|
|
3304
|
+
cleanup.add("job subscription", unsubscribeJobs);
|
|
3305
|
+
adapters.jobs("outbox", 5e3, () => deliverBatch(database, config, senders, secrets, repositories));
|
|
3306
|
+
adapters.jobs("due-reminders", 6e4, () => sendDueReminders(database));
|
|
3232
3307
|
const imports = adapters.jobs("imports", 2e3, async () => {
|
|
3233
3308
|
if (await processImports(domain)) imports.trigger().catch(() => {});
|
|
3234
3309
|
});
|
|
@@ -3256,35 +3331,16 @@ async function createApplication(database, config, overrides = {}) {
|
|
|
3256
3331
|
code: typeof error.body?.code === "string" ? error.body.code : "authentication_error",
|
|
3257
3332
|
message: typeof error.body?.message === "string" ? error.body.message : "Authentication request failed"
|
|
3258
3333
|
} }, { status: error.statusCode });
|
|
3259
|
-
if (error instanceof ApiError) {
|
|
3260
|
-
const retry = error.status === 429 && error.details && typeof error.details === "object" && "retryAfterSeconds" in error.details ? String(error.details.retryAfterSeconds) : void 0;
|
|
3261
|
-
return Response.json({ error: {
|
|
3262
|
-
status: error.status,
|
|
3263
|
-
code: error.code,
|
|
3264
|
-
message: error.message,
|
|
3265
|
-
details: error.details
|
|
3266
|
-
} }, {
|
|
3267
|
-
status: error.status,
|
|
3268
|
-
headers: retry ? { "Retry-After": retry } : {}
|
|
3269
|
-
});
|
|
3270
|
-
}
|
|
3271
|
-
if (error instanceof z$1.ZodError) return Response.json({ error: {
|
|
3272
|
-
code: "validation_error",
|
|
3273
|
-
message: "Invalid request",
|
|
3274
|
-
details: error.issues.map((issue) => ({
|
|
3275
|
-
path: issue.path.join("."),
|
|
3276
|
-
message: issue.message
|
|
3277
|
-
}))
|
|
3278
|
-
} }, { status: 400 });
|
|
3279
3334
|
if (error instanceof SyntaxError || error instanceof HTTPException) return Response.json({ error: {
|
|
3280
3335
|
code: "invalid_request",
|
|
3281
3336
|
message: "The request could not be parsed"
|
|
3282
3337
|
} }, { status: error instanceof HTTPException ? error.status : 400 });
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3338
|
+
const retry = error instanceof ApiError && error.status === 429 && error.details && typeof error.details === "object" && "retryAfterSeconds" in error.details ? String(error.details.retryAfterSeconds) : void 0;
|
|
3339
|
+
const envelope = errorEnvelope(error);
|
|
3340
|
+
return Response.json(envelope.body, {
|
|
3341
|
+
status: envelope.status,
|
|
3342
|
+
headers: retry ? { "Retry-After": retry } : {}
|
|
3343
|
+
});
|
|
3288
3344
|
});
|
|
3289
3345
|
app.notFound(() => Response.json({ error: {
|
|
3290
3346
|
code: "not_found",
|
|
@@ -3383,6 +3439,7 @@ async function createApplication(database, config, overrides = {}) {
|
|
|
3383
3439
|
app.use("/api/v1/*", async (c, next) => {
|
|
3384
3440
|
access.checkOrigin(c.req.raw);
|
|
3385
3441
|
const actor = await access.authenticate(c.req.raw);
|
|
3442
|
+
if (intakeOnly(actor) && !(c.req.method === "POST" && /^\/api\/v1\/projects\/[^/]+\/tickets$/.test(c.req.path))) fail(403, "insufficient_scope", "Intake credentials can only create tickets");
|
|
3386
3443
|
c.set("actor", actor);
|
|
3387
3444
|
if (!actor.machine && ![
|
|
3388
3445
|
"GET",
|
|
@@ -3757,22 +3814,13 @@ async function createApplication(database, config, overrides = {}) {
|
|
|
3757
3814
|
blobs,
|
|
3758
3815
|
search,
|
|
3759
3816
|
realtime,
|
|
3760
|
-
close:
|
|
3761
|
-
await imports.close();
|
|
3762
|
-
unsubscribeJobs();
|
|
3763
|
-
await realtime.close();
|
|
3764
|
-
await search.close();
|
|
3765
|
-
await blobs.close();
|
|
3766
|
-
await integrationDatabase.pool.end();
|
|
3767
|
-
await outbox.close();
|
|
3768
|
-
await reminders.close();
|
|
3769
|
-
}
|
|
3817
|
+
close: cleanup.close
|
|
3770
3818
|
};
|
|
3771
3819
|
}
|
|
3772
3820
|
//#endregion
|
|
3773
3821
|
//#region src/index.ts
|
|
3774
3822
|
const config = readConfig();
|
|
3775
|
-
const database = createDatabase(config
|
|
3823
|
+
const database = createDatabase(config);
|
|
3776
3824
|
await migrateDatabase(database);
|
|
3777
3825
|
const application = await createApplication(database, config);
|
|
3778
3826
|
const server = serve({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { n as createDatabase, t as readConfig } from "./config-
|
|
1
|
+
import { n as createDatabase, t as readConfig } from "./config-DKuNQY5b.mjs";
|
|
2
2
|
import { t as migrateDatabase } from "./migrate-C9f4ozB4.mjs";
|
|
3
3
|
//#region src/cli/migrate.ts
|
|
4
|
-
const database = createDatabase(readConfig()
|
|
4
|
+
const database = createDatabase(readConfig());
|
|
5
5
|
try {
|
|
6
6
|
await migrateDatabase(database);
|
|
7
7
|
console.info("Kanvil database is current.");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { d as user, n as createDatabase, r as account, t as readConfig, u as session } from "./config-
|
|
2
|
-
import { A as hasAdminRole } from "./src-
|
|
3
|
-
import {
|
|
1
|
+
import { d as user, n as createDatabase, r as account, t as readConfig, u as session } from "./config-DKuNQY5b.mjs";
|
|
2
|
+
import { A as hasAdminRole } from "./src-DptOUNRd.mjs";
|
|
3
|
+
import { K as instanceSettings, p as fail, t as createAuth } from "./auth-Cs_whzgk.mjs";
|
|
4
4
|
import { and, eq, isNull, sql } from "drizzle-orm";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { parseArgs } from "node:util";
|
|
@@ -56,7 +56,7 @@ const password = process.stdin.isTTY ? await passwordPrompt({
|
|
|
56
56
|
validate: (value) => localPasswordSchema.safeParse(value).success || "Use 12 to 128 characters"
|
|
57
57
|
}) : readFileSync(0, "utf8").replace(/\r?\n$/, "");
|
|
58
58
|
const config = readConfig();
|
|
59
|
-
const database = createDatabase(config
|
|
59
|
+
const database = createDatabase(config);
|
|
60
60
|
try {
|
|
61
61
|
await recoverLocalPassword(database, config, values.email, password, values["enable-password-sign-in"]);
|
|
62
62
|
if (values["enable-password-sign-in"]) console.info("Instance password sign-in enabled.");
|
|
@@ -1548,6 +1548,10 @@ var en_US_default = {
|
|
|
1548
1548
|
custom: "Custom permissions"
|
|
1549
1549
|
},
|
|
1550
1550
|
permission: {
|
|
1551
|
+
intake: {
|
|
1552
|
+
name: "Submit reports",
|
|
1553
|
+
description: "Create quarantined tickets only. Cannot read or edit tickets. Use alone."
|
|
1554
|
+
},
|
|
1551
1555
|
read: {
|
|
1552
1556
|
name: "Read tickets",
|
|
1553
1557
|
description: "View projects, tickets, comments, and attachments."
|
|
@@ -2844,7 +2848,8 @@ const scopes = [
|
|
|
2844
2848
|
"read",
|
|
2845
2849
|
"write",
|
|
2846
2850
|
"claim",
|
|
2847
|
-
"admin"
|
|
2851
|
+
"admin",
|
|
2852
|
+
"intake"
|
|
2848
2853
|
];
|
|
2849
2854
|
const attachmentLimit = 1e7;
|
|
2850
2855
|
const stagedUploadLifetime = 864e5;
|
|
@@ -3037,10 +3042,13 @@ function rejectConflicts(filter, context) {
|
|
|
3037
3042
|
});
|
|
3038
3043
|
}
|
|
3039
3044
|
}
|
|
3040
|
-
const
|
|
3045
|
+
const selectedTicket = z.object({
|
|
3041
3046
|
ticketId: id,
|
|
3042
3047
|
expectedVersion: version
|
|
3043
|
-
})
|
|
3048
|
+
});
|
|
3049
|
+
const selectionOf = (item) => z.array(item).min(1).max(100).refine((values) => new Set(values.map((v) => v.ticketId)).size === values.length, "Tickets must be unique");
|
|
3050
|
+
const ticketSelection = selectionOf(selectedTicket);
|
|
3051
|
+
const claimedTicketSelection = selectionOf(selectedTicket.extend({ claimId: z.uuid().optional() }));
|
|
3044
3052
|
const ticketFilter = z.object({
|
|
3045
3053
|
q: z.string().trim().max(200).optional(),
|
|
3046
3054
|
...filterShape,
|
|
@@ -3257,6 +3265,26 @@ const ticketSchema = z.object({
|
|
|
3257
3265
|
createdAt: timestamp,
|
|
3258
3266
|
updatedAt: timestamp
|
|
3259
3267
|
});
|
|
3268
|
+
const ticketSummarySchema = ticketSchema.pick({
|
|
3269
|
+
id: true,
|
|
3270
|
+
key: true,
|
|
3271
|
+
number: true,
|
|
3272
|
+
projectId: true,
|
|
3273
|
+
title: true,
|
|
3274
|
+
status: true,
|
|
3275
|
+
stateId: true,
|
|
3276
|
+
kind: true,
|
|
3277
|
+
difficulty: true,
|
|
3278
|
+
priority: true,
|
|
3279
|
+
labels: true,
|
|
3280
|
+
scopes: true,
|
|
3281
|
+
archived: true,
|
|
3282
|
+
automationReady: true,
|
|
3283
|
+
updatedAt: true,
|
|
3284
|
+
version: true
|
|
3285
|
+
});
|
|
3286
|
+
const ticketView = { view: z.enum(["summary", "full"]).default("full") };
|
|
3287
|
+
const ticketRow = z.union([ticketSchema, ticketSummarySchema]);
|
|
3260
3288
|
const snapshotSchema = z.object({
|
|
3261
3289
|
project: projectSchema,
|
|
3262
3290
|
tickets: z.array(ticketSchema),
|
|
@@ -3292,8 +3320,13 @@ const relationSchema = z.object({
|
|
|
3292
3320
|
]),
|
|
3293
3321
|
sourceKey: z.string().optional(),
|
|
3294
3322
|
sourceTitle: z.string().optional(),
|
|
3323
|
+
sourceProjectId: z.uuid().optional(),
|
|
3324
|
+
sourceProjectKey: z.string().optional(),
|
|
3295
3325
|
targetKey: z.string().optional(),
|
|
3296
|
-
targetTitle: z.string().optional()
|
|
3326
|
+
targetTitle: z.string().optional(),
|
|
3327
|
+
targetProjectId: z.uuid().optional(),
|
|
3328
|
+
targetProjectKey: z.string().optional(),
|
|
3329
|
+
restricted: z.boolean().optional()
|
|
3297
3330
|
});
|
|
3298
3331
|
const relationDirections = z.enum(["outgoing", "incoming"]);
|
|
3299
3332
|
const relationLabel = (type, outgoing) => t(`common.relation.${type}.${outgoing ? "outgoing" : "incoming"}`);
|
|
@@ -3440,14 +3473,15 @@ const searchResultSchema = z.object({
|
|
|
3440
3473
|
type: z.enum(searchResultTypes),
|
|
3441
3474
|
id: z.string(),
|
|
3442
3475
|
project: projectRef,
|
|
3443
|
-
ticket: z.object({
|
|
3476
|
+
ticket: z.union([ticketSummarySchema, z.object({
|
|
3444
3477
|
id: z.uuid(),
|
|
3445
3478
|
key: z.string(),
|
|
3446
3479
|
title: z.string(),
|
|
3447
3480
|
status: z.enum(states)
|
|
3448
|
-
}).nullable(),
|
|
3481
|
+
})]).nullable(),
|
|
3449
3482
|
title: z.string(),
|
|
3450
3483
|
excerpt: z.string(),
|
|
3484
|
+
snippet: z.string().optional(),
|
|
3451
3485
|
actorId: z.string().nullable(),
|
|
3452
3486
|
at: timestamp
|
|
3453
3487
|
});
|
|
@@ -3789,7 +3823,7 @@ const credentialProjectsSchema = z.object({ projectIds: z.array(z.uuid()).max(1e
|
|
|
3789
3823
|
const credentialInput = z.object({
|
|
3790
3824
|
name: z.string().trim().min(1).max(100),
|
|
3791
3825
|
projectIds: credentialProjectsSchema.shape.projectIds.refine((ids) => ids === null || ids.length > 0),
|
|
3792
|
-
scopes: z.array(z.enum(scopes)).min(1),
|
|
3826
|
+
scopes: z.array(z.enum(scopes)).min(1).refine((values) => !values.includes("intake") || values.every((value) => value === "intake"), "Intake cannot be combined with other scopes"),
|
|
3793
3827
|
expiresIn: z.number().int().min(3600).max(31536e3).nullable().default(7776e3)
|
|
3794
3828
|
}).strict();
|
|
3795
3829
|
z.object({
|
|
@@ -4364,8 +4398,9 @@ const operations = {
|
|
|
4364
4398
|
relatedTo: id.optional(),
|
|
4365
4399
|
stateId: z.uuid().optional(),
|
|
4366
4400
|
scheduledFrom: timestamp.optional(),
|
|
4367
|
-
scheduledTo: timestamp.optional()
|
|
4368
|
-
|
|
4401
|
+
scheduledTo: timestamp.optional(),
|
|
4402
|
+
...ticketView
|
|
4403
|
+
}).superRefine(rejectConflicts), page(ticketRow), "GET", "/projects/{projectId}/tickets", "read", "Search tickets with server-side filters, stable ordering, and pagination. Each property filter takes one value or a repeated list (any of them); its `Not` twin excludes values. Double-quoted segments of `q` match as exact phrases. Pass `view: \"summary\"` when scanning results: rows then omit the description and acceptance criteria."),
|
|
4369
4404
|
list_ticket_labels: op(projectInput.extend({ archived: ticketFilter.shape.archived }), z.array(z.object({
|
|
4370
4405
|
name: z.string(),
|
|
4371
4406
|
count: z.number().int().nonnegative()
|
|
@@ -4489,6 +4524,11 @@ const operations = {
|
|
|
4489
4524
|
changes: ticketChanges,
|
|
4490
4525
|
claimId: z.uuid().optional()
|
|
4491
4526
|
}).strict(), ticketSchema, "PATCH", "/projects/{projectId}/tickets/{ticketId}", "write", "Update a ticket with optimistic concurrency. Worker completion requires its active claim. `changes.customFields` sets only the named fields; null clears one."),
|
|
4527
|
+
update_ticket_labels: op(ticketInput.extend({
|
|
4528
|
+
...mutation,
|
|
4529
|
+
expectedVersion: version,
|
|
4530
|
+
labels: tags
|
|
4531
|
+
}).strict(), ticketSchema, "PATCH", "/projects/{projectId}/tickets/{ticketId}/labels", "admin", "Replace one ticket's labels with optimistic concurrency, for label administration and triage. Takes no worker claim and leaves any claim, ownership requirement, readiness, and every other field unchanged; ordinary edits use update_ticket. Reuse requestId when retrying this write."),
|
|
4492
4532
|
move_ticket: op(ticketInput.extend({
|
|
4493
4533
|
...mutation,
|
|
4494
4534
|
expectedVersion: version,
|
|
@@ -4509,16 +4549,16 @@ const operations = {
|
|
|
4509
4549
|
destinationProjectId: id,
|
|
4510
4550
|
status: z.enum(states).optional(),
|
|
4511
4551
|
stateId: z.uuid().optional()
|
|
4512
|
-
}).strict(), ticketSchema, "POST", "/projects/{projectId}/tickets/{ticketId}/relocate", "write", "Move a ticket to another project of the same workspace. It keeps its ID, comments, attachments, evidence, links, and followers, takes the destination's next number as its new key, and its previous key keeps resolving. A claim, a parent or children, relationships, an assignee without destination access, custom field values, or a destination field that is required without a default block the move with `relocation_blocked`; the ticket takes the destination's custom field defaults. Activity before the move stays with the original project. Reuse requestId when retrying this write."),
|
|
4552
|
+
}).strict(), ticketSchema, "POST", "/projects/{projectId}/tickets/{ticketId}/relocate", "write", "Move a ticket to another project of the same workspace. It keeps its ID, comments, attachments, evidence, links, and followers, takes the destination's next number as its new key, and its previous key keeps resolving. A claim (or, for a worker, a ticket that was claimed and has no claim now), a parent or children, relationships, an assignee without destination access, custom field values, or a destination field that is required without a default block the move with `relocation_blocked`; the ticket takes the destination's custom field defaults. Activity before the move stays with the original project. Reuse requestId when retrying this write."),
|
|
4513
4553
|
resolve_ticket: op(z.object({ ticketId: id }).strict(), z.object({
|
|
4514
4554
|
ticket: ticketSchema,
|
|
4515
4555
|
project: projectRef
|
|
4516
4556
|
}), "GET", "/tickets/resolve", "read", "Find a ticket by ID, current key, or any earlier key from a prefix change or a move, across every accessible project. An unknown or inaccessible ticket reads as not found."),
|
|
4517
4557
|
bulk_update_tickets: op(projectInput.extend({
|
|
4518
4558
|
...mutation,
|
|
4519
|
-
tickets:
|
|
4559
|
+
tickets: claimedTicketSelection,
|
|
4520
4560
|
changes: ticketChanges
|
|
4521
|
-
}).strict(), z.array(ticketSchema), "POST", "/projects/{projectId}/tickets/bulk", "write", "Apply an atomic bulk edit using each ticket's current version."),
|
|
4561
|
+
}).strict(), z.array(ticketSchema), "POST", "/projects/{projectId}/tickets/bulk", "write", "Apply an atomic bulk edit using each ticket's current version. A worker passes each claimed ticket's active `claimId`."),
|
|
4522
4562
|
delete_ticket: op(ticketInput.extend({
|
|
4523
4563
|
...mutation,
|
|
4524
4564
|
expectedVersion: version
|
|
@@ -4530,25 +4570,28 @@ const operations = {
|
|
|
4530
4570
|
search_tickets: op(z.object({
|
|
4531
4571
|
q: z.string().trim().min(1).max(200),
|
|
4532
4572
|
workspaceId: z.uuid().optional(),
|
|
4533
|
-
limit: z.coerce.number().int().min(1).max(50).default(20)
|
|
4573
|
+
limit: z.coerce.number().int().min(1).max(50).default(20),
|
|
4574
|
+
...ticketView
|
|
4534
4575
|
}).strict(), z.object({ items: z.array(z.object({
|
|
4535
|
-
ticket:
|
|
4536
|
-
project: projectRef
|
|
4537
|
-
|
|
4576
|
+
ticket: ticketRow,
|
|
4577
|
+
project: projectRef,
|
|
4578
|
+
snippet: z.string().optional()
|
|
4579
|
+
})) }), "GET", "/tickets/search", "read", "Search unarchived tickets by key or text across every accessible project, optionally within one workspace. Results order by exact key match, then relevance, then recency. Double-quoted segments of `q` match as exact phrases. Pass `view: \"summary\"` when scanning results: each ticket is then a compact row and the result carries a `snippet` of the matching text."),
|
|
4538
4580
|
search_workspace: op(z.object({
|
|
4539
4581
|
q: z.string().trim().min(1).max(200),
|
|
4540
4582
|
workspaceId: z.uuid().optional(),
|
|
4541
4583
|
type: z.enum(searchResultTypes).optional(),
|
|
4542
4584
|
...filterShape,
|
|
4543
4585
|
limit: z.coerce.number().int().min(1).max(50).default(20),
|
|
4544
|
-
offset: z.coerce.number().int().min(0).max(1e3).default(0)
|
|
4586
|
+
offset: z.coerce.number().int().min(0).max(1e3).default(0),
|
|
4587
|
+
...ticketView
|
|
4545
4588
|
}).strict().superRefine(rejectConflicts), z.object({
|
|
4546
4589
|
items: z.array(searchResultSchema),
|
|
4547
4590
|
total: z.number().int().nonnegative(),
|
|
4548
4591
|
counts: z.record(z.enum(searchResultTypes), z.number().int().nonnegative()),
|
|
4549
4592
|
engine: z.enum(["postgres", "index"]),
|
|
4550
4593
|
indexing: z.boolean()
|
|
4551
|
-
}), "GET", "/search", "read", "Search accessible tickets, projects, comments, and activity by text or ticket key, optionally within one workspace or one result type. Property filters restrict results to matching tickets. Results order by exact key match, then type, then recency."),
|
|
4594
|
+
}), "GET", "/search", "read", "Search accessible tickets, projects, comments, and activity by text or ticket key, optionally within one workspace or one result type. Property filters restrict results to matching tickets. Results order by exact key match, then type, then ticket relevance, then recency. Double-quoted segments of `q` match ticket text as exact phrases. Pass `view: \"summary\"` when scanning results: ticket results then carry their summary row and each result a `snippet` of the matching text."),
|
|
4552
4595
|
list_my_work: op(z.object({
|
|
4553
4596
|
workspaceId: z.uuid().optional(),
|
|
4554
4597
|
q: ticketFilter.shape.q,
|
|
@@ -4561,17 +4604,17 @@ const operations = {
|
|
|
4561
4604
|
ticket: ticketSchema,
|
|
4562
4605
|
readiness: readinessSchema
|
|
4563
4606
|
})), "GET", "/projects/{projectId}/eligibility", "read", "Inspect eligibility and explicit blocking reasons for open tickets."),
|
|
4564
|
-
list_relations: op(ticketInput, z.array(relationSchema), "GET", "/projects/{projectId}/tickets/{ticketId}/relations", "read", "List incoming and outgoing ticket relationships."),
|
|
4607
|
+
list_relations: op(ticketInput, z.array(relationSchema), "GET", "/projects/{projectId}/tickets/{ticketId}/relations", "read", "List incoming and outgoing ticket relationships with each side's key, title, and project. A ticket in a project the caller cannot read appears by ID and key alone, with `restricted: true`."),
|
|
4565
4608
|
add_relation: op(ticketInput.extend({
|
|
4566
4609
|
...mutation,
|
|
4567
|
-
targetId:
|
|
4610
|
+
targetId: id,
|
|
4568
4611
|
type: relationSchema.shape.type,
|
|
4569
4612
|
direction: relationDirections.optional()
|
|
4570
|
-
}).strict(), relationSchema, "POST", "/projects/{projectId}/tickets/{ticketId}/relations", "write", "Relate
|
|
4613
|
+
}).strict(), relationSchema, "POST", "/projects/{projectId}/tickets/{ticketId}/relations", "write", "Relate a ticket to another by ID or key, in this project or any project the caller can read, while rejecting dependency cycles across projects. Blocking or marking as duplicate a ticket of another project also needs write there. Both projects' feeds record the change."),
|
|
4571
4614
|
remove_relation: op(projectInput.extend({
|
|
4572
4615
|
...mutation,
|
|
4573
4616
|
relationId: z.uuid()
|
|
4574
|
-
}).strict(), okSchema, "DELETE", "/projects/{projectId}/relations/{relationId}", "write", "Remove a ticket relationship."),
|
|
4617
|
+
}).strict(), okSchema, "DELETE", "/projects/{projectId}/relations/{relationId}", "write", "Remove a ticket relationship that names a ticket of this project."),
|
|
4575
4618
|
list_comments: op(ticketInput.extend(pagination), page(commentSchema), "GET", "/projects/{projectId}/tickets/{ticketId}/comments", "read", "Read ticket discussion."),
|
|
4576
4619
|
add_comment: op(ticketInput.extend({
|
|
4577
4620
|
...mutation,
|
|
@@ -4927,6 +4970,7 @@ function isOperation(name) {
|
|
|
4927
4970
|
return Object.hasOwn(operations, name);
|
|
4928
4971
|
}
|
|
4929
4972
|
const errorSchema = z.object({ error: z.object({
|
|
4973
|
+
status: z.number().int().optional(),
|
|
4930
4974
|
code: z.string(),
|
|
4931
4975
|
message: z.string(),
|
|
4932
4976
|
details: z.unknown().optional()
|
|
@@ -4952,4 +4996,4 @@ function parseOutput(name, value) {
|
|
|
4952
4996
|
return operations[name].output.parse(value);
|
|
4953
4997
|
}
|
|
4954
4998
|
//#endregion
|
|
4955
|
-
export { permissionLabels as $, hasAdminRole as A,
|
|
4999
|
+
export { permissionLabels as $, hasAdminRole as A, workflowOrder as At, memberSchema as B, searchSettingsSchema as Bt, errorSchema as C, streamErrorSchema as Ct, filterKey as D, ticketPredicates as Dt, eventSchema as E, ticketImportSchema as Et, isHexColor as F, instanceUpdateSchema as Ft, notificationReadInput as G, notificationIdsInput as H, isOperation as I, photoInputSchema as It, operationPermission as J, notificationsSchema as K, isPresetColor as L, photoResultSchema as Lt, importProviderDefinitions as M, adminInstanceSchema as Mt, importSecretFields as N, authenticationPolicySchema as Nt, filterList as O, ticketSchema as Ot, invitationStatuses as P, brokerSettingsSchema as Pt, parsePublicOutput as Q, isPublicOperation as R, s3SettingsSchema as Rt, difficulties as S, states as St, eventLabels as T, ticketFilter as Tt, notificationPreferencesInput as U, mentionScheme as V, notificationPreferencesSchema as W, parseCustomFieldFilter as X, operations as Y, parseOutput as Z, deletedAccountName as _, seededPermissions as _t, checkpointSchema as a, publicOperations as at, destinationEventKeys as b, stagedUploadLifetime as bt, credentialInput as c, repositoryProviderDefinitions as ct, customFieldSchema as d, resourceProvider as dt, permissionScope as et, customFieldValue as f, roleCategory as ft, defaultWorkflow as g, searchResultTypes as gt, defaultOrder as h, scopes as ht, channelRouteAllows as i, projectSchema as it, importLimits as j, workspaceSchema as jt, formatEvent as k, ticketSummarySchema as kt, credentialProjectsSchema as l, repositoryProviders as lt, defaultClaimMaxLeaseSeconds as m, roles as mt, attachmentLimit as n, priorities as nt, claimLeaseSecondsSchema as o, pushDeviceInput as ot, customFieldValueSchema as p, roleLabels as pt, okSchema as q, channelKinds as r, priorityLabels as rt, closedStates as s, remoteKinds as st, ApiError as t, permissions as tt, customFieldFilterTokens as u, repositorySecretFields as ut, deliverySecretFields as v, signInMethodLabels as vt, eventCategories as w, ticketExportFormat as wt, destinationKinds as x, stateLabels as xt, deliverySettingsSchema as y, snapshotSchema as yt, isSeededRole as z, searchAuthentication as zt };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Ga as e,_a as t,ba as n,ya as r}from"./search-
|
|
1
|
+
import{Ga as e,_a as t,ba as n,ya as r}from"./search-Ble6WSEU.js";import{i}from"./forms-BlEL8C_P.js";var a={name:`chevrons-up-down`,size:24,node:[[`path`,{d:`m7 15 5 5 5-5`,key:`1hf1tw`}],[`path`,{d:`m7 9 5-5 5 5`,key:`sgt6xg`}]]};a.node;var o=e(a),s={name:`pencil`,size:24,node:[[`path`,{d:`M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z`,key:`1a8usu`}],[`path`,{d:`m15 5 4 4`,key:`1mk7zo`}]]};s.node;var c=e(s),l={name:`trash`,size:24,node:[[`path`,{d:`M10 11v6`,key:`nco0om`}],[`path`,{d:`M14 11v6`,key:`outv1u`}],[`path`,{d:`M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6`,key:`miytrc`}],[`path`,{d:`M3 6h18`,key:`d0wm0j`}],[`path`,{d:`M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2`,key:`e791ji`}]],aliases:[`trash-2`]};l.node;var u=e(l);function d(e){let{render:a,className:o,style:s,state:c=n,props:l=r,refs:u=r,metadata:d,stateAttributesMapping:f,tag:p=`div`,...m}=e,{compositeProps:h,compositeRef:g}=i({metadata:d});return t(p,e,{state:c,ref:[g,...u],props:[h,...l,m],stateAttributesMapping:f})}export{o as i,u as n,c as r,d as t};
|