@lunora/do 1.0.0-alpha.35 → 1.0.0-alpha.36
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/dist/index.d.mts +27 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.mjs +3 -3
- package/dist/packem_shared/{ADMIN_FUNCTIONS-CqVmUVNs.mjs → ADMIN_FUNCTIONS-DVk02KpP.mjs} +4 -0
- package/dist/packem_shared/{ROOT_DO_SIZE_WARN_BYTES-QSOI2hpe.mjs → ROOT_DO_SIZE_WARN_BYTES-CBlw_ir3.mjs} +207 -8
- package/dist/packem_shared/{serveRelationFanout-Yiyx2OQB.mjs → serveRelationFanout-FdrPflv1.mjs} +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -2757,6 +2757,7 @@ declare const FLAGS_FUNCTION_PREFIX = "__lunora_flags__:";
|
|
|
2757
2757
|
*/
|
|
2758
2758
|
declare const ADMIN_FUNCTIONS: {
|
|
2759
2759
|
readonly applyCdc: "__lunora_admin__:applyCdc";
|
|
2760
|
+
readonly assignIssue: "__lunora_admin__:assignIssue";
|
|
2760
2761
|
readonly cdcSync: "__lunora_admin__:cdcSync";
|
|
2761
2762
|
readonly clearCapturedMail: "__lunora_admin__:clearCapturedMail";
|
|
2762
2763
|
readonly clearQueueMessages: "__lunora_admin__:clearQueueMessages";
|
|
@@ -2786,6 +2787,7 @@ declare const ADMIN_FUNCTIONS: {
|
|
|
2786
2787
|
readonly getSettings: "__lunora_admin__:getSettings";
|
|
2787
2788
|
readonly getTraces: "__lunora_admin__:getTraces";
|
|
2788
2789
|
readonly getWorkflowInstanceStatus: "__lunora_admin__:getWorkflowInstanceStatus";
|
|
2790
|
+
readonly ignoreIssue: "__lunora_admin__:ignoreIssue";
|
|
2789
2791
|
readonly importShard: "__lunora_admin__:importShard";
|
|
2790
2792
|
readonly listFlags: "__lunora_admin__:listFlags";
|
|
2791
2793
|
readonly listQueues: "__lunora_admin__:listQueues";
|
|
@@ -2802,12 +2804,14 @@ declare const ADMIN_FUNCTIONS: {
|
|
|
2802
2804
|
readonly recordMail: "__lunora_admin__:recordMail";
|
|
2803
2805
|
readonly recordQueueMessage: "__lunora_admin__:recordQueueMessage";
|
|
2804
2806
|
readonly replayQueueMessage: "__lunora_admin__:replayQueueMessage";
|
|
2807
|
+
readonly resolveIssue: "__lunora_admin__:resolveIssue";
|
|
2805
2808
|
readonly rlsPolicies: "__lunora_admin__:rlsPolicies";
|
|
2806
2809
|
readonly runAs: "__lunora_admin__:runAs";
|
|
2807
2810
|
readonly runMigration: "__lunora_admin__:runMigration";
|
|
2808
2811
|
readonly runSql: "__lunora_admin__:runSql";
|
|
2809
2812
|
readonly sendQueueMessage: "__lunora_admin__:sendQueueMessage";
|
|
2810
2813
|
readonly sendTestMail: "__lunora_admin__:sendTestMail";
|
|
2814
|
+
readonly setIssueSeverity: "__lunora_admin__:setIssueSeverity";
|
|
2811
2815
|
readonly storageOrphans: "__lunora_admin__:storageOrphans";
|
|
2812
2816
|
readonly storageReferences: "__lunora_admin__:storageReferences";
|
|
2813
2817
|
readonly storageRules: "__lunora_admin__:storageRules";
|
|
@@ -5921,6 +5925,29 @@ declare abstract class ShardDO {
|
|
|
5921
5925
|
* mirroring `handlePitrAdminOp`.
|
|
5922
5926
|
*/
|
|
5923
5927
|
private handleExtraAdminOp;
|
|
5928
|
+
/**
|
|
5929
|
+
* Serve the four Issue-triage admin writes — `resolveIssue` / `ignoreIssue`
|
|
5930
|
+
* (a status change), `assignIssue` (set/clear an owner), `setIssueSeverity`
|
|
5931
|
+
* (tag/clear severity). Each upserts one row in the reserved
|
|
5932
|
+
* `__lunora_issue_state__` side table keyed by the Issue's fingerprint
|
|
5933
|
+
* `hash`, then re-derives at read time in {@link readErrorIssues}. Returns
|
|
5934
|
+
* `undefined` for any path it doesn't own so `handleExtraAdminOp` falls
|
|
5935
|
+
* through. Admin-gated by `handleAdminRpc`'s caller (the `LUNORA_ADMIN_TOKEN`
|
|
5936
|
+
* bearer); a bad/missing `hash` (or a bad status/severity value) is a 400.
|
|
5937
|
+
*
|
|
5938
|
+
* The write lands through raw SQL the change-tracker can't observe, so it
|
|
5939
|
+
* marks {@link ISSUE_STATE_TABLE} changed and flushes — the live Issues
|
|
5940
|
+
* subscription is an admin-wildcard memo that re-runs whenever a flush finds
|
|
5941
|
+
* a changed table, so the triage shows up without an unrelated write.
|
|
5942
|
+
*/
|
|
5943
|
+
private handleIssueTriageOp;
|
|
5944
|
+
/**
|
|
5945
|
+
* Map an Issue-triage admin path to the `IssueStatePatch` it applies, or
|
|
5946
|
+
* `undefined` when the path isn't a triage write. `assignIssue`/
|
|
5947
|
+
* `setIssueSeverity` accept an explicit `null` to CLEAR the field (unassign /
|
|
5948
|
+
* untag); a missing or malformed value is a 400 rather than a silent no-op.
|
|
5949
|
+
*/
|
|
5950
|
+
private parseIssueTriagePatch;
|
|
5924
5951
|
/**
|
|
5925
5952
|
* Record one app-level auth attempt for the auth-failure SLO (PLAN3 §2.3).
|
|
5926
5953
|
* The worker calls this fire-and-forget (via `waitUntil`) after a top-level
|
package/dist/index.d.ts
CHANGED
|
@@ -2757,6 +2757,7 @@ declare const FLAGS_FUNCTION_PREFIX = "__lunora_flags__:";
|
|
|
2757
2757
|
*/
|
|
2758
2758
|
declare const ADMIN_FUNCTIONS: {
|
|
2759
2759
|
readonly applyCdc: "__lunora_admin__:applyCdc";
|
|
2760
|
+
readonly assignIssue: "__lunora_admin__:assignIssue";
|
|
2760
2761
|
readonly cdcSync: "__lunora_admin__:cdcSync";
|
|
2761
2762
|
readonly clearCapturedMail: "__lunora_admin__:clearCapturedMail";
|
|
2762
2763
|
readonly clearQueueMessages: "__lunora_admin__:clearQueueMessages";
|
|
@@ -2786,6 +2787,7 @@ declare const ADMIN_FUNCTIONS: {
|
|
|
2786
2787
|
readonly getSettings: "__lunora_admin__:getSettings";
|
|
2787
2788
|
readonly getTraces: "__lunora_admin__:getTraces";
|
|
2788
2789
|
readonly getWorkflowInstanceStatus: "__lunora_admin__:getWorkflowInstanceStatus";
|
|
2790
|
+
readonly ignoreIssue: "__lunora_admin__:ignoreIssue";
|
|
2789
2791
|
readonly importShard: "__lunora_admin__:importShard";
|
|
2790
2792
|
readonly listFlags: "__lunora_admin__:listFlags";
|
|
2791
2793
|
readonly listQueues: "__lunora_admin__:listQueues";
|
|
@@ -2802,12 +2804,14 @@ declare const ADMIN_FUNCTIONS: {
|
|
|
2802
2804
|
readonly recordMail: "__lunora_admin__:recordMail";
|
|
2803
2805
|
readonly recordQueueMessage: "__lunora_admin__:recordQueueMessage";
|
|
2804
2806
|
readonly replayQueueMessage: "__lunora_admin__:replayQueueMessage";
|
|
2807
|
+
readonly resolveIssue: "__lunora_admin__:resolveIssue";
|
|
2805
2808
|
readonly rlsPolicies: "__lunora_admin__:rlsPolicies";
|
|
2806
2809
|
readonly runAs: "__lunora_admin__:runAs";
|
|
2807
2810
|
readonly runMigration: "__lunora_admin__:runMigration";
|
|
2808
2811
|
readonly runSql: "__lunora_admin__:runSql";
|
|
2809
2812
|
readonly sendQueueMessage: "__lunora_admin__:sendQueueMessage";
|
|
2810
2813
|
readonly sendTestMail: "__lunora_admin__:sendTestMail";
|
|
2814
|
+
readonly setIssueSeverity: "__lunora_admin__:setIssueSeverity";
|
|
2811
2815
|
readonly storageOrphans: "__lunora_admin__:storageOrphans";
|
|
2812
2816
|
readonly storageReferences: "__lunora_admin__:storageReferences";
|
|
2813
2817
|
readonly storageRules: "__lunora_admin__:storageRules";
|
|
@@ -5921,6 +5925,29 @@ declare abstract class ShardDO {
|
|
|
5921
5925
|
* mirroring `handlePitrAdminOp`.
|
|
5922
5926
|
*/
|
|
5923
5927
|
private handleExtraAdminOp;
|
|
5928
|
+
/**
|
|
5929
|
+
* Serve the four Issue-triage admin writes — `resolveIssue` / `ignoreIssue`
|
|
5930
|
+
* (a status change), `assignIssue` (set/clear an owner), `setIssueSeverity`
|
|
5931
|
+
* (tag/clear severity). Each upserts one row in the reserved
|
|
5932
|
+
* `__lunora_issue_state__` side table keyed by the Issue's fingerprint
|
|
5933
|
+
* `hash`, then re-derives at read time in {@link readErrorIssues}. Returns
|
|
5934
|
+
* `undefined` for any path it doesn't own so `handleExtraAdminOp` falls
|
|
5935
|
+
* through. Admin-gated by `handleAdminRpc`'s caller (the `LUNORA_ADMIN_TOKEN`
|
|
5936
|
+
* bearer); a bad/missing `hash` (or a bad status/severity value) is a 400.
|
|
5937
|
+
*
|
|
5938
|
+
* The write lands through raw SQL the change-tracker can't observe, so it
|
|
5939
|
+
* marks {@link ISSUE_STATE_TABLE} changed and flushes — the live Issues
|
|
5940
|
+
* subscription is an admin-wildcard memo that re-runs whenever a flush finds
|
|
5941
|
+
* a changed table, so the triage shows up without an unrelated write.
|
|
5942
|
+
*/
|
|
5943
|
+
private handleIssueTriageOp;
|
|
5944
|
+
/**
|
|
5945
|
+
* Map an Issue-triage admin path to the `IssueStatePatch` it applies, or
|
|
5946
|
+
* `undefined` when the path isn't a triage write. `assignIssue`/
|
|
5947
|
+
* `setIssueSeverity` accept an explicit `null` to CLEAR the field (unassign /
|
|
5948
|
+
* untag); a missing or malformed value is a 400 rather than a silent no-op.
|
|
5949
|
+
*/
|
|
5950
|
+
private parseIssueTriagePatch;
|
|
5924
5951
|
/**
|
|
5925
5952
|
* Record one app-level auth attempt for the auth-failure SLO (PLAN3 §2.3).
|
|
5926
5953
|
* The worker calls this fire-and-forget (via `waitUntil`) after a top-level
|
package/dist/index.mjs
CHANGED
|
@@ -12,7 +12,7 @@ export { diffExternalSource } from './packem_shared/diffExternalSource-CovHfdyo.
|
|
|
12
12
|
export { materializeExternalRows, materializeExternalRowsIncremental, readExternalSourceBaseline, runExternalSourceTick } from './packem_shared/materializeExternalRows-DlQWMlw_.mjs';
|
|
13
13
|
export { isSoftDeleted, isSourceDue, liftSourceId, pullExternalSourceIncrementalTick, pullExternalSourceTick } from './packem_shared/isSoftDeleted-YLKR6JYw.mjs';
|
|
14
14
|
export { FUNCTION_METRICS_BUCKETS_TABLE, FUNCTION_METRICS_BUCKET_MS, FUNCTION_METRICS_BUCKET_RETENTION, FUNCTION_METRICS_INDEX_TABLE, FUNCTION_METRICS_TABLE, ensureFunctionMetricsTables, readFunctionMetricBuckets, readFunctionMetricIndexHits, readFunctionMetrics, readFunctionMetricsTotals, recordFunctionMetric } from './packem_shared/FUNCTION_METRICS_BUCKETS_TABLE-UDNVD7FS.mjs';
|
|
15
|
-
export { ADMIN_FUNCTIONS, ADMIN_FUNCTION_PREFIX, FLAGS_FUNCTION_PREFIX, RELATION_FUNCTION_PREFIX, facetColumn, listTables, readTablePage, selectMatchingIds } from './packem_shared/ADMIN_FUNCTIONS-
|
|
15
|
+
export { ADMIN_FUNCTIONS, ADMIN_FUNCTION_PREFIX, FLAGS_FUNCTION_PREFIX, RELATION_FUNCTION_PREFIX, facetColumn, listTables, readTablePage, selectMatchingIds } from './packem_shared/ADMIN_FUNCTIONS-DVk02KpP.mjs';
|
|
16
16
|
export { LogBuffer } from './packem_shared/LogBuffer-B_Ezju_N.mjs';
|
|
17
17
|
export { MAIL_RETENTION, MAIL_TABLE, clearCapturedMail, ensureMailTable, readCapturedMail, recordCapturedMail } from './packem_shared/MAIL_RETENTION-CPpgl-dX.mjs';
|
|
18
18
|
export { default as NotFoundError } from './packem_shared/NotFoundError-C70b9hLw.mjs';
|
|
@@ -20,14 +20,14 @@ export { armRestore, readBookmark } from './packem_shared/armRestore-4Px61hHS.mj
|
|
|
20
20
|
export { applySelect, buildSeekWhere, decodeCursor, encodeCursor, normalizeOrderKeys, softDeleteScope } from './packem_shared/applySelect-WQY8m62C.mjs';
|
|
21
21
|
export { RANK_TIEBREAK, encodePartitionKey, matchesRankStaticWhere, rankTableName, resolveRankPartition, sortColumnName } from './packem_shared/RANK_TIEBREAK-CXhdcA1o.mjs';
|
|
22
22
|
export { ReactiveCache, reactiveCacheKey } from './packem_shared/ReactiveCache-DnSvbjil.mjs';
|
|
23
|
-
export { serveRelationFanout } from './packem_shared/serveRelationFanout-
|
|
23
|
+
export { serveRelationFanout } from './packem_shared/serveRelationFanout-FdrPflv1.mjs';
|
|
24
24
|
export { DEFAULT_MAX_RELATION_KEYS, assertFlatPredicate, assertShapeShardable, containsRelationPredicate, isRelationPredicate, resolveRelationPredicates } from './packem_shared/DEFAULT_MAX_RELATION_KEYS-BEan1CRD.mjs';
|
|
25
25
|
export { applyOnDelete, fanOutScalarCounts, resolveWith, runRowValidators } from './packem_shared/applyOnDelete-BXSq3S70.mjs';
|
|
26
26
|
export { RLS_UNWRAP_SYMBOL, RlsRequiredError, guardWriter } from './packem_shared/RLS_UNWRAP_SYMBOL-DTvHvRzY.mjs';
|
|
27
27
|
export { buildFtsMatch, ftsTableName, scoreDocument, stringifySearchText, tokenizeSearch } from './packem_shared/buildFtsMatch-BLEMawrp.mjs';
|
|
28
28
|
export { M as MIN_ADMIN_TOKEN_LENGTH, a as MIN_AUTH_SECRET_LENGTH, b as buildSecurityAudit } from './packem_shared/security-audit-CucgBice.mjs';
|
|
29
29
|
export { SESSION_DO_TTL_DEFAULT, SessionDO } from './packem_shared/SESSION_DO_TTL_DEFAULT-BnSKgVO4.mjs';
|
|
30
|
-
export { ROOT_DO_SIZE_WARN_BYTES, ROOT_SHARD_NAME, ShardDO } from './packem_shared/ROOT_DO_SIZE_WARN_BYTES-
|
|
30
|
+
export { ROOT_DO_SIZE_WARN_BYTES, ROOT_SHARD_NAME, ShardDO } from './packem_shared/ROOT_DO_SIZE_WARN_BYTES-CBlw_ir3.mjs';
|
|
31
31
|
export { SHARD_REGISTRY_DO_NAME, ShardRegistryDO } from './packem_shared/SHARD_REGISTRY_DO_NAME-D99roc-r.mjs';
|
|
32
32
|
export { MAX_SQL_ROWS, assertReadonly, runReadonlySql } from './packem_shared/MAX_SQL_ROWS-iFAA8FbD.mjs';
|
|
33
33
|
export { createSystemReader } from './packem_shared/createSystemReader-D12eNH13.mjs';
|
|
@@ -7,6 +7,7 @@ const RELATION_FUNCTION_PREFIX = "__lunora_relation__:";
|
|
|
7
7
|
const FLAGS_FUNCTION_PREFIX = "__lunora_flags__:";
|
|
8
8
|
const ADMIN_FUNCTIONS = {
|
|
9
9
|
applyCdc: "__lunora_admin__:applyCdc",
|
|
10
|
+
assignIssue: "__lunora_admin__:assignIssue",
|
|
10
11
|
cdcSync: "__lunora_admin__:cdcSync",
|
|
11
12
|
clearCapturedMail: "__lunora_admin__:clearCapturedMail",
|
|
12
13
|
clearQueueMessages: "__lunora_admin__:clearQueueMessages",
|
|
@@ -37,6 +38,7 @@ const ADMIN_FUNCTIONS = {
|
|
|
37
38
|
getTraces: "__lunora_admin__:getTraces",
|
|
38
39
|
// eslint-disable-next-line no-secrets/no-secrets -- reserved admin RPC path constant, not a credential
|
|
39
40
|
getWorkflowInstanceStatus: "__lunora_admin__:getWorkflowInstanceStatus",
|
|
41
|
+
ignoreIssue: "__lunora_admin__:ignoreIssue",
|
|
40
42
|
importShard: "__lunora_admin__:importShard",
|
|
41
43
|
listFlags: "__lunora_admin__:listFlags",
|
|
42
44
|
listQueues: "__lunora_admin__:listQueues",
|
|
@@ -53,12 +55,14 @@ const ADMIN_FUNCTIONS = {
|
|
|
53
55
|
recordMail: "__lunora_admin__:recordMail",
|
|
54
56
|
recordQueueMessage: "__lunora_admin__:recordQueueMessage",
|
|
55
57
|
replayQueueMessage: "__lunora_admin__:replayQueueMessage",
|
|
58
|
+
resolveIssue: "__lunora_admin__:resolveIssue",
|
|
56
59
|
rlsPolicies: "__lunora_admin__:rlsPolicies",
|
|
57
60
|
runAs: "__lunora_admin__:runAs",
|
|
58
61
|
runMigration: "__lunora_admin__:runMigration",
|
|
59
62
|
runSql: "__lunora_admin__:runSql",
|
|
60
63
|
sendQueueMessage: "__lunora_admin__:sendQueueMessage",
|
|
61
64
|
sendTestMail: "__lunora_admin__:sendTestMail",
|
|
65
|
+
setIssueSeverity: "__lunora_admin__:setIssueSeverity",
|
|
62
66
|
storageOrphans: "__lunora_admin__:storageOrphans",
|
|
63
67
|
storageReferences: "__lunora_admin__:storageReferences",
|
|
64
68
|
storageRules: "__lunora_admin__:storageRules",
|
|
@@ -9,7 +9,7 @@ import { n as normalizeLogFields, r as resolveTraceAnchor, a as createTracer, c
|
|
|
9
9
|
import { DATA_MIGRATION_STATE_TABLE, readMigrationStatus } from './DATA_MIGRATION_STATE_TABLE-CYwBpyTr.mjs';
|
|
10
10
|
import { SCAN_DEP, createDependencyTracker, tableFromDepKey } from './SCAN_DEP-DLJF8dsj.mjs';
|
|
11
11
|
import { readFunctionMetricsTotals, readFunctionMetricIndexHits, recordFunctionMetric, mergeScanAttribution, readFunctionMetrics, readFunctionMetricBuckets } from './FUNCTION_METRICS_BUCKETS_TABLE-UDNVD7FS.mjs';
|
|
12
|
-
import { createFanoutCounters, ADMIN_FUNCTION_PREFIX, RELATION_FUNCTION_PREFIX, selectMatchingIds, ADMIN_FUNCTIONS, findStorageReferences, listTables, summarizeSubscriptions, summarizeFanoutTopics, readTablePage, facetColumn, FLAGS_FUNCTION_PREFIX, recordFanoutPass, MAX_PAGE_SIZE } from './ADMIN_FUNCTIONS-
|
|
12
|
+
import { createFanoutCounters, ADMIN_FUNCTION_PREFIX, RELATION_FUNCTION_PREFIX, selectMatchingIds, ADMIN_FUNCTIONS, findStorageReferences, listTables, summarizeSubscriptions, summarizeFanoutTopics, readTablePage, facetColumn, FLAGS_FUNCTION_PREFIX, recordFanoutPass, MAX_PAGE_SIZE } from './ADMIN_FUNCTIONS-DVk02KpP.mjs';
|
|
13
13
|
import { LogBuffer } from './LogBuffer-B_Ezju_N.mjs';
|
|
14
14
|
import { recordCapturedMail, clearCapturedMail, readCapturedMail, MAIL_TABLE } from './MAIL_RETENTION-CPpgl-dX.mjs';
|
|
15
15
|
import { stableStringify } from './stableStringify-mC40mZts.mjs';
|
|
@@ -93,12 +93,12 @@ const verifyWsAdminToken = async (secret, token, now = Date.now()) => {
|
|
|
93
93
|
|
|
94
94
|
const AUDIT_LOG_TABLE = "__lunora_audit__";
|
|
95
95
|
const AUDIT_LOG_RETENTION = 1e3;
|
|
96
|
-
const runSql$
|
|
96
|
+
const runSql$4 = (sql, query, ...params) => {
|
|
97
97
|
const runner = sql.exec;
|
|
98
98
|
return runner.call(sql, query, ...params);
|
|
99
99
|
};
|
|
100
100
|
const ensureAuditTable = (sql) => {
|
|
101
|
-
runSql$
|
|
101
|
+
runSql$4(
|
|
102
102
|
sql,
|
|
103
103
|
`CREATE TABLE IF NOT EXISTS "${AUDIT_LOG_TABLE}" (
|
|
104
104
|
seq INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -112,7 +112,7 @@ const ensureAuditTable = (sql) => {
|
|
|
112
112
|
};
|
|
113
113
|
const appendAuditEntry = (sql, entry) => {
|
|
114
114
|
ensureAuditTable(sql);
|
|
115
|
-
runSql$
|
|
115
|
+
runSql$4(
|
|
116
116
|
sql,
|
|
117
117
|
`INSERT INTO "${AUDIT_LOG_TABLE}" (ts, op, "table", id, detail) VALUES (?, ?, ?, ?, ?)`,
|
|
118
118
|
entry.ts,
|
|
@@ -124,13 +124,13 @@ const appendAuditEntry = (sql, entry) => {
|
|
|
124
124
|
// eslint-disable-next-line unicorn/no-null -- SQL NULL is the correct value for an op with no associated table/id/detail.
|
|
125
125
|
entry.detail === void 0 ? null : JSON.stringify(entry.detail)
|
|
126
126
|
);
|
|
127
|
-
runSql$
|
|
127
|
+
runSql$4(sql, `DELETE FROM "${AUDIT_LOG_TABLE}" WHERE seq <= (SELECT MAX(seq) - ? FROM "${AUDIT_LOG_TABLE}")`, AUDIT_LOG_RETENTION);
|
|
128
128
|
};
|
|
129
129
|
const readAuditLog = (sql, options = {}) => {
|
|
130
130
|
ensureAuditTable(sql);
|
|
131
131
|
const sinceSeq = options.sinceSeq ?? 0;
|
|
132
132
|
const limit = Math.max(1, Math.min(options.limit ?? AUDIT_LOG_RETENTION, 1e4));
|
|
133
|
-
const rows = runSql$
|
|
133
|
+
const rows = runSql$4(
|
|
134
134
|
sql,
|
|
135
135
|
`SELECT seq, ts, op, "table", id, detail FROM "${AUDIT_LOG_TABLE}" WHERE seq > ? ORDER BY seq DESC LIMIT ?`,
|
|
136
136
|
sinceSeq,
|
|
@@ -183,6 +183,99 @@ const buildBatchEntryRequest = (batchRequest, entry) => {
|
|
|
183
183
|
});
|
|
184
184
|
};
|
|
185
185
|
|
|
186
|
+
const ISSUE_STATE_TABLE = "__lunora_issue_state__";
|
|
187
|
+
const HASH_QUERY_BATCH = 100;
|
|
188
|
+
const ISSUE_STATUSES = ["ignored", "open", "resolved"];
|
|
189
|
+
const ISSUE_SEVERITIES = ["critical", "high", "low", "medium"];
|
|
190
|
+
const runSql$3 = (sql, query, ...parameters) => {
|
|
191
|
+
const runner = sql.exec;
|
|
192
|
+
return runner.call(sql, query, ...parameters);
|
|
193
|
+
};
|
|
194
|
+
const SQL_NULL = null;
|
|
195
|
+
const orNull$1 = (value) => value ?? SQL_NULL;
|
|
196
|
+
const ensureIssueStateTable = (sql) => {
|
|
197
|
+
runSql$3(
|
|
198
|
+
sql,
|
|
199
|
+
`CREATE TABLE IF NOT EXISTS "${ISSUE_STATE_TABLE}" (
|
|
200
|
+
hash TEXT PRIMARY KEY,
|
|
201
|
+
status TEXT NOT NULL DEFAULT 'open',
|
|
202
|
+
assignee TEXT,
|
|
203
|
+
severity TEXT,
|
|
204
|
+
updated_at REAL NOT NULL,
|
|
205
|
+
updated_by TEXT
|
|
206
|
+
)`
|
|
207
|
+
);
|
|
208
|
+
};
|
|
209
|
+
const hydrate = (row) => {
|
|
210
|
+
return {
|
|
211
|
+
...row.assignee === null ? {} : { assignee: row.assignee },
|
|
212
|
+
hash: row.hash,
|
|
213
|
+
...row.severity === null ? {} : { severity: row.severity },
|
|
214
|
+
status: row.status,
|
|
215
|
+
updatedAt: row.updated_at,
|
|
216
|
+
...row.updated_by === null ? {} : { updatedBy: row.updated_by }
|
|
217
|
+
};
|
|
218
|
+
};
|
|
219
|
+
const readIssueStates = (sql, hashes) => {
|
|
220
|
+
const states = /* @__PURE__ */ new Map();
|
|
221
|
+
if (hashes.length === 0) {
|
|
222
|
+
return states;
|
|
223
|
+
}
|
|
224
|
+
ensureIssueStateTable(sql);
|
|
225
|
+
for (let start = 0; start < hashes.length; start += HASH_QUERY_BATCH) {
|
|
226
|
+
const batch = hashes.slice(start, start + HASH_QUERY_BATCH);
|
|
227
|
+
const placeholders = batch.map(() => "?").join(", ");
|
|
228
|
+
const rows = runSql$3(
|
|
229
|
+
sql,
|
|
230
|
+
`SELECT hash, status, assignee, severity, updated_at, updated_by FROM "${ISSUE_STATE_TABLE}" WHERE hash IN (${placeholders})`,
|
|
231
|
+
...batch
|
|
232
|
+
).toArray();
|
|
233
|
+
for (const row of rows) {
|
|
234
|
+
states.set(row.hash, hydrate(row));
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return states;
|
|
238
|
+
};
|
|
239
|
+
const upsertIssueState = (sql, hash, patch, updatedAt, updatedBy) => {
|
|
240
|
+
ensureIssueStateTable(sql);
|
|
241
|
+
const status = orNull$1(patch.status);
|
|
242
|
+
const assignee = orNull$1(patch.assignee);
|
|
243
|
+
const clearAssignee = patch.assignee === null ? 1 : 0;
|
|
244
|
+
const severity = orNull$1(patch.severity);
|
|
245
|
+
const clearSeverity = patch.severity === null ? 1 : 0;
|
|
246
|
+
const actor = orNull$1(updatedBy);
|
|
247
|
+
runSql$3(
|
|
248
|
+
sql,
|
|
249
|
+
`INSERT INTO "${ISSUE_STATE_TABLE}" (hash, status, assignee, severity, updated_at, updated_by)
|
|
250
|
+
VALUES (?, COALESCE(?, 'open'), ?, ?, ?, ?)
|
|
251
|
+
ON CONFLICT(hash) DO UPDATE SET
|
|
252
|
+
status = COALESCE(?, status),
|
|
253
|
+
assignee = CASE WHEN ? = 1 THEN NULL ELSE COALESCE(?, assignee) END,
|
|
254
|
+
severity = CASE WHEN ? = 1 THEN NULL ELSE COALESCE(?, severity) END,
|
|
255
|
+
updated_at = ?,
|
|
256
|
+
updated_by = ?`,
|
|
257
|
+
hash,
|
|
258
|
+
status,
|
|
259
|
+
assignee,
|
|
260
|
+
severity,
|
|
261
|
+
updatedAt,
|
|
262
|
+
actor,
|
|
263
|
+
status,
|
|
264
|
+
clearAssignee,
|
|
265
|
+
assignee,
|
|
266
|
+
clearSeverity,
|
|
267
|
+
severity,
|
|
268
|
+
updatedAt,
|
|
269
|
+
actor
|
|
270
|
+
);
|
|
271
|
+
const [row] = runSql$3(
|
|
272
|
+
sql,
|
|
273
|
+
`SELECT hash, status, assignee, severity, updated_at, updated_by FROM "${ISSUE_STATE_TABLE}" WHERE hash = ?`,
|
|
274
|
+
hash
|
|
275
|
+
).toArray();
|
|
276
|
+
return row === void 0 ? { hash, status: status ?? "open", updatedAt, ...updatedBy === void 0 ? {} : { updatedBy } } : hydrate(row);
|
|
277
|
+
};
|
|
278
|
+
|
|
186
279
|
const DEFAULT_CAPACITY$1 = 256;
|
|
187
280
|
const seriesKey = (event) => `${event.kind}\0${event.name}\0${stableStringify(event.attributes ?? {})}`;
|
|
188
281
|
class MetricBuffer {
|
|
@@ -1452,6 +1545,23 @@ const readRequestLog = (sql, options = {}) => {
|
|
|
1452
1545
|
return base;
|
|
1453
1546
|
});
|
|
1454
1547
|
};
|
|
1548
|
+
const applyIssueStates = (sql, issues) => {
|
|
1549
|
+
const states = readIssueStates(sql, [...issues.keys()]);
|
|
1550
|
+
for (const issue of issues.values()) {
|
|
1551
|
+
const state = states.get(issue.hash);
|
|
1552
|
+
if (state === void 0) {
|
|
1553
|
+
continue;
|
|
1554
|
+
}
|
|
1555
|
+
issue.stateUpdatedAt = state.updatedAt;
|
|
1556
|
+
if (state.assignee !== void 0) {
|
|
1557
|
+
issue.assignee = state.assignee;
|
|
1558
|
+
}
|
|
1559
|
+
if (state.severity !== void 0) {
|
|
1560
|
+
issue.severity = state.severity;
|
|
1561
|
+
}
|
|
1562
|
+
issue.status = state.status === "resolved" && issue.lastSeen > state.updatedAt ? "open" : state.status;
|
|
1563
|
+
}
|
|
1564
|
+
};
|
|
1455
1565
|
const readErrorIssues = (sql, options = {}) => {
|
|
1456
1566
|
ensureRequestLogTable(sql);
|
|
1457
1567
|
const limit = Math.max(1, Math.min(options.limit ?? REQUEST_LOG_RETENTION, 1e4));
|
|
@@ -1483,7 +1593,7 @@ const readErrorIssues = (sql, options = {}) => {
|
|
|
1483
1593
|
const { culprit, hash, title } = fingerprintError({ functionPath: row.function_path, message });
|
|
1484
1594
|
const existing = issues.get(hash);
|
|
1485
1595
|
if (existing === void 0) {
|
|
1486
|
-
issues.set(hash, { count: 1, culprit, firstSeen: row.ts, hash, lastSeen: row.ts, sampleMessage: message, title });
|
|
1596
|
+
issues.set(hash, { count: 1, culprit, firstSeen: row.ts, hash, lastSeen: row.ts, sampleMessage: message, status: "open", title });
|
|
1487
1597
|
sampleTs.set(hash, row.ts);
|
|
1488
1598
|
continue;
|
|
1489
1599
|
}
|
|
@@ -1496,7 +1606,10 @@ const readErrorIssues = (sql, options = {}) => {
|
|
|
1496
1606
|
existing.title = title;
|
|
1497
1607
|
}
|
|
1498
1608
|
}
|
|
1499
|
-
|
|
1609
|
+
applyIssueStates(sql, issues);
|
|
1610
|
+
const folded = [...issues.values()];
|
|
1611
|
+
const filtered = options.status === void 0 ? folded : folded.filter((issue) => issue.status === options.status);
|
|
1612
|
+
return filtered.toSorted((a, b) => b.lastSeen - a.lastSeen);
|
|
1500
1613
|
};
|
|
1501
1614
|
|
|
1502
1615
|
const runSocketPool = async (items, processOne, concurrency = 8) => {
|
|
@@ -1761,6 +1874,36 @@ const parseWriteRowArgs = (args) => {
|
|
|
1761
1874
|
}
|
|
1762
1875
|
return { doc: record, id, op, table };
|
|
1763
1876
|
};
|
|
1877
|
+
const isIssueStatus = (value) => typeof value === "string" && ISSUE_STATUSES.includes(value);
|
|
1878
|
+
const isIssueSeverity = (value) => typeof value === "string" && ISSUE_SEVERITIES.includes(value);
|
|
1879
|
+
const parseIssueHash = (args) => {
|
|
1880
|
+
const hash = typeof args["hash"] === "string" ? args["hash"].trim() : "";
|
|
1881
|
+
if (hash === "") {
|
|
1882
|
+
throw new LunoraError("BAD_REQUEST", "issue triage: `hash` is required");
|
|
1883
|
+
}
|
|
1884
|
+
return hash;
|
|
1885
|
+
};
|
|
1886
|
+
const CLEAR = null;
|
|
1887
|
+
const parseAssigneeArgument = (args) => {
|
|
1888
|
+
const raw = args["assignee"];
|
|
1889
|
+
if (raw === null) {
|
|
1890
|
+
return CLEAR;
|
|
1891
|
+
}
|
|
1892
|
+
if (typeof raw === "string" && raw.trim() !== "") {
|
|
1893
|
+
return raw;
|
|
1894
|
+
}
|
|
1895
|
+
throw new LunoraError("BAD_REQUEST", "assignIssue: `assignee` must be a non-empty string (assign) or null (unassign)");
|
|
1896
|
+
};
|
|
1897
|
+
const parseSeverityArgument = (args) => {
|
|
1898
|
+
const raw = args["severity"];
|
|
1899
|
+
if (raw === null) {
|
|
1900
|
+
return CLEAR;
|
|
1901
|
+
}
|
|
1902
|
+
if (isIssueSeverity(raw)) {
|
|
1903
|
+
return raw;
|
|
1904
|
+
}
|
|
1905
|
+
throw new LunoraError("BAD_REQUEST", "setIssueSeverity: `severity` must be one of critical|high|medium|low, or null to clear");
|
|
1906
|
+
};
|
|
1764
1907
|
const parseCreateWorkflowInstanceArgs = (args) => {
|
|
1765
1908
|
const exportName = typeof args["exportName"] === "string" ? args["exportName"].trim() : "";
|
|
1766
1909
|
if (exportName === "") {
|
|
@@ -4955,8 +5098,63 @@ class ShardDO {
|
|
|
4955
5098
|
if (functionPath === ADMIN_FUNCTIONS.listFlags) {
|
|
4956
5099
|
return this.handleListFlags(args);
|
|
4957
5100
|
}
|
|
5101
|
+
const triaged = await this.handleIssueTriageOp(functionPath, args);
|
|
5102
|
+
if (triaged !== void 0) {
|
|
5103
|
+
return triaged;
|
|
5104
|
+
}
|
|
4958
5105
|
return this.handlePitrAdminOp(functionPath, args);
|
|
4959
5106
|
}
|
|
5107
|
+
/**
|
|
5108
|
+
* Serve the four Issue-triage admin writes — `resolveIssue` / `ignoreIssue`
|
|
5109
|
+
* (a status change), `assignIssue` (set/clear an owner), `setIssueSeverity`
|
|
5110
|
+
* (tag/clear severity). Each upserts one row in the reserved
|
|
5111
|
+
* `__lunora_issue_state__` side table keyed by the Issue's fingerprint
|
|
5112
|
+
* `hash`, then re-derives at read time in {@link readErrorIssues}. Returns
|
|
5113
|
+
* `undefined` for any path it doesn't own so `handleExtraAdminOp` falls
|
|
5114
|
+
* through. Admin-gated by `handleAdminRpc`'s caller (the `LUNORA_ADMIN_TOKEN`
|
|
5115
|
+
* bearer); a bad/missing `hash` (or a bad status/severity value) is a 400.
|
|
5116
|
+
*
|
|
5117
|
+
* The write lands through raw SQL the change-tracker can't observe, so it
|
|
5118
|
+
* marks {@link ISSUE_STATE_TABLE} changed and flushes — the live Issues
|
|
5119
|
+
* subscription is an admin-wildcard memo that re-runs whenever a flush finds
|
|
5120
|
+
* a changed table, so the triage shows up without an unrelated write.
|
|
5121
|
+
*/
|
|
5122
|
+
async handleIssueTriageOp(functionPath, args) {
|
|
5123
|
+
const patch = this.parseIssueTriagePatch(functionPath, args);
|
|
5124
|
+
if (patch === void 0) {
|
|
5125
|
+
return void 0;
|
|
5126
|
+
}
|
|
5127
|
+
const hash = parseIssueHash(args);
|
|
5128
|
+
const updatedBy = typeof args["updatedBy"] === "string" ? args["updatedBy"] : void 0;
|
|
5129
|
+
const sql = this.state.storage.sql;
|
|
5130
|
+
const state = upsertIssueState(sql, hash, patch, Date.now(), updatedBy);
|
|
5131
|
+
this.recordChangedTable(ISSUE_STATE_TABLE);
|
|
5132
|
+
await this.flushChangedTables();
|
|
5133
|
+
this.recordAudit(functionPath.slice(ADMIN_FUNCTION_PREFIX.length), { detail: { ...patch, hash } });
|
|
5134
|
+
return jsonResponse({ result: { state } }, 200);
|
|
5135
|
+
}
|
|
5136
|
+
/**
|
|
5137
|
+
* Map an Issue-triage admin path to the `IssueStatePatch` it applies, or
|
|
5138
|
+
* `undefined` when the path isn't a triage write. `assignIssue`/
|
|
5139
|
+
* `setIssueSeverity` accept an explicit `null` to CLEAR the field (unassign /
|
|
5140
|
+
* untag); a missing or malformed value is a 400 rather than a silent no-op.
|
|
5141
|
+
*/
|
|
5142
|
+
// eslint-disable-next-line class-methods-use-this -- kept an instance method for symmetry with the other `parse*`/handler seams
|
|
5143
|
+
parseIssueTriagePatch(functionPath, args) {
|
|
5144
|
+
if (functionPath === ADMIN_FUNCTIONS.resolveIssue) {
|
|
5145
|
+
return { status: "resolved" };
|
|
5146
|
+
}
|
|
5147
|
+
if (functionPath === ADMIN_FUNCTIONS.ignoreIssue) {
|
|
5148
|
+
return { status: "ignored" };
|
|
5149
|
+
}
|
|
5150
|
+
if (functionPath === ADMIN_FUNCTIONS.assignIssue) {
|
|
5151
|
+
return { assignee: parseAssigneeArgument(args), status: "open" };
|
|
5152
|
+
}
|
|
5153
|
+
if (functionPath === ADMIN_FUNCTIONS.setIssueSeverity) {
|
|
5154
|
+
return { severity: parseSeverityArgument(args) };
|
|
5155
|
+
}
|
|
5156
|
+
return void 0;
|
|
5157
|
+
}
|
|
4960
5158
|
/**
|
|
4961
5159
|
* Record one app-level auth attempt for the auth-failure SLO (PLAN3 §2.3).
|
|
4962
5160
|
* The worker calls this fire-and-forget (via `waitUntil`) after a top-level
|
|
@@ -5729,6 +5927,7 @@ class ShardDO {
|
|
|
5729
5927
|
functionPathPrefix: typeof args["functionPathPrefix"] === "string" ? args["functionPathPrefix"] : void 0,
|
|
5730
5928
|
limit: typeof args["limit"] === "number" ? args["limit"] : void 0,
|
|
5731
5929
|
shardKey: typeof args["shardKey"] === "string" ? args["shardKey"] : void 0,
|
|
5930
|
+
status: isIssueStatus(args["status"]) ? args["status"] : void 0,
|
|
5732
5931
|
userId: typeof args["userId"] === "string" ? args["userId"] : void 0
|
|
5733
5932
|
})
|
|
5734
5933
|
};
|
package/dist/packem_shared/{serveRelationFanout-Yiyx2OQB.mjs → serveRelationFanout-FdrPflv1.mjs}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LunoraError } from '@lunora/errors';
|
|
2
|
-
import { RELATION_FUNCTION_PREFIX } from './ADMIN_FUNCTIONS-
|
|
2
|
+
import { RELATION_FUNCTION_PREFIX } from './ADMIN_FUNCTIONS-DVk02KpP.mjs';
|
|
3
3
|
|
|
4
4
|
const serveRelationFanout = async (schema, database, functionPath, args) => {
|
|
5
5
|
const table = typeof args["table"] === "string" ? args["table"] : "";
|