@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.
- package/bin/restart.ts +48 -23
- package/bin/restartExitWatchdog.ts +99 -0
- package/bin/run.ts +16 -10
- package/dist/bin/restart.js +39 -21
- package/dist/bin/restart.js.map +1 -1
- package/dist/bin/restartExitWatchdog.d.ts +5 -0
- package/dist/bin/restartExitWatchdog.js +100 -0
- package/dist/bin/restartExitWatchdog.js.map +1 -0
- package/dist/bin/run.d.ts +2 -0
- package/dist/bin/run.js +17 -10
- package/dist/bin/run.js.map +1 -1
- package/dist/resources/DatabaseTransaction.d.ts +18 -1
- package/dist/resources/DatabaseTransaction.js +63 -1
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/LMDBTransaction.d.ts +2 -0
- package/dist/resources/LMDBTransaction.js +7 -1
- package/dist/resources/LMDBTransaction.js.map +1 -1
- package/dist/resources/Resource.js +5 -4
- package/dist/resources/Resource.js.map +1 -1
- package/dist/resources/ResourceInterface.d.ts +5 -0
- package/dist/resources/ResourceInterface.js.map +1 -1
- package/dist/resources/Table.js +53 -9
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/transaction.js +1 -1
- package/dist/resources/transaction.js.map +1 -1
- package/dist/server/threads/manageThreads.d.ts +1 -0
- package/dist/server/threads/manageThreads.js +20 -3
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/utility/processManagement/processManagement.js +21 -3
- package/dist/utility/processManagement/processManagement.js.map +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/resources/DESIGN.md +19 -19
- package/resources/DatabaseTransaction.ts +63 -2
- package/resources/LMDBTransaction.ts +7 -1
- package/resources/Resource.ts +6 -5
- package/resources/ResourceInterface.ts +5 -0
- package/resources/Table.ts +57 -8
- package/resources/transaction.ts +2 -2
- package/server/DESIGN.md +6 -0
- package/server/threads/manageThreads.js +17 -3
- package/studio/web/assets/{Chat-Lgj1d-8d.js → Chat-BNHY84-Z.js} +1 -1
- package/studio/web/assets/{FloatingChat-jLWvR4kI.js → FloatingChat-BbztUci0.js} +3 -3
- package/studio/web/assets/{apiToken-DYI4DqWa.js → apiToken-D0x_S8Wq.js} +1 -1
- package/studio/web/assets/{applications-DCmc9-lk.js → applications-BU83fSEG.js} +1 -1
- package/studio/web/assets/{index-CqbCnqsT.js → index-BQB9R8Ug.js} +4 -4
- package/studio/web/assets/{index.lazy-BNqr3j0f.js → index.lazy-CtErm5q7.js} +3 -3
- package/studio/web/assets/{notifications-Bb2cj14_.js → notifications-B8rDagJM.js} +1 -1
- package/studio/web/assets/{notifications-DVlKonbI.js → notifications-CPwYKDDH.js} +1 -1
- package/studio/web/assets/{profile-BSQWfYfq.js → profile-D0hB1xdm.js} +1 -1
- package/studio/web/assets/{regions-Dk3g8bBF.js → regions-y_jxsBpN.js} +1 -1
- package/studio/web/assets/{setComponentFile-DoITgNLb.js → setComponentFile-DSHbURTI.js} +1 -1
- package/studio/web/assets/{setup-CiEALLa7.js → setup-J5SrM1Kp.js} +1 -1
- package/studio/web/assets/{status-CK9tD-Nd.js → status-IoJkDzlx.js} +1 -1
- package/studio/web/assets/{swagger-ui-react-CxjCDFB-.js → swagger-ui-react-BlgSS25O.js} +1 -1
- package/studio/web/assets/{useEntityRestURL-Cy-0i1UZ.js → useEntityRestURL-qfahJnvr.js} +1 -1
- package/studio/web/index.html +1 -1
- 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
|
-
|
|
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;
|
package/resources/Resource.ts
CHANGED
|
@@ -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
|
|
773
|
-
//
|
|
774
|
-
//
|
|
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
|
|
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
|
package/resources/Table.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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 (!
|
|
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
|
-
(
|
|
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
|
-
|
|
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
|
-
|
|
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;
|
package/resources/transaction.ts
CHANGED
|
@@ -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
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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};
|