@harperfast/harper 5.2.5 → 5.2.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 (58) hide show
  1. package/bin/restart.ts +48 -23
  2. package/bin/restartExitWatchdog.ts +99 -0
  3. package/bin/run.ts +16 -10
  4. package/dist/bin/restart.js +39 -21
  5. package/dist/bin/restart.js.map +1 -1
  6. package/dist/bin/restartExitWatchdog.d.ts +5 -0
  7. package/dist/bin/restartExitWatchdog.js +100 -0
  8. package/dist/bin/restartExitWatchdog.js.map +1 -0
  9. package/dist/bin/run.d.ts +2 -0
  10. package/dist/bin/run.js +17 -10
  11. package/dist/bin/run.js.map +1 -1
  12. package/dist/resources/DatabaseTransaction.d.ts +18 -1
  13. package/dist/resources/DatabaseTransaction.js +63 -1
  14. package/dist/resources/DatabaseTransaction.js.map +1 -1
  15. package/dist/resources/LMDBTransaction.d.ts +2 -0
  16. package/dist/resources/LMDBTransaction.js +7 -1
  17. package/dist/resources/LMDBTransaction.js.map +1 -1
  18. package/dist/resources/Resource.js +5 -4
  19. package/dist/resources/Resource.js.map +1 -1
  20. package/dist/resources/ResourceInterface.d.ts +5 -0
  21. package/dist/resources/ResourceInterface.js.map +1 -1
  22. package/dist/resources/Table.js +53 -9
  23. package/dist/resources/Table.js.map +1 -1
  24. package/dist/resources/transaction.js +1 -1
  25. package/dist/resources/transaction.js.map +1 -1
  26. package/dist/server/threads/manageThreads.d.ts +1 -0
  27. package/dist/server/threads/manageThreads.js +20 -3
  28. package/dist/server/threads/manageThreads.js.map +1 -1
  29. package/dist/utility/processManagement/processManagement.js +21 -3
  30. package/dist/utility/processManagement/processManagement.js.map +1 -1
  31. package/npm-shrinkwrap.json +2 -2
  32. package/package.json +1 -1
  33. package/resources/DESIGN.md +19 -19
  34. package/resources/DatabaseTransaction.ts +63 -2
  35. package/resources/LMDBTransaction.ts +7 -1
  36. package/resources/Resource.ts +6 -5
  37. package/resources/ResourceInterface.ts +5 -0
  38. package/resources/Table.ts +57 -8
  39. package/resources/transaction.ts +2 -2
  40. package/server/DESIGN.md +6 -0
  41. package/server/threads/manageThreads.js +17 -3
  42. package/studio/web/assets/{Chat-Lgj1d-8d.js → Chat-BNHY84-Z.js} +1 -1
  43. package/studio/web/assets/{FloatingChat-jLWvR4kI.js → FloatingChat-BbztUci0.js} +3 -3
  44. package/studio/web/assets/{apiToken-DYI4DqWa.js → apiToken-D0x_S8Wq.js} +1 -1
  45. package/studio/web/assets/{applications-DCmc9-lk.js → applications-BU83fSEG.js} +1 -1
  46. package/studio/web/assets/{index-CqbCnqsT.js → index-BQB9R8Ug.js} +4 -4
  47. package/studio/web/assets/{index.lazy-BNqr3j0f.js → index.lazy-CtErm5q7.js} +3 -3
  48. package/studio/web/assets/{notifications-Bb2cj14_.js → notifications-B8rDagJM.js} +1 -1
  49. package/studio/web/assets/{notifications-DVlKonbI.js → notifications-CPwYKDDH.js} +1 -1
  50. package/studio/web/assets/{profile-BSQWfYfq.js → profile-D0hB1xdm.js} +1 -1
  51. package/studio/web/assets/{regions-Dk3g8bBF.js → regions-y_jxsBpN.js} +1 -1
  52. package/studio/web/assets/{setComponentFile-DoITgNLb.js → setComponentFile-DSHbURTI.js} +1 -1
  53. package/studio/web/assets/{setup-CiEALLa7.js → setup-J5SrM1Kp.js} +1 -1
  54. package/studio/web/assets/{status-CK9tD-Nd.js → status-IoJkDzlx.js} +1 -1
  55. package/studio/web/assets/{swagger-ui-react-CxjCDFB-.js → swagger-ui-react-BlgSS25O.js} +1 -1
  56. package/studio/web/assets/{useEntityRestURL-Cy-0i1UZ.js → useEntityRestURL-qfahJnvr.js} +1 -1
  57. package/studio/web/index.html +1 -1
  58. package/utility/processManagement/processManagement.js +19 -3
@@ -261,7 +261,9 @@ export type TransactionWrite = {
261
261
  before?: () => void | Promise<void>;
262
262
  beforeIntermediate?: () => void | Promise<void>;
263
263
  commit?: (txnTime: number, existingEntry: Partial<Entry>, retry: boolean, transaction: any) => MaybePromise<void>;
264
- validate?: (txnTime: number) => void;
264
+ // Once a write has been taken over, the transaction committing it is not the one that staged it, and
265
+ // overload accounting, the replay marker and a no-op write's removal all belong to the committer.
266
+ validate?: (txnTime: number, committedBy: DatabaseTransaction) => void;
265
267
  fullUpdate?: boolean;
266
268
  saved?: boolean;
267
269
  deferSave?: boolean;
@@ -278,6 +280,10 @@ export type TransactionWrite = {
278
280
  // sticky: a non-isRetry staging of this write appended its audit entry (set in save(); the retry
279
281
  // dedup guards in the commit handler read it to ignore the write's own orphaned entry)
280
282
  appendedAuditEntry?: boolean;
283
+ // the transaction holding this write in its `writes` (set in addWrite). A deferred write's save() is
284
+ // only its trigger, so it can be triggered after the context has moved on to another transaction;
285
+ // this is who commits it when the transaction current at that point is not a scope (#2292).
286
+ stagedIn?: DatabaseTransaction;
281
287
  // the preceding write to the same store and key in this transaction, if any (linked in addWrite)
282
288
  priorWrite?: TransactionWrite;
283
289
  // set only by a write that BOTH reads priorStagedWrite() and publishes stagedEntry; addWrite orders
@@ -361,6 +367,11 @@ export class DatabaseTransaction implements Transaction {
361
367
  timeoutBudget = 0;
362
368
  // save() only stages here; ImmediateTransaction overrides it to commit, which addWrite must not defer
363
369
  saveCommits = false;
370
+ // True where save() puts the write into this transaction's native handle, which is what lets a scope
371
+ // take over a write staged in another transaction's `writes` (Table.ts's #saveOperation).
372
+ // LMDBTransaction's save() is a no-op — its commit applies `writes` — so there a write can only be
373
+ // committed by the transaction that holds it.
374
+ stagesWriteOnSave = true;
364
375
  validated = 0;
365
376
  timestamp = 0;
366
377
  retries = 0;
@@ -590,11 +601,47 @@ export class DatabaseTransaction implements Transaction {
590
601
  writesForStore.set(keyId, operation);
591
602
  }
592
603
 
604
+ /**
605
+ * Drop a staged write from this transaction, and from its per-key chain, so the transaction taking it
606
+ * over becomes its only owner (Table.ts's #saveOperation).
607
+ */
608
+ detachWrite(operation: TransactionWrite): void {
609
+ const index = this.writes.indexOf(operation);
610
+ if (index > -1) this.writes[index] = null;
611
+ if (operation.key === undefined) return;
612
+ const writesForStore = this.writesByKey?.get(operation.store);
613
+ if (!writesForStore) return;
614
+ const keyId = writeKeyId(operation.key);
615
+ // Membership, not `stagedIn`, which every commit handler clears and so cannot tell a takeover from a
616
+ // write done in place; a prior already taken over must not become this transaction's basis again.
617
+ let prior = operation.priorWrite;
618
+ while (prior && !this.writes.includes(prior)) prior = prior.priorWrite;
619
+ const tail = writesForStore.get(keyId);
620
+ if (tail === operation) {
621
+ if (prior) writesForStore.set(keyId, prior);
622
+ else writesForStore.delete(keyId);
623
+ return;
624
+ }
625
+ // A successor left chained to it would take its merge basis and index diff from a record another
626
+ // transaction owns and may roll back (harper#1968's failure class).
627
+ for (let successor = tail; successor; successor = successor.priorWrite) {
628
+ if (successor.priorWrite === operation) {
629
+ successor.priorWrite = prior;
630
+ return;
631
+ }
632
+ }
633
+ }
634
+
593
635
  /**
594
636
  * Discard the staged write set (committed or aborted); the per-key chain must go with it so a
595
637
  * reused transaction never bases a write on a previous batch's staged state.
596
638
  */
597
639
  clearWrites(): void {
640
+ // A deferred write's `stagedIn` must not outlive this transaction's ability to commit it: save() can
641
+ // fire after a commit or abort, and routing it back here would revive a write this transaction
642
+ // already rolled back — whose blobs abort() has reclaimed. Cleared here, save() resolves the
643
+ // context's current transaction as it did before `stagedIn` existed.
644
+ for (const write of this.writes) if (write?.stagedIn === this) write.stagedIn = undefined;
598
645
  this.writes = [];
599
646
  this.writesByKey = undefined;
600
647
  }
@@ -729,6 +776,7 @@ export class DatabaseTransaction implements Transaction {
729
776
  this.writeTimeout = this.timeout;
730
777
  this.linkWrite(operation);
731
778
  this.writes.push(operation);
779
+ operation.stagedIn = this;
732
780
  // Hold this write back while any earlier same-key write has not run — out of staging order both
733
781
  // diff against the pre-transaction record (harper#2211, DESIGN.md). The whole chain, not just the
734
782
  // immediate link: an eager non-chaining write in between would otherwise launder the deferral.
@@ -807,7 +855,7 @@ export class DatabaseTransaction implements Transaction {
807
855
  if (!operation.saved) {
808
856
  operation.saved = true;
809
857
  // immediately execute in this transaction
810
- if ((operation.validate?.(txnTime) as any) === false) {
858
+ if ((operation.validate?.(txnTime, this) as any) === false) {
811
859
  operation.commit = () => {}; // noop if we try again
812
860
  return;
813
861
  }
@@ -1491,6 +1539,19 @@ export function isReleasedTransaction(value: unknown): boolean {
1491
1539
  return value === RELEASED_TRANSACTION;
1492
1540
  }
1493
1541
 
1542
+ /**
1543
+ * Whether this transaction can be joined as the atomic scope resources/transaction.ts promises. OPEN is
1544
+ * not sufficient: an ImmediateTransaction commits every write as it is made, so a caller that joined one
1545
+ * would get per-write autocommit with no final commit or abort to roll back to. txnForContext installs
1546
+ * one in a context slot that is empty or holds the released placeholder, where it reports OPEN with
1547
+ * nothing owning a commit for it (#2292). Ownership itself is deliberately not the test — a context
1548
+ * pre-seeded with an externally driven DatabaseTransaction (replayLogs.ts) still owns the writes it is
1549
+ * given, and its own commit/abort still governs them.
1550
+ */
1551
+ export function isJoinableScope(transaction: DatabaseTransaction | null | undefined): boolean {
1552
+ return transaction?.open === TRANSACTION_STATE.OPEN && !transaction.saveCommits;
1553
+ }
1554
+
1494
1555
  let timer;
1495
1556
 
1496
1557
  /**
@@ -25,6 +25,7 @@ export function replicationConfirmation(callback) {
25
25
  }
26
26
 
27
27
  export class LMDBTransaction extends DatabaseTransaction {
28
+ stagesWriteOnSave = false;
28
29
  #context: Context;
29
30
  writes: TransactionWrite[] = []; // the set of writes to commit if the conditions are met
30
31
  validated = 0;
@@ -97,6 +98,9 @@ export class LMDBTransaction extends DatabaseTransaction {
97
98
  const immediateTxn = new ImmediateTransaction(this.db);
98
99
  immediateTxn.addWrite(operation);
99
100
  const result = immediateTxn.commit({});
101
+ // Nothing may be sent back to this throwaway: the write is already committed, and its
102
+ // durability is the promise below.
103
+ operation.stagedIn = undefined;
100
104
  if (result?.then) {
101
105
  operation.promise = result;
102
106
  } else {
@@ -107,6 +111,7 @@ export class LMDBTransaction extends DatabaseTransaction {
107
111
 
108
112
  this.linkWrite(operation);
109
113
  this.writes.push(operation); // standard path, add to current transaction
114
+ operation.stagedIn = this;
110
115
  }
111
116
 
112
117
  removeWrite(operation: TransactionWrite) {
@@ -133,7 +138,7 @@ export class LMDBTransaction extends DatabaseTransaction {
133
138
  this.validated = this.writes.length;
134
139
  for (let i = start; i < this.validated; i++) {
135
140
  const write = this.writes[i];
136
- write?.validate?.(this.timestamp);
141
+ write?.validate?.(this.timestamp, this);
137
142
  }
138
143
  let hasBefore;
139
144
  for (let i = start; i < this.validated; i++) {
@@ -342,6 +347,7 @@ export class LMDBTransaction extends DatabaseTransaction {
342
347
  }
343
348
 
344
349
  export class ImmediateTransaction extends LMDBTransaction {
350
+ saveCommits = true;
345
351
  constructor(db: RootDatabaseKind) {
346
352
  super();
347
353
  this.db = db;
@@ -12,8 +12,8 @@ import {
12
12
  import { randomUUID } from 'crypto';
13
13
  import {
14
14
  DatabaseTransaction,
15
+ isJoinableScope,
15
16
  isReleasedTransaction,
16
- TRANSACTION_STATE,
17
17
  type Transaction,
18
18
  } from './DatabaseTransaction.ts';
19
19
  import { IterableEventQueue } from './IterableEventQueue.ts';
@@ -769,9 +769,10 @@ function transactional(
769
769
  if (isCollection) resourceOptions.isCollection = true;
770
770
  } else resourceOptions = options;
771
771
  const loadAsInstance = this.loadAsInstance;
772
- // Only join an existing transaction if it is still genuinely OPEN (mirrors the reuse check
773
- // resources/transaction.ts's transaction() helper already applies to itself). A `context`
774
- // object can carry a *stale* `.transaction` left over from an earlier, unrelated call that
772
+ // Only join an existing transaction that can actually be a scope (isJoinableScope: OPEN, and it
773
+ // stages its writes rather than committing each one — the same gate resources/transaction.ts's
774
+ // transaction() helper applies to itself). Beyond that, a `context` object can carry a *stale*
775
+ // `.transaction` left over from an earlier, unrelated call that
775
776
  // already ran to completion: ambient contexts obtained via contextStorage.getStore() are
776
777
  // no longer guaranteed to be fresh, one-shot objects now that processLocalTransaction (#1591/
777
778
  // #1592) installs one shared, long-lived context for the lifetime of an entire operation
@@ -795,7 +796,7 @@ function transactional(
795
796
  // starting fresh) makes the write throw transactionOpenTooLongError via addWrite()/commit()'s
796
797
  // poison check, correctly propagating the abort to the caller. See
797
798
  // integrationTests/resources/txn-overtime-atomicity.test.ts.
798
- if (context?.transaction?.open === TRANSACTION_STATE.OPEN || context?.transaction?.timedOut) {
799
+ if (isJoinableScope(context?.transaction) || context?.transaction?.timedOut) {
799
800
  // we are already in a transaction (or it was poisoned by a timeout abort and must fail), proceed
800
801
  const resource = this.getResource(query, context, resourceOptions);
801
802
  return resource.then
@@ -76,6 +76,11 @@ export interface Context {
76
76
  * so there the completed transaction itself stays in the slot — also safe to call, but retained.
77
77
  * `null` was the previous released marker and is still accepted defensively.
78
78
  *
79
+ * A read that resolves a transaction without going through the static-API wrappers (an instance load,
80
+ * for one) replaces a released or never-set slot with an ImmediateTransaction, which commits every
81
+ * write as it is made. `transaction()` and the static API start their own scope rather than joining
82
+ * that, so an explicit `transaction()` is atomic on a released slot as it is on a fresh one.
83
+ *
79
84
  * A transaction its own handler commits mid-scope is rotated to a fresh open generation, so the rest
80
85
  * of that scope's writes are committed — or rolled back — with the scope's final commit rather than
81
86
  * each committing itself immediately. Two cases keep the older per-write behavior: a commit made
@@ -36,6 +36,7 @@ import {
36
36
  DatabaseTransaction,
37
37
  ImmediateTransaction,
38
38
  priorStagedWrite,
39
+ isJoinableScope,
39
40
  isReleasedTransaction,
40
41
  TRANSACTION_STATE,
41
42
  writeKeyId,
@@ -1873,7 +1874,28 @@ export function makeTable(options) {
1873
1874
  }
1874
1875
  #saveOperation(operation: any) {
1875
1876
  const transaction = txnForContext(this.getContext());
1876
- if (transaction.save) return transaction.save(operation) || operation.promise || operation.result;
1877
+ const holder = operation.stagedIn;
1878
+ // never-drop-on-conflict lives on the transaction and would not travel with the write, so an
1879
+ // apply or a replay keeps it (harper-pro#348)
1880
+ const holderOwnsPolicy = holder?.sourceApply || holder?.isReplay;
1881
+ // stagesWriteOnSave: LMDBTransaction's addWrite never runs the write (its commit applies
1882
+ // `writes`), so handing it one is a dead end
1883
+ if (
1884
+ holder &&
1885
+ holder !== transaction &&
1886
+ !holderOwnsPolicy &&
1887
+ transaction.stagesWriteOnSave &&
1888
+ isJoinableScope(transaction)
1889
+ ) {
1890
+ holder.detachWrite(operation);
1891
+ // The basis chain belongs to the holder: derived from a write this scope cannot commit, the
1892
+ // merge and index diff would be relative to a record that may never land.
1893
+ operation.priorWrite = undefined;
1894
+ operation.deferSave = false;
1895
+ return when(transaction.addWrite(operation), () => operation.promise ?? operation.result);
1896
+ }
1897
+ const owner = holder ?? transaction;
1898
+ if (owner.save) return owner.save(operation) || operation.promise || operation.result;
1877
1899
  }
1878
1900
 
1879
1901
  addTo(property: any, value: any) {
@@ -2314,11 +2336,11 @@ export function makeTable(options) {
2314
2336
  nodeName: (context as any)?.nodeName,
2315
2337
  fullUpdate,
2316
2338
  deferSave: true,
2317
- validate: (txnTime) => {
2339
+ validate: (txnTime, committedBy = transaction) => {
2318
2340
  if (!recordUpdate) recordUpdate = this.#changes;
2319
2341
  if (fullUpdate || (recordUpdate && hasChanges(this.#changes === recordUpdate ? this : recordUpdate))) {
2320
2342
  if (!(context as any)?.source) {
2321
- transaction.checkOverloaded();
2343
+ committedBy.checkOverloaded();
2322
2344
  // A record must be a plain object. Reject primitive, string/number, bare-binary,
2323
2345
  // and bare-array roots — e.g. a raw Buffer from an application/octet-stream PUT, a
2324
2346
  // JSON string/number body, or a top-level JSON array. Such roots carry no primary
@@ -2356,7 +2378,7 @@ export function makeTable(options) {
2356
2378
  // by replayLogs). Records were valid when originally written; post-crash schema
2357
2379
  // evolution (e.g. newly required fields) must not prevent replaying them
2358
2380
  // (harper#1316, facet b).
2359
- if (!transaction.isReplay) this.validate(recordUpdate, !fullUpdate);
2381
+ if (!committedBy.isReplay) this.validate(recordUpdate, !fullUpdate);
2360
2382
  if (updatedTimeProperty) {
2361
2383
  recordUpdate[updatedTimeProperty.name] =
2362
2384
  updatedTimeProperty.type === 'Date'
@@ -2391,7 +2413,7 @@ export function makeTable(options) {
2391
2413
  // TODO: else freeze after we have applied the changes
2392
2414
  }
2393
2415
  } else {
2394
- (transaction as any).removeWrite?.(write);
2416
+ (committedBy as any).removeWrite?.(write);
2395
2417
  return false;
2396
2418
  }
2397
2419
  },
@@ -2434,6 +2456,7 @@ export function makeTable(options) {
2434
2456
  let incrementalUpdateToApply: boolean;
2435
2457
 
2436
2458
  this.#savingOperation = null;
2459
+ write.stagedIn = undefined; // nothing may pin this write's transaction past its commit
2437
2460
  let omitLocalRecord = false;
2438
2461
  // we use optimistic locking to only commit if the existing record state still holds true.
2439
2462
  // this is superior to using an async transaction since it doesn't require JS execution
@@ -5645,10 +5668,33 @@ export function makeTable(options) {
5645
5668
  // See if this is a transaction for our database and if so, use it
5646
5669
  if (transaction.db?.path === primaryStore.path) return transaction;
5647
5670
  // try the next one:
5648
- const nextTxn = transaction.next;
5671
+ let nextTxn = transaction.next;
5672
+ // A self-committing link is CLOSED once it has committed, and a further write through it
5673
+ // commits on a native handle nothing awaits (#2323). Spent — closed, handle detached, none of
5674
+ // its OWN writes left (hasPendingWrites walks successors, which is not this question) — it
5675
+ // holds nothing, so drop it. A run of them can be spent, hence the loop. A timeout-poisoned
5676
+ // link is kept: reusing it is what makes the rest of the operation fail atomically (#1411).
5677
+ while (
5678
+ nextTxn?.saveCommits &&
5679
+ nextTxn.open !== TRANSACTION_STATE.OPEN &&
5680
+ !nextTxn.timedOut &&
5681
+ !nextTxn.transaction &&
5682
+ !nextTxn.writes.some((write) => write)
5683
+ ) {
5684
+ transaction.next = nextTxn.next;
5685
+ nextTxn = transaction.next;
5686
+ }
5649
5687
  if (!nextTxn) {
5650
5688
  // no next one, then add our database
5651
- transaction.next = isRocksDB ? new DatabaseTransaction() : new LMDBTransaction();
5689
+ // A staging link under a self-committing head is committed only if the head's own database
5690
+ // is written again and cascades the chain, so a handler writing this one last loses it (#2292).
5691
+ transaction.next = transaction.saveCommits
5692
+ ? ((isRocksDB
5693
+ ? new ImmediateTransaction(primaryStore as any)
5694
+ : new ImmediateLMDBTransaction(primaryStore as any)) as any)
5695
+ : isRocksDB
5696
+ ? new DatabaseTransaction()
5697
+ : new LMDBTransaction();
5652
5698
  // The chain root, so a link that only ever receives a blind write is supervised by the
5653
5699
  // long-transaction monitor as part of its logical transaction rather than as its own
5654
5700
  // timeout root (issue #2231).
@@ -5670,8 +5716,11 @@ export function makeTable(options) {
5670
5716
  // A second database joined after a mid-scope commit belongs to the same snapshot-free
5671
5717
  // generation as the head, or its reads would re-pin what the commit just unpinned.
5672
5718
  transaction.next.snapshotFree = transaction.snapshotFree;
5673
- if (transaction.open === TRANSACTION_STATE.CLOSED) {
5719
+ if (transaction.open === TRANSACTION_STATE.CLOSED && !transaction.next.saveCommits) {
5674
5720
  // if the current transaction is already closed, we need to retain that state on new databases we work with
5721
+ // Never onto a self-committing link: CLOSED is what routes its first write through the
5722
+ // commit re-entry that drops the native commit promise (#2323), and it commits per write
5723
+ // regardless of this state.
5675
5724
  transaction.next.open = TRANSACTION_STATE.CLOSED;
5676
5725
  }
5677
5726
  transaction = transaction.next;
@@ -2,9 +2,9 @@ import type { Context } from './ResourceInterface.ts';
2
2
  import { _assignPackageExport } from '../globals.js';
3
3
  import {
4
4
  DatabaseTransaction,
5
+ isJoinableScope,
5
6
  isReleasedTransaction,
6
7
  type Transaction,
7
- TRANSACTION_STATE,
8
8
  } from './DatabaseTransaction.ts';
9
9
  import { AsyncLocalStorage } from 'async_hooks';
10
10
 
@@ -41,7 +41,7 @@ export function transaction<T>(
41
41
  if (typeof callback !== 'function') {
42
42
  throw new TypeError('Callback function must be provided to transaction');
43
43
  }
44
- if (context?.transaction?.open === TRANSACTION_STATE.OPEN && typeof callback === 'function') {
44
+ if (isJoinableScope(context?.transaction) && typeof callback === 'function') {
45
45
  return callback(context.transaction); // nothing to be done, already in open transaction
46
46
  }
47
47
 
package/server/DESIGN.md CHANGED
@@ -68,6 +68,12 @@ A request entering `http.ts` does **not** go through Fastify. The two `handleApp
68
68
  | `threads/itc.js` | Inter-thread comms primitives. |
69
69
  | `transactionLogCooling.ts` | Main-thread timer that cools transaction-log mmaps. |
70
70
 
71
+ Process-wide shutdown begins by calling `beginProcessShutdown()` in `threads/manageThreads.js`.
72
+ Once set, this terminal state prevents every worker replacement path and makes new `startWorker()`
73
+ calls fail with `ERR_HARPER_PROCESS_SHUTTING_DOWN`; scoped worker-type restarts do not set it.
74
+ `shutdownWorkersNow()` remains an immediate teardown: its worker shutdown messages are best-effort,
75
+ and it force-terminates the remaining worker set rather than waiting for application drain hooks.
76
+
71
77
  > Workers receive `workerData.noServerStart = true` — never start the server inside a worker.
72
78
  >
73
79
  > `threadServer.listenOnDomainSocket()` skips a listener only when its path exceeds the platform's
@@ -46,6 +46,7 @@ const chokidar = require('chokidar');
46
46
  const isBun = typeof globalThis.Bun !== 'undefined';
47
47
  const MB = 1024 * 1024;
48
48
  const workers = []; // these are our child workers that we are managing
49
+ let processShuttingDown = false;
49
50
  const connectedPorts = []; // these are all known connected worker ports (siblings, children, parents)
50
51
  const MAX_UNEXPECTED_RESTARTS = 50;
51
52
  // Threads get 10s to die before they're forced. In dev (`harper dev`) we widen this: a reload's old
@@ -150,6 +151,7 @@ module.exports = {
150
151
  setTerminateTimeout,
151
152
  extendShutdownDeadline,
152
153
  restoreShutdownDeadline,
154
+ beginProcessShutdown,
153
155
  registerWorkerDataProvider,
154
156
  onThreadExit,
155
157
  registerProcessGroup,
@@ -324,6 +326,11 @@ listenersByType.set(THREAD_INFO, null);
324
326
  listenersByType.set(PROCESS_GROUP_TERMINATION_CONFIRMED, null);
325
327
 
326
328
  function startWorker(path, options = {}) {
329
+ if (processShuttingDown) {
330
+ const error = new Error('Cannot start a worker while the Harper process is shutting down');
331
+ error.code = 'ERR_HARPER_PROCESS_SHUTTING_DOWN';
332
+ throw error;
333
+ }
327
334
  // Take a percentage of total memory to determine the max memory for each thread. The percentage is based
328
335
  // on the thread count. Generally, it is unrealistic to efficiently use the majority of total memory for a single
329
336
  // NodeJS worker since it would lead to massive swap space usage with other processes and there is significant
@@ -435,7 +442,7 @@ function startWorker(path, options = {}) {
435
442
  });
436
443
  worker.on('exit', (_code) => {
437
444
  workers.splice(workers.indexOf(worker), 1);
438
- if (!worker.wasShutdown && options.autoRestart !== false) {
445
+ if (!processShuttingDown && !worker.wasShutdown && options.autoRestart !== false) {
439
446
  // if this wasn't an intentional shutdown, restart now (unless we have tried too many times)
440
447
  if (worker.unexpectedRestarts < MAX_UNEXPECTED_RESTARTS) {
441
448
  options.unexpectedRestarts = worker.unexpectedRestarts + 1;
@@ -469,6 +476,7 @@ async function restartWorkers(
469
476
  startReplacementThreads = true
470
477
  ) {
471
478
  if (isMainThread) {
479
+ if (processShuttingDown && startReplacementThreads) return;
472
480
  try {
473
481
  // we do this because it is possible for a component to chdir to itself, get re-deployed and then the cwd
474
482
  // inode link is invalid and it can cause a lot of problems. But process.cwd() still returns the path, for
@@ -506,6 +514,8 @@ async function restartWorkers(
506
514
  // listenOnPorts() treat a dedicated listener's EADDRINUSE as an external conflict.
507
515
  const canPreStartReplacement = process.platform !== 'win32' && process.platform !== 'darwin' && !isBun;
508
516
  for (let worker of workers.slice(0)) {
517
+ // Terminal shutdown: stop replacing workers mid-loop — the guard for every replacement start below.
518
+ if (processShuttingDown && startReplacementThreads) break;
509
519
  if ((name && worker.name !== name) || worker.wasShutdown) continue; // filter by type, if specified
510
520
  const overlapping = OVERLAPPING_RESTART_TYPES.indexOf(worker.name) > -1;
511
521
  if (overlapping && startReplacementThreads && canPreStartReplacement) {
@@ -590,7 +600,7 @@ async function restartWorkers(
590
600
  // Overlapping types we couldn't pre-start (Windows/Bun): start the replacement now that the old
591
601
  // worker is releasing its port. server.close() stops accepting immediately, so the port frees up
592
602
  // well before the replacement finishes booting and binds.
593
- if (overlapping && startReplacementThreads && !canPreStartReplacement) worker.startCopy();
603
+ if (overlapping && startReplacementThreads && !canPreStartReplacement && !processShuttingDown) worker.startCopy();
594
604
  let whenDone = new Promise((resolve) => {
595
605
  // in case the exit inside the thread doesn't timeout, force it from the outside
596
606
  const armTerminate = (delay) =>
@@ -627,7 +637,7 @@ async function restartWorkers(
627
637
  const index = waitingToFinish.indexOf(whenDone);
628
638
  if (index > -1) waitingToFinish.splice(index, 1);
629
639
  // non-overlapping types have no advance replacement, so start it once the old one is gone
630
- if (!overlapping && startReplacementThreads) worker.startCopy();
640
+ if (!overlapping && startReplacementThreads && !processShuttingDown) worker.startCopy();
631
641
  resolve();
632
642
  });
633
643
  });
@@ -650,7 +660,11 @@ async function restartWorkers(
650
660
  function shutdownWorkers(name) {
651
661
  return restartWorkers(name, Infinity, false);
652
662
  }
663
+ function beginProcessShutdown() {
664
+ processShuttingDown = true;
665
+ }
653
666
  async function shutdownWorkersNow(name) {
667
+ if (name == null) beginProcessShutdown();
654
668
  shutdownWorkers(name); // set the state of all the workers to shut down. this should finish the important stuff synchronously
655
669
  if (isBun) {
656
670
  // worker.terminate() triggers a NAPI segfault in Bun; ask workers to self-exit instead
@@ -1,4 +1,4 @@
1
- import{a as e,t}from"./rolldown-runtime-B0Z9INg1.js";import{C as n,S as r,_ as i,b as a,c as o,f as s,g as c,h as l,i as u,l as d,m as f,n as p,o as m,p as h,r as g,s as _,u as v,v as ee,x as te,y}from"./vendor-core-CddkYGh5.js";import{i as b,t as x}from"./button-DfBmT4rc.js";import{H as ne,L as re,k as ie,z as ae}from"./vendor-tanstack-FsM5XZNE.js";import{a as oe}from"./vendor-datadog-XDrpA25D.js";import{r as se}from"./vendor-react-BhazFIp8.js";import{Rt as S}from"./vendor-ui-BLIveqaL.js";import{t as C}from"./createLucideIcon-BMkDbMrz.js";import{l as ce,t as le}from"./react-VeAY02s6.js";import{i as ue,n as de,r as fe,t as pe}from"./x-D39AGKMb.js";import{t as me}from"./chevron-right-CY-tr2sG.js";import{c as he,f as ge,g as _e,h as ve,i as ye,l as be,m as xe,p as Se,r as Ce,t as we,u as Te}from"./setComponentFile-DoITgNLb.js";import{r as Ee}from"./queryClient-BLhQvmWC.js";import{n as De}from"./setLocalStorage-CD_L8p_D.js";import{t as Oe}from"./useLocalStorage-DetQlhBe.js";import{o as ke}from"./pollUnlessForbidden-DIDXGBc5.js";import{$n as Ae,At as je,Gt as Me,H as Ne,Kn as Pe,Nt as Fe,Ot as Ie,Un as Le,V as Re,Vn as ze,Wn as Be,Y as Ve,Yn as He,_t as Ue,ar as We,c as Ge,ct as Ke,d as qe,dn as Je,er as Ye,f as Xe,jt as Ze,kt as Qe,m as $e,or as et,rr as tt,ut as nt}from"./index-CqbCnqsT.js";import{t as rt}from"./useEntityRestURL-Cy-0i1UZ.js";import{n as it}from"./getAnalytics-rTxZLIM5.js";var at=C(`between-horizontal-start`,[[`rect`,{width:`13`,height:`7`,x:`8`,y:`3`,rx:`1`,key:`pkso9a`}],[`path`,{d:`m2 9 3 3-3 3`,key:`1agib5`}],[`rect`,{width:`13`,height:`7`,x:`8`,y:`14`,rx:`1`,key:`1q5fc1`}]]),ot=C(`book`,[[`path`,{d:`M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H19a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6.5a1 1 0 0 1 0-5H20`,key:`k3hazp`}]]),st=C(`chart-area`,[[`path`,{d:`M3 3v16a2 2 0 0 0 2 2h16`,key:`c24i48`}],[`path`,{d:`M7 11.207a.5.5 0 0 1 .146-.353l2-2a.5.5 0 0 1 .708 0l3.292 3.292a.5.5 0 0 0 .708 0l4.292-4.292a.5.5 0 0 1 .854.353V16a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1z`,key:`q0gr47`}]]),ct=C(`circle-x`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m15 9-6 6`,key:`1uzhvr`}],[`path`,{d:`m9 9 6 6`,key:`z0biqf`}]]),lt=C(`file-pen`,[[`path`,{d:`M12.659 22H18a2 2 0 0 0 2-2V8a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 14 2H6a2 2 0 0 0-2 2v9.34`,key:`o6klzx`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`M10.378 12.622a1 1 0 0 1 3 3.003L8.36 20.637a2 2 0 0 1-.854.506l-2.867.837a.5.5 0 0 1-.62-.62l.836-2.869a2 2 0 0 1 .506-.853z`,key:`zhnas1`}]]),ut=C(`logs`,[[`path`,{d:`M3 5h1`,key:`1mv5vm`}],[`path`,{d:`M3 12h1`,key:`lp3yf2`}],[`path`,{d:`M3 19h1`,key:`w6f3n9`}],[`path`,{d:`M8 5h1`,key:`1nxr5w`}],[`path`,{d:`M8 12h1`,key:`1con00`}],[`path`,{d:`M8 19h1`,key:`k7p10e`}],[`path`,{d:`M13 5h8`,key:`a7qcls`}],[`path`,{d:`M13 12h8`,key:`h98zly`}],[`path`,{d:`M13 19h8`,key:`c3s6r1`}]]),dt=C(`message-square-heart`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}],[`path`,{d:`M7.5 9.5c0 .687.265 1.383.697 1.844l3.009 3.264a1.14 1.14 0 0 0 .407.314 1 1 0 0 0 .783-.004 1.14 1.14 0 0 0 .398-.31l3.008-3.264A2.77 2.77 0 0 0 16.5 9.5 2.5 2.5 0 0 0 12 8a2.5 2.5 0 0 0-4.5 1.5`,key:`1faxuh`}]]),ft=C(`send`,[[`path`,{d:`M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z`,key:`1ffxy3`}],[`path`,{d:`m21.854 2.147-10.94 10.939`,key:`12cjpa`}]]),pt=C(`wrench`,[[`path`,{d:`M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.106-3.105c.32-.322.863-.22.983.218a6 6 0 0 1-8.259 7.057l-7.91 7.91a1 1 0 0 1-2.999-3l7.91-7.91a6 6 0 0 1 7.057-8.259c.438.12.54.662.219.984z`,key:`1ngwbx`}]]);async function mt(){await b.delete(`/Chat/Messages/`)}var w=e(oe(),1),T=se();function ht({setMessages:e}){let[t,n]=(0,w.useState)(!1),r=(0,w.useCallback)(async()=>{if(!t){n(!0);try{await mt(),e([])}catch(e){console.error(`Failed to clear chat:`,e)}finally{n(!1)}}},[t,e]);return(0,T.jsxs)(`button`,{type:`button`,className:`clear-chat-button gap-1`,onClick:r,disabled:t,title:`Clear chat`,children:[t?(0,T.jsx)(Ae,{className:`animate-spin`,size:18}):(0,T.jsx)(Be,{size:18}),`Clear`]})}async function gt(){let{data:e}=await b.get(`/Chat/Messages/`);return e}var _t=`vercel.ai.error`,vt=Symbol.for(_t),yt,bt,E=class e extends (bt=Error,yt=vt,bt){constructor({name:e,message:t,cause:n}){super(t),this[yt]=!0,this.name=e,this.cause=n}static isInstance(t){return e.hasMarker(t,_t)}static hasMarker(e,t){let n=Symbol.for(t);return typeof e==`object`&&!!e&&n in e&&typeof e[n]==`boolean`&&e[n]===!0}};function xt(e){return e==null?`unknown error`:typeof e==`string`?e:e instanceof Error?e.toString():JSON.stringify(e)}var St=`AI_InvalidArgumentError`,Ct=`vercel.ai.error.${St}`,wt=Symbol.for(Ct),Tt,Et,Dt=class extends (Et=E,Tt=wt,Et){constructor({message:e,cause:t,argument:n}){super({name:St,message:e,cause:t}),this[Tt]=!0,this.argument=n}static isInstance(e){return E.hasMarker(e,Ct)}},Ot=`AI_JSONParseError`,kt=`vercel.ai.error.${Ot}`,At=Symbol.for(kt),jt,Mt,Nt=class extends (Mt=E,jt=At,Mt){constructor({text:e,cause:t}){super({name:Ot,message:`JSON parsing failed: Text: ${e}.
1
+ import{a as e,t}from"./rolldown-runtime-B0Z9INg1.js";import{C as n,S as r,_ as i,b as a,c as o,f as s,g as c,h as l,i as u,l as d,m as f,n as p,o as m,p as h,r as g,s as _,u as v,v as ee,x as te,y}from"./vendor-core-CddkYGh5.js";import{i as b,t as x}from"./button-DfBmT4rc.js";import{H as ne,L as re,k as ie,z as ae}from"./vendor-tanstack-FsM5XZNE.js";import{a as oe}from"./vendor-datadog-XDrpA25D.js";import{r as se}from"./vendor-react-BhazFIp8.js";import{Rt as S}from"./vendor-ui-BLIveqaL.js";import{t as C}from"./createLucideIcon-BMkDbMrz.js";import{l as ce,t as le}from"./react-VeAY02s6.js";import{i as ue,n as de,r as fe,t as pe}from"./x-D39AGKMb.js";import{t as me}from"./chevron-right-CY-tr2sG.js";import{c as he,f as ge,g as _e,h as ve,i as ye,l as be,m as xe,p as Se,r as Ce,t as we,u as Te}from"./setComponentFile-DSHbURTI.js";import{r as Ee}from"./queryClient-BLhQvmWC.js";import{n as De}from"./setLocalStorage-CD_L8p_D.js";import{t as Oe}from"./useLocalStorage-DetQlhBe.js";import{o as ke}from"./pollUnlessForbidden-DIDXGBc5.js";import{$n as Ae,At as je,Gt as Me,H as Ne,Kn as Pe,Nt as Fe,Ot as Ie,Un as Le,V as Re,Vn as ze,Wn as Be,Y as Ve,Yn as He,_t as Ue,ar as We,c as Ge,ct as Ke,d as qe,dn as Je,er as Ye,f as Xe,jt as Ze,kt as Qe,m as $e,or as et,rr as tt,ut as nt}from"./index-BQB9R8Ug.js";import{t as rt}from"./useEntityRestURL-qfahJnvr.js";import{n as it}from"./getAnalytics-rTxZLIM5.js";var at=C(`between-horizontal-start`,[[`rect`,{width:`13`,height:`7`,x:`8`,y:`3`,rx:`1`,key:`pkso9a`}],[`path`,{d:`m2 9 3 3-3 3`,key:`1agib5`}],[`rect`,{width:`13`,height:`7`,x:`8`,y:`14`,rx:`1`,key:`1q5fc1`}]]),ot=C(`book`,[[`path`,{d:`M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H19a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6.5a1 1 0 0 1 0-5H20`,key:`k3hazp`}]]),st=C(`chart-area`,[[`path`,{d:`M3 3v16a2 2 0 0 0 2 2h16`,key:`c24i48`}],[`path`,{d:`M7 11.207a.5.5 0 0 1 .146-.353l2-2a.5.5 0 0 1 .708 0l3.292 3.292a.5.5 0 0 0 .708 0l4.292-4.292a.5.5 0 0 1 .854.353V16a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1z`,key:`q0gr47`}]]),ct=C(`circle-x`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m15 9-6 6`,key:`1uzhvr`}],[`path`,{d:`m9 9 6 6`,key:`z0biqf`}]]),lt=C(`file-pen`,[[`path`,{d:`M12.659 22H18a2 2 0 0 0 2-2V8a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 14 2H6a2 2 0 0 0-2 2v9.34`,key:`o6klzx`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`M10.378 12.622a1 1 0 0 1 3 3.003L8.36 20.637a2 2 0 0 1-.854.506l-2.867.837a.5.5 0 0 1-.62-.62l.836-2.869a2 2 0 0 1 .506-.853z`,key:`zhnas1`}]]),ut=C(`logs`,[[`path`,{d:`M3 5h1`,key:`1mv5vm`}],[`path`,{d:`M3 12h1`,key:`lp3yf2`}],[`path`,{d:`M3 19h1`,key:`w6f3n9`}],[`path`,{d:`M8 5h1`,key:`1nxr5w`}],[`path`,{d:`M8 12h1`,key:`1con00`}],[`path`,{d:`M8 19h1`,key:`k7p10e`}],[`path`,{d:`M13 5h8`,key:`a7qcls`}],[`path`,{d:`M13 12h8`,key:`h98zly`}],[`path`,{d:`M13 19h8`,key:`c3s6r1`}]]),dt=C(`message-square-heart`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}],[`path`,{d:`M7.5 9.5c0 .687.265 1.383.697 1.844l3.009 3.264a1.14 1.14 0 0 0 .407.314 1 1 0 0 0 .783-.004 1.14 1.14 0 0 0 .398-.31l3.008-3.264A2.77 2.77 0 0 0 16.5 9.5 2.5 2.5 0 0 0 12 8a2.5 2.5 0 0 0-4.5 1.5`,key:`1faxuh`}]]),ft=C(`send`,[[`path`,{d:`M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z`,key:`1ffxy3`}],[`path`,{d:`m21.854 2.147-10.94 10.939`,key:`12cjpa`}]]),pt=C(`wrench`,[[`path`,{d:`M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.106-3.105c.32-.322.863-.22.983.218a6 6 0 0 1-8.259 7.057l-7.91 7.91a1 1 0 0 1-2.999-3l7.91-7.91a6 6 0 0 1 7.057-8.259c.438.12.54.662.219.984z`,key:`1ngwbx`}]]);async function mt(){await b.delete(`/Chat/Messages/`)}var w=e(oe(),1),T=se();function ht({setMessages:e}){let[t,n]=(0,w.useState)(!1),r=(0,w.useCallback)(async()=>{if(!t){n(!0);try{await mt(),e([])}catch(e){console.error(`Failed to clear chat:`,e)}finally{n(!1)}}},[t,e]);return(0,T.jsxs)(`button`,{type:`button`,className:`clear-chat-button gap-1`,onClick:r,disabled:t,title:`Clear chat`,children:[t?(0,T.jsx)(Ae,{className:`animate-spin`,size:18}):(0,T.jsx)(Be,{size:18}),`Clear`]})}async function gt(){let{data:e}=await b.get(`/Chat/Messages/`);return e}var _t=`vercel.ai.error`,vt=Symbol.for(_t),yt,bt,E=class e extends (bt=Error,yt=vt,bt){constructor({name:e,message:t,cause:n}){super(t),this[yt]=!0,this.name=e,this.cause=n}static isInstance(t){return e.hasMarker(t,_t)}static hasMarker(e,t){let n=Symbol.for(t);return typeof e==`object`&&!!e&&n in e&&typeof e[n]==`boolean`&&e[n]===!0}};function xt(e){return e==null?`unknown error`:typeof e==`string`?e:e instanceof Error?e.toString():JSON.stringify(e)}var St=`AI_InvalidArgumentError`,Ct=`vercel.ai.error.${St}`,wt=Symbol.for(Ct),Tt,Et,Dt=class extends (Et=E,Tt=wt,Et){constructor({message:e,cause:t,argument:n}){super({name:St,message:e,cause:t}),this[Tt]=!0,this.argument=n}static isInstance(e){return E.hasMarker(e,Ct)}},Ot=`AI_JSONParseError`,kt=`vercel.ai.error.${Ot}`,At=Symbol.for(kt),jt,Mt,Nt=class extends (Mt=E,jt=At,Mt){constructor({text:e,cause:t}){super({name:Ot,message:`JSON parsing failed: Text: ${e}.
2
2
  Error message: ${xt(t)}`,cause:t}),this[jt]=!0,this.text=e}static isInstance(e){return E.hasMarker(e,kt)}},Pt=`AI_TypeValidationError`,Ft=`vercel.ai.error.${Pt}`,It=Symbol.for(Ft),Lt,Rt,D=class e extends (Rt=E,Lt=It,Rt){constructor({value:e,cause:t,context:n}){let r=`Type validation failed`;if(n?.field&&(r+=` for ${n.field}`),n?.entityName||n?.entityId){r+=` (`;let e=[];n.entityName&&e.push(n.entityName),n.entityId&&e.push(`id: "${n.entityId}"`),r+=e.join(`, `),r+=`)`}super({name:Pt,message:`${r}: Value: ${JSON.stringify(e)}.
3
3
  Error message: ${xt(t)}`,cause:t}),this[Lt]=!0,this.value=e,this.context=n}static isInstance(e){return E.hasMarker(e,Ft)}static wrap({value:t,cause:n,context:r}){return e.isInstance(n)&&n.value===t&&n.context?.field===r?.field&&n.context?.entityName===r?.entityName&&n.context?.entityId===r?.entityId?n:new e({value:t,cause:n,context:r})}},zt=class extends Error{constructor(e,t){super(e),this.name=`ParseError`,this.type=t.type,this.field=t.field,this.value=t.value,this.line=t.line}},Bt=10,Vt=13,O=32;function Ht(e){}function Ut(e){if(typeof e==`function`)throw TypeError("`config` must be an object, got a function instead. Did you mean `createParser({onEvent: fn})`?");let{onEvent:t=Ht,onError:n=Ht,onRetry:r=Ht,onComment:i,maxBufferSize:a}=e,o=[],s=0,c=!0,l,u=``,d=0,f,p=!1;function m(e){if(p)throw Error("Cannot feed parser: it was terminated after exceeding the configured max buffer size. Call `reset()` to resume parsing.");if(c&&(c=!1,e.charCodeAt(0)===239&&e.charCodeAt(1)===187&&e.charCodeAt(2)===191&&(e=e.slice(3))),o.length===0){let t=g(e);t!==``&&(o.push(t),s=t.length),h();return}if(e.indexOf(`
4
4
  `)===-1&&e.indexOf(`\r`)===-1){o.push(e),s+=e.length,h();return}o.push(e);let t=o.join(``);o.length=0,s=0;let n=g(t);n!==``&&(o.push(n),s=n.length),h()}function h(){a!==void 0&&(s+u.length<=a||(p=!0,o.length=0,s=0,l=void 0,u=``,d=0,f=void 0,n(new zt(`Buffered data exceeded max buffer size of ${a} characters`,{type:`max-buffer-size-exceeded`}))))}function g(e){let n=0;if(e.indexOf(`\r`)===-1){let r=e.indexOf(`
@@ -1,5 +1,5 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Chat-Lgj1d-8d.js","assets/rolldown-runtime-B0Z9INg1.js","assets/vendor-core-CddkYGh5.js","assets/button-DfBmT4rc.js","assets/vendor-datadog-XDrpA25D.js","assets/vendor-react-BhazFIp8.js","assets/vendor-ui-BLIveqaL.js","assets/vendor-tanstack-FsM5XZNE.js","assets/createLucideIcon-BMkDbMrz.js","assets/react-VeAY02s6.js","assets/x-D39AGKMb.js","assets/chevron-right-CY-tr2sG.js","assets/setComponentFile-DoITgNLb.js","assets/pollUnlessForbidden-DIDXGBc5.js","assets/authStore-B3IhXrn6.js","assets/index-CqbCnqsT.js","assets/useAuth-DiJUZS1C.js","assets/card-ByrPS_wa.js","assets/select-CKgJgpkn.js","assets/setLocalStorage-CD_L8p_D.js","assets/useLocalStorage-DetQlhBe.js","assets/getRegistrationInfo--NLLrics.js","assets/table-BvFflPWi.js","assets/errorText-NpBmvk9I.js","assets/queryClient-BLhQvmWC.js","assets/textarea-a3RnTY31.js","assets/tokenization-CWuvR2gh.js","assets/index-BO3NaEw8.css","assets/useEntityRestURL-Cy-0i1UZ.js","assets/getAnalytics-rTxZLIM5.js","assets/Chat-B-7kW9XZ.css"])))=>i.map(i=>d[i]);
2
- import{a as e}from"./rolldown-runtime-B0Z9INg1.js";import{a as t,i as n}from"./vendor-datadog-XDrpA25D.js";import{r}from"./vendor-react-BhazFIp8.js";import{a as i,c as a,i as o,l as s,n as c,o as l,r as u,s as d,t as f}from"./react-VeAY02s6.js";import{n as p}from"./setLocalStorage-CD_L8p_D.js";import{t as m}from"./useLocalStorage-DetQlhBe.js";import{At as h,kn as g}from"./index-CqbCnqsT.js";var _=e(t(),1);function v(e,t){if(typeof e==`function`)return e(t);e!=null&&(e.current=t)}function y(...e){return t=>{let n=!1,r=e.map(e=>{let r=v(e,t);return!n&&typeof r==`function`&&(n=!0),r});if(n)return()=>{for(let t=0;t<r.length;t++){let n=r[t];typeof n==`function`?n():v(e[t],null)}}}}function b(...e){return _.useCallback(y(...e),e)}var x=r(),S=class extends _.Component{getSnapshotBeforeUpdate(e){let t=this.props.childRef.current;if(o(t)&&e.isPresent&&!this.props.isPresent&&this.props.pop!==!1){let e=t.offsetParent,n=o(e)&&e.offsetWidth||0,r=o(e)&&e.offsetHeight||0,i=getComputedStyle(t),a=this.props.sizeRef.current;a.height=parseFloat(i.height),a.width=parseFloat(i.width),a.top=t.offsetTop,a.left=t.offsetLeft,a.right=n-a.width-a.left,a.bottom=r-a.height-a.top,a.direction=i.direction}return null}componentDidUpdate(){}render(){return this.props.children}};function C({children:e,isPresent:t,anchorX:n,anchorY:r,root:i,pop:a}){let o=(0,_.useId)(),s=(0,_.useRef)(null),c=(0,_.useRef)({width:0,height:0,top:0,left:0,right:0,bottom:0,direction:`ltr`}),{nonce:l}=(0,_.useContext)(u),d=b(s,a===!1?void 0:e.props?.ref??e?.ref);return(0,_.useInsertionEffect)(()=>{let{width:e,height:u,top:d,left:f,right:p,bottom:m,direction:h}=c.current;if(t||a===!1||!s.current||!e||!u)return;let g=h===`rtl`,_=n===`left`?g?`right: ${p}`:`left: ${f}`:g?`left: ${f}`:`right: ${p}`,v=r===`bottom`?`bottom: ${m}`:`top: ${d}`;s.current.dataset.motionPopId=o;let y=document.createElement(`style`);l&&(y.nonce=l);let b=i??document.head;return b.appendChild(y),y.sheet&&y.sheet.insertRule(`
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Chat-BNHY84-Z.js","assets/rolldown-runtime-B0Z9INg1.js","assets/vendor-core-CddkYGh5.js","assets/button-DfBmT4rc.js","assets/vendor-datadog-XDrpA25D.js","assets/vendor-react-BhazFIp8.js","assets/vendor-ui-BLIveqaL.js","assets/vendor-tanstack-FsM5XZNE.js","assets/createLucideIcon-BMkDbMrz.js","assets/react-VeAY02s6.js","assets/x-D39AGKMb.js","assets/chevron-right-CY-tr2sG.js","assets/setComponentFile-DSHbURTI.js","assets/pollUnlessForbidden-DIDXGBc5.js","assets/authStore-B3IhXrn6.js","assets/index-BQB9R8Ug.js","assets/useAuth-DiJUZS1C.js","assets/card-ByrPS_wa.js","assets/select-CKgJgpkn.js","assets/setLocalStorage-CD_L8p_D.js","assets/useLocalStorage-DetQlhBe.js","assets/getRegistrationInfo--NLLrics.js","assets/table-BvFflPWi.js","assets/errorText-NpBmvk9I.js","assets/queryClient-BLhQvmWC.js","assets/textarea-a3RnTY31.js","assets/tokenization-CWuvR2gh.js","assets/index-BO3NaEw8.css","assets/useEntityRestURL-qfahJnvr.js","assets/getAnalytics-rTxZLIM5.js","assets/Chat-B-7kW9XZ.css"])))=>i.map(i=>d[i]);
2
+ import{a as e}from"./rolldown-runtime-B0Z9INg1.js";import{a as t,i as n}from"./vendor-datadog-XDrpA25D.js";import{r}from"./vendor-react-BhazFIp8.js";import{a as i,c as a,i as o,l as s,n as c,o as l,r as u,s as d,t as f}from"./react-VeAY02s6.js";import{n as p}from"./setLocalStorage-CD_L8p_D.js";import{t as m}from"./useLocalStorage-DetQlhBe.js";import{At as h,kn as g}from"./index-BQB9R8Ug.js";var _=e(t(),1);function v(e,t){if(typeof e==`function`)return e(t);e!=null&&(e.current=t)}function y(...e){return t=>{let n=!1,r=e.map(e=>{let r=v(e,t);return!n&&typeof r==`function`&&(n=!0),r});if(n)return()=>{for(let t=0;t<r.length;t++){let n=r[t];typeof n==`function`?n():v(e[t],null)}}}}function b(...e){return _.useCallback(y(...e),e)}var x=r(),S=class extends _.Component{getSnapshotBeforeUpdate(e){let t=this.props.childRef.current;if(o(t)&&e.isPresent&&!this.props.isPresent&&this.props.pop!==!1){let e=t.offsetParent,n=o(e)&&e.offsetWidth||0,r=o(e)&&e.offsetHeight||0,i=getComputedStyle(t),a=this.props.sizeRef.current;a.height=parseFloat(i.height),a.width=parseFloat(i.width),a.top=t.offsetTop,a.left=t.offsetLeft,a.right=n-a.width-a.left,a.bottom=r-a.height-a.top,a.direction=i.direction}return null}componentDidUpdate(){}render(){return this.props.children}};function C({children:e,isPresent:t,anchorX:n,anchorY:r,root:i,pop:a}){let o=(0,_.useId)(),s=(0,_.useRef)(null),c=(0,_.useRef)({width:0,height:0,top:0,left:0,right:0,bottom:0,direction:`ltr`}),{nonce:l}=(0,_.useContext)(u),d=b(s,a===!1?void 0:e.props?.ref??e?.ref);return(0,_.useInsertionEffect)(()=>{let{width:e,height:u,top:d,left:f,right:p,bottom:m,direction:h}=c.current;if(t||a===!1||!s.current||!e||!u)return;let g=h===`rtl`,_=n===`left`?g?`right: ${p}`:`left: ${f}`:g?`left: ${f}`:`right: ${p}`,v=r===`bottom`?`bottom: ${m}`:`top: ${d}`;s.current.dataset.motionPopId=o;let y=document.createElement(`style`);l&&(y.nonce=l);let b=i??document.head;return b.appendChild(y),y.sheet&&y.sheet.insertRule(`
3
3
  [data-motion-pop-id="${o}"] {
4
4
  position: absolute !important;
5
5
  width: ${e}px !important;
@@ -7,7 +7,7 @@ import{a as e}from"./rolldown-runtime-B0Z9INg1.js";import{a as t,i as n}from"./v
7
7
  ${_}px !important;
8
8
  ${v}px !important;
9
9
  }
10
- `),()=>{s.current?.removeAttribute(`data-motion-pop-id`),b.contains(y)&&b.removeChild(y)}},[t]),(0,x.jsx)(S,{isPresent:t,childRef:s,sizeRef:c,pop:a,children:a===!1?e:_.cloneElement(e,{ref:d})})}var w=({children:e,initial:t,isPresent:n,onExitComplete:r,custom:a,presenceAffectsLayout:o,mode:s,anchorX:c,anchorY:u,root:f})=>{let p=d(T),m=(0,_.useId)(),h=(0,_.useRef)(n),g=(0,_.useRef)(r);l(()=>{h.current=n,g.current=r});let v=!0,y=(0,_.useMemo)(()=>(v=!1,{id:m,initial:t,isPresent:n,custom:a,onExitComplete:e=>{p.set(e,!0);for(let e of p.values())if(!e)return;r&&r()},register:e=>(p.set(e,!1),()=>{p.delete(e),!h.current&&!p.size&&g.current?.()})}),[n,p,r]);return o&&v&&(y={...y}),(0,_.useMemo)(()=>{p.forEach((e,t)=>p.set(t,!1))},[n]),_.useEffect(()=>{!n&&!p.size&&r&&r()},[n]),e=(0,x.jsx)(C,{pop:s===`popLayout`,isPresent:n,anchorX:c,anchorY:u,root:f,children:e}),(0,x.jsx)(i.Provider,{value:y,children:e})};function T(){return new Map}var E=e=>e.key||``;function D(e){let t=[];return _.Children.forEach(e,e=>{(0,_.isValidElement)(e)&&t.push(e)}),t}var O=({children:e,custom:t,initial:n=!0,onExitComplete:r,presenceAffectsLayout:i=!0,mode:o=`sync`,propagate:s=!1,anchorX:u=`left`,anchorY:f=`top`,root:p})=>{let[m,h]=c(s),g=(0,_.useMemo)(()=>D(e),[e]),v=s&&!m?[]:g.map(E),y=(0,_.useRef)(!0),b=(0,_.useRef)(g),S=d(()=>new Map),C=(0,_.useRef)(new Set),[T,O]=(0,_.useState)(g),[k,A]=(0,_.useState)(g);l(()=>{s&&!m&&!k.length&&h?.()},[m,s,k.length,h]),l(()=>{y.current=!1,b.current=g;for(let e=0;e<k.length;e++){let t=E(k[e]);v.includes(t)?(S.delete(t),C.current.delete(t)):S.get(t)!==!0&&S.set(t,!1)}},[k,v.length,v.join(`-`)]);let j=[];if(g!==T){let e=[...g];for(let t=0;t<k.length;t++){let n=k[t],r=E(n);v.includes(r)||(e.splice(t,0,n),j.push(n))}return o===`wait`&&j.length&&(e=j),A(D(e)),O(g),null}let{forceRender:M}=(0,_.useContext)(a);return(0,x.jsx)(x.Fragment,{children:k.map(e=>{let a=E(e),c=s&&!m?!1:g===k||v.includes(a);return(0,x.jsx)(w,{isPresent:c,initial:!y.current||n?void 0:!1,custom:t,presenceAffectsLayout:i,mode:o,root:p,onExitComplete:c?void 0:()=>{if(C.current.has(a))return;if(S.has(a))C.current.add(a),S.set(a,!0);else return;let e=!0;S.forEach(t=>{t||(e=!1)}),e&&(M?.(),A(b.current),s&&h?.(),r&&r())},anchorX:u,anchorY:f,children:e},a)})})},k=(0,_.lazy)(()=>n(()=>import(`./Chat-Lgj1d-8d.js`).then(e=>({default:e.Chat})),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]))),A=56,j=24;function M(){let[e,t]=(0,_.useState)(!1),[n,r]=(0,_.useState)(!1),[i,a]=(0,_.useState)(!1),[o,c]=h(`ApplicationChatOpen`,!1),[l,u]=m(p.ApplicationChatPosition,{x:-40,y:-40}),[d,v]=m(p.ApplicationChatWidth,600),y=(0,_.useRef)(null);(0,_.useEffect)(()=>{let e=()=>{let e=window.innerWidth<768;t(e),!e&&d>window.innerWidth&&v(window.innerWidth)};return e(),window.addEventListener(`resize`,e),()=>window.removeEventListener(`resize`,e)},[d,v]);let b=(0,_.useCallback)(e=>{e.preventDefault(),a(!0)},[]);(0,_.useEffect)(()=>{if(!i)return;let e=e=>{let t=window.innerWidth-e.clientX,n=Math.min(Math.max(t,300),window.innerWidth);v(n)},t=()=>{a(!1)};return window.addEventListener(`mousemove`,e),window.addEventListener(`mouseup`,t),()=>{window.removeEventListener(`mousemove`,e),window.removeEventListener(`mouseup`,t)}},[i,v]);let S=(0,_.useCallback)(()=>{n||c(e=>!e)},[n]),C=(0,_.useCallback)(()=>{c(!1)},[]);return(0,_.useEffect)(()=>{if(o){let e=e=>{e.key===`Escape`&&C()};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)}},[o,C]),(0,x.jsxs)(`div`,{className:`fixed inset-0 pointer-events-none z-50`,ref:y,children:[(0,x.jsx)(O,{children:o&&(0,x.jsxs)(f.div,{initial:e?{opacity:0,y:`100%`}:{opacity:0,x:`100%`},animate:e?{opacity:1,y:0}:{opacity:1,x:0},exit:e?{opacity:0,y:`100%`}:{opacity:0,x:`100%`},transition:{type:`spring`,damping:25,stiffness:200},style:e?{}:{top:0,bottom:0,right:0,width:d,maxWidth:`100vw`},className:`
10
+ `),()=>{s.current?.removeAttribute(`data-motion-pop-id`),b.contains(y)&&b.removeChild(y)}},[t]),(0,x.jsx)(S,{isPresent:t,childRef:s,sizeRef:c,pop:a,children:a===!1?e:_.cloneElement(e,{ref:d})})}var w=({children:e,initial:t,isPresent:n,onExitComplete:r,custom:a,presenceAffectsLayout:o,mode:s,anchorX:c,anchorY:u,root:f})=>{let p=d(T),m=(0,_.useId)(),h=(0,_.useRef)(n),g=(0,_.useRef)(r);l(()=>{h.current=n,g.current=r});let v=!0,y=(0,_.useMemo)(()=>(v=!1,{id:m,initial:t,isPresent:n,custom:a,onExitComplete:e=>{p.set(e,!0);for(let e of p.values())if(!e)return;r&&r()},register:e=>(p.set(e,!1),()=>{p.delete(e),!h.current&&!p.size&&g.current?.()})}),[n,p,r]);return o&&v&&(y={...y}),(0,_.useMemo)(()=>{p.forEach((e,t)=>p.set(t,!1))},[n]),_.useEffect(()=>{!n&&!p.size&&r&&r()},[n]),e=(0,x.jsx)(C,{pop:s===`popLayout`,isPresent:n,anchorX:c,anchorY:u,root:f,children:e}),(0,x.jsx)(i.Provider,{value:y,children:e})};function T(){return new Map}var E=e=>e.key||``;function D(e){let t=[];return _.Children.forEach(e,e=>{(0,_.isValidElement)(e)&&t.push(e)}),t}var O=({children:e,custom:t,initial:n=!0,onExitComplete:r,presenceAffectsLayout:i=!0,mode:o=`sync`,propagate:s=!1,anchorX:u=`left`,anchorY:f=`top`,root:p})=>{let[m,h]=c(s),g=(0,_.useMemo)(()=>D(e),[e]),v=s&&!m?[]:g.map(E),y=(0,_.useRef)(!0),b=(0,_.useRef)(g),S=d(()=>new Map),C=(0,_.useRef)(new Set),[T,O]=(0,_.useState)(g),[k,A]=(0,_.useState)(g);l(()=>{s&&!m&&!k.length&&h?.()},[m,s,k.length,h]),l(()=>{y.current=!1,b.current=g;for(let e=0;e<k.length;e++){let t=E(k[e]);v.includes(t)?(S.delete(t),C.current.delete(t)):S.get(t)!==!0&&S.set(t,!1)}},[k,v.length,v.join(`-`)]);let j=[];if(g!==T){let e=[...g];for(let t=0;t<k.length;t++){let n=k[t],r=E(n);v.includes(r)||(e.splice(t,0,n),j.push(n))}return o===`wait`&&j.length&&(e=j),A(D(e)),O(g),null}let{forceRender:M}=(0,_.useContext)(a);return(0,x.jsx)(x.Fragment,{children:k.map(e=>{let a=E(e),c=s&&!m?!1:g===k||v.includes(a);return(0,x.jsx)(w,{isPresent:c,initial:!y.current||n?void 0:!1,custom:t,presenceAffectsLayout:i,mode:o,root:p,onExitComplete:c?void 0:()=>{if(C.current.has(a))return;if(S.has(a))C.current.add(a),S.set(a,!0);else return;let e=!0;S.forEach(t=>{t||(e=!1)}),e&&(M?.(),A(b.current),s&&h?.(),r&&r())},anchorX:u,anchorY:f,children:e},a)})})},k=(0,_.lazy)(()=>n(()=>import(`./Chat-BNHY84-Z.js`).then(e=>({default:e.Chat})),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]))),A=56,j=24;function M(){let[e,t]=(0,_.useState)(!1),[n,r]=(0,_.useState)(!1),[i,a]=(0,_.useState)(!1),[o,c]=h(`ApplicationChatOpen`,!1),[l,u]=m(p.ApplicationChatPosition,{x:-40,y:-40}),[d,v]=m(p.ApplicationChatWidth,600),y=(0,_.useRef)(null);(0,_.useEffect)(()=>{let e=()=>{let e=window.innerWidth<768;t(e),!e&&d>window.innerWidth&&v(window.innerWidth)};return e(),window.addEventListener(`resize`,e),()=>window.removeEventListener(`resize`,e)},[d,v]);let b=(0,_.useCallback)(e=>{e.preventDefault(),a(!0)},[]);(0,_.useEffect)(()=>{if(!i)return;let e=e=>{let t=window.innerWidth-e.clientX,n=Math.min(Math.max(t,300),window.innerWidth);v(n)},t=()=>{a(!1)};return window.addEventListener(`mousemove`,e),window.addEventListener(`mouseup`,t),()=>{window.removeEventListener(`mousemove`,e),window.removeEventListener(`mouseup`,t)}},[i,v]);let S=(0,_.useCallback)(()=>{n||c(e=>!e)},[n]),C=(0,_.useCallback)(()=>{c(!1)},[]);return(0,_.useEffect)(()=>{if(o){let e=e=>{e.key===`Escape`&&C()};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)}},[o,C]),(0,x.jsxs)(`div`,{className:`fixed inset-0 pointer-events-none z-50`,ref:y,children:[(0,x.jsx)(O,{children:o&&(0,x.jsxs)(f.div,{initial:e?{opacity:0,y:`100%`}:{opacity:0,x:`100%`},animate:e?{opacity:1,y:0}:{opacity:1,x:0},exit:e?{opacity:0,y:`100%`}:{opacity:0,x:`100%`},transition:{type:`spring`,damping:25,stiffness:200},style:e?{}:{top:0,bottom:0,right:0,width:d,maxWidth:`100vw`},className:`
11
11
  pointer-events-auto
12
12
  fixed bg-background shadow-2xl border-l border-border overflow-visible
13
13
  ${e?`inset-0 w-full h-full rounded-none`:`h-full`}
@@ -1 +1 @@
1
- import{a as e}from"./rolldown-runtime-B0Z9INg1.js";import{i as t,t as n}from"./button-DfBmT4rc.js";import{I as r}from"./vendor-tanstack-FsM5XZNE.js";import{a as i}from"./vendor-datadog-XDrpA25D.js";import{r as a}from"./vendor-react-BhazFIp8.js";import{a as o,i as s,n as c,r as l,t as u}from"./card-ByrPS_wa.js";import{Kt as d,ir as f,rn as p,sr as m}from"./index-CqbCnqsT.js";async function h(){let{data:e}=await t.post(`/Admin/ApiToken`,{});return e}function g(){return r({mutationFn:h,gcTime:0})}var _=e(i(),1),v=a();function y(){let{mutate:e,isPending:t,reset:r}=g(),[i,a]=(0,_.useState)(null),h=d();return(0,v.jsxs)(`div`,{className:`max-w-2xl`,children:[(0,v.jsx)(`h1`,{className:`text-2xl font-light`,children:`API Token`}),(0,v.jsxs)(`p`,{className:`mt-2 text-sm text-muted-foreground`,children:[`Generate a short-lived token for programmatic API access. It authenticates as you, with your permissions. Send it as a bearer token:`,` `,(0,v.jsx)(`code`,{className:`rounded bg-muted px-1 py-0.5 text-xs`,children:`Authorization: Bearer <token>`})]}),(0,v.jsxs)(n,{className:`mt-4`,variant:`submit`,onClick:()=>{e(void 0,{onSuccess:e=>{a(e),r()}})},disabled:t,children:[(0,v.jsx)(f,{}),t?`Generating…`:`Generate token`]}),i&&(0,v.jsxs)(u,{className:`mt-6`,children:[(0,v.jsxs)(s,{children:[(0,v.jsx)(o,{children:`Your API token`}),(0,v.jsxs)(l,{children:[`Copy it now — it won't be shown again. Expires `,new Date(i.expiresAt).toLocaleString(),`.`]})]}),(0,v.jsxs)(c,{className:`flex items-center gap-2`,children:[(0,v.jsx)(p,{readOnly:!0,value:i.operationToken,className:`font-mono text-xs`,onClick:()=>h(i.operationToken)}),(0,v.jsx)(n,{type:`button`,size:`icon`,variant:`ghost`,className:`shrink-0`,"aria-label":`Copy token`,onClick:()=>h(i.operationToken),children:(0,v.jsx)(m,{})})]})]})]})}export{y as ApiTokenIndex};
1
+ import{a as e}from"./rolldown-runtime-B0Z9INg1.js";import{i as t,t as n}from"./button-DfBmT4rc.js";import{I as r}from"./vendor-tanstack-FsM5XZNE.js";import{a as i}from"./vendor-datadog-XDrpA25D.js";import{r as a}from"./vendor-react-BhazFIp8.js";import{a as o,i as s,n as c,r as l,t as u}from"./card-ByrPS_wa.js";import{Kt as d,ir as f,rn as p,sr as m}from"./index-BQB9R8Ug.js";async function h(){let{data:e}=await t.post(`/Admin/ApiToken`,{});return e}function g(){return r({mutationFn:h,gcTime:0})}var _=e(i(),1),v=a();function y(){let{mutate:e,isPending:t,reset:r}=g(),[i,a]=(0,_.useState)(null),h=d();return(0,v.jsxs)(`div`,{className:`max-w-2xl`,children:[(0,v.jsx)(`h1`,{className:`text-2xl font-light`,children:`API Token`}),(0,v.jsxs)(`p`,{className:`mt-2 text-sm text-muted-foreground`,children:[`Generate a short-lived token for programmatic API access. It authenticates as you, with your permissions. Send it as a bearer token:`,` `,(0,v.jsx)(`code`,{className:`rounded bg-muted px-1 py-0.5 text-xs`,children:`Authorization: Bearer <token>`})]}),(0,v.jsxs)(n,{className:`mt-4`,variant:`submit`,onClick:()=>{e(void 0,{onSuccess:e=>{a(e),r()}})},disabled:t,children:[(0,v.jsx)(f,{}),t?`Generating…`:`Generate token`]}),i&&(0,v.jsxs)(u,{className:`mt-6`,children:[(0,v.jsxs)(s,{children:[(0,v.jsx)(o,{children:`Your API token`}),(0,v.jsxs)(l,{children:[`Copy it now — it won't be shown again. Expires `,new Date(i.expiresAt).toLocaleString(),`.`]})]}),(0,v.jsxs)(c,{className:`flex items-center gap-2`,children:[(0,v.jsx)(p,{readOnly:!0,value:i.operationToken,className:`font-mono text-xs`,onClick:()=>h(i.operationToken)}),(0,v.jsx)(n,{type:`button`,size:`icon`,variant:`ghost`,className:`shrink-0`,"aria-label":`Copy token`,onClick:()=>h(i.operationToken),children:(0,v.jsx)(m,{})})]})]})]})}export{y as ApiTokenIndex};