@cerefox/memory 1.18.0 → 1.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENT_GUIDE.md +8 -3
- package/AGENT_QUICK_REFERENCE.md +3 -3
- package/dist/bin/cerefox.js +847 -659
- package/dist/frontend/assets/index-01k5C3sG.css +1 -0
- package/dist/frontend/assets/index-HNs8rgY1.js +121 -0
- package/dist/frontend/assets/index-HNs8rgY1.js.map +1 -0
- package/dist/frontend/index.html +2 -2
- package/dist/server-assets/_shared/ef-meta/index.ts +3 -3
- package/dist/server-assets/_shared/embeddings/onnx-embedder.ts +25 -9
- package/dist/server-assets/_shared/mcp-tools/_document-meta.ts +24 -2
- package/dist/server-assets/_shared/mcp-tools/_utils.ts +92 -0
- package/dist/server-assets/_shared/mcp-tools/audit-log.ts +6 -2
- package/dist/server-assets/_shared/mcp-tools/audit-ops.ts +27 -0
- package/dist/server-assets/_shared/mcp-tools/get-document.ts +11 -1
- package/dist/server-assets/_shared/mcp-tools/get-help-content.ts +3 -3
- package/dist/server-assets/_shared/mcp-tools/ingest.ts +55 -17
- package/dist/server-assets/_shared/mcp-tools/metadata-search.ts +3 -1
- package/dist/server-assets/_shared/mcp-tools/partial-edits.ts +8 -13
- package/dist/server-assets/_shared/mcp-tools/search.ts +11 -2
- package/dist/server-assets/_shared/mcp-tools/set-document-metadata.ts +31 -5
- package/dist/server-assets/db/migrations/0035_drop_content_hash_unique.sql +21 -0
- package/dist/server-assets/db/migrations/0036_metadata_revision.sql +43 -0
- package/dist/server-assets/db/rpcs.sql +252 -53
- package/dist/server-assets/db/schema.sql +41 -4
- package/dist/server-assets/supabase/functions/cerefox-get-document/index.ts +8 -1
- package/dist/server-assets/supabase/functions/cerefox-ingest/index.ts +42 -6
- package/docs/api/openapi.json +67 -1
- package/docs/guides/cli.md +3 -1
- package/docs/guides/configuration.md +1 -1
- package/docs/guides/connect-agents.md +18 -7
- package/docs/guides/ops-scripts.md +1 -1
- package/docs/guides/setup-local.md +30 -6
- package/docs/guides/upgrading.md +14 -0
- package/package.json +6 -6
- package/dist/frontend/assets/index-B0H_N4if.css +0 -1
- package/dist/frontend/assets/index-CxMT7hjH.js +0 -121
- package/dist/frontend/assets/index-CxMT7hjH.js.map +0 -1
package/dist/bin/cerefox.js
CHANGED
|
@@ -5318,7 +5318,7 @@ var init_cli_core = __esm(() => {
|
|
|
5318
5318
|
});
|
|
5319
5319
|
|
|
5320
5320
|
// src/meta.ts
|
|
5321
|
-
var PKG_VERSION = "1.
|
|
5321
|
+
var PKG_VERSION = "1.19.1";
|
|
5322
5322
|
var init_meta = () => {};
|
|
5323
5323
|
|
|
5324
5324
|
// ../../_shared/config/paths.ts
|
|
@@ -5436,7 +5436,7 @@ var init_config = __esm(() => {
|
|
|
5436
5436
|
init_env();
|
|
5437
5437
|
});
|
|
5438
5438
|
|
|
5439
|
-
// ../../node_modules/.bun/@supabase+supabase-js@2.117.
|
|
5439
|
+
// ../../node_modules/.bun/@supabase+supabase-js@2.117.3/node_modules/@supabase/supabase-js/dist/tracingRegistry.mjs
|
|
5440
5440
|
function getTraceContextExtractor() {
|
|
5441
5441
|
return globalThis[EXTRACTOR_KEY];
|
|
5442
5442
|
}
|
|
@@ -6050,7 +6050,7 @@ var require_tslib = __commonJS(function(exports, module) {
|
|
|
6050
6050
|
});
|
|
6051
6051
|
});
|
|
6052
6052
|
|
|
6053
|
-
// ../../node_modules/.bun/@supabase+functions-js@2.117.
|
|
6053
|
+
// ../../node_modules/.bun/@supabase+functions-js@2.117.3/node_modules/@supabase/functions-js/dist/main/helper.js
|
|
6054
6054
|
var require_helper = __commonJS(function(exports) {
|
|
6055
6055
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6056
6056
|
exports.resolveFetch = undefined;
|
|
@@ -6063,7 +6063,7 @@ var require_helper = __commonJS(function(exports) {
|
|
|
6063
6063
|
exports.resolveFetch = resolveFetch;
|
|
6064
6064
|
});
|
|
6065
6065
|
|
|
6066
|
-
// ../../node_modules/.bun/@supabase+functions-js@2.117.
|
|
6066
|
+
// ../../node_modules/.bun/@supabase+functions-js@2.117.3/node_modules/@supabase/functions-js/dist/main/types.js
|
|
6067
6067
|
var require_types = __commonJS(function(exports) {
|
|
6068
6068
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6069
6069
|
exports.FunctionRegion = exports.FunctionsHttpError = exports.FunctionsRelayError = exports.FunctionsFetchError = exports.FunctionsError = undefined;
|
|
@@ -6124,7 +6124,7 @@ var require_types = __commonJS(function(exports) {
|
|
|
6124
6124
|
})(FunctionRegion || (exports.FunctionRegion = FunctionRegion = {}));
|
|
6125
6125
|
});
|
|
6126
6126
|
|
|
6127
|
-
// ../../node_modules/.bun/@supabase+functions-js@2.117.
|
|
6127
|
+
// ../../node_modules/.bun/@supabase+functions-js@2.117.3/node_modules/@supabase/functions-js/dist/main/FunctionsClient.js
|
|
6128
6128
|
var require_FunctionsClient = __commonJS(function(exports) {
|
|
6129
6129
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6130
6130
|
exports.FunctionsClient = undefined;
|
|
@@ -6164,7 +6164,7 @@ var require_FunctionsClient = __commonJS(function(exports) {
|
|
|
6164
6164
|
const hasContentTypeHeader = !!headers && Object.keys(headers).some((key) => key.toLowerCase() === "content-type");
|
|
6165
6165
|
if (functionArgs && !hasContentTypeHeader) {
|
|
6166
6166
|
if (typeof Blob !== "undefined" && functionArgs instanceof Blob || functionArgs instanceof ArrayBuffer) {
|
|
6167
|
-
_headers["Content-Type"] = "application/octet-stream";
|
|
6167
|
+
_headers["Content-Type"] = functionArgs.type || "application/octet-stream";
|
|
6168
6168
|
body = functionArgs;
|
|
6169
6169
|
} else if (typeof functionArgs === "string") {
|
|
6170
6170
|
_headers["Content-Type"] = "text/plain";
|
|
@@ -6243,7 +6243,7 @@ var require_FunctionsClient = __commonJS(function(exports) {
|
|
|
6243
6243
|
exports.FunctionsClient = FunctionsClient;
|
|
6244
6244
|
});
|
|
6245
6245
|
|
|
6246
|
-
// ../../node_modules/.bun/@supabase+functions-js@2.117.
|
|
6246
|
+
// ../../node_modules/.bun/@supabase+functions-js@2.117.3/node_modules/@supabase/functions-js/dist/main/index.js
|
|
6247
6247
|
var require_main = __commonJS(function(exports) {
|
|
6248
6248
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6249
6249
|
exports.FunctionRegion = exports.FunctionsRelayError = exports.FunctionsHttpError = exports.FunctionsFetchError = exports.FunctionsError = exports.FunctionsClient = undefined;
|
|
@@ -6269,7 +6269,7 @@ var require_main = __commonJS(function(exports) {
|
|
|
6269
6269
|
} });
|
|
6270
6270
|
});
|
|
6271
6271
|
|
|
6272
|
-
// ../../node_modules/.bun/@supabase+postgrest-js@2.117.
|
|
6272
|
+
// ../../node_modules/.bun/@supabase+postgrest-js@2.117.3/node_modules/@supabase/postgrest-js/dist/index.mjs
|
|
6273
6273
|
function _typeof(o) {
|
|
6274
6274
|
"@babel/helpers - typeof";
|
|
6275
6275
|
return _typeof = typeof Symbol == "function" && typeof Symbol.iterator == "symbol" ? function(o$1) {
|
|
@@ -6364,7 +6364,8 @@ async function fetchWithRetry(fetchImpl, url, request, retryEnabled) {
|
|
|
6364
6364
|
signal: request.signal
|
|
6365
6365
|
});
|
|
6366
6366
|
} catch (fetchError) {
|
|
6367
|
-
|
|
6367
|
+
var _request$signal;
|
|
6368
|
+
if ((fetchError === null || fetchError === undefined ? undefined : fetchError.name) === "AbortError" || (fetchError === null || fetchError === undefined ? undefined : fetchError.code) === "ABORT_ERR" || (fetchError === null || fetchError === undefined ? undefined : fetchError.name) === "TimeoutError" && ((_request$signal = request.signal) === null || _request$signal === undefined ? undefined : _request$signal.aborted))
|
|
6368
6369
|
throw fetchError;
|
|
6369
6370
|
if (!RETRYABLE_METHODS.includes(request.method))
|
|
6370
6371
|
throw fetchError;
|
|
@@ -7179,7 +7180,7 @@ var init_dist = __esm(() => {
|
|
|
7179
7180
|
};
|
|
7180
7181
|
});
|
|
7181
7182
|
|
|
7182
|
-
// ../../node_modules/.bun/@supabase+realtime-js@2.117.
|
|
7183
|
+
// ../../node_modules/.bun/@supabase+realtime-js@2.117.3/node_modules/@supabase/realtime-js/dist/main/lib/websocket-factory.js
|
|
7183
7184
|
var require_websocket_factory = __commonJS(function(exports) {
|
|
7184
7185
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7185
7186
|
exports.WebSocketFactory = undefined;
|
|
@@ -7256,14 +7257,14 @@ Suggested solution: ${env.workaround}`;
|
|
|
7256
7257
|
exports.default = WebSocketFactory;
|
|
7257
7258
|
});
|
|
7258
7259
|
|
|
7259
|
-
// ../../node_modules/.bun/@supabase+realtime-js@2.117.
|
|
7260
|
+
// ../../node_modules/.bun/@supabase+realtime-js@2.117.3/node_modules/@supabase/realtime-js/dist/main/lib/version.js
|
|
7260
7261
|
var require_version = __commonJS(function(exports) {
|
|
7261
7262
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7262
7263
|
exports.version = undefined;
|
|
7263
|
-
exports.version = "2.117.
|
|
7264
|
+
exports.version = "2.117.3";
|
|
7264
7265
|
});
|
|
7265
7266
|
|
|
7266
|
-
// ../../node_modules/.bun/@supabase+realtime-js@2.117.
|
|
7267
|
+
// ../../node_modules/.bun/@supabase+realtime-js@2.117.3/node_modules/@supabase/realtime-js/dist/main/lib/constants.js
|
|
7267
7268
|
var require_constants = __commonJS(function(exports) {
|
|
7268
7269
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7269
7270
|
exports.CONNECTION_STATE = exports.TRANSPORTS = exports.CHANNEL_EVENTS = exports.CHANNEL_STATES = exports.SOCKET_STATES = exports.MAX_PUSH_BUFFER_SIZE = exports.WS_CLOSE_NORMAL = exports.POSTGRES_CHANGES_WAIT_ERROR_GRACE = exports.DEFAULT_POSTGRES_CHANGES_WAIT_TIMEOUT = exports.DEFAULT_TIMEOUT = exports.VERSION = exports.DEFAULT_VSN = exports.VSN_2_0_0 = exports.VSN_1_0_0 = exports.DEFAULT_VERSION = undefined;
|
|
@@ -7310,7 +7311,7 @@ var require_constants = __commonJS(function(exports) {
|
|
|
7310
7311
|
};
|
|
7311
7312
|
});
|
|
7312
7313
|
|
|
7313
|
-
// ../../node_modules/.bun/@supabase+realtime-js@2.117.
|
|
7314
|
+
// ../../node_modules/.bun/@supabase+realtime-js@2.117.3/node_modules/@supabase/realtime-js/dist/main/lib/serializer.js
|
|
7314
7315
|
var require_serializer = __commonJS(function(exports) {
|
|
7315
7316
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7316
7317
|
|
|
@@ -7462,7 +7463,7 @@ var require_serializer = __commonJS(function(exports) {
|
|
|
7462
7463
|
exports.default = Serializer;
|
|
7463
7464
|
});
|
|
7464
7465
|
|
|
7465
|
-
// ../../node_modules/.bun/@supabase+realtime-js@2.117.
|
|
7466
|
+
// ../../node_modules/.bun/@supabase+realtime-js@2.117.3/node_modules/@supabase/realtime-js/dist/main/lib/transformers.js
|
|
7466
7467
|
var require_transformers = __commonJS(function(exports) {
|
|
7467
7468
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7468
7469
|
exports.httpEndpointURL = exports.toTimestampString = exports.toArray = exports.toJson = exports.toNumber = exports.toBoolean = exports.convertCell = exports.convertColumn = exports.convertChangeData = exports.PostgresTypes = undefined;
|
|
@@ -9047,7 +9048,7 @@ var require_phoenix_cjs = __commonJS(function(exports, module) {
|
|
|
9047
9048
|
};
|
|
9048
9049
|
});
|
|
9049
9050
|
|
|
9050
|
-
// ../../node_modules/.bun/@supabase+realtime-js@2.117.
|
|
9051
|
+
// ../../node_modules/.bun/@supabase+realtime-js@2.117.3/node_modules/@supabase/realtime-js/dist/main/phoenix/presenceAdapter.js
|
|
9051
9052
|
var require_presenceAdapter = __commonJS(function(exports) {
|
|
9052
9053
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9053
9054
|
var phoenix_1 = require_phoenix_cjs();
|
|
@@ -9122,7 +9123,7 @@ var require_presenceAdapter = __commonJS(function(exports) {
|
|
|
9122
9123
|
}
|
|
9123
9124
|
});
|
|
9124
9125
|
|
|
9125
|
-
// ../../node_modules/.bun/@supabase+realtime-js@2.117.
|
|
9126
|
+
// ../../node_modules/.bun/@supabase+realtime-js@2.117.3/node_modules/@supabase/realtime-js/dist/main/RealtimePresence.js
|
|
9126
9127
|
var require_RealtimePresence = __commonJS(function(exports) {
|
|
9127
9128
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9128
9129
|
exports.REALTIME_PRESENCE_LISTEN_EVENTS = undefined;
|
|
@@ -9147,7 +9148,7 @@ var require_RealtimePresence = __commonJS(function(exports) {
|
|
|
9147
9148
|
exports.default = RealtimePresence;
|
|
9148
9149
|
});
|
|
9149
9150
|
|
|
9150
|
-
// ../../node_modules/.bun/@supabase+realtime-js@2.117.
|
|
9151
|
+
// ../../node_modules/.bun/@supabase+realtime-js@2.117.3/node_modules/@supabase/realtime-js/dist/main/lib/normalizeChannelError.js
|
|
9151
9152
|
var require_normalizeChannelError = __commonJS(function(exports) {
|
|
9152
9153
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9153
9154
|
exports.normalizeChannelError = normalizeChannelError;
|
|
@@ -9170,7 +9171,7 @@ var require_normalizeChannelError = __commonJS(function(exports) {
|
|
|
9170
9171
|
}
|
|
9171
9172
|
});
|
|
9172
9173
|
|
|
9173
|
-
// ../../node_modules/.bun/@supabase+realtime-js@2.117.
|
|
9174
|
+
// ../../node_modules/.bun/@supabase+realtime-js@2.117.3/node_modules/@supabase/realtime-js/dist/main/phoenix/channelAdapter.js
|
|
9174
9175
|
var require_channelAdapter = __commonJS(function(exports) {
|
|
9175
9176
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9176
9177
|
var constants_1 = require_constants();
|
|
@@ -9272,7 +9273,7 @@ var require_channelAdapter = __commonJS(function(exports) {
|
|
|
9272
9273
|
}
|
|
9273
9274
|
});
|
|
9274
9275
|
|
|
9275
|
-
// ../../node_modules/.bun/@supabase+realtime-js@2.117.
|
|
9276
|
+
// ../../node_modules/.bun/@supabase+realtime-js@2.117.3/node_modules/@supabase/realtime-js/dist/main/RealtimePostgresFilterBuilder.js
|
|
9276
9277
|
var require_RealtimePostgresFilterBuilder = __commonJS(function(exports) {
|
|
9277
9278
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9278
9279
|
exports.postgresChangesFilter = exports.RealtimePostgresFilterBuilder = undefined;
|
|
@@ -9362,7 +9363,7 @@ var require_RealtimePostgresFilterBuilder = __commonJS(function(exports) {
|
|
|
9362
9363
|
exports.postgresChangesFilter = postgresChangesFilter;
|
|
9363
9364
|
});
|
|
9364
9365
|
|
|
9365
|
-
// ../../node_modules/.bun/@supabase+realtime-js@2.117.
|
|
9366
|
+
// ../../node_modules/.bun/@supabase+realtime-js@2.117.3/node_modules/@supabase/realtime-js/dist/main/RealtimeChannel.js
|
|
9366
9367
|
var require_RealtimeChannel = __commonJS(function(exports) {
|
|
9367
9368
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9368
9369
|
exports.REALTIME_CHANNEL_STATES = exports.REALTIME_SUBSCRIBE_STATES = exports.REALTIME_LISTEN_TYPES = exports.REALTIME_POSTGRES_CHANGES_LISTEN_EVENT = exports.postgresChangesFilter = exports.RealtimePostgresFilterBuilder = undefined;
|
|
@@ -9767,7 +9768,7 @@ var require_RealtimeChannel = __commonJS(function(exports) {
|
|
|
9767
9768
|
exports.default = RealtimeChannel;
|
|
9768
9769
|
});
|
|
9769
9770
|
|
|
9770
|
-
// ../../node_modules/.bun/@supabase+realtime-js@2.117.
|
|
9771
|
+
// ../../node_modules/.bun/@supabase+realtime-js@2.117.3/node_modules/@supabase/realtime-js/dist/main/phoenix/socketAdapter.js
|
|
9771
9772
|
var require_socketAdapter = __commonJS(function(exports) {
|
|
9772
9773
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9773
9774
|
var phoenix_1 = require_phoenix_cjs();
|
|
@@ -9883,7 +9884,7 @@ var require_socketAdapter = __commonJS(function(exports) {
|
|
|
9883
9884
|
exports.default = SocketAdapter;
|
|
9884
9885
|
});
|
|
9885
9886
|
|
|
9886
|
-
// ../../node_modules/.bun/@supabase+realtime-js@2.117.
|
|
9887
|
+
// ../../node_modules/.bun/@supabase+realtime-js@2.117.3/node_modules/@supabase/realtime-js/dist/main/RealtimeClient.js
|
|
9887
9888
|
var require_RealtimeClient = __commonJS(function(exports) {
|
|
9888
9889
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9889
9890
|
var tslib_1 = require_tslib();
|
|
@@ -10349,7 +10350,7 @@ var require_RealtimeClient = __commonJS(function(exports) {
|
|
|
10349
10350
|
exports.default = RealtimeClient;
|
|
10350
10351
|
});
|
|
10351
10352
|
|
|
10352
|
-
// ../../node_modules/.bun/@supabase+realtime-js@2.117.
|
|
10353
|
+
// ../../node_modules/.bun/@supabase+realtime-js@2.117.3/node_modules/@supabase/realtime-js/dist/main/index.js
|
|
10353
10354
|
var require_main2 = __commonJS(function(exports) {
|
|
10354
10355
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10355
10356
|
exports.WebSocketFactory = exports.REALTIME_CHANNEL_STATES = exports.REALTIME_SUBSCRIBE_STATES = exports.REALTIME_PRESENCE_LISTEN_EVENTS = exports.REALTIME_POSTGRES_CHANGES_LISTEN_EVENT = exports.REALTIME_LISTEN_TYPES = exports.postgresChangesFilter = exports.RealtimePostgresFilterBuilder = exports.RealtimeClient = exports.RealtimeChannel = exports.RealtimePresence = undefined;
|
|
@@ -10685,7 +10686,7 @@ var init_dist2 = __esm(() => {
|
|
|
10685
10686
|
};
|
|
10686
10687
|
});
|
|
10687
10688
|
|
|
10688
|
-
// ../../node_modules/.bun/@supabase+storage-js@2.117.
|
|
10689
|
+
// ../../node_modules/.bun/@supabase+storage-js@2.117.3/node_modules/@supabase/storage-js/dist/index.mjs
|
|
10689
10690
|
function _typeof2(o) {
|
|
10690
10691
|
"@babel/helpers - typeof";
|
|
10691
10692
|
return _typeof2 = typeof Symbol == "function" && typeof Symbol.iterator == "symbol" ? function(o$1) {
|
|
@@ -10993,7 +10994,7 @@ var StorageError, StorageApiError, StorageUnknownError, resolveFetch = (customFe
|
|
|
10993
10994
|
throw error;
|
|
10994
10995
|
}
|
|
10995
10996
|
}
|
|
10996
|
-
}, DEFAULT_SEARCH_OPTIONS, DEFAULT_FILE_OPTIONS, StorageFileApi, version = "2.117.
|
|
10997
|
+
}, DEFAULT_SEARCH_OPTIONS, DEFAULT_FILE_OPTIONS, StorageFileApi, version = "2.117.3", DEFAULT_HEADERS, StorageBucketApi, StorageAnalyticsClient, VectorIndexApi, VectorDataApi, VectorBucketApi, StorageVectorsClient, VectorBucketScope, VectorIndexScope, StorageClient;
|
|
10997
10998
|
var init_dist3 = __esm(() => {
|
|
10998
10999
|
init_dist2();
|
|
10999
11000
|
StorageError = class extends Error {
|
|
@@ -11063,19 +11064,9 @@ var init_dist3 = __esm(() => {
|
|
|
11063
11064
|
const options = _objectSpread22(_objectSpread22({}, DEFAULT_FILE_OPTIONS), fileOptions);
|
|
11064
11065
|
let headers = _objectSpread22(_objectSpread22({}, _this.headers), method === "POST" && { "x-upsert": String(options.upsert) });
|
|
11065
11066
|
const metadata = options.metadata;
|
|
11066
|
-
if (typeof Blob !== "undefined" && fileBody instanceof Blob)
|
|
11067
|
-
body =
|
|
11068
|
-
|
|
11069
|
-
if (metadata)
|
|
11070
|
-
body.append("metadata", _this.encodeMetadata(metadata));
|
|
11071
|
-
body.append("", fileBody);
|
|
11072
|
-
} else if (typeof FormData !== "undefined" && fileBody instanceof FormData) {
|
|
11073
|
-
body = fileBody;
|
|
11074
|
-
if (!body.has("cacheControl"))
|
|
11075
|
-
body.append("cacheControl", options.cacheControl);
|
|
11076
|
-
if (metadata && !body.has("metadata"))
|
|
11077
|
-
body.append("metadata", _this.encodeMetadata(metadata));
|
|
11078
|
-
} else {
|
|
11067
|
+
if (typeof Blob !== "undefined" && fileBody instanceof Blob || typeof FormData !== "undefined" && fileBody instanceof FormData)
|
|
11068
|
+
body = _this.prepareUploadFormData(fileBody, options);
|
|
11069
|
+
else {
|
|
11079
11070
|
body = fileBody;
|
|
11080
11071
|
headers["cache-control"] = `max-age=${options.cacheControl}`;
|
|
11081
11072
|
headers["content-type"] = options.contentType;
|
|
@@ -11111,19 +11102,9 @@ var init_dist3 = __esm(() => {
|
|
|
11111
11102
|
const options = _objectSpread22(_objectSpread22({}, DEFAULT_FILE_OPTIONS), fileOptions);
|
|
11112
11103
|
let headers = _objectSpread22(_objectSpread22({}, _this3.headers), { "x-upsert": String(options.upsert) });
|
|
11113
11104
|
const metadata = options.metadata;
|
|
11114
|
-
if (typeof Blob !== "undefined" && fileBody instanceof Blob)
|
|
11115
|
-
body =
|
|
11116
|
-
|
|
11117
|
-
if (metadata)
|
|
11118
|
-
body.append("metadata", _this3.encodeMetadata(metadata));
|
|
11119
|
-
body.append("", fileBody);
|
|
11120
|
-
} else if (typeof FormData !== "undefined" && fileBody instanceof FormData) {
|
|
11121
|
-
body = fileBody;
|
|
11122
|
-
if (!body.has("cacheControl"))
|
|
11123
|
-
body.append("cacheControl", options.cacheControl);
|
|
11124
|
-
if (metadata && !body.has("metadata"))
|
|
11125
|
-
body.append("metadata", _this3.encodeMetadata(metadata));
|
|
11126
|
-
} else {
|
|
11105
|
+
if (typeof Blob !== "undefined" && fileBody instanceof Blob || typeof FormData !== "undefined" && fileBody instanceof FormData)
|
|
11106
|
+
body = _this3.prepareUploadFormData(fileBody, options);
|
|
11107
|
+
else {
|
|
11127
11108
|
body = fileBody;
|
|
11128
11109
|
headers["cache-control"] = `max-age=${options.cacheControl}`;
|
|
11129
11110
|
headers["content-type"] = options.contentType;
|
|
@@ -11320,6 +11301,26 @@ var init_dist3 = __esm(() => {
|
|
|
11320
11301
|
return await post(_this15.fetch, `${_this15.url}/object/list-v2/${_this15.bucketId}`, body, { headers: _this15.headers }, parameters);
|
|
11321
11302
|
});
|
|
11322
11303
|
}
|
|
11304
|
+
prepareUploadFormData(fileBody, options) {
|
|
11305
|
+
const body = new FormData;
|
|
11306
|
+
const files = [];
|
|
11307
|
+
if (fileBody instanceof FormData)
|
|
11308
|
+
fileBody.forEach((value, name) => {
|
|
11309
|
+
if (typeof value === "string")
|
|
11310
|
+
body.append(name, value);
|
|
11311
|
+
else
|
|
11312
|
+
files.push([name, value]);
|
|
11313
|
+
});
|
|
11314
|
+
else
|
|
11315
|
+
files.push(["", fileBody]);
|
|
11316
|
+
if (!body.has("cacheControl"))
|
|
11317
|
+
body.append("cacheControl", options.cacheControl);
|
|
11318
|
+
if (options.metadata && !body.has("metadata"))
|
|
11319
|
+
body.append("metadata", this.encodeMetadata(options.metadata));
|
|
11320
|
+
for (const [name, file] of files)
|
|
11321
|
+
body.append(name, file);
|
|
11322
|
+
return body;
|
|
11323
|
+
}
|
|
11323
11324
|
encodeMetadata(metadata) {
|
|
11324
11325
|
return JSON.stringify(metadata);
|
|
11325
11326
|
}
|
|
@@ -11760,14 +11761,14 @@ var init_dist3 = __esm(() => {
|
|
|
11760
11761
|
};
|
|
11761
11762
|
});
|
|
11762
11763
|
|
|
11763
|
-
// ../../node_modules/.bun/@supabase+auth-js@2.117.
|
|
11764
|
+
// ../../node_modules/.bun/@supabase+auth-js@2.117.3/node_modules/@supabase/auth-js/dist/main/lib/version.js
|
|
11764
11765
|
var require_version2 = __commonJS(function(exports) {
|
|
11765
11766
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11766
11767
|
exports.version = undefined;
|
|
11767
|
-
exports.version = "2.117.
|
|
11768
|
+
exports.version = "2.117.3";
|
|
11768
11769
|
});
|
|
11769
11770
|
|
|
11770
|
-
// ../../node_modules/.bun/@supabase+auth-js@2.117.
|
|
11771
|
+
// ../../node_modules/.bun/@supabase+auth-js@2.117.3/node_modules/@supabase/auth-js/dist/main/lib/constants.js
|
|
11771
11772
|
var require_constants2 = __commonJS(function(exports) {
|
|
11772
11773
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11773
11774
|
exports.JWKS_TTL = exports.PKCE_MAX_CONCURRENT_FLOWS = exports.PKCE_FLOW_ID_PARAM = exports.BASE64URL_REGEX = exports.API_VERSIONS = exports.API_VERSION_HEADER_NAME = exports.NETWORK_FAILURE = exports.DEFAULT_HEADERS = exports.AUDIENCE = exports.STORAGE_KEY = exports.GOTRUE_URL = exports.REFRESH_FAILURE_COOLDOWN_MS = exports.EXPIRY_MARGIN_MS = exports.AUTO_REFRESH_TICK_THRESHOLD = exports.AUTO_REFRESH_TICK_DURATION_MS = undefined;
|
|
@@ -11797,7 +11798,7 @@ var require_constants2 = __commonJS(function(exports) {
|
|
|
11797
11798
|
exports.JWKS_TTL = 10 * 60 * 1000;
|
|
11798
11799
|
});
|
|
11799
11800
|
|
|
11800
|
-
// ../../node_modules/.bun/@supabase+auth-js@2.117.
|
|
11801
|
+
// ../../node_modules/.bun/@supabase+auth-js@2.117.3/node_modules/@supabase/auth-js/dist/main/lib/errors.js
|
|
11801
11802
|
var require_errors = __commonJS(function(exports) {
|
|
11802
11803
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11803
11804
|
exports.AuthInvalidJwtError = exports.AuthWeakPasswordError = exports.AuthRefreshDiscardedError = exports.AuthRetryableFetchError = exports.AuthPKCECodeVerifierMissingError = exports.AuthPKCEGrantCodeExchangeError = exports.AuthImplicitGrantRedirectError = exports.AuthInvalidCredentialsError = exports.AuthInvalidTokenResponseError = exports.AuthSessionMissingError = exports.CustomAuthError = exports.AuthUnknownError = exports.AuthApiError = exports.AuthError = undefined;
|
|
@@ -11966,7 +11967,7 @@ var require_errors = __commonJS(function(exports) {
|
|
|
11966
11967
|
exports.AuthInvalidJwtError = AuthInvalidJwtError;
|
|
11967
11968
|
});
|
|
11968
11969
|
|
|
11969
|
-
// ../../node_modules/.bun/@supabase+auth-js@2.117.
|
|
11970
|
+
// ../../node_modules/.bun/@supabase+auth-js@2.117.3/node_modules/@supabase/auth-js/dist/main/lib/base64url.js
|
|
11970
11971
|
var require_base64url = __commonJS(function(exports) {
|
|
11971
11972
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11972
11973
|
exports.byteToBase64URL = byteToBase64URL;
|
|
@@ -12154,7 +12155,7 @@ var require_base64url = __commonJS(function(exports) {
|
|
|
12154
12155
|
}
|
|
12155
12156
|
});
|
|
12156
12157
|
|
|
12157
|
-
// ../../node_modules/.bun/@supabase+auth-js@2.117.
|
|
12158
|
+
// ../../node_modules/.bun/@supabase+auth-js@2.117.3/node_modules/@supabase/auth-js/dist/main/lib/helpers.js
|
|
12158
12159
|
var require_helpers = __commonJS(function(exports) {
|
|
12159
12160
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12160
12161
|
exports.pkceVerifierSlotKey = exports.Deferred = exports.removeItemAsync = exports.getItemAsync = exports.setItemAsync = exports.looksLikeFetchResponse = exports.resolveFetch = exports.supportsLocalStorage = exports.isBrowser = undefined;
|
|
@@ -12563,7 +12564,7 @@ var require_helpers = __commonJS(function(exports) {
|
|
|
12563
12564
|
}
|
|
12564
12565
|
});
|
|
12565
12566
|
|
|
12566
|
-
// ../../node_modules/.bun/@supabase+auth-js@2.117.
|
|
12567
|
+
// ../../node_modules/.bun/@supabase+auth-js@2.117.3/node_modules/@supabase/auth-js/dist/main/lib/fetch.js
|
|
12567
12568
|
var require_fetch = __commonJS(function(exports) {
|
|
12568
12569
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12569
12570
|
exports.handleError = handleError;
|
|
@@ -12747,14 +12748,14 @@ var require_fetch = __commonJS(function(exports) {
|
|
|
12747
12748
|
}
|
|
12748
12749
|
});
|
|
12749
12750
|
|
|
12750
|
-
// ../../node_modules/.bun/@supabase+auth-js@2.117.
|
|
12751
|
+
// ../../node_modules/.bun/@supabase+auth-js@2.117.3/node_modules/@supabase/auth-js/dist/main/lib/types.js
|
|
12751
12752
|
var require_types2 = __commonJS(function(exports) {
|
|
12752
12753
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12753
12754
|
exports.SIGN_OUT_SCOPES = undefined;
|
|
12754
12755
|
exports.SIGN_OUT_SCOPES = ["global", "local", "others"];
|
|
12755
12756
|
});
|
|
12756
12757
|
|
|
12757
|
-
// ../../node_modules/.bun/@supabase+auth-js@2.117.
|
|
12758
|
+
// ../../node_modules/.bun/@supabase+auth-js@2.117.3/node_modules/@supabase/auth-js/dist/main/GoTrueAdminApi.js
|
|
12758
12759
|
var require_GoTrueAdminApi = __commonJS(function(exports) {
|
|
12759
12760
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12760
12761
|
var tslib_1 = require_tslib();
|
|
@@ -13199,7 +13200,7 @@ var require_GoTrueAdminApi = __commonJS(function(exports) {
|
|
|
13199
13200
|
exports.default = GoTrueAdminApi;
|
|
13200
13201
|
});
|
|
13201
13202
|
|
|
13202
|
-
// ../../node_modules/.bun/@supabase+auth-js@2.117.
|
|
13203
|
+
// ../../node_modules/.bun/@supabase+auth-js@2.117.3/node_modules/@supabase/auth-js/dist/main/lib/local-storage.js
|
|
13203
13204
|
var require_local_storage = __commonJS(function(exports) {
|
|
13204
13205
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13205
13206
|
exports.memoryLocalStorageAdapter = memoryLocalStorageAdapter;
|
|
@@ -13218,7 +13219,7 @@ var require_local_storage = __commonJS(function(exports) {
|
|
|
13218
13219
|
}
|
|
13219
13220
|
});
|
|
13220
13221
|
|
|
13221
|
-
// ../../node_modules/.bun/@supabase+auth-js@2.117.
|
|
13222
|
+
// ../../node_modules/.bun/@supabase+auth-js@2.117.3/node_modules/@supabase/auth-js/dist/main/lib/locks.js
|
|
13222
13223
|
var require_locks = __commonJS(function(exports) {
|
|
13223
13224
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13224
13225
|
exports.ProcessLockAcquireTimeoutError = exports.NavigatorLockAcquireTimeoutError = exports.LockAcquireTimeoutError = exports.internals = undefined;
|
|
@@ -13390,7 +13391,7 @@ var require_locks = __commonJS(function(exports) {
|
|
|
13390
13391
|
}
|
|
13391
13392
|
});
|
|
13392
13393
|
|
|
13393
|
-
// ../../node_modules/.bun/@supabase+auth-js@2.117.
|
|
13394
|
+
// ../../node_modules/.bun/@supabase+auth-js@2.117.3/node_modules/@supabase/auth-js/dist/main/lib/polyfills.js
|
|
13394
13395
|
var require_polyfills = __commonJS(function(exports) {
|
|
13395
13396
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13396
13397
|
exports.polyfillGlobalThis = polyfillGlobalThis;
|
|
@@ -13414,7 +13415,7 @@ var require_polyfills = __commonJS(function(exports) {
|
|
|
13414
13415
|
}
|
|
13415
13416
|
});
|
|
13416
13417
|
|
|
13417
|
-
// ../../node_modules/.bun/@supabase+auth-js@2.117.
|
|
13418
|
+
// ../../node_modules/.bun/@supabase+auth-js@2.117.3/node_modules/@supabase/auth-js/dist/main/lib/web3/ethereum.js
|
|
13418
13419
|
var require_ethereum = __commonJS(function(exports) {
|
|
13419
13420
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13420
13421
|
exports.getAddress = getAddress;
|
|
@@ -13491,7 +13492,7 @@ ${suffix}`;
|
|
|
13491
13492
|
}
|
|
13492
13493
|
});
|
|
13493
13494
|
|
|
13494
|
-
// ../../node_modules/.bun/@supabase+auth-js@2.117.
|
|
13495
|
+
// ../../node_modules/.bun/@supabase+auth-js@2.117.3/node_modules/@supabase/auth-js/dist/main/lib/webauthn.errors.js
|
|
13495
13496
|
var require_webauthn_errors = __commonJS(function(exports) {
|
|
13496
13497
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13497
13498
|
exports.WebAuthnUnknownError = exports.WebAuthnError = undefined;
|
|
@@ -13678,7 +13679,7 @@ var require_webauthn_errors = __commonJS(function(exports) {
|
|
|
13678
13679
|
}
|
|
13679
13680
|
});
|
|
13680
13681
|
|
|
13681
|
-
// ../../node_modules/.bun/@supabase+auth-js@2.117.
|
|
13682
|
+
// ../../node_modules/.bun/@supabase+auth-js@2.117.3/node_modules/@supabase/auth-js/dist/main/lib/webauthn.js
|
|
13682
13683
|
var require_webauthn = __commonJS(function(exports) {
|
|
13683
13684
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13684
13685
|
exports.WebAuthnApi = exports.DEFAULT_REQUEST_OPTIONS = exports.DEFAULT_CREATION_OPTIONS = exports.webAuthnAbortService = exports.WebAuthnAbortService = exports.identifyAuthenticationError = exports.identifyRegistrationError = exports.isWebAuthnError = exports.WebAuthnError = undefined;
|
|
@@ -14132,7 +14133,7 @@ var require_webauthn = __commonJS(function(exports) {
|
|
|
14132
14133
|
exports.WebAuthnApi = WebAuthnApi;
|
|
14133
14134
|
});
|
|
14134
14135
|
|
|
14135
|
-
// ../../node_modules/.bun/@supabase+auth-js@2.117.
|
|
14136
|
+
// ../../node_modules/.bun/@supabase+auth-js@2.117.3/node_modules/@supabase/auth-js/dist/main/GoTrueClient.js
|
|
14136
14137
|
var require_GoTrueClient = __commonJS(function(exports) {
|
|
14137
14138
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14138
14139
|
var tslib_1 = require_tslib();
|
|
@@ -17015,7 +17016,7 @@ var require_GoTrueClient = __commonJS(function(exports) {
|
|
|
17015
17016
|
exports.default = GoTrueClient;
|
|
17016
17017
|
});
|
|
17017
17018
|
|
|
17018
|
-
// ../../node_modules/.bun/@supabase+auth-js@2.117.
|
|
17019
|
+
// ../../node_modules/.bun/@supabase+auth-js@2.117.3/node_modules/@supabase/auth-js/dist/main/AuthAdminApi.js
|
|
17019
17020
|
var require_AuthAdminApi = __commonJS(function(exports) {
|
|
17020
17021
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17021
17022
|
var tslib_1 = require_tslib();
|
|
@@ -17024,7 +17025,7 @@ var require_AuthAdminApi = __commonJS(function(exports) {
|
|
|
17024
17025
|
exports.default = AuthAdminApi;
|
|
17025
17026
|
});
|
|
17026
17027
|
|
|
17027
|
-
// ../../node_modules/.bun/@supabase+auth-js@2.117.
|
|
17028
|
+
// ../../node_modules/.bun/@supabase+auth-js@2.117.3/node_modules/@supabase/auth-js/dist/main/AuthClient.js
|
|
17028
17029
|
var require_AuthClient = __commonJS(function(exports) {
|
|
17029
17030
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17030
17031
|
var tslib_1 = require_tslib();
|
|
@@ -17033,7 +17034,7 @@ var require_AuthClient = __commonJS(function(exports) {
|
|
|
17033
17034
|
exports.default = AuthClient;
|
|
17034
17035
|
});
|
|
17035
17036
|
|
|
17036
|
-
// ../../node_modules/.bun/@supabase+auth-js@2.117.
|
|
17037
|
+
// ../../node_modules/.bun/@supabase+auth-js@2.117.3/node_modules/@supabase/auth-js/dist/main/index.js
|
|
17037
17038
|
var require_main3 = __commonJS(function(exports) {
|
|
17038
17039
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17039
17040
|
exports.processLock = exports.lockInternals = exports.NavigatorLockAcquireTimeoutError = exports.navigatorLock = exports.AuthClient = exports.AuthAdminApi = exports.GoTrueClient = exports.GoTrueAdminApi = undefined;
|
|
@@ -17063,7 +17064,7 @@ var require_main3 = __commonJS(function(exports) {
|
|
|
17063
17064
|
} });
|
|
17064
17065
|
});
|
|
17065
17066
|
|
|
17066
|
-
// ../../node_modules/.bun/@supabase+supabase-js@2.117.
|
|
17067
|
+
// ../../node_modules/.bun/@supabase+supabase-js@2.117.3/node_modules/@supabase/supabase-js/dist/index.mjs
|
|
17067
17068
|
var exports_dist = {};
|
|
17068
17069
|
__export(exports_dist, {
|
|
17069
17070
|
createClient: () => createClient
|
|
@@ -17286,7 +17287,7 @@ function shouldShowDeprecationWarning() {
|
|
|
17286
17287
|
return false;
|
|
17287
17288
|
return parseInt(versionMatch[1], 10) <= 20;
|
|
17288
17289
|
}
|
|
17289
|
-
var import_functions_js, import_realtime_js, import_auth_js, version2 = "2.117.
|
|
17290
|
+
var import_functions_js, import_realtime_js, import_auth_js, version2 = "2.117.3", JS_ENV = "", JS_RUNTIME_VERSION, _Deno$version, _process$version, _runtimeMeta, DEFAULT_HEADERS2, DEFAULT_GLOBAL_OPTIONS, DEFAULT_DB_OPTIONS, DEFAULT_AUTH_OPTIONS, DEFAULT_REALTIME_OPTIONS, DEFAULT_TRACE_PROPAGATION_OPTIONS, resolveFetch2 = (customFetch) => {
|
|
17290
17291
|
if (customFetch)
|
|
17291
17292
|
return (...args) => customFetch(...args);
|
|
17292
17293
|
return (...args) => fetch(...args);
|
|
@@ -23684,6 +23685,23 @@ function auditDocLabel(docTitle, documentId, operation) {
|
|
|
23684
23685
|
return documentId.slice(0, 8) + "…";
|
|
23685
23686
|
return isStoreLevelAuditOp(operation) ? "(store)" : "(deleted)";
|
|
23686
23687
|
}
|
|
23688
|
+
function metadataChangeSummary(before, after) {
|
|
23689
|
+
if (before == null && after == null)
|
|
23690
|
+
return null;
|
|
23691
|
+
const b = before ?? {};
|
|
23692
|
+
const a = after ?? {};
|
|
23693
|
+
const show = (v) => typeof v === "string" ? v : JSON.stringify(v);
|
|
23694
|
+
const set = Object.keys(a).filter((k) => JSON.stringify(a[k]) !== JSON.stringify(b[k])).map((k) => `${k}=${show(a[k])}`);
|
|
23695
|
+
const removed = Object.keys(b).filter((k) => !Object.hasOwn(a, k));
|
|
23696
|
+
if (set.length === 0 && removed.length === 0)
|
|
23697
|
+
return null;
|
|
23698
|
+
const parts = [];
|
|
23699
|
+
if (set.length)
|
|
23700
|
+
parts.push(`set ${set.join(", ")}`);
|
|
23701
|
+
if (removed.length)
|
|
23702
|
+
parts.push(`removed ${removed.join(", ")}`);
|
|
23703
|
+
return parts.join("; ");
|
|
23704
|
+
}
|
|
23687
23705
|
var STORE_LEVEL_AUDIT_OPS, AUDIT_OPERATIONS;
|
|
23688
23706
|
var init_audit_ops = __esm(() => {
|
|
23689
23707
|
STORE_LEVEL_AUDIT_OPS = [
|
|
@@ -23728,6 +23746,25 @@ function getConfiguredSearchAlpha() {
|
|
|
23728
23746
|
function getMinTermCoverage() {
|
|
23729
23747
|
return;
|
|
23730
23748
|
}
|
|
23749
|
+
function metadataTokenParams(expected, lastWriteWins) {
|
|
23750
|
+
return {
|
|
23751
|
+
...expected != null ? { p_expected_metadata_revision: expected } : {},
|
|
23752
|
+
...lastWriteWins ? { p_last_write_wins: true } : {}
|
|
23753
|
+
};
|
|
23754
|
+
}
|
|
23755
|
+
function metadataTokenError(message) {
|
|
23756
|
+
if (message.includes("CEREFOX_METADATA_CONFLICT")) {
|
|
23757
|
+
const id = message.match(/document ([0-9a-f-]{36})/)?.[1] ?? "(unknown)";
|
|
23758
|
+
const expected = message.match(/expected metadata_revision (\d+)/)?.[1] ?? "?";
|
|
23759
|
+
const current = message.match(/current (\d+)/)?.[1] ?? "?";
|
|
23760
|
+
return new Error(`Metadata conflict: the metadata of document ${id} changed since you read it ` + `(your metadata_revision: ${expected}, current: ${current}). Nothing was written. ` + `To resolve: (1) cerefox_get_document("${id}", outline: true) for the current metadata ` + `and metadata_revision, (2) reapply your change to it, (3) retry with ` + `expected_metadata_revision set to the new value. Do not overwrite blindly — ` + `another writer's keys may be in there.`);
|
|
23761
|
+
}
|
|
23762
|
+
if (message.includes("CEREFOX_METADATA_TOKEN_REQUIRED")) {
|
|
23763
|
+
const current = message.match(/Current metadata_revision: (\d+)/)?.[1];
|
|
23764
|
+
return new Error(`Replacing all metadata deletes every key you do not list, so it needs ` + `expected_metadata_revision: the metadata_revision you read (returned by ` + `cerefox_get_document and cerefox_metadata_search).` + (current ? ` The document's current metadata_revision is ${current}; pass it ONLY if you read the current metadata.` : "") + ` To change some keys, drop replace and merge instead (null removes a key). ` + `To overwrite regardless, pass last_write_wins=true.`);
|
|
23765
|
+
}
|
|
23766
|
+
return null;
|
|
23767
|
+
}
|
|
23731
23768
|
function extractConflictHashes(message) {
|
|
23732
23769
|
return {
|
|
23733
23770
|
expected: message.match(/expected hash ([0-9a-f]{64})/)?.[1] ?? "unknown",
|
|
@@ -23740,6 +23777,16 @@ function isDocumentNotFoundError(error) {
|
|
|
23740
23777
|
function isAuditCheckError(message) {
|
|
23741
23778
|
return /cerefox_audit_log_operation_check/.test(message);
|
|
23742
23779
|
}
|
|
23780
|
+
function duplicateContentDocumentId(message) {
|
|
23781
|
+
if (!message.includes("CEREFOX_DUPLICATE_CONTENT"))
|
|
23782
|
+
return null;
|
|
23783
|
+
return message.match(/document ([0-9a-f-]{36})/i)?.[1] ?? null;
|
|
23784
|
+
}
|
|
23785
|
+
function legacyContentUniqueError(message) {
|
|
23786
|
+
if (!message.includes("cerefox_documents_hash_unique"))
|
|
23787
|
+
return null;
|
|
23788
|
+
return new Error("Another document (possibly one in the trash) already has exactly this content, " + "and this server predates schema 0.20.0, which still refuses that. " + `Run \`cerefox server deploy\`, then retry. (${message})`);
|
|
23789
|
+
}
|
|
23743
23790
|
function isDuplicateKeyError(message) {
|
|
23744
23791
|
return /duplicate key|unique constraint|23505/i.test(message);
|
|
23745
23792
|
}
|
|
@@ -23775,9 +23822,25 @@ function resolveByteBudget(requested, ceiling) {
|
|
|
23775
23822
|
return ceiling;
|
|
23776
23823
|
return Math.min(Math.max(n, 1), ceiling);
|
|
23777
23824
|
}
|
|
23778
|
-
var MAX_RESPONSE_BYTES = 200000;
|
|
23825
|
+
var MAX_RESPONSE_BYTES = 200000, MetadataConcurrencyError, DuplicateContentError;
|
|
23779
23826
|
var init__utils = __esm(() => {
|
|
23780
23827
|
init_audit_ops();
|
|
23828
|
+
MetadataConcurrencyError = class MetadataConcurrencyError extends Error {
|
|
23829
|
+
tokenRequired;
|
|
23830
|
+
constructor(message) {
|
|
23831
|
+
super(message);
|
|
23832
|
+
this.name = "MetadataConcurrencyError";
|
|
23833
|
+
this.tokenRequired = message.includes("CEREFOX_METADATA_TOKEN_REQUIRED");
|
|
23834
|
+
}
|
|
23835
|
+
};
|
|
23836
|
+
DuplicateContentError = class DuplicateContentError extends Error {
|
|
23837
|
+
existingDocumentId;
|
|
23838
|
+
constructor(existingDocumentId, message) {
|
|
23839
|
+
super(message);
|
|
23840
|
+
this.existingDocumentId = existingDocumentId;
|
|
23841
|
+
this.name = "DuplicateContentError";
|
|
23842
|
+
}
|
|
23843
|
+
};
|
|
23781
23844
|
});
|
|
23782
23845
|
|
|
23783
23846
|
// ../../_shared/server-assets/index.ts
|
|
@@ -25967,13 +26030,17 @@ async function updateDocumentFacets(supabase, opts) {
|
|
|
25967
26030
|
};
|
|
25968
26031
|
if (opts.metadata !== undefined) {
|
|
25969
26032
|
await step(async () => {
|
|
25970
|
-
const { data: doc, error } = await supabase.from("cerefox_documents").select("
|
|
26033
|
+
const { data: doc, error } = await supabase.from("cerefox_documents").select("*").eq("id", opts.documentId).is("deleted_at", null).limit(1);
|
|
25971
26034
|
if (error)
|
|
25972
26035
|
throw new Error(`Metadata read failed: ${error.message}`);
|
|
25973
26036
|
if (!doc?.length) {
|
|
25974
26037
|
throw new FacetNotFoundError(`Document not found (or in the trash): ${opts.documentId}`);
|
|
25975
26038
|
}
|
|
25976
26039
|
const stored = doc[0].metadata ?? {};
|
|
26040
|
+
const storedRevision = doc[0].metadata_revision;
|
|
26041
|
+
if (opts.expectedMetadataRevision != null && storedRevision != null && storedRevision !== opts.expectedMetadataRevision && !opts.metadataLastWriteWins) {
|
|
26042
|
+
throw new MetadataConcurrencyError(`CEREFOX_METADATA_CONFLICT: the metadata of document ${opts.documentId} changed since it was read ` + `(expected metadata_revision ${opts.expectedMetadataRevision}, current ${storedRevision}).`);
|
|
26043
|
+
}
|
|
25977
26044
|
const wanted = normalizeMetadata(opts.metadata);
|
|
25978
26045
|
if (stableStringify(stored) !== stableStringify(wanted)) {
|
|
25979
26046
|
const { error: rpcErr } = await supabase.rpc("cerefox_set_document_metadata", {
|
|
@@ -25981,10 +26048,13 @@ async function updateDocumentFacets(supabase, opts) {
|
|
|
25981
26048
|
p_metadata: wanted,
|
|
25982
26049
|
p_replace: true,
|
|
25983
26050
|
p_author: opts.author,
|
|
25984
|
-
p_author_type: opts.authorType
|
|
26051
|
+
p_author_type: opts.authorType,
|
|
26052
|
+
...metadataTokenParams(opts.expectedMetadataRevision, opts.metadataLastWriteWins)
|
|
25985
26053
|
});
|
|
25986
26054
|
if (rpcErr) {
|
|
25987
26055
|
const msg = rpcErr.message ?? String(rpcErr);
|
|
26056
|
+
if (msg.includes("CEREFOX_METADATA_"))
|
|
26057
|
+
throw new MetadataConcurrencyError(msg);
|
|
25988
26058
|
if (/not found/i.test(msg))
|
|
25989
26059
|
throw new FacetNotFoundError(msg);
|
|
25990
26060
|
throw new Error(`Metadata update failed: ${msg}`);
|
|
@@ -26362,7 +26432,7 @@ var init_compatibility = __esm(() => {
|
|
|
26362
26432
|
};
|
|
26363
26433
|
});
|
|
26364
26434
|
|
|
26365
|
-
// ../../node_modules/.bun/@hono+node-server@2.1.
|
|
26435
|
+
// ../../node_modules/.bun/@hono+node-server@2.1.4+c539cad7f494f5c9/node_modules/@hono/node-server/dist/conninfo.mjs
|
|
26366
26436
|
var getConnInfo = (c) => {
|
|
26367
26437
|
const bindings = c.env.server ? c.env.server : c.env;
|
|
26368
26438
|
const address = bindings.incoming.socket.remoteAddress;
|
|
@@ -26778,7 +26848,7 @@ var init_update_check = __esm(() => {
|
|
|
26778
26848
|
});
|
|
26779
26849
|
|
|
26780
26850
|
// ../../_shared/ef-meta/index.ts
|
|
26781
|
-
var EF_VERSION = "1.
|
|
26851
|
+
var EF_VERSION = "1.19.1", CEREFOX_VERSION = "1.19.1", EF_LAST_CHANGED = "1.19.0";
|
|
26782
26852
|
var init_ef_meta = () => {};
|
|
26783
26853
|
|
|
26784
26854
|
// ../../_shared/embeddings/onnx-embedder.ts
|
|
@@ -26933,9 +27003,7 @@ async function ensurePipeline() {
|
|
|
26933
27003
|
pipelinePromise = (async () => {
|
|
26934
27004
|
const transformers = await loadTransformers();
|
|
26935
27005
|
if (isModelCached()) {
|
|
26936
|
-
const pipe = await transformers.pipeline("feature-extraction", ONNX_MODEL_ID,
|
|
26937
|
-
dtype: ONNX_MODEL_DTYPE
|
|
26938
|
-
});
|
|
27006
|
+
const pipe = await transformers.pipeline("feature-extraction", ONNX_MODEL_ID, PIPELINE_OPTIONS);
|
|
26939
27007
|
return pipe;
|
|
26940
27008
|
}
|
|
26941
27009
|
const mb = ONNX_MODEL_APPROX_MB;
|
|
@@ -27016,9 +27084,7 @@ async function ensurePipeline() {
|
|
|
27016
27084
|
}
|
|
27017
27085
|
};
|
|
27018
27086
|
await downloadModelFiles(String(transformers.env.remoteHost ?? "https://huggingface.co/"), (file, loaded, total) => progressCallback({ status: "progress", file, loaded, total }), (file, size) => progressCallback({ status: "done", file, total: size }));
|
|
27019
|
-
const pipe = await transformers.pipeline("feature-extraction", ONNX_MODEL_ID,
|
|
27020
|
-
dtype: ONNX_MODEL_DTYPE
|
|
27021
|
-
});
|
|
27087
|
+
const pipe = await transformers.pipeline("feature-extraction", ONNX_MODEL_ID, PIPELINE_OPTIONS);
|
|
27022
27088
|
process.stderr.write(`[cerefox-embed] embedder ready.
|
|
27023
27089
|
`);
|
|
27024
27090
|
return pipe;
|
|
@@ -27061,7 +27127,7 @@ async function onnxEmbed(texts, role) {
|
|
|
27061
27127
|
}
|
|
27062
27128
|
return vectors;
|
|
27063
27129
|
}
|
|
27064
|
-
var ONNX_MODEL_ID = "nomic-ai/nomic-embed-text-v1.5", ONNX_MODEL_NAME = "nomic-embed-text-v1.5", ONNX_MODEL_DTYPE = "q8", ONNX_MODEL_DIM = 768, ONNX_MODEL_APPROX_MB = 130, MODEL_REPO_FILES, MODEL_FILES, EmbedderDownloadError, DOWNLOAD_ATTEMPTS = 6, SEGMENT_BYTES, REQUEST_TIMEOUT_MS = 120000, transformersModule = null, pipelinePromise = null, DEFAULT_ONNX_BATCH =
|
|
27130
|
+
var ONNX_MODEL_ID = "nomic-ai/nomic-embed-text-v1.5", ONNX_MODEL_NAME = "nomic-embed-text-v1.5", ONNX_MODEL_DTYPE = "q8", ONNX_MODEL_DIM = 768, ONNX_MODEL_APPROX_MB = 130, MODEL_REPO_FILES, MODEL_FILES, EmbedderDownloadError, DOWNLOAD_ATTEMPTS = 6, SEGMENT_BYTES, REQUEST_TIMEOUT_MS = 120000, transformersModule = null, pipelinePromise = null, PIPELINE_OPTIONS, DEFAULT_ONNX_BATCH = 1;
|
|
27065
27131
|
var init_onnx_embedder = __esm(() => {
|
|
27066
27132
|
MODEL_REPO_FILES = [
|
|
27067
27133
|
"config.json",
|
|
@@ -27078,6 +27144,10 @@ var init_onnx_embedder = __esm(() => {
|
|
|
27078
27144
|
}
|
|
27079
27145
|
};
|
|
27080
27146
|
SEGMENT_BYTES = 4 * 1024 * 1024;
|
|
27147
|
+
PIPELINE_OPTIONS = {
|
|
27148
|
+
dtype: ONNX_MODEL_DTYPE,
|
|
27149
|
+
session_options: { enableCpuMemArena: false }
|
|
27150
|
+
};
|
|
27081
27151
|
});
|
|
27082
27152
|
|
|
27083
27153
|
// ../../_shared/embeddings/index.ts
|
|
@@ -50983,7 +51053,8 @@ async function handler(supabase, args, ctx) {
|
|
|
50983
51053
|
const lines = entries.map((e) => {
|
|
50984
51054
|
const docLabel = auditDocLabel(e.doc_title, e.document_id, e.operation);
|
|
50985
51055
|
const sizeInfo = e.size_before != null && e.size_after != null ? ` | ${e.size_before} -> ${e.size_after} chars` : e.size_after != null ? ` | ${e.size_after} chars` : "";
|
|
50986
|
-
|
|
51056
|
+
const change = metadataChangeSummary(e.metadata_before, e.metadata_after);
|
|
51057
|
+
return `${utcStamp2(e.created_at)} | ${e.operation} | ${e.author} (${e.author_type}) | ${docLabel}${sizeInfo} | ${e.description}${change ? ` | ${change}` : ""}`;
|
|
50987
51058
|
});
|
|
50988
51059
|
return `Audit log (${entries.length} entries, newest first):
|
|
50989
51060
|
|
|
@@ -51510,6 +51581,8 @@ async function handler4(supabase, args, ctx) {
|
|
|
51510
51581
|
return JSON.stringify({
|
|
51511
51582
|
title: row.doc_title ?? "Untitled",
|
|
51512
51583
|
content_hash: archived ? null : row.content_hash ?? null,
|
|
51584
|
+
metadata: row.doc_metadata ?? {},
|
|
51585
|
+
metadata_revision: archived ? null : row.metadata_revision ?? null,
|
|
51513
51586
|
total_chars: row.total_chars ?? (row.full_content ?? "").length,
|
|
51514
51587
|
outline: nodes,
|
|
51515
51588
|
note: archived ? "This is an ARCHIVED version's structure, so no content_hash is returned: these anchors describe the old version and must not be used to edit the current one. Re-read without version_id to edit." : nodes.length === 0 ? "This document has no headings, so it has no anchors: only end_of_document inserts apply." : "Use a path as anchor_heading in cerefox_insert / cerefox_edit; content_hash is your expected_content_hash."
|
|
@@ -51536,7 +51609,8 @@ async function handler4(supabase, args, ctx) {
|
|
|
51536
51609
|
}, null, 2);
|
|
51537
51610
|
}
|
|
51538
51611
|
const label = version_id !== null ? " (archived version)" : " (current)";
|
|
51539
|
-
const
|
|
51612
|
+
const revision = version_id === null && row.metadata_revision != null ? ` · metadata_revision: ${row.metadata_revision}` : "";
|
|
51613
|
+
const hashLine = row.content_hash ? `content_hash: ${row.content_hash}${revision}
|
|
51540
51614
|
|
|
51541
51615
|
` : "";
|
|
51542
51616
|
return `# ${row.doc_title ?? "Untitled"}${label}
|
|
@@ -51716,9 +51790,6 @@ async function applyAndWrite(supabase, ctx, args) {
|
|
|
51716
51790
|
if (message.includes("CEREFOX_CONFLICT")) {
|
|
51717
51791
|
throw conflictError2(documentId, expectedHash, extractConflictHashes(message).current);
|
|
51718
51792
|
}
|
|
51719
|
-
if (message.includes("cerefox_documents_hash_unique")) {
|
|
51720
|
-
throw new Error(`This edit would make "${doc.title}" (id: ${documentId}) byte-identical to another ` + `document in the store, and content must be unique. No write was performed. ` + `Usually this means the two documents have converged and one should be removed or ` + `merged, or that this edit was already applied to the other one — ` + `cerefox_search for the resulting content to find it.`);
|
|
51721
|
-
}
|
|
51722
51793
|
if (message.includes("CEREFOX_UNRESOLVED_LINKS")) {
|
|
51723
51794
|
const ids = message.match(/do not exist: ([^.]+)\./)?.[1] ?? "(unparsed)";
|
|
51724
51795
|
throw new Error(`Edit rejected — this edit introduces link(s) to document id(s) that do not ` + `exist: ${ids}. The UUIDs are almost certainly mangled — re-read the source ` + `you copied each link from, correct the id(s), and retry. Do not retry ` + `unchanged. Deliberate examples belong in code formatting (backticks).`);
|
|
@@ -51729,6 +51800,9 @@ async function applyAndWrite(supabase, ctx, args) {
|
|
|
51729
51800
|
if (isMissingFunctionError(message, "cerefox_ingest_document")) {
|
|
51730
51801
|
throw new Error(`This server is behind: partial edits need schema 0.11.0 or newer. ` + `Run \`cerefox server deploy\`, then retry. (${message})`);
|
|
51731
51802
|
}
|
|
51803
|
+
const legacy = legacyContentUniqueError(message);
|
|
51804
|
+
if (legacy)
|
|
51805
|
+
throw legacy;
|
|
51732
51806
|
throw new Error(`Edit failed: ${message}`);
|
|
51733
51807
|
}
|
|
51734
51808
|
const row = data?.[0] ?? undefined;
|
|
@@ -51935,12 +52009,12 @@ var init_partial_edits2 = __esm(() => {
|
|
|
51935
52009
|
});
|
|
51936
52010
|
|
|
51937
52011
|
// ../../_shared/mcp-tools/get-help-content.ts
|
|
51938
|
-
var HELP_FULL = '# Cerefox Knowledge Base -- Agent Quick Reference\n\nCerefox is a persistent, shared knowledge base. You have **15 core MCP tools** (14 with CLI equivalents — `cerefox_get_help` is MCP-only), plus 4 dormant relation tools that appear only when `relations_enabled` is on. For the full guide, search Cerefox for "How AI Agents Use Cerefox" or call `cerefox_get_help` to retrieve this content over MCP.\n\n## Tools\n\n| Tool | Purpose | Key params |\n|------|---------|------------|\n| `cerefox_search` | Find documents (hybrid FTS + semantic) | `query` (required), `project_name`, `metadata_filter`, `author` |\n| `cerefox_ingest` | Save or update a document | `title`, `content` (required), `document_id` (update by ID), `expected_content_hash` (**required on content updates** — see rule 10), `last_write_wins`, `update_if_exists`, `project_name` (single, non-destructive add on update), `project_names` (list, destructive replace on update), `metadata` (omit on update to keep existing tags; `{}` clears), `author` |\n| `cerefox_insert` | **Add** to a document without resending it. Cannot destroy content. | `document_id`, `text`, `position` (`end_of_document`/`end_of_section`/`after_heading`/`before_heading`), `expected_content_hash` (required), `anchor_heading` (unless `end_of_document`), `section_part`, `author` |\n| `cerefox_edit` | **Change** parts of a document: 1..n operations applied atomically | `document_id`, `operations` (`insert`/`replace_section`/`delete_section`/`rename_section`), `expected_content_hash` (required), `author` |\n| `cerefox_delete_document` | **Soft**-delete a document (to trash; excluded from search; permanent purge is human-only) | `document_id`, `expected_content_hash` (**required** — a delete must follow a read), `reason` (recorded in the audit log — give one), `author` |\n| `cerefox_restore_document` | Restore a soft-deleted document from the trash (audited inverse of delete; no-op if not deleted) | `document_id` (required), `reason` (recorded in the audit log), `author` |\n| `cerefox_get_document` | Get full document by ID (header includes `content_hash` — the update token), or with `outline: true` just its heading paths, sizes and hash, or with `section: "## Heading"` one section\'s text | `document_id` (required), `outline`, `section`, `section_part`, `author` |\n| `cerefox_list_versions` | Version history of a document | `document_id` (required), `author` |\n| `cerefox_set_relation` ⚑ | Link two documents (`source --rel_type--> target`) | `source_id`, `target_id`, `rel_type` (required), `metadata`, `author` |\n| `cerefox_delete_relation` ⚑ | Remove a relation | `source_id`, `target_id`, `rel_type`, `author` |\n| `cerefox_get_relations` ⚑ | All relations touching a document, both directions | `document_id` |\n| `cerefox_get_neighbors` ⚑ | Walk the graph along ONE relation type | `document_id`, `rel_type` (required), `depth`, `from_time`, `to_time`, `limit` |\n| `cerefox_metadata_search` | Find or list docs by metadata, project, or time (no text query) | `metadata_filter`, `project_name` (list a project\'s docs), `updated_since`, `include_content` — **at least one** of metadata_filter/project_name/updated_since/created_since |\n| `cerefox_list_metadata_keys` | Discover available metadata keys | (none required) |\n| `cerefox_list_projects` | List all projects | (none required) |\n| `cerefox_set_document_metadata` | Change tags WITHOUT resending content. **Merges** by default; a `null` value removes a key | `document_id`, `metadata` (required), `replace` (rare: set exactly this object), `author` |\n| `cerefox_set_document_projects` | Set doc\'s project memberships to exactly the given list (destructive replace; metadata-only, no content change) | `document_id`, `project_names` (required), `author` |\n| `cerefox_get_audit_log` | Query write operation history | `document_id`, `by_author` (filter), `operation`, `since`, `author` |\n| `cerefox_get_help` | Retrieve Cerefox conventions (this reference) over MCP. **Call this whenever uncertain.** | `topic` (optional, case-insensitive H2 substring match) |\n\n⚑ **Opt-in — usually absent.** The four relation tools are hidden unless the\noperator enables them (`relations_enabled`). **Trust your own tool list**: if\nthey are not in it, the feature is switched off for this deployment. That is\nnormal, not an error, and not something to work around.\n\n## Editing part of a document (prefer this over re-sending)\n\n**Re-sending a whole document to change part of it is the main way agents lose\ndata.** You have to reproduce the untouched remainder verbatim, and any drift\nsilently rewrites content nobody asked you to touch — which the caller cannot\ndiff. Use the partial-edit tools instead:\n\n1. **Learn the anchors** — `cerefox_get_document(document_id, outline: true)`.\n Returns heading paths, per-section sizes and the `content_hash`, without the\n body. The paths it returns are exactly what `anchor_heading` accepts.\n2. **Add** → `cerefox_insert`. `end_of_document` is a plain append;\n `end_of_section` adds inside a named section. It is structurally incapable of\n removing anything, so "I meant to append" cannot become "I replaced the file".\n3. **Look before you overwrite** — `cerefox_get_document(document_id,\n section: "## Heading")` returns exactly the text a `replace_section` on that\n anchor would destroy. The outline gives you a section\'s *size*, never its\n *text*, so on a document you did not write yourself this is the difference\n between a replace and a blind overwrite.\n4. **Change or remove** → `cerefox_edit`. Put changes that belong together in\n ONE call: they apply atomically, so a table row and the total it feeds cannot\n end up disagreeing. To change a single line, `replace_section` on its\n smallest enclosing heading — that is the intended granularity, not a\n workaround. To fix a stale heading (`## OPEN TODOs (as of ...)`), use\n `rename_section`: it changes the heading text and leaves the body and\n position alone.\n5. All of them require `expected_content_hash` and **have no last-write-wins**. A\n conflict means someone else changed the document; re-read and decide, do not\n force it.\n\n**A section runs to the next same-or-higher heading, or to the end of the\ndocument.** So `end_of_document` inserts land inside the *last* section, and\nreplacing or deleting that section removes them too. A large shrink in the\nresponse is your warning; `cerefox_list_versions` has the previous content.\n\n**When an anchor is ambiguous the tool refuses and hands you the options** — a\nrepeated heading returns the qualifying paths, and a section with both its own\ncontent and sub-sections returns both `section_part` choices. That is a\nrecoverable answer, not a failure: retry with what it gave you.\n\n## Essential Rules\n\n1. **Search before ingesting** -- check if the document exists first.\n2. **Prefer ID-based updates** -- pass `document_id` from search results for deterministic updates. Falls back to title-matching with `update_if_exists: true`.\n3. **Set `author`** to your name on every call, reads and writes alike (e.g., "Claude Code", "archiver"). Same parameter on every tool. (`requestor` is still accepted everywhere as the pre-1.13.1 alias.) On the CLI it is `--author` on every command too (plus `--author-type` on writes); or rely on `CEREFOX_AUTHOR_NAME`/`CEREFOX_AUTHOR_TYPE` env vars set in the user\'s `.env`.\n4. **Use `document_id` from search results** `[id: uuid]` for get_document and list_versions.\n5. **`max_bytes` has to fit a whole document.** Search returns COMPLETE documents, so a budget smaller than the top hit fits nothing. You get a header-only list saying so (never "No results found." — that means the store really has nothing). Raise `max_bytes`, or read one document with `cerefox_get_document` using `outline: true` or `section`.\n6. **Add metadata** -- at minimum `type` ("decision-log", "research", "design-doc") and `status` ("active", "draft").\n7. **Write for retrieval: the title does real work.** The document title is indexed at the **highest weight** *and* prepended to every chunk before it is embedded, so it steers both halves of hybrid search (keyword and semantic) for every chunk in the document. Name the document with the distinctive terms someone would actually search for -- "Cerefox Response Size Limits", not "Notes" or "Update 3". Renaming re-indexes and re-embeds, so correcting a vague title is cheap and takes effect immediately. Write the characters themselves: `&` and `<>`, never `&` or `<>` (entities are stored literally and the write reply will say so). Inside the content, write structured Markdown with H1/H2/H3 headings: the chunker follows them, and a chunk\'s own heading carries the same weight as the title.\n8. **Deletes are soft (recoverable); permanent purge is web-UI-only.** `cerefox_delete_document` requires the document\'s `content_hash` as you read it (read before you delete) and takes a `reason` — give one; it is what the human reviewing the trash sees. `cerefox_restore_document` undoes a mistaken delete (also audited, also takes a `reason`). Always surface deletes AND restores to the user. Once a human purges from the web UI, the document is gone for good; so is one auto-purged after `trash_retention_days`, if the operator has turned trash auto-purge on.\n9. **Cross-doc links inside content**: **always use `[Text](document-uuid)`.** UUIDs are the only fully reliable link form — stable across title changes, never ambiguous, no encoding gotchas. Every `cerefox_search` result shows `[id: <uuid>]` after the title; grab it and use it. Title-based linking (`[Text](<Title With Spaces>)`) is fragile (breaks on colons, parens, ampersands, brackets — silently navigates to wrong page) — **don\'t write title-based links**; do an extra search to get the UUID instead. Repo-path forms (`[Text](docs/path.md)`) exist for repo-ingested files; don\'t construct manually. **The server validates `](uuid)` links on every write** (v1.7.0): a link to a nonexistent id rejects the write, naming the offender — that means you mangled the UUID; re-read the source and correct it, do not retry unchanged. Example ids go in backticks (code is not validated). `[[Wikilinks]]` may dangle. See `AGENT_GUIDE.md → Writing linkable content` for the full rule.\n10. **Concurrency: content updates require `expected_content_hash`.** Pass the `content_hash` you last saw — every read shows one (`cerefox_get_document` incl. outline mode, `cerefox_search`, `cerefox_metadata_search`) and **every write returns the new one, including create** (v1.3.0, #189), so after writing you already hold the token for your next edit; no re-read needed. If it\'s stale you get a **conflict** — re-read the document, merge your changes into the latest content, retry with the new hash. **Never resolve a conflict by overwriting blindly** — the current content includes another writer\'s work. `last_write_wins: true` skips the check; use it ONLY when an external source of truth makes conflicts meaningless (file re-sync), never to silence a conflict.\n11. **Search: prefer a few distinctive terms; heed `below confidence`.** When nothing clears the relevance threshold, `cerefox_search` returns the closest candidates prefixed with a `below confidence` warning instead of an empty set — that flag means **weak signal, not absent knowledge**: check the candidates\' scores and titles before concluding the KB lacks the content. A truly empty response means nothing even weakly related exists.\n12. **Relations express how documents relate; lifecycle tells you if knowledge is still good.** Use `cerefox_set_relation` when one document supersedes, contradicts, references, or continues another. `supersedes` marks the target **superseded**; `contradicts` marks **both** stale; `related_to`/`duplicates`/`contradicts` are symmetric (both directions written). Any other type string is accepted without special behavior. When a search result or `cerefox_get_relations` shows a neighbour marked `[superseded]` or `[stale]`, say so rather than presenting it as current.\n13. **Project memberships — non-destructive by default**: on `cerefox_ingest` updates, **`project_name` (singular) is a non-destructive add** (ensures membership, preserves others). Use **`project_names` (list)** when you want to set the doc\'s full project set in one call (destructive replace). For metadata-only project changes without writing content, use **`cerefox_set_document_projects(document_id, project_names)`** — that tool is the destructive-replace contract made explicit. Never call `cerefox_set_document_projects` with a single name when you mean "add" — that would REMOVE the doc from all other projects. When in doubt, use `cerefox_ingest` with singular `project_name`.\n\n## Update Workflow (ID-based -- preferred)\n\n```\nsearch("topic") -> find doc [id: abc123] -> get_document(abc123) -> note its content_hash -> modify ->\ningest(title="Same Title", content="...", document_id="abc123",\n expected_content_hash="<the hash you read>", author="my-agent")\n```\n\nOn a **conflict** error: get_document again (fresh content + fresh hash) -> merge your changes -> retry with the new hash.\n\n## Update Workflow (title-based -- fallback)\n\n```\nsearch("topic") -> find doc (note its hash) -> modify ->\ningest(title="Same Title", content="...", update_if_exists=true,\n expected_content_hash="<the hash you read>", author="my-agent")\n```\n\n## Catch-Up Workflow\n\n```\nmetadata_search(metadata_filter={"type": "decision-log"}, updated_since="2026-03-28T00:00:00Z")\n```\n\n## CLI fallback (when MCP is unavailable)\n\nIf `cerefox_search` is not in your tool list, your user has likely installed the Cerefox CLI. The canonical invocation is plain **`cerefox <subcommand>`** (the TypeScript CLI, installed via `npm install -g @cerefox/memory`). It uses a resource-verb shape (`cerefox document get`, `cerefox project list`, …).\n\nSame operations, same conventions. Full reference: [`docs/guides/cli.md`](docs/guides/cli.md). CLI flag names match MCP parameter names exactly (e.g. `metadata_filter` ↔ `--metadata-filter`); common flags also have single-letter short forms (`-f`, `-p`, `-c`, `-m`, `-u`, `-a`). Use the canonical long name (what `--help` shows) or its short form — there are no long-form aliases like `--filter` or `--count`.\n\n| MCP tool | CLI |\n|---|---|\n| `cerefox_search` | `cerefox search "<q>" --author "<your-name>"` |\n| `cerefox_ingest` (paste) | `printf \'...\' \\| cerefox document ingest --paste --title "<t>" --author "<your-name>" --author-type agent` |\n| `cerefox_ingest` (update by ID) | `printf \'...\' \\| cerefox document ingest --paste --title "<t>" --document-id "<uuid>" --expected-content-hash "<hash>" --author "<your-name>" --author-type agent` |\n| `cerefox_get_document` | `cerefox document get <id> --version-id <vid> --author "<your-name>"` |\n| `cerefox_list_versions` | `cerefox document version list <id> --author "<your-name>"` |\n| `cerefox_list_projects` | `cerefox project list --author "<your-name>"` |\n| `cerefox_list_metadata_keys` | `cerefox metadata keys` |\n| `cerefox_insert` | `cerefox document insert <id> -t "<text>" -p <position> -a "<anchor-heading>" -e "<hash>" --author "<your-name>" --author-type agent` |\n| `cerefox_edit` | `cerefox document edit-parts <id> --operations \'<json>\' -e "<hash>" --author "<your-name>" --author-type agent` |\n| `cerefox_delete_document` | `cerefox document delete <id> --reason "<why>" --author "<your-name>" --author-type agent --yes` (confirms interactively instead of requiring the hash) |\n| `cerefox_restore_document` | `cerefox document restore <id> --reason "<why>" --author "<your-name>" --author-type agent` |\n| `cerefox_metadata_search` | `cerefox metadata search --metadata-filter \'<json>\' --author "<your-name>"` (list a project: `cerefox document list --project <name>`) |\n| `cerefox_set_document_metadata` | `cerefox document set-metadata <id> --set key=value` (also `--remove key`, `--json \'{...}\'`, `--replace`) |\n| `cerefox_set_document_projects` | `cerefox document set-projects <id> <name...> --author "<your-name>" --author-type agent` (or `--clear` to remove all) |\n| `cerefox_get_audit_log` | `cerefox audit list --author "<your-name>"` (add `--json` for scripted access) |\n| `cerefox_get_help` | `cerefox guides show agent-quick-reference` (or `cerefox guides list` for the full bundled-docs index) |\n\n**Set identity on every call**, exactly as you would on MCP:\n- Writes (`document ingest`, `document ingest-dir`): `--author "<your-name>" --author-type agent`\n- Reads: `--author "<your-name>"` (the same flag; `--requestor` still works as a hidden alias)\n\nOr have your user set `CEREFOX_AUTHOR_NAME` / `CEREFOX_AUTHOR_TYPE` / `CEREFOX_REQUESTOR_NAME` in their `.env` to apply defaults once.\n\n## Timestamps are UTC\n\nEvery timestamp Cerefox returns — `created_at` on audit entries, version\nhistory, document metadata — is **UTC**, and now carries its `Z` marker so it\ncannot be mistaken for local time.\n\n**When you write a date into a document\'s CONTENT, use your own clock, not a\nCerefox timestamp.** These are different things: a timestamp records when the\nserver stored something; a date in a log entry or a heading is authored content\nand belongs to your timezone. An agent working a Pacific afternoon read\n`2026-08-11` from version history, wrote "8/11" into its entries, and put a\nday\'s work in the future — the timestamp was correct, and copying it into\ncontent was not.\n\nCerefox deliberately does not convert to local time on the API or MCP paths.\n"Local" has no server-side meaning: the remote MCP server runs in a cloud\nfunction whose local time *is* UTC, while a local MCP server runs in yours, so\nthe same document would report two different times depending on transport. The\nweb UI converts because a browser knows the viewer\'s timezone; nothing\nserver-side does.\n\n## Mistakes that have actually happened\n\nEach of these comes from a real agent session, and each is easy to make.\n\n- **`cerefox_ingest` always replaces the ENTIRE document.** Never a section.\n Before sending, check that the tool name matches the intent: if the intent is\n "change one section", the call is `cerefox_edit` with `replace_section`. A\n section-sized edit sent as a full ingest truncated a 13,000-character index to\n a single word. It was recovered from version history within the minute, but\n only because it was noticed immediately.\n\n- **Do not include the anchor\'s own heading in your text.** `replace_section`\n keeps the heading and `insert` places your text inside the section, so\n including it produces two. This is now refused rather than silently applied,\n but the shape is worth knowing: it happened twice in one session, the second\n time while trying to repair the first. A *deeper* sub-heading inside your text\n is fine.\n\n- **Content between sections belongs to the section ABOVE it.** A section runs\n to the next heading of the same or higher level, so a `---` rule, a note, or\n any trailing text sitting just above the next heading is part of the section\n before it — even when it visually reads as belonging below. Replacing that\n section takes it too. An agent hit exactly this: a `---` that separated two\n major sections disappeared when the section above it was replaced. The write\n was correct by the addressing rules; the surprise is that "the end of this\n section" is further down the page than it looks. Note the loss warning will\n not catch it if your replacement text is longer than what it replaced, since\n there is then no net loss to report.\n\n- **To change only tags, use `cerefox_set_document_metadata`, never `cerefox_ingest`.**\n Ingest replaces the whole document, so re-sending it to set one tag carries the\n full transcription risk for no reason. The metadata tool merges: the keys you\n pass are set, everything else is left alone, so you do not need to read the\n document first and cannot drop a tag another agent set. Pass `null` as a value\n to remove a key.\n\n- **Never partial-edit to fix a partial edit.** If a write leaves unexpected\n structure, stop. Use `cerefox_list_versions`, retrieve the last good version,\n and re-ingest cleanly. Repairing edits with more edits compounds the damage.\n\n- **A rejected batch is safe.** Operations in one `cerefox_edit` are\n all-or-nothing: if any is invalid, nothing is written. A refusal costs you a\n retry, not data — so prefer one call for changes that belong together, and do\n not split a batch to "make it more likely to succeed".\n\n- **Read before replacing.** `cerefox_get_document(section: "## Heading")`\n returns exactly what a `replace_section` on that anchor would overwrite. Use it\n for any section you did not write in this session. The outline gives a\n section\'s *size*, never its *text*.\n\n- **Verify after writing** — read the result back before reporting success, and\n report what the read actually shows.\n\n- **Partial edits cannot change a document\'s stored TITLE.** `rename_section`\n changes a heading inside the content; the title is a separate field and still\n needs `cerefox_ingest`.\n\n- **If a capability seems missing from one server, suspect your client first.**\n Local and remote run the same code. **Every `cerefox_get_help()` response\n begins with the server\'s version and the operations it registers** — you do\n not need a special topic, and the *absence* of that block is itself an answer:\n a server that does not print it predates v1.5.0. If that\n disagrees with your tool list, the client is holding a list it fetched before\n an upgrade — clients cache it at connect time. Ask the user to restart the\n client. Do not record a capability difference between servers as a fact; every\n such report so far has been a stale client.\n- Long inline bodies can arrive with literal `\\n`/`\\"` (the author over-escaped; Cerefox stores bytes faithfully). For long or quote-dense content, ingest from a file or build incrementally with `cerefox_insert`; read back multi-line writes.\n', HELP_SECTIONS, HELP_SECTION_HEADINGS;
|
|
52012
|
+
var HELP_FULL = '# Cerefox Knowledge Base -- Agent Quick Reference\n\nCerefox is a persistent, shared knowledge base. You have **15 core MCP tools** (14 with CLI equivalents — `cerefox_get_help` is MCP-only), plus 4 dormant relation tools that appear only when `relations_enabled` is on. For the full guide, search Cerefox for "How AI Agents Use Cerefox" or call `cerefox_get_help` to retrieve this content over MCP.\n\n## Tools\n\n| Tool | Purpose | Key params |\n|------|---------|------------|\n| `cerefox_search` | Find documents (hybrid FTS + semantic) | `query` (required), `project_name`, `metadata_filter`, `author` |\n| `cerefox_ingest` | Save or update a document | `title`, `content` (required), `document_id` (update by ID), `expected_content_hash` (**required on content updates** — see rule 10), `last_write_wins`, `update_if_exists`, `project_name` (single, non-destructive add on update), `project_names` (list, destructive replace on update), `metadata` (on update it **merges**: `null` removes a key, omitted keys are kept), `expected_metadata_revision` (optional, see rule 10), `author` |\n| `cerefox_insert` | **Add** to a document without resending it. Cannot destroy content. | `document_id`, `text`, `position` (`end_of_document`/`end_of_section`/`after_heading`/`before_heading`), `expected_content_hash` (required), `anchor_heading` (unless `end_of_document`), `section_part`, `author` |\n| `cerefox_edit` | **Change** parts of a document: 1..n operations applied atomically | `document_id`, `operations` (`insert`/`replace_section`/`delete_section`/`rename_section`), `expected_content_hash` (required), `author` |\n| `cerefox_delete_document` | **Soft**-delete a document (to trash; excluded from search; permanent purge is human-only) | `document_id`, `expected_content_hash` (**required** — a delete must follow a read), `reason` (recorded in the audit log — give one), `author` |\n| `cerefox_restore_document` | Restore a soft-deleted document from the trash (audited inverse of delete; no-op if not deleted) | `document_id` (required), `reason` (recorded in the audit log), `author` |\n| `cerefox_get_document` | Get full document by ID (header includes `content_hash` — the update token), or with `outline: true` just its heading paths, sizes and hash, or with `section: "## Heading"` one section\'s text | `document_id` (required), `outline`, `section`, `section_part`, `author` |\n| `cerefox_list_versions` | Version history of a document | `document_id` (required), `author` |\n| `cerefox_set_relation` ⚑ | Link two documents (`source --rel_type--> target`) | `source_id`, `target_id`, `rel_type` (required), `metadata`, `author` |\n| `cerefox_delete_relation` ⚑ | Remove a relation | `source_id`, `target_id`, `rel_type`, `author` |\n| `cerefox_get_relations` ⚑ | All relations touching a document, both directions | `document_id` |\n| `cerefox_get_neighbors` ⚑ | Walk the graph along ONE relation type | `document_id`, `rel_type` (required), `depth`, `from_time`, `to_time`, `limit` |\n| `cerefox_metadata_search` | Find or list docs by metadata, project, or time (no text query) | `metadata_filter`, `project_name` (list a project\'s docs), `updated_since`, `include_content` — **at least one** of metadata_filter/project_name/updated_since/created_since |\n| `cerefox_list_metadata_keys` | Discover available metadata keys | (none required) |\n| `cerefox_list_projects` | List all projects | (none required) |\n| `cerefox_set_document_metadata` | Change tags WITHOUT resending content. **Merges** by default; a `null` value removes a key | `document_id`, `metadata` (required), `replace` (rare: set exactly this object; needs `expected_metadata_revision`), `expected_metadata_revision`, `author` |\n| `cerefox_set_document_projects` | Set doc\'s project memberships to exactly the given list (destructive replace; metadata-only, no content change) | `document_id`, `project_names` (required), `author` |\n| `cerefox_get_audit_log` | Query write operation history | `document_id`, `by_author` (filter), `operation`, `since`, `author` |\n| `cerefox_get_help` | Retrieve Cerefox conventions (this reference) over MCP. **Call this whenever uncertain.** | `topic` (optional, case-insensitive H2 substring match) |\n\n⚑ **Opt-in — usually absent.** The four relation tools are hidden unless the\noperator enables them (`relations_enabled`). **Trust your own tool list**: if\nthey are not in it, the feature is switched off for this deployment. That is\nnormal, not an error, and not something to work around.\n\n## Editing part of a document (prefer this over re-sending)\n\n**Re-sending a whole document to change part of it is the main way agents lose\ndata.** You have to reproduce the untouched remainder verbatim, and any drift\nsilently rewrites content nobody asked you to touch — which the caller cannot\ndiff. Use the partial-edit tools instead:\n\n1. **Learn the anchors** — `cerefox_get_document(document_id, outline: true)`.\n Returns heading paths, per-section sizes and the `content_hash`, without the\n body. The paths it returns are exactly what `anchor_heading` accepts.\n2. **Add** → `cerefox_insert`. `end_of_document` is a plain append;\n `end_of_section` adds inside a named section. It is structurally incapable of\n removing anything, so "I meant to append" cannot become "I replaced the file".\n3. **Look before you overwrite** — `cerefox_get_document(document_id,\n section: "## Heading")` returns exactly the text a `replace_section` on that\n anchor would destroy. The outline gives you a section\'s *size*, never its\n *text*, so on a document you did not write yourself this is the difference\n between a replace and a blind overwrite.\n4. **Change or remove** → `cerefox_edit`. Put changes that belong together in\n ONE call: they apply atomically, so a table row and the total it feeds cannot\n end up disagreeing. To change a single line, `replace_section` on its\n smallest enclosing heading — that is the intended granularity, not a\n workaround. To fix a stale heading (`## OPEN TODOs (as of ...)`), use\n `rename_section`: it changes the heading text and leaves the body and\n position alone.\n5. All of them require `expected_content_hash` and **have no last-write-wins**. A\n conflict means someone else changed the document; re-read and decide, do not\n force it.\n\n**A section runs to the next same-or-higher heading, or to the end of the\ndocument.** So `end_of_document` inserts land inside the *last* section, and\nreplacing or deleting that section removes them too. A large shrink in the\nresponse is your warning; `cerefox_list_versions` has the previous content.\n\n**When an anchor is ambiguous the tool refuses and hands you the options** — a\nrepeated heading returns the qualifying paths, and a section with both its own\ncontent and sub-sections returns both `section_part` choices. That is a\nrecoverable answer, not a failure: retry with what it gave you.\n\n## Essential Rules\n\n1. **Search before ingesting** -- check if the document exists first.\n2. **Prefer ID-based updates** -- pass `document_id` from search results for deterministic updates. Falls back to title-matching with `update_if_exists: true`.\n3. **Set `author`** to your name on every call, reads and writes alike (e.g., "Claude Code", "archiver"). Same parameter on every tool. (`requestor` is still accepted everywhere as the pre-1.13.1 alias.) On the CLI it is `--author` on every command too (plus `--author-type` on writes); or rely on `CEREFOX_AUTHOR_NAME`/`CEREFOX_AUTHOR_TYPE` env vars set in the user\'s `.env`.\n4. **Use `document_id` from search results** `[id: uuid]` for get_document and list_versions.\n5. **`max_bytes` has to fit a whole document.** Search returns COMPLETE documents, so a budget smaller than the top hit fits nothing. You get a header-only list saying so (never "No results found." — that means the store really has nothing). Raise `max_bytes`, or read one document with `cerefox_get_document` using `outline: true` or `section`.\n6. **Add metadata** -- at minimum `type` ("decision-log", "research", "design-doc") and `status` ("active", "draft").\n7. **Write for retrieval: the title does real work.** The document title is indexed at the **highest weight** *and* prepended to every chunk before it is embedded, so it steers both halves of hybrid search (keyword and semantic) for every chunk in the document. Name the document with the distinctive terms someone would actually search for -- "Cerefox Response Size Limits", not "Notes" or "Update 3". Renaming re-indexes and re-embeds, so correcting a vague title is cheap and takes effect immediately. Write the characters themselves: `&` and `<>`, never `&` or `<>` (entities are stored literally and the write reply will say so). Inside the content, write structured Markdown with H1/H2/H3 headings: the chunker follows them, and a chunk\'s own heading carries the same weight as the title.\n8. **Deletes are soft (recoverable); permanent purge is web-UI-only.** `cerefox_delete_document` requires the document\'s `content_hash` as you read it (read before you delete) and takes a `reason` — give one; it is what the human reviewing the trash sees. `cerefox_restore_document` undoes a mistaken delete (also audited, also takes a `reason`). Always surface deletes AND restores to the user. Once a human purges from the web UI, the document is gone for good; so is one auto-purged after `trash_retention_days`, if the operator has turned trash auto-purge on.\n9. **Cross-doc links inside content**: **always use `[Text](document-uuid)`.** UUIDs are the only fully reliable link form — stable across title changes, never ambiguous, no encoding gotchas. Every `cerefox_search` result shows `[id: <uuid>]` after the title; grab it and use it. Title-based linking (`[Text](<Title With Spaces>)`) is fragile (breaks on colons, parens, ampersands, brackets — silently navigates to wrong page) — **don\'t write title-based links**; do an extra search to get the UUID instead. Repo-path forms (`[Text](docs/path.md)`) exist for repo-ingested files; don\'t construct manually. **The server validates `](uuid)` links on every write** (v1.7.0): a link to a nonexistent id rejects the write, naming the offender — that means you mangled the UUID; re-read the source and correct it, do not retry unchanged. Example ids go in backticks (code is not validated). `[[Wikilinks]]` may dangle. See `AGENT_GUIDE.md → Writing linkable content` for the full rule.\n10. **Concurrency: content updates require `expected_content_hash`.** Pass the `content_hash` you last saw — every read shows one (`cerefox_get_document` incl. outline mode, `cerefox_search`, `cerefox_metadata_search`) and **every write returns the new one, including create** (v1.3.0, #189), so after writing you already hold the token for your next edit; no re-read needed. If it\'s stale you get a **conflict** — re-read the document, merge your changes into the latest content, retry with the new hash. **Never resolve a conflict by overwriting blindly** — the current content includes another writer\'s work. `last_write_wins: true` skips the check; use it ONLY when an external source of truth makes conflicts meaningless (file re-sync), never to silence a conflict. **Metadata has its own token, `metadata_revision`** (shown next to `content_hash` wherever it appears). It is optional on a merge (pass it when your change depends on the current values, e.g. a status transition) and **required with `replace: true`**. A stale one is a *metadata conflict*: re-read, reapply, retry.\n11. **Search: prefer a few distinctive terms; heed `below confidence`.** When nothing clears the relevance threshold, `cerefox_search` returns the closest candidates prefixed with a `below confidence` warning instead of an empty set — that flag means **weak signal, not absent knowledge**: check the candidates\' scores and titles before concluding the KB lacks the content. A truly empty response means nothing even weakly related exists.\n12. **Relations express how documents relate; lifecycle tells you if knowledge is still good.** Use `cerefox_set_relation` when one document supersedes, contradicts, references, or continues another. `supersedes` marks the target **superseded**; `contradicts` marks **both** stale; `related_to`/`duplicates`/`contradicts` are symmetric (both directions written). Any other type string is accepted without special behavior. When a search result or `cerefox_get_relations` shows a neighbour marked `[superseded]` or `[stale]`, say so rather than presenting it as current.\n13. **Project memberships — non-destructive by default**: on `cerefox_ingest` updates, **`project_name` (singular) is a non-destructive add** (ensures membership, preserves others). Use **`project_names` (list)** when you want to set the doc\'s full project set in one call (destructive replace). For metadata-only project changes without writing content, use **`cerefox_set_document_projects(document_id, project_names)`** — that tool is the destructive-replace contract made explicit. Never call `cerefox_set_document_projects` with a single name when you mean "add" — that would REMOVE the doc from all other projects. When in doubt, use `cerefox_ingest` with singular `project_name`.\n\n## Update Workflow (ID-based -- preferred)\n\n```\nsearch("topic") -> find doc [id: abc123] -> get_document(abc123) -> note its content_hash -> modify ->\ningest(title="Same Title", content="...", document_id="abc123",\n expected_content_hash="<the hash you read>", author="my-agent")\n```\n\nOn a **conflict** error: get_document again (fresh content + fresh hash) -> merge your changes -> retry with the new hash.\n\n## Update Workflow (title-based -- fallback)\n\n```\nsearch("topic") -> find doc (note its hash) -> modify ->\ningest(title="Same Title", content="...", update_if_exists=true,\n expected_content_hash="<the hash you read>", author="my-agent")\n```\n\n## Catch-Up Workflow\n\n```\nmetadata_search(metadata_filter={"type": "decision-log"}, updated_since="2026-03-28T00:00:00Z")\n```\n\n## CLI fallback (when MCP is unavailable)\n\nIf `cerefox_search` is not in your tool list, your user has likely installed the Cerefox CLI. The canonical invocation is plain **`cerefox <subcommand>`** (the TypeScript CLI, installed via `npm install -g @cerefox/memory`). It uses a resource-verb shape (`cerefox document get`, `cerefox project list`, …).\n\nSame operations, same conventions. Full reference: [`docs/guides/cli.md`](docs/guides/cli.md). CLI flag names match MCP parameter names exactly (e.g. `metadata_filter` ↔ `--metadata-filter`); common flags also have single-letter short forms (`-f`, `-p`, `-c`, `-m`, `-u`, `-a`). Use the canonical long name (what `--help` shows) or its short form — there are no long-form aliases like `--filter` or `--count`.\n\n| MCP tool | CLI |\n|---|---|\n| `cerefox_search` | `cerefox search "<q>" --author "<your-name>"` |\n| `cerefox_ingest` (paste) | `printf \'...\' \\| cerefox document ingest --paste --title "<t>" --author "<your-name>" --author-type agent` |\n| `cerefox_ingest` (update by ID) | `printf \'...\' \\| cerefox document ingest --paste --title "<t>" --document-id "<uuid>" --expected-content-hash "<hash>" --author "<your-name>" --author-type agent` |\n| `cerefox_get_document` | `cerefox document get <id> --version-id <vid> --author "<your-name>"` |\n| `cerefox_list_versions` | `cerefox document version list <id> --author "<your-name>"` |\n| `cerefox_list_projects` | `cerefox project list --author "<your-name>"` |\n| `cerefox_list_metadata_keys` | `cerefox metadata keys` |\n| `cerefox_insert` | `cerefox document insert <id> -t "<text>" -p <position> -a "<anchor-heading>" -e "<hash>" --author "<your-name>" --author-type agent` |\n| `cerefox_edit` | `cerefox document edit-parts <id> --operations \'<json>\' -e "<hash>" --author "<your-name>" --author-type agent` |\n| `cerefox_delete_document` | `cerefox document delete <id> --reason "<why>" --author "<your-name>" --author-type agent --yes` (confirms interactively instead of requiring the hash) |\n| `cerefox_restore_document` | `cerefox document restore <id> --reason "<why>" --author "<your-name>" --author-type agent` |\n| `cerefox_metadata_search` | `cerefox metadata search --metadata-filter \'<json>\' --author "<your-name>"` (list a project: `cerefox document list --project <name>`) |\n| `cerefox_set_document_metadata` | `cerefox document set-metadata <id> --set key=value` (also `--remove key`, `--json \'{...}\'`, `--replace`) |\n| `cerefox_set_document_projects` | `cerefox document set-projects <id> <name...> --author "<your-name>" --author-type agent` (or `--clear` to remove all) |\n| `cerefox_get_audit_log` | `cerefox audit list --author "<your-name>"` (add `--json` for scripted access) |\n| `cerefox_get_help` | `cerefox guides show agent-quick-reference` (or `cerefox guides list` for the full bundled-docs index) |\n\n**Set identity on every call**, exactly as you would on MCP:\n- Writes (`document ingest`, `document ingest-dir`): `--author "<your-name>" --author-type agent`\n- Reads: `--author "<your-name>"` (the same flag; `--requestor` still works as a hidden alias)\n\nOr have your user set `CEREFOX_AUTHOR_NAME` / `CEREFOX_AUTHOR_TYPE` / `CEREFOX_REQUESTOR_NAME` in their `.env` to apply defaults once.\n\n## Timestamps are UTC\n\nEvery timestamp Cerefox returns — `created_at` on audit entries, version\nhistory, document metadata — is **UTC**, and now carries its `Z` marker so it\ncannot be mistaken for local time.\n\n**When you write a date into a document\'s CONTENT, use your own clock, not a\nCerefox timestamp.** These are different things: a timestamp records when the\nserver stored something; a date in a log entry or a heading is authored content\nand belongs to your timezone. An agent working a Pacific afternoon read\n`2026-08-11` from version history, wrote "8/11" into its entries, and put a\nday\'s work in the future — the timestamp was correct, and copying it into\ncontent was not.\n\nCerefox deliberately does not convert to local time on the API or MCP paths.\n"Local" has no server-side meaning: the remote MCP server runs in a cloud\nfunction whose local time *is* UTC, while a local MCP server runs in yours, so\nthe same document would report two different times depending on transport. The\nweb UI converts because a browser knows the viewer\'s timezone; nothing\nserver-side does.\n\n## Mistakes that have actually happened\n\nEach of these comes from a real agent session, and each is easy to make.\n\n- **`cerefox_ingest` always replaces the ENTIRE document.** Never a section.\n Before sending, check that the tool name matches the intent: if the intent is\n "change one section", the call is `cerefox_edit` with `replace_section`. A\n section-sized edit sent as a full ingest truncated a 13,000-character index to\n a single word. It was recovered from version history within the minute, but\n only because it was noticed immediately.\n\n- **Do not include the anchor\'s own heading in your text.** `replace_section`\n keeps the heading and `insert` places your text inside the section, so\n including it produces two. This is now refused rather than silently applied,\n but the shape is worth knowing: it happened twice in one session, the second\n time while trying to repair the first. A *deeper* sub-heading inside your text\n is fine.\n\n- **Content between sections belongs to the section ABOVE it.** A section runs\n to the next heading of the same or higher level, so a `---` rule, a note, or\n any trailing text sitting just above the next heading is part of the section\n before it — even when it visually reads as belonging below. Replacing that\n section takes it too. An agent hit exactly this: a `---` that separated two\n major sections disappeared when the section above it was replaced. The write\n was correct by the addressing rules; the surprise is that "the end of this\n section" is further down the page than it looks. Note the loss warning will\n not catch it if your replacement text is longer than what it replaced, since\n there is then no net loss to report.\n\n- **To change only tags, use `cerefox_set_document_metadata`, never `cerefox_ingest`.**\n Ingest replaces the whole document, so re-sending it to set one tag carries the\n full transcription risk for no reason. The metadata tool merges: the keys you\n pass are set, everything else is left alone, so you do not need to read the\n document first and cannot drop a tag another agent set. Pass `null` as a value\n to remove a key.\n\n- **Never partial-edit to fix a partial edit.** If a write leaves unexpected\n structure, stop. Use `cerefox_list_versions`, retrieve the last good version,\n and re-ingest cleanly. Repairing edits with more edits compounds the damage.\n\n- **A rejected batch is safe.** Operations in one `cerefox_edit` are\n all-or-nothing: if any is invalid, nothing is written. A refusal costs you a\n retry, not data — so prefer one call for changes that belong together, and do\n not split a batch to "make it more likely to succeed".\n\n- **Read before replacing.** `cerefox_get_document(section: "## Heading")`\n returns exactly what a `replace_section` on that anchor would overwrite. Use it\n for any section you did not write in this session. The outline gives a\n section\'s *size*, never its *text*.\n\n- **Verify after writing** — read the result back before reporting success, and\n report what the read actually shows.\n\n- **Partial edits cannot change a document\'s stored TITLE.** `rename_section`\n changes a heading inside the content; the title is a separate field and still\n needs `cerefox_ingest`.\n\n- **If a capability seems missing from one server, suspect your client first.**\n Local and remote run the same code. **Every `cerefox_get_help()` response\n begins with the server\'s version and the operations it registers** — you do\n not need a special topic, and the *absence* of that block is itself an answer:\n a server that does not print it predates v1.5.0. If that\n disagrees with your tool list, the client is holding a list it fetched before\n an upgrade — clients cache it at connect time. Ask the user to restart the\n client. Do not record a capability difference between servers as a fact; every\n such report so far has been a stale client.\n- Long inline bodies can arrive with literal `\\n`/`\\"` (the author over-escaped; Cerefox stores bytes faithfully). For long or quote-dense content, ingest from a file or build incrementally with `cerefox_insert`; read back multi-line writes.\n', HELP_SECTIONS, HELP_SECTION_HEADINGS;
|
|
51939
52013
|
var init_get_help_content = __esm(() => {
|
|
51940
52014
|
HELP_SECTIONS = {
|
|
51941
|
-
Tools: "## Tools\n\n| Tool | Purpose | Key params |\n|------|---------|------------|\n| `cerefox_search` | Find documents (hybrid FTS + semantic) | `query` (required), `project_name`, `metadata_filter`, `author` |\n| `cerefox_ingest` | Save or update a document | `title`, `content` (required), `document_id` (update by ID), `expected_content_hash` (**required on content updates** — see rule 10), `last_write_wins`, `update_if_exists`, `project_name` (single, non-destructive add on update), `project_names` (list, destructive replace on update), `metadata` (
|
|
52015
|
+
Tools: "## Tools\n\n| Tool | Purpose | Key params |\n|------|---------|------------|\n| `cerefox_search` | Find documents (hybrid FTS + semantic) | `query` (required), `project_name`, `metadata_filter`, `author` |\n| `cerefox_ingest` | Save or update a document | `title`, `content` (required), `document_id` (update by ID), `expected_content_hash` (**required on content updates** — see rule 10), `last_write_wins`, `update_if_exists`, `project_name` (single, non-destructive add on update), `project_names` (list, destructive replace on update), `metadata` (on update it **merges**: `null` removes a key, omitted keys are kept), `expected_metadata_revision` (optional, see rule 10), `author` |\n| `cerefox_insert` | **Add** to a document without resending it. Cannot destroy content. | `document_id`, `text`, `position` (`end_of_document`/`end_of_section`/`after_heading`/`before_heading`), `expected_content_hash` (required), `anchor_heading` (unless `end_of_document`), `section_part`, `author` |\n| `cerefox_edit` | **Change** parts of a document: 1..n operations applied atomically | `document_id`, `operations` (`insert`/`replace_section`/`delete_section`/`rename_section`), `expected_content_hash` (required), `author` |\n| `cerefox_delete_document` | **Soft**-delete a document (to trash; excluded from search; permanent purge is human-only) | `document_id`, `expected_content_hash` (**required** — a delete must follow a read), `reason` (recorded in the audit log — give one), `author` |\n| `cerefox_restore_document` | Restore a soft-deleted document from the trash (audited inverse of delete; no-op if not deleted) | `document_id` (required), `reason` (recorded in the audit log), `author` |\n| `cerefox_get_document` | Get full document by ID (header includes `content_hash` — the update token), or with `outline: true` just its heading paths, sizes and hash, or with `section: \"## Heading\"` one section's text | `document_id` (required), `outline`, `section`, `section_part`, `author` |\n| `cerefox_list_versions` | Version history of a document | `document_id` (required), `author` |\n| `cerefox_set_relation` ⚑ | Link two documents (`source --rel_type--> target`) | `source_id`, `target_id`, `rel_type` (required), `metadata`, `author` |\n| `cerefox_delete_relation` ⚑ | Remove a relation | `source_id`, `target_id`, `rel_type`, `author` |\n| `cerefox_get_relations` ⚑ | All relations touching a document, both directions | `document_id` |\n| `cerefox_get_neighbors` ⚑ | Walk the graph along ONE relation type | `document_id`, `rel_type` (required), `depth`, `from_time`, `to_time`, `limit` |\n| `cerefox_metadata_search` | Find or list docs by metadata, project, or time (no text query) | `metadata_filter`, `project_name` (list a project's docs), `updated_since`, `include_content` — **at least one** of metadata_filter/project_name/updated_since/created_since |\n| `cerefox_list_metadata_keys` | Discover available metadata keys | (none required) |\n| `cerefox_list_projects` | List all projects | (none required) |\n| `cerefox_set_document_metadata` | Change tags WITHOUT resending content. **Merges** by default; a `null` value removes a key | `document_id`, `metadata` (required), `replace` (rare: set exactly this object; needs `expected_metadata_revision`), `expected_metadata_revision`, `author` |\n| `cerefox_set_document_projects` | Set doc's project memberships to exactly the given list (destructive replace; metadata-only, no content change) | `document_id`, `project_names` (required), `author` |\n| `cerefox_get_audit_log` | Query write operation history | `document_id`, `by_author` (filter), `operation`, `since`, `author` |\n| `cerefox_get_help` | Retrieve Cerefox conventions (this reference) over MCP. **Call this whenever uncertain.** | `topic` (optional, case-insensitive H2 substring match) |\n\n⚑ **Opt-in — usually absent.** The four relation tools are hidden unless the\noperator enables them (`relations_enabled`). **Trust your own tool list**: if\nthey are not in it, the feature is switched off for this deployment. That is\nnormal, not an error, and not something to work around.",
|
|
51942
52016
|
"Editing part of a document (prefer this over re-sending)": '## Editing part of a document (prefer this over re-sending)\n\n**Re-sending a whole document to change part of it is the main way agents lose\ndata.** You have to reproduce the untouched remainder verbatim, and any drift\nsilently rewrites content nobody asked you to touch — which the caller cannot\ndiff. Use the partial-edit tools instead:\n\n1. **Learn the anchors** — `cerefox_get_document(document_id, outline: true)`.\n Returns heading paths, per-section sizes and the `content_hash`, without the\n body. The paths it returns are exactly what `anchor_heading` accepts.\n2. **Add** → `cerefox_insert`. `end_of_document` is a plain append;\n `end_of_section` adds inside a named section. It is structurally incapable of\n removing anything, so "I meant to append" cannot become "I replaced the file".\n3. **Look before you overwrite** — `cerefox_get_document(document_id,\n section: "## Heading")` returns exactly the text a `replace_section` on that\n anchor would destroy. The outline gives you a section\'s *size*, never its\n *text*, so on a document you did not write yourself this is the difference\n between a replace and a blind overwrite.\n4. **Change or remove** → `cerefox_edit`. Put changes that belong together in\n ONE call: they apply atomically, so a table row and the total it feeds cannot\n end up disagreeing. To change a single line, `replace_section` on its\n smallest enclosing heading — that is the intended granularity, not a\n workaround. To fix a stale heading (`## OPEN TODOs (as of ...)`), use\n `rename_section`: it changes the heading text and leaves the body and\n position alone.\n5. All of them require `expected_content_hash` and **have no last-write-wins**. A\n conflict means someone else changed the document; re-read and decide, do not\n force it.\n\n**A section runs to the next same-or-higher heading, or to the end of the\ndocument.** So `end_of_document` inserts land inside the *last* section, and\nreplacing or deleting that section removes them too. A large shrink in the\nresponse is your warning; `cerefox_list_versions` has the previous content.\n\n**When an anchor is ambiguous the tool refuses and hands you the options** — a\nrepeated heading returns the qualifying paths, and a section with both its own\ncontent and sub-sections returns both `section_part` choices. That is a\nrecoverable answer, not a failure: retry with what it gave you.',
|
|
51943
|
-
"Essential Rules": '## Essential Rules\n\n1. **Search before ingesting** -- check if the document exists first.\n2. **Prefer ID-based updates** -- pass `document_id` from search results for deterministic updates. Falls back to title-matching with `update_if_exists: true`.\n3. **Set `author`** to your name on every call, reads and writes alike (e.g., "Claude Code", "archiver"). Same parameter on every tool. (`requestor` is still accepted everywhere as the pre-1.13.1 alias.) On the CLI it is `--author` on every command too (plus `--author-type` on writes); or rely on `CEREFOX_AUTHOR_NAME`/`CEREFOX_AUTHOR_TYPE` env vars set in the user\'s `.env`.\n4. **Use `document_id` from search results** `[id: uuid]` for get_document and list_versions.\n5. **`max_bytes` has to fit a whole document.** Search returns COMPLETE documents, so a budget smaller than the top hit fits nothing. You get a header-only list saying so (never "No results found." — that means the store really has nothing). Raise `max_bytes`, or read one document with `cerefox_get_document` using `outline: true` or `section`.\n6. **Add metadata** -- at minimum `type` ("decision-log", "research", "design-doc") and `status` ("active", "draft").\n7. **Write for retrieval: the title does real work.** The document title is indexed at the **highest weight** *and* prepended to every chunk before it is embedded, so it steers both halves of hybrid search (keyword and semantic) for every chunk in the document. Name the document with the distinctive terms someone would actually search for -- "Cerefox Response Size Limits", not "Notes" or "Update 3". Renaming re-indexes and re-embeds, so correcting a vague title is cheap and takes effect immediately. Write the characters themselves: `&` and `<>`, never `&` or `<>` (entities are stored literally and the write reply will say so). Inside the content, write structured Markdown with H1/H2/H3 headings: the chunker follows them, and a chunk\'s own heading carries the same weight as the title.\n8. **Deletes are soft (recoverable); permanent purge is web-UI-only.** `cerefox_delete_document` requires the document\'s `content_hash` as you read it (read before you delete) and takes a `reason` — give one; it is what the human reviewing the trash sees. `cerefox_restore_document` undoes a mistaken delete (also audited, also takes a `reason`). Always surface deletes AND restores to the user. Once a human purges from the web UI, the document is gone for good; so is one auto-purged after `trash_retention_days`, if the operator has turned trash auto-purge on.\n9. **Cross-doc links inside content**: **always use `[Text](document-uuid)`.** UUIDs are the only fully reliable link form — stable across title changes, never ambiguous, no encoding gotchas. Every `cerefox_search` result shows `[id: <uuid>]` after the title; grab it and use it. Title-based linking (`[Text](<Title With Spaces>)`) is fragile (breaks on colons, parens, ampersands, brackets — silently navigates to wrong page) — **don\'t write title-based links**; do an extra search to get the UUID instead. Repo-path forms (`[Text](docs/path.md)`) exist for repo-ingested files; don\'t construct manually. **The server validates `](uuid)` links on every write** (v1.7.0): a link to a nonexistent id rejects the write, naming the offender — that means you mangled the UUID; re-read the source and correct it, do not retry unchanged. Example ids go in backticks (code is not validated). `[[Wikilinks]]` may dangle. See `AGENT_GUIDE.md → Writing linkable content` for the full rule.\n10. **Concurrency: content updates require `expected_content_hash`.** Pass the `content_hash` you last saw — every read shows one (`cerefox_get_document` incl. outline mode, `cerefox_search`, `cerefox_metadata_search`) and **every write returns the new one, including create** (v1.3.0, #189), so after writing you already hold the token for your next edit; no re-read needed. If it\'s stale you get a **conflict** — re-read the document, merge your changes into the latest content, retry with the new hash. **Never resolve a conflict by overwriting blindly** — the current content includes another writer\'s work. `last_write_wins: true` skips the check; use it ONLY when an external source of truth makes conflicts meaningless (file re-sync), never to silence a conflict.\n11. **Search: prefer a few distinctive terms; heed `below confidence`.** When nothing clears the relevance threshold, `cerefox_search` returns the closest candidates prefixed with a `below confidence` warning instead of an empty set — that flag means **weak signal, not absent knowledge**: check the candidates\' scores and titles before concluding the KB lacks the content. A truly empty response means nothing even weakly related exists.\n12. **Relations express how documents relate; lifecycle tells you if knowledge is still good.** Use `cerefox_set_relation` when one document supersedes, contradicts, references, or continues another. `supersedes` marks the target **superseded**; `contradicts` marks **both** stale; `related_to`/`duplicates`/`contradicts` are symmetric (both directions written). Any other type string is accepted without special behavior. When a search result or `cerefox_get_relations` shows a neighbour marked `[superseded]` or `[stale]`, say so rather than presenting it as current.\n13. **Project memberships — non-destructive by default**: on `cerefox_ingest` updates, **`project_name` (singular) is a non-destructive add** (ensures membership, preserves others). Use **`project_names` (list)** when you want to set the doc\'s full project set in one call (destructive replace). For metadata-only project changes without writing content, use **`cerefox_set_document_projects(document_id, project_names)`** — that tool is the destructive-replace contract made explicit. Never call `cerefox_set_document_projects` with a single name when you mean "add" — that would REMOVE the doc from all other projects. When in doubt, use `cerefox_ingest` with singular `project_name`.',
|
|
52017
|
+
"Essential Rules": '## Essential Rules\n\n1. **Search before ingesting** -- check if the document exists first.\n2. **Prefer ID-based updates** -- pass `document_id` from search results for deterministic updates. Falls back to title-matching with `update_if_exists: true`.\n3. **Set `author`** to your name on every call, reads and writes alike (e.g., "Claude Code", "archiver"). Same parameter on every tool. (`requestor` is still accepted everywhere as the pre-1.13.1 alias.) On the CLI it is `--author` on every command too (plus `--author-type` on writes); or rely on `CEREFOX_AUTHOR_NAME`/`CEREFOX_AUTHOR_TYPE` env vars set in the user\'s `.env`.\n4. **Use `document_id` from search results** `[id: uuid]` for get_document and list_versions.\n5. **`max_bytes` has to fit a whole document.** Search returns COMPLETE documents, so a budget smaller than the top hit fits nothing. You get a header-only list saying so (never "No results found." — that means the store really has nothing). Raise `max_bytes`, or read one document with `cerefox_get_document` using `outline: true` or `section`.\n6. **Add metadata** -- at minimum `type` ("decision-log", "research", "design-doc") and `status` ("active", "draft").\n7. **Write for retrieval: the title does real work.** The document title is indexed at the **highest weight** *and* prepended to every chunk before it is embedded, so it steers both halves of hybrid search (keyword and semantic) for every chunk in the document. Name the document with the distinctive terms someone would actually search for -- "Cerefox Response Size Limits", not "Notes" or "Update 3". Renaming re-indexes and re-embeds, so correcting a vague title is cheap and takes effect immediately. Write the characters themselves: `&` and `<>`, never `&` or `<>` (entities are stored literally and the write reply will say so). Inside the content, write structured Markdown with H1/H2/H3 headings: the chunker follows them, and a chunk\'s own heading carries the same weight as the title.\n8. **Deletes are soft (recoverable); permanent purge is web-UI-only.** `cerefox_delete_document` requires the document\'s `content_hash` as you read it (read before you delete) and takes a `reason` — give one; it is what the human reviewing the trash sees. `cerefox_restore_document` undoes a mistaken delete (also audited, also takes a `reason`). Always surface deletes AND restores to the user. Once a human purges from the web UI, the document is gone for good; so is one auto-purged after `trash_retention_days`, if the operator has turned trash auto-purge on.\n9. **Cross-doc links inside content**: **always use `[Text](document-uuid)`.** UUIDs are the only fully reliable link form — stable across title changes, never ambiguous, no encoding gotchas. Every `cerefox_search` result shows `[id: <uuid>]` after the title; grab it and use it. Title-based linking (`[Text](<Title With Spaces>)`) is fragile (breaks on colons, parens, ampersands, brackets — silently navigates to wrong page) — **don\'t write title-based links**; do an extra search to get the UUID instead. Repo-path forms (`[Text](docs/path.md)`) exist for repo-ingested files; don\'t construct manually. **The server validates `](uuid)` links on every write** (v1.7.0): a link to a nonexistent id rejects the write, naming the offender — that means you mangled the UUID; re-read the source and correct it, do not retry unchanged. Example ids go in backticks (code is not validated). `[[Wikilinks]]` may dangle. See `AGENT_GUIDE.md → Writing linkable content` for the full rule.\n10. **Concurrency: content updates require `expected_content_hash`.** Pass the `content_hash` you last saw — every read shows one (`cerefox_get_document` incl. outline mode, `cerefox_search`, `cerefox_metadata_search`) and **every write returns the new one, including create** (v1.3.0, #189), so after writing you already hold the token for your next edit; no re-read needed. If it\'s stale you get a **conflict** — re-read the document, merge your changes into the latest content, retry with the new hash. **Never resolve a conflict by overwriting blindly** — the current content includes another writer\'s work. `last_write_wins: true` skips the check; use it ONLY when an external source of truth makes conflicts meaningless (file re-sync), never to silence a conflict. **Metadata has its own token, `metadata_revision`** (shown next to `content_hash` wherever it appears). It is optional on a merge (pass it when your change depends on the current values, e.g. a status transition) and **required with `replace: true`**. A stale one is a *metadata conflict*: re-read, reapply, retry.\n11. **Search: prefer a few distinctive terms; heed `below confidence`.** When nothing clears the relevance threshold, `cerefox_search` returns the closest candidates prefixed with a `below confidence` warning instead of an empty set — that flag means **weak signal, not absent knowledge**: check the candidates\' scores and titles before concluding the KB lacks the content. A truly empty response means nothing even weakly related exists.\n12. **Relations express how documents relate; lifecycle tells you if knowledge is still good.** Use `cerefox_set_relation` when one document supersedes, contradicts, references, or continues another. `supersedes` marks the target **superseded**; `contradicts` marks **both** stale; `related_to`/`duplicates`/`contradicts` are symmetric (both directions written). Any other type string is accepted without special behavior. When a search result or `cerefox_get_relations` shows a neighbour marked `[superseded]` or `[stale]`, say so rather than presenting it as current.\n13. **Project memberships — non-destructive by default**: on `cerefox_ingest` updates, **`project_name` (singular) is a non-destructive add** (ensures membership, preserves others). Use **`project_names` (list)** when you want to set the doc\'s full project set in one call (destructive replace). For metadata-only project changes without writing content, use **`cerefox_set_document_projects(document_id, project_names)`** — that tool is the destructive-replace contract made explicit. Never call `cerefox_set_document_projects` with a single name when you mean "add" — that would REMOVE the doc from all other projects. When in doubt, use `cerefox_ingest` with singular `project_name`.',
|
|
51944
52018
|
"Update Workflow (ID-based -- preferred)": `## Update Workflow (ID-based -- preferred)
|
|
51945
52019
|
|
|
51946
52020
|
\`\`\`
|
|
@@ -52152,6 +52226,9 @@ function conflictError3(documentId, expectedHash, currentHash) {
|
|
|
52152
52226
|
return new Error(`Conflict: document ${documentId} changed since you read it ` + `(your base hash: ${expectedHash}, current hash: ${currentHash}). ` + `To resolve: (1) cerefox_get_document("${documentId}") to fetch the latest content ` + `and its content_hash, (2) merge your changes into it, (3) retry cerefox_ingest ` + `with expected_content_hash set to the new hash. Do not overwrite blindly — ` + `the current content may include another writer's work.`);
|
|
52153
52227
|
}
|
|
52154
52228
|
function mapIngestRpcError(message, documentId) {
|
|
52229
|
+
const metaErr = metadataTokenError(message);
|
|
52230
|
+
if (metaErr)
|
|
52231
|
+
return metaErr;
|
|
52155
52232
|
if (message.includes("CEREFOX_CONFLICT")) {
|
|
52156
52233
|
const { expected, current } = extractConflictHashes(message);
|
|
52157
52234
|
return conflictError3(documentId, expected, current);
|
|
@@ -52168,7 +52245,7 @@ function mapIngestRpcError(message, documentId) {
|
|
|
52168
52245
|
const current = message.match(/Current hash: ([0-9a-f]{64})/)?.[1];
|
|
52169
52246
|
return new Error(`Concurrency token required: content updates need expected_content_hash — ` + `the content_hash of the version you based your edit on (returned by ` + `cerefox_get_document, cerefox_search, and cerefox_metadata_search).` + (current ? ` The document's current hash is ${current}; pass it ONLY if your edit was based on the current content.` : "") + ` If you have not read the document, read it first. To deliberately overwrite ` + `regardless of concurrent changes, pass last_write_wins=true.`);
|
|
52170
52247
|
}
|
|
52171
|
-
return new Error(`Ingest RPC failed: ${message}`);
|
|
52248
|
+
return legacyContentUniqueError(message) ?? new Error(`Ingest RPC failed: ${message}`);
|
|
52172
52249
|
}
|
|
52173
52250
|
async function handler6(supabase, args, ctx) {
|
|
52174
52251
|
const title = args.title?.trim();
|
|
@@ -52187,6 +52264,11 @@ async function handler6(supabase, args, ctx) {
|
|
|
52187
52264
|
const author_type = "agent";
|
|
52188
52265
|
const expected_content_hash = args.expected_content_hash?.trim() || null;
|
|
52189
52266
|
const last_write_wins = args.last_write_wins ?? false;
|
|
52267
|
+
const expectedMetaRaw = args.expected_metadata_revision;
|
|
52268
|
+
if (expectedMetaRaw !== undefined && expectedMetaRaw !== null && !(typeof expectedMetaRaw === "number" && Number.isInteger(expectedMetaRaw))) {
|
|
52269
|
+
throw new McpInvalidParams("expected_metadata_revision must be an integer (the metadata_revision you read)");
|
|
52270
|
+
}
|
|
52271
|
+
const expected_metadata_revision = expectedMetaRaw ?? null;
|
|
52190
52272
|
if (!title || !content?.trim()) {
|
|
52191
52273
|
throw new McpInvalidParams("title and content are required");
|
|
52192
52274
|
}
|
|
@@ -52242,7 +52324,8 @@ async function handler6(supabase, args, ctx) {
|
|
|
52242
52324
|
p_source_label: source,
|
|
52243
52325
|
p_expected_content_hash: expected_content_hash,
|
|
52244
52326
|
p_last_write_wins: last_write_wins,
|
|
52245
|
-
p_content_format: CONTENT_FORMAT_BLIND_STITCH
|
|
52327
|
+
p_content_format: CONTENT_FORMAT_BLIND_STITCH,
|
|
52328
|
+
...metadataTokenParams(expected_metadata_revision, false)
|
|
52246
52329
|
});
|
|
52247
52330
|
if (ingestErr)
|
|
52248
52331
|
throw mapIngestRpcError(ingestErr.message, existingDoc.id);
|
|
@@ -52305,7 +52388,8 @@ async function handler6(supabase, args, ctx) {
|
|
|
52305
52388
|
p_source_label: source,
|
|
52306
52389
|
p_expected_content_hash: expected_content_hash,
|
|
52307
52390
|
p_last_write_wins: last_write_wins,
|
|
52308
|
-
p_content_format: CONTENT_FORMAT_BLIND_STITCH
|
|
52391
|
+
p_content_format: CONTENT_FORMAT_BLIND_STITCH,
|
|
52392
|
+
...metadataTokenParams(expected_metadata_revision, false)
|
|
52309
52393
|
});
|
|
52310
52394
|
if (ingestErr)
|
|
52311
52395
|
throw mapIngestRpcError(ingestErr.message, existingDoc.id);
|
|
@@ -52324,12 +52408,9 @@ async function handler6(supabase, args, ctx) {
|
|
|
52324
52408
|
return `Document updated: "${existingDoc.title}" (id: ${existingDoc.id}), ${chunks.length} chunk(s), ${totalChars} chars. New content_hash: ${contentHash}.${escapedContentNote(content)}${escapedTitleNote(title)}`;
|
|
52325
52409
|
}
|
|
52326
52410
|
}
|
|
52327
|
-
const { data: hashMatch } = await supabase.from("cerefox_documents").select("id, title
|
|
52411
|
+
const { data: hashMatch } = await supabase.from("cerefox_documents").select("id, title").eq("content_hash", contentHash).is("deleted_at", null).order("created_at", { ascending: true }).limit(1);
|
|
52328
52412
|
if (hashMatch?.length) {
|
|
52329
|
-
|
|
52330
|
-
return `This exact content is already in the TRASH as "${hashMatch[0].title}" ` + `(soft-deleted, id: ${hashMatch[0].id}). Restore it with ` + `cerefox_restore_document instead of re-ingesting — or have your user ` + `purge it from the web UI Trash to start fresh.`;
|
|
52331
|
-
}
|
|
52332
|
-
return `Document already up-to-date: "${hashMatch[0].title}" (id: ${hashMatch[0].id}). Content hash unchanged (${contentHash}) — pass it as expected_content_hash to edit it.`;
|
|
52413
|
+
return alreadyExistsMessage(hashMatch[0].title, hashMatch[0].id, contentHash);
|
|
52333
52414
|
}
|
|
52334
52415
|
const chunks = chunkMarkdown(content);
|
|
52335
52416
|
if (chunks.length === 0)
|
|
@@ -52358,7 +52439,15 @@ async function handler6(supabase, args, ctx) {
|
|
|
52358
52439
|
p_author_type: author_type,
|
|
52359
52440
|
p_content_format: CONTENT_FORMAT_BLIND_STITCH
|
|
52360
52441
|
});
|
|
52442
|
+
const duplicateId = duplicateContentDocumentId(ingestErr?.message ?? "");
|
|
52443
|
+
if (duplicateId) {
|
|
52444
|
+
const { data: existing } = await supabase.from("cerefox_documents").select("title").eq("id", duplicateId).maybeSingle();
|
|
52445
|
+
return alreadyExistsMessage(existing?.title ?? title, duplicateId, contentHash);
|
|
52446
|
+
}
|
|
52361
52447
|
if (ingestErr || !ingestResult?.length) {
|
|
52448
|
+
const legacy = legacyContentUniqueError(ingestErr?.message ?? "");
|
|
52449
|
+
if (legacy)
|
|
52450
|
+
throw legacy;
|
|
52362
52451
|
throw new Error(`Ingest RPC failed: ${ingestErr?.message ?? "no data returned"}`);
|
|
52363
52452
|
}
|
|
52364
52453
|
const documentId = ingestResult[0].document_id;
|
|
@@ -52377,6 +52466,9 @@ async function handler6(supabase, args, ctx) {
|
|
|
52377
52466
|
const projectInfo = project_name ? `, project: "${project_name}"` : "";
|
|
52378
52467
|
return `Document saved: "${title}" (id: ${documentId}), ${chunks.length} chunk(s), ${totalChars} chars${projectInfo}. ` + `content_hash: ${contentHash} — pass it as expected_content_hash on your next edit.` + escapedContentNote(content) + escapedTitleNote(title);
|
|
52379
52468
|
}
|
|
52469
|
+
function alreadyExistsMessage(title, id, contentHash) {
|
|
52470
|
+
return `Document already up-to-date: "${title}" (id: ${id}). Content hash unchanged (${contentHash}) — pass it as expected_content_hash to edit it.`;
|
|
52471
|
+
}
|
|
52380
52472
|
var ingestTool;
|
|
52381
52473
|
var init_ingest = __esm(() => {
|
|
52382
52474
|
init_escape_heuristic();
|
|
@@ -52427,7 +52519,14 @@ var init_ingest = __esm(() => {
|
|
|
52427
52519
|
type: "boolean",
|
|
52428
52520
|
description: "Explicitly skip the concurrency check and overwrite regardless of concurrent changes (default: false). Use ONLY when an external source of truth makes conflicts meaningless (e.g. re-syncing from files). Recorded in the audit log."
|
|
52429
52521
|
},
|
|
52430
|
-
metadata: {
|
|
52522
|
+
metadata: {
|
|
52523
|
+
type: "object",
|
|
52524
|
+
description: "JSON metadata (optional). On an UPDATE it is MERGED into the existing metadata: keys you pass are set, a null value removes that key, keys you omit are kept. To change only metadata, use cerefox_set_document_metadata instead."
|
|
52525
|
+
},
|
|
52526
|
+
expected_metadata_revision: {
|
|
52527
|
+
type: "integer",
|
|
52528
|
+
description: "Optional, with metadata on an update: the metadata_revision you read (cerefox_get_document / cerefox_metadata_search). The write fails if the metadata changed since."
|
|
52529
|
+
},
|
|
52431
52530
|
author: AUTHOR_PARAM_WRITE
|
|
52432
52531
|
}
|
|
52433
52532
|
},
|
|
@@ -52666,8 +52765,9 @@ ${lines.join(`
|
|
|
52666
52765
|
const parts = rows.map((row) => {
|
|
52667
52766
|
const projects = row.project_names?.length ? ` | projects: ${row.project_names.join(", ")}` : "";
|
|
52668
52767
|
const meta = Object.entries(row.doc_metadata ?? {}).map(([k, v]) => `${k}=${v}`).join(", ");
|
|
52768
|
+
const rev = row.metadata_revision != null ? ` · metadata_revision: ${row.metadata_revision}` : "";
|
|
52669
52769
|
const hash = row.content_hash ? `
|
|
52670
|
-
hash: ${row.content_hash}` : "";
|
|
52770
|
+
hash: ${row.content_hash}${rev}` : "";
|
|
52671
52771
|
const header = `## ${row.title} [id: ${row.document_id}]
|
|
52672
52772
|
` + `${meta}${projects} | ${row.total_chars} chars | ${showReview ? `${row.review_status} | ` : ""}updated ${row.updated_at?.slice(0, 10) ?? "?"}${hash}`;
|
|
52673
52773
|
if (include_content && row.content) {
|
|
@@ -52766,12 +52866,18 @@ function shortLabel(row) {
|
|
|
52766
52866
|
const id = row.document_id ? ` [id: ${row.document_id}]` : "";
|
|
52767
52867
|
return `${leaf ? `${doc} › ${leaf}` : doc}${chunk}${id}`;
|
|
52768
52868
|
}
|
|
52869
|
+
function hashLine(row) {
|
|
52870
|
+
if (!row.content_hash)
|
|
52871
|
+
return "";
|
|
52872
|
+
const rev = row.metadata_revision != null ? ` · metadata_revision: ${row.metadata_revision}` : "";
|
|
52873
|
+
return `
|
|
52874
|
+
hash: ${row.content_hash}${rev}`;
|
|
52875
|
+
}
|
|
52769
52876
|
function renderRow(row) {
|
|
52770
52877
|
const raw = row.best_score ?? row.score;
|
|
52771
52878
|
const score = raw != null ? ` (score: ${raw.toFixed(3)})` : "";
|
|
52772
52879
|
const partial = row.is_partial ? ` -- partial (${row.chunk_count} of ${(row.total_chars ?? 0).toLocaleString()} chars)` : "";
|
|
52773
|
-
const hash = row
|
|
52774
|
-
hash: ${row.content_hash}` : "";
|
|
52880
|
+
const hash = hashLine(row);
|
|
52775
52881
|
return `## ${rowHeading(row)}${score}${partial}${hash}
|
|
52776
52882
|
|
|
52777
52883
|
${rowContent(row)}`;
|
|
@@ -52780,8 +52886,7 @@ function headerLine(row) {
|
|
|
52780
52886
|
const raw = row.best_score ?? row.score;
|
|
52781
52887
|
const score = raw != null ? ` (score: ${raw.toFixed(3)})` : "";
|
|
52782
52888
|
const size = row.total_chars != null ? ` -- ${row.total_chars.toLocaleString()} chars` : "";
|
|
52783
|
-
const hash = row
|
|
52784
|
-
hash: ${row.content_hash}` : "";
|
|
52889
|
+
const hash = hashLine(row);
|
|
52785
52890
|
return `## ${rowHeading(row)}${score}${size}${hash}`;
|
|
52786
52891
|
}
|
|
52787
52892
|
function degradedToHeaders(matched, rendered, maxBytes, belowConfidence) {
|
|
@@ -53043,6 +53148,11 @@ async function handler12(supabase, args, ctx) {
|
|
|
53043
53148
|
const document_id = args.document_id;
|
|
53044
53149
|
const metadata = args.metadata;
|
|
53045
53150
|
const replace = args.replace ?? false;
|
|
53151
|
+
const expectedRevision = args.expected_metadata_revision;
|
|
53152
|
+
if (expectedRevision !== undefined && expectedRevision !== null && !(typeof expectedRevision === "number" && Number.isInteger(expectedRevision))) {
|
|
53153
|
+
throw new McpInvalidParams("expected_metadata_revision must be an integer (the metadata_revision you read)");
|
|
53154
|
+
}
|
|
53155
|
+
const lastWriteWins = args.last_write_wins ?? false;
|
|
53046
53156
|
if (!document_id)
|
|
53047
53157
|
throw new McpInvalidParams("document_id is required");
|
|
53048
53158
|
if (metadata === undefined || metadata === null) {
|
|
@@ -53061,10 +53171,11 @@ async function handler12(supabase, args, ctx) {
|
|
|
53061
53171
|
p_metadata: metadata,
|
|
53062
53172
|
p_replace: replace,
|
|
53063
53173
|
p_author: author ?? "unknown",
|
|
53064
|
-
p_author_type: authorType
|
|
53174
|
+
p_author_type: authorType,
|
|
53175
|
+
...metadataTokenParams(expectedRevision, lastWriteWins)
|
|
53065
53176
|
});
|
|
53066
53177
|
if (error)
|
|
53067
|
-
throw new Error(`RPC error: ${error.message}`);
|
|
53178
|
+
throw metadataTokenError(error.message) ?? new Error(`RPC error: ${error.message}`);
|
|
53068
53179
|
const row = data?.[0];
|
|
53069
53180
|
if (!row)
|
|
53070
53181
|
throw new Error("cerefox_set_document_metadata returned no data");
|
|
@@ -53080,7 +53191,8 @@ async function handler12(supabase, args, ctx) {
|
|
|
53080
53191
|
const summary = set === 0 && removed === 0 ? "No change: every key already held that value." : `${set} key(s) set, ${removed} removed.`;
|
|
53081
53192
|
return `Metadata ${replace ? "replaced" : "merged"} on ${document_id}. ${summary}
|
|
53082
53193
|
` + `Now: ${JSON.stringify(row.metadata ?? {})}
|
|
53083
|
-
` +
|
|
53194
|
+
` + (row.metadata_revision != null ? `metadata_revision: ${row.metadata_revision}
|
|
53195
|
+
` : "") + `Content untouched — no new version, no re-embedding.`;
|
|
53084
53196
|
}
|
|
53085
53197
|
var setDocumentMetadataTool;
|
|
53086
53198
|
var init_set_document_metadata = __esm(() => {
|
|
@@ -53089,7 +53201,7 @@ var init_set_document_metadata = __esm(() => {
|
|
|
53089
53201
|
init_identity();
|
|
53090
53202
|
setDocumentMetadataTool = {
|
|
53091
53203
|
name: "cerefox_set_document_metadata",
|
|
53092
|
-
description: `Change a document's metadata WITHOUT resending its content. MERGES by default: the keys you pass are set, every other key is left alone — so you do not need to read the document first, and you cannot accidentally drop tags another agent set. To REMOVE a key, pass it with a null value ({"stale_key": null}). Pass replace: true to set the metadata to exactly the object given, discarding everything else (rare; the
|
|
53204
|
+
description: `Change a document's metadata WITHOUT resending its content. MERGES by default: the keys you pass are set, every other key is left alone — so you do not need to read the document first, and you cannot accidentally drop tags another agent set. To REMOVE a key, pass it with a null value ({"stale_key": null}). Pass replace: true to set the metadata to exactly the object given, discarding everything else (rare; it requires expected_metadata_revision or last_write_wins). To make a merge fail if anyone changed the metadata since you read it, pass expected_metadata_revision. Content, chunks and embeddings are untouched and no new version is created. Use this instead of cerefox_ingest whenever only the tags are changing.`,
|
|
53093
53205
|
annotations: {
|
|
53094
53206
|
title: "Set document metadata",
|
|
53095
53207
|
readOnlyHint: false,
|
|
@@ -53108,7 +53220,15 @@ var init_set_document_metadata = __esm(() => {
|
|
|
53108
53220
|
},
|
|
53109
53221
|
replace: {
|
|
53110
53222
|
type: "boolean",
|
|
53111
|
-
description: "Set the metadata to EXACTLY this object, discarding any key not listed. Defaults to false (merge). Use only when you mean to reset a document's tags wholesale."
|
|
53223
|
+
description: "Set the metadata to EXACTLY this object, discarding any key not listed. Defaults to false (merge). Use only when you mean to reset a document's tags wholesale. Requires expected_metadata_revision (or last_write_wins)."
|
|
53224
|
+
},
|
|
53225
|
+
expected_metadata_revision: {
|
|
53226
|
+
type: "integer",
|
|
53227
|
+
description: "The metadata_revision you read (from cerefox_get_document or cerefox_metadata_search). Optional on a merge: when given, the write fails if the metadata changed since. Required with replace: true."
|
|
53228
|
+
},
|
|
53229
|
+
last_write_wins: {
|
|
53230
|
+
type: "boolean",
|
|
53231
|
+
description: "Replace without a metadata_revision, regardless of concurrent changes (default false). Recorded in the audit log. Use only when an external source of truth makes conflicts meaningless."
|
|
53112
53232
|
},
|
|
53113
53233
|
author: AUTHOR_PARAM_WRITE
|
|
53114
53234
|
}
|
|
@@ -68631,6 +68751,7 @@ function registerDocumentRestore(parent) {
|
|
|
68631
68751
|
// src/cli/commands/document-set-metadata.ts
|
|
68632
68752
|
init_cli_core();
|
|
68633
68753
|
init_client();
|
|
68754
|
+
init__utils();
|
|
68634
68755
|
async function action13(documentId, options) {
|
|
68635
68756
|
const patch = {};
|
|
68636
68757
|
if (options.json) {
|
|
@@ -68669,6 +68790,13 @@ async function action13(documentId, options) {
|
|
|
68669
68790
|
if (Object.keys(patch).length === 0 && !options.replace) {
|
|
68670
68791
|
throw userError("Nothing to change. Pass --set key=value, --remove key, or --json '{...}'. " + "To clear all metadata use --replace --json '{}'.");
|
|
68671
68792
|
}
|
|
68793
|
+
let expectedRevision = null;
|
|
68794
|
+
if (options.expectedMetadataRevision !== undefined) {
|
|
68795
|
+
expectedRevision = Number(options.expectedMetadataRevision);
|
|
68796
|
+
if (!Number.isInteger(expectedRevision)) {
|
|
68797
|
+
throw userError("--expected-metadata-revision must be an integer (the metadata_revision you read).");
|
|
68798
|
+
}
|
|
68799
|
+
}
|
|
68672
68800
|
const client = getClient();
|
|
68673
68801
|
let rows;
|
|
68674
68802
|
try {
|
|
@@ -68677,12 +68805,19 @@ async function action13(documentId, options) {
|
|
|
68677
68805
|
p_metadata: patch,
|
|
68678
68806
|
p_replace: Boolean(options.replace),
|
|
68679
68807
|
p_author: resolveAuthor(options.author),
|
|
68680
|
-
p_author_type: options.authorType === "agent" ? "agent" : "user"
|
|
68808
|
+
p_author_type: options.authorType === "agent" ? "agent" : "user",
|
|
68809
|
+
...metadataTokenParams(expectedRevision, options.lastWriteWins)
|
|
68681
68810
|
});
|
|
68682
68811
|
} catch (err) {
|
|
68683
68812
|
const msg = err instanceof Error ? err.message : String(err);
|
|
68684
68813
|
if (/not found/i.test(msg))
|
|
68685
68814
|
throw notFound(`Document ${documentId} not found (or is deleted).`);
|
|
68815
|
+
if (msg.includes("CEREFOX_METADATA_CONFLICT")) {
|
|
68816
|
+
throw userError(`The metadata of ${documentId} changed since you read it. Re-read it ` + `(cerefox document get ${documentId} --outline), reapply your change, and retry ` + `with the new --expected-metadata-revision.`);
|
|
68817
|
+
}
|
|
68818
|
+
if (msg.includes("CEREFOX_METADATA_TOKEN_REQUIRED")) {
|
|
68819
|
+
throw userError(`--replace discards every key you do not list, so it needs --expected-metadata-revision ` + `(from cerefox document get ${documentId} --outline) or --last-write-wins.`);
|
|
68820
|
+
}
|
|
68686
68821
|
throw systemError(`Could not set metadata: ${msg}`);
|
|
68687
68822
|
}
|
|
68688
68823
|
if (!rows || rows.length === 0) {
|
|
@@ -68700,10 +68835,12 @@ async function action13(documentId, options) {
|
|
|
68700
68835
|
println(c.green(`✓ ${verb} metadata on ${documentId}: ${row.keys_set} key(s) set, ${row.keys_removed} removed.`));
|
|
68701
68836
|
}
|
|
68702
68837
|
println(c.dim(` Now: ${JSON.stringify(row.metadata ?? {})}`));
|
|
68838
|
+
if (row.metadata_revision != null)
|
|
68839
|
+
println(c.dim(` metadata_revision: ${row.metadata_revision}`));
|
|
68703
68840
|
println(c.dim(" Content untouched — no new version, no re-embedding."));
|
|
68704
68841
|
}
|
|
68705
68842
|
function registerDocumentSetMetadata(parent) {
|
|
68706
|
-
parent.command("set-metadata").description("Change a document's metadata without resending its content (merges by default).").argument("<document-id>", "UUID of the document.").option("-s, --set <key=value...>", "Set a key. Repeatable. Values are stored as JSON strings; quote to force JSON parsing.").option("-r, --remove <key...>", "Remove a key. Repeatable. (Sends a JSON null.)").option("--json <object>", "A JSON object of keys to set; a null value removes that key.").option("--replace", "Set the metadata to EXACTLY what was given, discarding every key not listed. Default is merge.").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").option("--json-out", "Emit the result as JSON.").action(action13);
|
|
68843
|
+
parent.command("set-metadata").description("Change a document's metadata without resending its content (merges by default).").argument("<document-id>", "UUID of the document.").option("-s, --set <key=value...>", "Set a key. Repeatable. Values are stored as JSON strings; quote to force JSON parsing.").option("-r, --remove <key...>", "Remove a key. Repeatable. (Sends a JSON null.)").option("--json <object>", "A JSON object of keys to set; a null value removes that key.").option("--replace", "Set the metadata to EXACTLY what was given, discarding every key not listed. Default is merge. Needs --expected-metadata-revision or --last-write-wins.").option("--expected-metadata-revision <n>", "The metadata_revision you read (document get). Fails if the metadata changed since. Required with --replace.").option("--last-write-wins", "Replace without --expected-metadata-revision (recorded in the audit log).").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").option("--json-out", "Emit the result as JSON.").action(action13);
|
|
68707
68844
|
}
|
|
68708
68845
|
|
|
68709
68846
|
// src/cli/commands/document-set-projects.ts
|
|
@@ -73338,7 +73475,8 @@ async function action18(options) {
|
|
|
73338
73475
|
operation: row.operation,
|
|
73339
73476
|
doc: auditDocLabel(row.doc_title, row.document_id, row.operation).slice(0, 40),
|
|
73340
73477
|
author: (row.author ?? "") + (row.author_type ? `(${row.author_type})` : ""),
|
|
73341
|
-
size_delta: row.size_before !== null && row.size_after !== null ? `${row.size_before} → ${row.size_after}` : ""
|
|
73478
|
+
size_delta: row.size_before !== null && row.size_after !== null ? `${row.size_before} → ${row.size_after}` : "",
|
|
73479
|
+
change: (metadataChangeSummary(row.metadata_before, row.metadata_after) ?? "").slice(0, 60)
|
|
73342
73480
|
})));
|
|
73343
73481
|
}
|
|
73344
73482
|
function registerGetAuditLog(program) {
|
|
@@ -73478,6 +73616,9 @@ init_cli_core();
|
|
|
73478
73616
|
init_cli_core();
|
|
73479
73617
|
init_partial_edits();
|
|
73480
73618
|
init_client();
|
|
73619
|
+
function revisionSuffix(doc) {
|
|
73620
|
+
return !doc.version_id && doc.metadata_revision != null ? ` · metadata_revision: ${doc.metadata_revision}` : "";
|
|
73621
|
+
}
|
|
73481
73622
|
async function action19(documentId, options) {
|
|
73482
73623
|
const section = (options.section ?? "").trim() || null;
|
|
73483
73624
|
if (section && options.outline) {
|
|
@@ -73511,6 +73652,7 @@ async function action19(documentId, options) {
|
|
|
73511
73652
|
printJson({
|
|
73512
73653
|
title: doc.doc_title,
|
|
73513
73654
|
content_hash: doc.content_hash,
|
|
73655
|
+
metadata_revision: doc.metadata_revision ?? null,
|
|
73514
73656
|
total_chars: doc.total_chars,
|
|
73515
73657
|
outline: nodes.map((n) => ({ path: n.path, level: n.level, chars: n.chars }))
|
|
73516
73658
|
});
|
|
@@ -73519,7 +73661,7 @@ async function action19(documentId, options) {
|
|
|
73519
73661
|
println(c.bold(`# ${doc.doc_title}`));
|
|
73520
73662
|
println(c.dim(`[${doc.document_id}] · chars: ${doc.total_chars}`));
|
|
73521
73663
|
if (doc.content_hash)
|
|
73522
|
-
println(c.dim(`content_hash: ${doc.content_hash}`));
|
|
73664
|
+
println(c.dim(`content_hash: ${doc.content_hash}${revisionSuffix(doc)}`));
|
|
73523
73665
|
println("");
|
|
73524
73666
|
if (nodes.length === 0) {
|
|
73525
73667
|
println(c.dim("No headings: only --position end_of_document applies to this document."));
|
|
@@ -73569,7 +73711,7 @@ async function action19(documentId, options) {
|
|
|
73569
73711
|
println(c.bold(`# ${doc.doc_title}`));
|
|
73570
73712
|
println(c.dim(`[${doc.document_id}] · chunks: ${doc.chunk_count} · chars: ${doc.total_chars}` + (doc.is_archived ? " · archived" : "") + (doc.version_id ? ` · version: ${doc.version_id}` : "")));
|
|
73571
73713
|
if (doc.content_hash) {
|
|
73572
|
-
println(c.dim(`content_hash: ${doc.content_hash}`));
|
|
73714
|
+
println(c.dim(`content_hash: ${doc.content_hash}${revisionSuffix(doc)}`));
|
|
73573
73715
|
}
|
|
73574
73716
|
println("");
|
|
73575
73717
|
println(doc.full_content);
|
|
@@ -73637,6 +73779,8 @@ init__projects();
|
|
|
73637
73779
|
init__utils();
|
|
73638
73780
|
|
|
73639
73781
|
// src/ingestion/types.ts
|
|
73782
|
+
init__utils();
|
|
73783
|
+
|
|
73640
73784
|
class ConcurrencyConflictError extends Error {
|
|
73641
73785
|
documentId;
|
|
73642
73786
|
currentHash;
|
|
@@ -73688,7 +73832,7 @@ class IngestionDbBridge {
|
|
|
73688
73832
|
return data ?? null;
|
|
73689
73833
|
}
|
|
73690
73834
|
async getDocumentByHash(contentHash) {
|
|
73691
|
-
const { data } = await this.supabase.from("cerefox_documents").select("*").eq("content_hash", contentHash).limit(1);
|
|
73835
|
+
const { data } = await this.supabase.from("cerefox_documents").select("*").eq("content_hash", contentHash).is("deleted_at", null).order("created_at", { ascending: true }).limit(1);
|
|
73692
73836
|
const rows = data ?? [];
|
|
73693
73837
|
return rows.length > 0 ? rows[0] : null;
|
|
73694
73838
|
}
|
|
@@ -73715,6 +73859,24 @@ class IngestionDbBridge {
|
|
|
73715
73859
|
const { data } = await this.supabase.from("cerefox_document_projects").select("project_id").eq("document_id", documentId);
|
|
73716
73860
|
return (data ?? []).map((r) => r.project_id);
|
|
73717
73861
|
}
|
|
73862
|
+
async setDocumentMetadataRpc(args) {
|
|
73863
|
+
const { data, error } = await this.supabase.rpc("cerefox_set_document_metadata", {
|
|
73864
|
+
p_document_id: args.documentId,
|
|
73865
|
+
p_metadata: args.metadata,
|
|
73866
|
+
p_replace: args.replace,
|
|
73867
|
+
p_author: args.author,
|
|
73868
|
+
p_author_type: args.authorType,
|
|
73869
|
+
...metadataTokenParams(args.expectedMetadataRevision, args.lastWriteWins)
|
|
73870
|
+
});
|
|
73871
|
+
if (error) {
|
|
73872
|
+
const msg = error.message ?? JSON.stringify(error);
|
|
73873
|
+
if (msg.includes("CEREFOX_METADATA_"))
|
|
73874
|
+
throw new MetadataConcurrencyError(msg);
|
|
73875
|
+
throw new Error(msg);
|
|
73876
|
+
}
|
|
73877
|
+
const row = Array.isArray(data) ? data[0] : data;
|
|
73878
|
+
return row ?? {};
|
|
73879
|
+
}
|
|
73718
73880
|
async ingestDocumentRpc(args) {
|
|
73719
73881
|
const params = {
|
|
73720
73882
|
p_document_id: args.documentId,
|
|
@@ -73738,6 +73900,11 @@ class IngestionDbBridge {
|
|
|
73738
73900
|
if (args.documentId !== null) {
|
|
73739
73901
|
params.p_expected_content_hash = args.expectedContentHash ?? null;
|
|
73740
73902
|
params.p_last_write_wins = args.lastWriteWins ?? false;
|
|
73903
|
+
if (args.expectedMetadataRevision != null) {
|
|
73904
|
+
params.p_expected_metadata_revision = args.expectedMetadataRevision;
|
|
73905
|
+
}
|
|
73906
|
+
if (args.replaceMetadata)
|
|
73907
|
+
params.p_replace_metadata = true;
|
|
73741
73908
|
}
|
|
73742
73909
|
const { data, error } = await this.supabase.rpc("cerefox_ingest_document", params);
|
|
73743
73910
|
if (error) {
|
|
@@ -73749,7 +73916,12 @@ class IngestionDbBridge {
|
|
|
73749
73916
|
if (msg.includes("CEREFOX_TOKEN_REQUIRED")) {
|
|
73750
73917
|
throw new ConcurrencyTokenRequiredError(msg);
|
|
73751
73918
|
}
|
|
73752
|
-
|
|
73919
|
+
if (msg.includes("CEREFOX_METADATA_"))
|
|
73920
|
+
throw new MetadataConcurrencyError(msg);
|
|
73921
|
+
const duplicateId = duplicateContentDocumentId(msg);
|
|
73922
|
+
if (duplicateId)
|
|
73923
|
+
throw new DuplicateContentError(duplicateId, msg);
|
|
73924
|
+
throw legacyContentUniqueError(msg) ?? new Error(msg);
|
|
73753
73925
|
}
|
|
73754
73926
|
if (Array.isArray(data) && data.length > 0) {
|
|
73755
73927
|
return data[0];
|
|
@@ -73913,6 +74085,7 @@ async function fileToMarkdown(filename, data) {
|
|
|
73913
74085
|
}
|
|
73914
74086
|
|
|
73915
74087
|
// src/ingestion/pipeline.ts
|
|
74088
|
+
init__utils();
|
|
73916
74089
|
function updateByIdNote(updateExisting) {
|
|
73917
74090
|
return updateExisting === false ? "document_id provided; update_if_exists flag was overridden" : undefined;
|
|
73918
74091
|
}
|
|
@@ -73947,7 +74120,9 @@ class IngestionPipeline {
|
|
|
73947
74120
|
authorType = "user",
|
|
73948
74121
|
expectedContentHash,
|
|
73949
74122
|
lastWriteWins = false,
|
|
73950
|
-
forceRechunk = false
|
|
74123
|
+
forceRechunk = false,
|
|
74124
|
+
expectedMetadataRevision = null,
|
|
74125
|
+
replaceMetadata = false
|
|
73951
74126
|
} = opts;
|
|
73952
74127
|
const listFormProvided = projectIds !== undefined && projectIds !== null || projectNames !== undefined && projectNames !== null;
|
|
73953
74128
|
const getOrCreate = (name) => this.db.getOrCreateProject(name, { author, authorType });
|
|
@@ -73972,7 +74147,9 @@ class IngestionPipeline {
|
|
|
73972
74147
|
authorType,
|
|
73973
74148
|
expectedContentHash,
|
|
73974
74149
|
lastWriteWins,
|
|
73975
|
-
forceRechunk
|
|
74150
|
+
forceRechunk,
|
|
74151
|
+
expectedMetadataRevision,
|
|
74152
|
+
replaceMetadata
|
|
73976
74153
|
});
|
|
73977
74154
|
if (!listFormProvided && (projectId || projectName)) {
|
|
73978
74155
|
const singular = await resolveProjectIds({ projectId, projectName }, getOrCreate);
|
|
@@ -74031,7 +74208,9 @@ class IngestionPipeline {
|
|
|
74031
74208
|
author,
|
|
74032
74209
|
authorType,
|
|
74033
74210
|
expectedContentHash,
|
|
74034
|
-
lastWriteWins
|
|
74211
|
+
lastWriteWins,
|
|
74212
|
+
expectedMetadataRevision,
|
|
74213
|
+
replaceMetadata
|
|
74035
74214
|
});
|
|
74036
74215
|
if (!listFormProvided && (projectId || projectName)) {
|
|
74037
74216
|
const singular = await resolveProjectIds({ projectId, projectName }, getOrCreate);
|
|
@@ -74057,7 +74236,7 @@ class IngestionPipeline {
|
|
|
74057
74236
|
action: "skipped",
|
|
74058
74237
|
reindexed: false,
|
|
74059
74238
|
projectIds: existingProjectIds,
|
|
74060
|
-
note:
|
|
74239
|
+
note: "",
|
|
74061
74240
|
contentHash: existingByHash.content_hash ?? hash
|
|
74062
74241
|
};
|
|
74063
74242
|
}
|
|
@@ -74079,18 +74258,37 @@ class IngestionPipeline {
|
|
|
74079
74258
|
embedder: this.embedderModel
|
|
74080
74259
|
}));
|
|
74081
74260
|
}
|
|
74082
|
-
|
|
74083
|
-
|
|
74084
|
-
|
|
74085
|
-
|
|
74086
|
-
|
|
74087
|
-
|
|
74088
|
-
|
|
74089
|
-
|
|
74090
|
-
|
|
74091
|
-
|
|
74092
|
-
|
|
74093
|
-
|
|
74261
|
+
let rpcResult;
|
|
74262
|
+
try {
|
|
74263
|
+
rpcResult = await this.db.ingestDocumentRpc({
|
|
74264
|
+
documentId: null,
|
|
74265
|
+
title,
|
|
74266
|
+
source: source ?? sourceOnCreate ?? null,
|
|
74267
|
+
sourcePath,
|
|
74268
|
+
contentHash: hash,
|
|
74269
|
+
metadata: validatedMeta,
|
|
74270
|
+
chunks: chunkRows,
|
|
74271
|
+
contentFormat: CONTENT_FORMAT_BLIND_STITCH,
|
|
74272
|
+
author,
|
|
74273
|
+
authorType
|
|
74274
|
+
});
|
|
74275
|
+
} catch (err) {
|
|
74276
|
+
if (!(err instanceof DuplicateContentError))
|
|
74277
|
+
throw err;
|
|
74278
|
+
const existingId = err.existingDocumentId;
|
|
74279
|
+
const existingRow = await this.db.getDocumentById(existingId);
|
|
74280
|
+
return {
|
|
74281
|
+
documentId: existingId,
|
|
74282
|
+
title: existingRow?.title ?? title,
|
|
74283
|
+
chunkCount: existingRow?.chunk_count ?? 0,
|
|
74284
|
+
totalChars: existingRow?.total_chars ?? 0,
|
|
74285
|
+
action: "skipped",
|
|
74286
|
+
reindexed: false,
|
|
74287
|
+
projectIds: await this.db.getDocumentProjectIds(existingId),
|
|
74288
|
+
note: "",
|
|
74289
|
+
contentHash: hash
|
|
74290
|
+
};
|
|
74291
|
+
}
|
|
74094
74292
|
const newDocumentId = rpcResult.document_id;
|
|
74095
74293
|
if (resolvedIds.length > 0) {
|
|
74096
74294
|
await this.db.assignDocumentProjects(newDocumentId, resolvedIds);
|
|
@@ -74104,7 +74302,8 @@ class IngestionPipeline {
|
|
|
74104
74302
|
reindexed: false,
|
|
74105
74303
|
projectIds: resolvedIds,
|
|
74106
74304
|
note: "",
|
|
74107
|
-
contentHash: hash
|
|
74305
|
+
contentHash: hash,
|
|
74306
|
+
metadataRevision: rpcResult.metadata_revision
|
|
74108
74307
|
};
|
|
74109
74308
|
}
|
|
74110
74309
|
async updateDocument(opts) {
|
|
@@ -74121,7 +74320,9 @@ class IngestionPipeline {
|
|
|
74121
74320
|
authorType = "user",
|
|
74122
74321
|
expectedContentHash,
|
|
74123
74322
|
lastWriteWins = false,
|
|
74124
|
-
forceRechunk = false
|
|
74323
|
+
forceRechunk = false,
|
|
74324
|
+
expectedMetadataRevision = null,
|
|
74325
|
+
replaceMetadata = false
|
|
74125
74326
|
} = opts;
|
|
74126
74327
|
const existing = await this.db.getDocumentById(documentId);
|
|
74127
74328
|
if (!existing) {
|
|
@@ -74137,10 +74338,6 @@ class IngestionPipeline {
|
|
|
74137
74338
|
if (!lastWriteWins && expectedHashTrimmed && expectedHashTrimmed !== existing.content_hash) {
|
|
74138
74339
|
throw new ConcurrencyConflictError(documentId, existing.content_hash, `CEREFOX_CONFLICT: document ${documentId} changed since it was read ` + `(expected hash ${expectedHashTrimmed}, current hash ${existing.content_hash}). ` + `Re-read the document, merge your changes, and retry with the new hash.`);
|
|
74139
74340
|
}
|
|
74140
|
-
const collision = await this.db.getDocumentByHash(newHash);
|
|
74141
|
-
if (collision && collision.id !== documentId) {
|
|
74142
|
-
throw new Error(`Identical content already exists as document ${JSON.stringify(collision.title)}. ` + "Edit that document or change the content before saving.");
|
|
74143
|
-
}
|
|
74144
74341
|
}
|
|
74145
74342
|
let newProjectIds = null;
|
|
74146
74343
|
if (projectIds !== undefined && projectIds !== null) {
|
|
@@ -74153,11 +74350,21 @@ class IngestionPipeline {
|
|
|
74153
74350
|
if (contentUnchanged && hasChunks && !forceRechunk) {
|
|
74154
74351
|
const oldTitle = existing.title ?? "";
|
|
74155
74352
|
const titleChanged = oldTitle !== title;
|
|
74156
|
-
const
|
|
74157
|
-
|
|
74158
|
-
|
|
74353
|
+
const metadataGiven = metadata !== undefined && metadata !== null;
|
|
74354
|
+
let metadataRevision;
|
|
74355
|
+
if (metadataGiven) {
|
|
74356
|
+
const r = await this.db.setDocumentMetadataRpc({
|
|
74357
|
+
documentId,
|
|
74358
|
+
metadata,
|
|
74359
|
+
replace: replaceMetadata,
|
|
74360
|
+
author,
|
|
74361
|
+
authorType,
|
|
74362
|
+
expectedMetadataRevision,
|
|
74363
|
+
lastWriteWins
|
|
74364
|
+
});
|
|
74365
|
+
metadataRevision = r.metadata_revision;
|
|
74159
74366
|
}
|
|
74160
|
-
await this.db.updateDocumentRow(documentId,
|
|
74367
|
+
await this.db.updateDocumentRow(documentId, { title });
|
|
74161
74368
|
if (titleChanged) {
|
|
74162
74369
|
const texts = actualChunks.map((c) => embeddingInputFor(title, c));
|
|
74163
74370
|
try {
|
|
@@ -74183,15 +74390,17 @@ class IngestionPipeline {
|
|
|
74183
74390
|
}
|
|
74184
74391
|
const chunkCount = existing.chunk_count ?? 0;
|
|
74185
74392
|
const totalChars = existing.total_chars ?? 0;
|
|
74186
|
-
|
|
74187
|
-
|
|
74188
|
-
|
|
74189
|
-
|
|
74190
|
-
|
|
74191
|
-
|
|
74192
|
-
|
|
74193
|
-
|
|
74194
|
-
|
|
74393
|
+
if (!metadataGiven || titleChanged) {
|
|
74394
|
+
await this.db.createAuditEntry({
|
|
74395
|
+
operation: "update-metadata",
|
|
74396
|
+
author,
|
|
74397
|
+
authorType,
|
|
74398
|
+
documentId,
|
|
74399
|
+
sizeBefore: totalChars,
|
|
74400
|
+
sizeAfter: totalChars,
|
|
74401
|
+
description: titleChanged ? `Title changed on '${title}' (was '${oldTitle}'; content unchanged)` : `Updated metadata for '${title}' (content unchanged)`
|
|
74402
|
+
});
|
|
74403
|
+
}
|
|
74195
74404
|
return {
|
|
74196
74405
|
documentId,
|
|
74197
74406
|
title,
|
|
@@ -74201,7 +74410,8 @@ class IngestionPipeline {
|
|
|
74201
74410
|
reindexed: false,
|
|
74202
74411
|
projectIds: finalProjectIds,
|
|
74203
74412
|
note: "",
|
|
74204
|
-
contentHash: existing.content_hash ?? newHash
|
|
74413
|
+
contentHash: existing.content_hash ?? newHash,
|
|
74414
|
+
metadataRevision: metadataRevision ?? existing.metadata_revision ?? undefined
|
|
74205
74415
|
};
|
|
74206
74416
|
}
|
|
74207
74417
|
const chunks = chunkMarkdown(text, this.settings.maxChunkChars, this.settings.minChunkChars);
|
|
@@ -74221,8 +74431,8 @@ class IngestionPipeline {
|
|
|
74221
74431
|
embedder: this.embedderModel
|
|
74222
74432
|
}));
|
|
74223
74433
|
}
|
|
74224
|
-
const metaToWrite = metadata
|
|
74225
|
-
await this.db.ingestDocumentRpc({
|
|
74434
|
+
const metaToWrite = metadata ?? null;
|
|
74435
|
+
const rpcResult = await this.db.ingestDocumentRpc({
|
|
74226
74436
|
documentId,
|
|
74227
74437
|
title,
|
|
74228
74438
|
source,
|
|
@@ -74235,7 +74445,9 @@ class IngestionPipeline {
|
|
|
74235
74445
|
authorType,
|
|
74236
74446
|
sourceLabel: sourceLabel ?? source ?? "manual",
|
|
74237
74447
|
expectedContentHash: expectedHashTrimmed ?? (forceRechunk && contentUnchanged ? existing.content_hash : null),
|
|
74238
|
-
lastWriteWins
|
|
74448
|
+
lastWriteWins,
|
|
74449
|
+
expectedMetadataRevision,
|
|
74450
|
+
replaceMetadata
|
|
74239
74451
|
});
|
|
74240
74452
|
let finalProjectIds;
|
|
74241
74453
|
if (newProjectIds !== null) {
|
|
@@ -74253,7 +74465,8 @@ class IngestionPipeline {
|
|
|
74253
74465
|
reindexed: true,
|
|
74254
74466
|
projectIds: finalProjectIds,
|
|
74255
74467
|
note: "",
|
|
74256
|
-
contentHash: newHash
|
|
74468
|
+
contentHash: newHash,
|
|
74469
|
+
metadataRevision: rpcResult.metadata_revision
|
|
74257
74470
|
};
|
|
74258
74471
|
}
|
|
74259
74472
|
async ingestFile(path, opts = {}) {
|
|
@@ -74300,6 +74513,15 @@ async function readContent(path, paste) {
|
|
|
74300
74513
|
const titleFromPath = basename2(path, extname3(path));
|
|
74301
74514
|
return { content, titleFromPath };
|
|
74302
74515
|
}
|
|
74516
|
+
function parseRevision(raw) {
|
|
74517
|
+
if (raw === undefined)
|
|
74518
|
+
return null;
|
|
74519
|
+
const n = Number(raw);
|
|
74520
|
+
if (!Number.isInteger(n)) {
|
|
74521
|
+
throw userError("--expected-metadata-revision must be an integer (the metadata_revision you read).");
|
|
74522
|
+
}
|
|
74523
|
+
return n;
|
|
74524
|
+
}
|
|
74303
74525
|
async function action20(path, options) {
|
|
74304
74526
|
const { content, titleFromPath } = await readContent(path, Boolean(options.paste));
|
|
74305
74527
|
const updatingById = Boolean(options.documentId);
|
|
@@ -74355,6 +74577,7 @@ async function action20(path, options) {
|
|
|
74355
74577
|
author,
|
|
74356
74578
|
authorType,
|
|
74357
74579
|
expectedContentHash: options.expectedContentHash ?? null,
|
|
74580
|
+
expectedMetadataRevision: parseRevision(options.expectedMetadataRevision),
|
|
74358
74581
|
lastWriteWins: Boolean(options.lastWriteWins)
|
|
74359
74582
|
}) : await pipeline.ingestText({
|
|
74360
74583
|
text: content,
|
|
@@ -74369,6 +74592,7 @@ async function action20(path, options) {
|
|
|
74369
74592
|
author,
|
|
74370
74593
|
authorType,
|
|
74371
74594
|
expectedContentHash: options.expectedContentHash ?? null,
|
|
74595
|
+
expectedMetadataRevision: parseRevision(options.expectedMetadataRevision),
|
|
74372
74596
|
lastWriteWins: Boolean(options.lastWriteWins)
|
|
74373
74597
|
});
|
|
74374
74598
|
let verb;
|
|
@@ -74394,7 +74618,7 @@ async function action20(path, options) {
|
|
|
74394
74618
|
}
|
|
74395
74619
|
}
|
|
74396
74620
|
function registerIngest(program) {
|
|
74397
|
-
program.command("ingest").description("Ingest a file (or stdin paste) into the knowledge base.").argument("[path]", "Path to the file to ingest. Omit when using --paste.").option("--paste", "Read content from stdin instead of a file.").option("-t, --title <title>", "Document title (required with --paste; defaults to filename without extension).").option("-p, --project-name <name>", "Single project membership (non-destructive on update).").option("-P, --project-names <names>", "Comma-separated full project membership set (destructive replace on update).").option("-m, --metadata <json>", "JSON metadata object.").option("--source <label>", 'Origin label. Omit it on an update and the document keeps the source it already has (#193); omit it on a create and it is recorded as "cli".').option("-u, --update-if-exists", "Update an existing doc with the same title.").option("-i, --document-id <uuid>", "Update a specific document by UUID (overrides --update-if-exists).").option("--expected-content-hash <sha256>", "Optimistic-concurrency token: the content_hash of the version this edit is based on (shown by `document get` / `search`). Required on content updates unless --last-write-wins.").option("--last-write-wins", "Skip the concurrency check and overwrite regardless of concurrent changes (recorded in the audit log).").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").action(action20);
|
|
74621
|
+
program.command("ingest").description("Ingest a file (or stdin paste) into the knowledge base.").argument("[path]", "Path to the file to ingest. Omit when using --paste.").option("--paste", "Read content from stdin instead of a file.").option("-t, --title <title>", "Document title (required with --paste; defaults to filename without extension).").option("-p, --project-name <name>", "Single project membership (non-destructive on update).").option("-P, --project-names <names>", "Comma-separated full project membership set (destructive replace on update).").option("-m, --metadata <json>", "JSON metadata object.").option("--source <label>", 'Origin label. Omit it on an update and the document keeps the source it already has (#193); omit it on a create and it is recorded as "cli".').option("-u, --update-if-exists", "Update an existing doc with the same title.").option("-i, --document-id <uuid>", "Update a specific document by UUID (overrides --update-if-exists).").option("--expected-metadata-revision <n>", "With --metadata on an update: the metadata_revision you read. Fails if the metadata changed since (metadata merges; a null value removes a key).").option("--expected-content-hash <sha256>", "Optimistic-concurrency token: the content_hash of the version this edit is based on (shown by `document get` / `search`). Required on content updates unless --last-write-wins.").option("--last-write-wins", "Skip the concurrency check and overwrite regardless of concurrent changes (recorded in the audit log).").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").action(action20);
|
|
74398
74622
|
}
|
|
74399
74623
|
|
|
74400
74624
|
// src/cli/commands/document-partial-edit.ts
|
|
@@ -75497,7 +75721,6 @@ async function action30(options) {
|
|
|
75497
75721
|
});
|
|
75498
75722
|
let converted = 0;
|
|
75499
75723
|
let skipped = 0;
|
|
75500
|
-
const duplicates = [];
|
|
75501
75724
|
const failures = [];
|
|
75502
75725
|
for (let i = 0;i < targets.length; i++) {
|
|
75503
75726
|
const id = targets[i];
|
|
@@ -75540,8 +75763,6 @@ async function action30(options) {
|
|
|
75540
75763
|
const message = err instanceof Error ? err.message : String(err);
|
|
75541
75764
|
if (/conflict/i.test(message)) {
|
|
75542
75765
|
skipped++;
|
|
75543
|
-
} else if (/identical content already exists/i.test(message)) {
|
|
75544
|
-
duplicates.push({ document: `${doc.doc_title} (${id})`, reason: message });
|
|
75545
75766
|
} else {
|
|
75546
75767
|
failures.push({ document: `${doc.doc_title} (${id})`, reason: message });
|
|
75547
75768
|
}
|
|
@@ -75555,12 +75776,6 @@ async function action30(options) {
|
|
|
75555
75776
|
if (targets.length < docIds.length) {
|
|
75556
75777
|
println(c.dim(` ${docIds.length - targets.length} document(s) still pending — re-run to continue.`));
|
|
75557
75778
|
}
|
|
75558
|
-
if (duplicates.length > 0) {
|
|
75559
|
-
println("");
|
|
75560
|
-
println(c.yellow(`⚠ ${duplicates.length} document(s) could not be converted because their content is ` + "byte-identical to another document."));
|
|
75561
|
-
println(c.dim(" Re-ingesting them would collide with the content-hash dedup check. They keep working " + "on the legacy format; de-duplicate them if you want them converted."));
|
|
75562
|
-
printTable(duplicates.map((d) => ({ document: d.document })));
|
|
75563
|
-
}
|
|
75564
75779
|
if (failures.length > 0) {
|
|
75565
75780
|
println("");
|
|
75566
75781
|
printTable(failures);
|
|
@@ -75634,8 +75849,20 @@ async function action31(target, options) {
|
|
|
75634
75849
|
let skipped = 0;
|
|
75635
75850
|
let errors = 0;
|
|
75636
75851
|
const errorDetails = [];
|
|
75852
|
+
const payloadIds = new Set(payload.documents.map((d) => d.id));
|
|
75637
75853
|
for (const doc of payload.documents) {
|
|
75638
|
-
const { data:
|
|
75854
|
+
const { data: byId } = await client.raw.from("cerefox_documents").select("id").eq("id", doc.id).limit(1);
|
|
75855
|
+
let existing = (byId ?? []).length > 0;
|
|
75856
|
+
if (!existing && !doc.deleted_at && doc.content_hash) {
|
|
75857
|
+
const PAGE = 500;
|
|
75858
|
+
for (let from = 0;!existing; from += PAGE) {
|
|
75859
|
+
const { data: byHash } = await client.raw.from("cerefox_documents").select("id").eq("content_hash", doc.content_hash).is("deleted_at", null).order("id").range(from, from + PAGE - 1);
|
|
75860
|
+
const rows = byHash ?? [];
|
|
75861
|
+
existing = rows.some((m) => !payloadIds.has(m.id));
|
|
75862
|
+
if (rows.length < PAGE)
|
|
75863
|
+
break;
|
|
75864
|
+
}
|
|
75865
|
+
}
|
|
75639
75866
|
if (existing) {
|
|
75640
75867
|
skipped++;
|
|
75641
75868
|
continue;
|
|
@@ -75893,7 +76120,7 @@ async function action32(query, options) {
|
|
|
75893
76120
|
println(c.bold(`## ${title}${docId}${score}${counts}${kind}`));
|
|
75894
76121
|
const bestMatch = doc.best_chunk_heading_path?.length ? doc.best_chunk_heading_path.join(" › ") : null;
|
|
75895
76122
|
const updated = doc.doc_updated_at ? doc.doc_updated_at.slice(0, 10) : null;
|
|
75896
|
-
const hash = doc.content_hash ? `hash: ${doc.content_hash}` : null;
|
|
76123
|
+
const hash = doc.content_hash ? `hash: ${doc.content_hash}` + (doc.metadata_revision != null ? ` · metadata_revision: ${doc.metadata_revision}` : "") : null;
|
|
75897
76124
|
if (bestMatch || updated || hash) {
|
|
75898
76125
|
const bits = [
|
|
75899
76126
|
bestMatch ? `best match: ${bestMatch}` : null,
|
|
@@ -76347,41 +76574,38 @@ init_sync_self_docs();
|
|
|
76347
76574
|
init_cli_core();
|
|
76348
76575
|
import { readFileSync as readFileSync21 } from "node:fs";
|
|
76349
76576
|
|
|
76350
|
-
// ../../node_modules/.bun/@hono+node-server@2.1.
|
|
76577
|
+
// ../../node_modules/.bun/@hono+node-server@2.1.4+c539cad7f494f5c9/node_modules/@hono/node-server/dist/constants-BLSFu_RU.mjs
|
|
76351
76578
|
var X_ALREADY_SENT = "x-hono-already-sent";
|
|
76352
76579
|
|
|
76353
|
-
// ../../node_modules/.bun/@hono+node-server@2.1.
|
|
76354
|
-
import { STATUS_CODES, createServer } from "node:http";
|
|
76580
|
+
// ../../node_modules/.bun/@hono+node-server@2.1.4+c539cad7f494f5c9/node_modules/@hono/node-server/dist/index.mjs
|
|
76581
|
+
import { STATUS_CODES, ServerResponse, createServer } from "node:http";
|
|
76355
76582
|
import { Http2ServerRequest, constants } from "node:http2";
|
|
76356
76583
|
import { Readable } from "node:stream";
|
|
76357
76584
|
|
|
76358
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
76585
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/helper/websocket/index.js
|
|
76359
76586
|
var defineWebSocketHelper = (handler) => {
|
|
76360
76587
|
return (...args) => {
|
|
76361
76588
|
if (typeof args[0] === "function") {
|
|
76362
76589
|
const [createEvents, options] = args;
|
|
76363
76590
|
return async function upgradeWebSocket(c, next) {
|
|
76364
|
-
const
|
|
76365
|
-
|
|
76366
|
-
if (result) {
|
|
76591
|
+
const result = await handler(c, await createEvents(c), options);
|
|
76592
|
+
if (result)
|
|
76367
76593
|
return result;
|
|
76368
|
-
}
|
|
76369
76594
|
await next();
|
|
76370
76595
|
};
|
|
76371
76596
|
} else {
|
|
76372
76597
|
const [c, events, options] = args;
|
|
76373
76598
|
return (async () => {
|
|
76374
76599
|
const upgraded = await handler(c, events, options);
|
|
76375
|
-
if (!upgraded)
|
|
76600
|
+
if (!upgraded)
|
|
76376
76601
|
throw new Error("Failed to upgrade WebSocket");
|
|
76377
|
-
}
|
|
76378
76602
|
return upgraded;
|
|
76379
76603
|
})();
|
|
76380
76604
|
}
|
|
76381
76605
|
};
|
|
76382
76606
|
};
|
|
76383
76607
|
|
|
76384
|
-
// ../../node_modules/.bun/@hono+node-server@2.1.
|
|
76608
|
+
// ../../node_modules/.bun/@hono+node-server@2.1.4+c539cad7f494f5c9/node_modules/@hono/node-server/dist/index.mjs
|
|
76385
76609
|
var RequestError = class extends Error {
|
|
76386
76610
|
constructor(message, options) {
|
|
76387
76611
|
super(message, options);
|
|
@@ -77337,8 +77561,11 @@ var handleResponseError = (e, outgoing) => {
|
|
|
77337
77561
|
console.info("The user aborted a request.");
|
|
77338
77562
|
else {
|
|
77339
77563
|
console.error(e);
|
|
77340
|
-
if (!outgoing.headersSent)
|
|
77564
|
+
if (!outgoing.headersSent) {
|
|
77565
|
+
if (outgoing instanceof ServerResponse)
|
|
77566
|
+
outgoing._contentLength = null;
|
|
77341
77567
|
outgoing.writeHead(500, { "Content-Type": "text/plain" });
|
|
77568
|
+
}
|
|
77342
77569
|
outgoing.end(`Error: ${err.message}`);
|
|
77343
77570
|
outgoing.destroy(err);
|
|
77344
77571
|
}
|
|
@@ -77347,6 +77574,23 @@ var flushHeaders = (outgoing) => {
|
|
|
77347
77574
|
if ("flushHeaders" in outgoing && outgoing.writable)
|
|
77348
77575
|
outgoing.flushHeaders();
|
|
77349
77576
|
};
|
|
77577
|
+
var trySetContentLength = (outgoing, status, length) => {
|
|
77578
|
+
const http1 = outgoing;
|
|
77579
|
+
if (http1._contentLength === null && http1._hasBody && http1.useChunkedEncodingByDefault && !http1._removedContLen && status >= 200 && status !== 204 && status !== 304 && !outgoing.hasHeader("content-length") && !outgoing.hasHeader("transfer-encoding") && !outgoing.hasHeader("trailer")) {
|
|
77580
|
+
http1._contentLength = length;
|
|
77581
|
+
return true;
|
|
77582
|
+
}
|
|
77583
|
+
return false;
|
|
77584
|
+
};
|
|
77585
|
+
var writeDefaultHeaders = (outgoing, status, length) => {
|
|
77586
|
+
if (trySetContentLength(outgoing, status, length))
|
|
77587
|
+
outgoing.writeHead(status, { "Content-Type": defaultContentType });
|
|
77588
|
+
else
|
|
77589
|
+
outgoing.writeHead(status, {
|
|
77590
|
+
"Content-Type": defaultContentType,
|
|
77591
|
+
"Content-Length": length
|
|
77592
|
+
});
|
|
77593
|
+
};
|
|
77350
77594
|
var responseViaCache = async (res, outgoing) => {
|
|
77351
77595
|
let [status, body, header] = res[cacheKey];
|
|
77352
77596
|
if (!header) {
|
|
@@ -77354,22 +77598,13 @@ var responseViaCache = async (res, outgoing) => {
|
|
|
77354
77598
|
outgoing.writeHead(status);
|
|
77355
77599
|
outgoing.end();
|
|
77356
77600
|
} else if (typeof body === "string") {
|
|
77357
|
-
outgoing
|
|
77358
|
-
"Content-Type": defaultContentType,
|
|
77359
|
-
"Content-Length": Buffer.byteLength(body)
|
|
77360
|
-
});
|
|
77601
|
+
writeDefaultHeaders(outgoing, status, Buffer.byteLength(body));
|
|
77361
77602
|
outgoing.end(body);
|
|
77362
77603
|
} else if (body instanceof Uint8Array) {
|
|
77363
|
-
outgoing
|
|
77364
|
-
"Content-Type": defaultContentType,
|
|
77365
|
-
"Content-Length": body.byteLength
|
|
77366
|
-
});
|
|
77604
|
+
writeDefaultHeaders(outgoing, status, body.byteLength);
|
|
77367
77605
|
outgoing.end(body);
|
|
77368
77606
|
} else if (body instanceof Blob) {
|
|
77369
|
-
outgoing
|
|
77370
|
-
"Content-Type": defaultContentType,
|
|
77371
|
-
"Content-Length": body.size
|
|
77372
|
-
});
|
|
77607
|
+
writeDefaultHeaders(outgoing, status, body.size);
|
|
77373
77608
|
outgoing.end(new Uint8Array(await body.arrayBuffer()));
|
|
77374
77609
|
} else {
|
|
77375
77610
|
outgoing.writeHead(status, { "Content-Type": defaultContentType });
|
|
@@ -77380,6 +77615,8 @@ var responseViaCache = async (res, outgoing) => {
|
|
|
77380
77615
|
return;
|
|
77381
77616
|
}
|
|
77382
77617
|
let hasContentLength = false;
|
|
77618
|
+
let plainHeaders = false;
|
|
77619
|
+
let canAutoLength = true;
|
|
77383
77620
|
if (header instanceof Headers) {
|
|
77384
77621
|
hasContentLength = header.has("content-length");
|
|
77385
77622
|
header = buildOutgoingHttpHeaders(header, body === null ? undefined : defaultContentType);
|
|
@@ -77387,19 +77624,30 @@ var responseViaCache = async (res, outgoing) => {
|
|
|
77387
77624
|
const headerObj = new Headers(header);
|
|
77388
77625
|
hasContentLength = headerObj.has("content-length");
|
|
77389
77626
|
header = buildOutgoingHttpHeaders(headerObj, body === null ? undefined : defaultContentType);
|
|
77390
|
-
} else
|
|
77391
|
-
|
|
77627
|
+
} else {
|
|
77628
|
+
plainHeaders = true;
|
|
77629
|
+
for (const key in header) {
|
|
77392
77630
|
if (key.length === 14 && key.toLowerCase() === "content-length") {
|
|
77393
77631
|
hasContentLength = true;
|
|
77394
77632
|
break;
|
|
77395
77633
|
}
|
|
77634
|
+
if (key.length === 17 && key.toLowerCase() === "transfer-encoding" || key.length === 7 && key.toLowerCase() === "trailer")
|
|
77635
|
+
canAutoLength = false;
|
|
77636
|
+
}
|
|
77637
|
+
}
|
|
77396
77638
|
if (!hasContentLength) {
|
|
77639
|
+
let length;
|
|
77397
77640
|
if (typeof body === "string")
|
|
77398
|
-
|
|
77641
|
+
length = Buffer.byteLength(body);
|
|
77399
77642
|
else if (body instanceof Uint8Array)
|
|
77400
|
-
|
|
77643
|
+
length = body.byteLength;
|
|
77401
77644
|
else if (body instanceof Blob)
|
|
77402
|
-
|
|
77645
|
+
length = body.size;
|
|
77646
|
+
if (length !== undefined && (!plainHeaders || !canAutoLength || !trySetContentLength(outgoing, status, length))) {
|
|
77647
|
+
if (plainHeaders)
|
|
77648
|
+
header = { ...header };
|
|
77649
|
+
header["Content-Length"] = length;
|
|
77650
|
+
}
|
|
77403
77651
|
}
|
|
77404
77652
|
outgoing.writeHead(status, header);
|
|
77405
77653
|
if (body == null)
|
|
@@ -77810,7 +78058,7 @@ var serve = (options, listeningListener) => {
|
|
|
77810
78058
|
return server;
|
|
77811
78059
|
};
|
|
77812
78060
|
|
|
77813
|
-
// ../../node_modules/.bun/@hono+node-server@2.1.
|
|
78061
|
+
// ../../node_modules/.bun/@hono+node-server@2.1.4+c539cad7f494f5c9/node_modules/@hono/node-server/dist/utils/stream.mjs
|
|
77814
78062
|
import { Readable as Readable2 } from "node:stream";
|
|
77815
78063
|
import { versions as versions2 } from "node:process";
|
|
77816
78064
|
var pr54206Applied = () => {
|
|
@@ -77876,16 +78124,14 @@ var createStreamBody = (stream, useNativeReadableToWeb = useReadableToWeb) => {
|
|
|
77876
78124
|
});
|
|
77877
78125
|
};
|
|
77878
78126
|
|
|
77879
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
78127
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/utils/mime.js
|
|
77880
78128
|
var getMimeType = (filename, mimes = baseMimes) => {
|
|
77881
|
-
const
|
|
77882
|
-
|
|
77883
|
-
if (!match) {
|
|
78129
|
+
const match = filename.match(/\.([a-zA-Z0-9]+?)$/);
|
|
78130
|
+
if (!match)
|
|
77884
78131
|
return;
|
|
77885
|
-
}
|
|
77886
78132
|
return mimes[match[1].toLowerCase()];
|
|
77887
78133
|
};
|
|
77888
|
-
var
|
|
78134
|
+
var baseMimes = {
|
|
77889
78135
|
aac: "audio/aac",
|
|
77890
78136
|
avi: "video/x-msvideo",
|
|
77891
78137
|
avif: "image/avif",
|
|
@@ -77943,9 +78189,8 @@ var _baseMimes = {
|
|
|
77943
78189
|
gltf: "model/gltf+json",
|
|
77944
78190
|
glb: "model/gltf-binary"
|
|
77945
78191
|
};
|
|
77946
|
-
var baseMimes = _baseMimes;
|
|
77947
78192
|
|
|
77948
|
-
// ../../node_modules/.bun/@hono+node-server@2.1.
|
|
78193
|
+
// ../../node_modules/.bun/@hono+node-server@2.1.4+c539cad7f494f5c9/node_modules/@hono/node-server/dist/serve-static.mjs
|
|
77949
78194
|
import { createReadStream, existsSync as existsSync16, statSync as statSync6 } from "node:fs";
|
|
77950
78195
|
import { join as join15 } from "node:path";
|
|
77951
78196
|
var COMPRESSIBLE_CONTENT_TYPE_REGEX = /^\s*(?:text\/[^;\s]+|application\/(?:javascript|json|xml|xml-dtd|ecmascript|dart|postscript|rtf|tar|toml|vnd\.dart|vnd\.ms-fontobject|vnd\.ms-opentype|wasm|x-httpd-php|x-javascript|x-ns-proxy-autoconfig|x-sh|x-tar|x-virtualbox-hdd|x-virtualbox-ova|x-virtualbox-ovf|x-virtualbox-vbox|x-virtualbox-vdi|x-virtualbox-vhd|x-virtualbox-vmdk|x-www-form-urlencoded)|font\/(?:otf|ttf)|image\/(?:bmp|vnd\.adobe\.photoshop|vnd\.microsoft\.icon|vnd\.ms-dds|x-icon|x-ms-bmp)|message\/rfc822|model\/gltf-binary|x-shader\/x-fragment|x-shader\/x-vertex|[^;\s]+?\+(?:json|text|xml|yaml))(?:[;\s]|$)/i;
|
|
@@ -78030,6 +78275,8 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
78030
78275
|
filename = optionPath;
|
|
78031
78276
|
else
|
|
78032
78277
|
try {
|
|
78278
|
+
if (!options.allowPercentInPath && c.req.path.includes("%"))
|
|
78279
|
+
throw new Error;
|
|
78033
78280
|
filename = tryDecodeURI(c.req.path);
|
|
78034
78281
|
if (/(?:^|[\/\\])\.{1,2}(?:$|[\/\\])|[\/\\]{2,}|\\/.test(filename))
|
|
78035
78282
|
throw new Error;
|
|
@@ -78108,150 +78355,86 @@ import { existsSync as existsSync20 } from "node:fs";
|
|
|
78108
78355
|
import { readFileSync as readFileSync20, statSync as statSync9 } from "node:fs";
|
|
78109
78356
|
import { join as join19 } from "node:path";
|
|
78110
78357
|
|
|
78111
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
78112
|
-
var
|
|
78113
|
-
return (context, next) => {
|
|
78114
|
-
let index = -1;
|
|
78115
|
-
return dispatch(0);
|
|
78116
|
-
async function dispatch(i) {
|
|
78117
|
-
if (i <= index) {
|
|
78118
|
-
throw new Error("next() called multiple times");
|
|
78119
|
-
}
|
|
78120
|
-
index = i;
|
|
78121
|
-
let res;
|
|
78122
|
-
let isError = false;
|
|
78123
|
-
let handler;
|
|
78124
|
-
if (middleware[i]) {
|
|
78125
|
-
handler = middleware[i][0][0];
|
|
78126
|
-
context.req.routeIndex = i;
|
|
78127
|
-
} else {
|
|
78128
|
-
handler = i === middleware.length && next || undefined;
|
|
78129
|
-
}
|
|
78130
|
-
if (handler) {
|
|
78131
|
-
try {
|
|
78132
|
-
res = await handler(context, () => dispatch(i + 1));
|
|
78133
|
-
} catch (err) {
|
|
78134
|
-
if (err instanceof Error && onError) {
|
|
78135
|
-
context.error = err;
|
|
78136
|
-
res = await onError(err, context);
|
|
78137
|
-
isError = true;
|
|
78138
|
-
} else {
|
|
78139
|
-
throw err;
|
|
78140
|
-
}
|
|
78141
|
-
}
|
|
78142
|
-
} else {
|
|
78143
|
-
if (context.finalized === false && onNotFound) {
|
|
78144
|
-
res = await onNotFound(context);
|
|
78145
|
-
}
|
|
78146
|
-
}
|
|
78147
|
-
if (res && (context.finalized === false || isError)) {
|
|
78148
|
-
context.res = res;
|
|
78149
|
-
}
|
|
78150
|
-
return context;
|
|
78151
|
-
}
|
|
78152
|
-
};
|
|
78153
|
-
};
|
|
78154
|
-
|
|
78155
|
-
// ../../node_modules/.bun/hono@4.13.7/node_modules/hono/dist/request/constants.js
|
|
78156
|
-
var GET_MATCH_RESULT = /* @__PURE__ */ Symbol();
|
|
78358
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/request/constants.js
|
|
78359
|
+
var GET_MATCH_RESULT = Symbol();
|
|
78157
78360
|
|
|
78158
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
78361
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/utils/buffer.js
|
|
78159
78362
|
var bufferToFormData = (arrayBuffer, contentType) => {
|
|
78160
|
-
|
|
78161
|
-
headers: {
|
|
78162
|
-
"Content-Type": contentType.replace(/^[^;]+/, (mediaType) => mediaType.toLowerCase())
|
|
78163
|
-
}
|
|
78164
|
-
});
|
|
78165
|
-
return response.formData();
|
|
78363
|
+
return new Response(arrayBuffer, { headers: { "Content-Type": contentType.replace(/^[^;]+/, (mediaType) => mediaType.toLowerCase()) } }).formData();
|
|
78166
78364
|
};
|
|
78167
78365
|
|
|
78168
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
78169
|
-
var MAX_NESTING_DEPTH = 32;
|
|
78366
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/utils/body.js
|
|
78170
78367
|
var MAX_NESTED_OBJECTS = 1e4;
|
|
78171
78368
|
var isRawRequest = (request) => ("headers" in request);
|
|
78172
|
-
var parseBody = async (request, options =
|
|
78369
|
+
var parseBody = async (request, options = Object.create(null)) => {
|
|
78173
78370
|
const { all = false, dot = false } = options;
|
|
78174
|
-
const
|
|
78175
|
-
|
|
78176
|
-
|
|
78177
|
-
|
|
78178
|
-
|
|
78179
|
-
|
|
78371
|
+
const mediaType = (isRawRequest(request) ? request.headers : request.raw.headers).get("Content-Type")?.split(";")[0].trim().toLowerCase();
|
|
78372
|
+
if (mediaType === "multipart/form-data" || mediaType === "application/x-www-form-urlencoded")
|
|
78373
|
+
return parseFormData(request, {
|
|
78374
|
+
all,
|
|
78375
|
+
dot
|
|
78376
|
+
});
|
|
78180
78377
|
return {};
|
|
78181
78378
|
};
|
|
78182
78379
|
async function parseFormData(request, options) {
|
|
78183
|
-
if (!isRawRequest(request) && request.bodyCache.formData)
|
|
78380
|
+
if (!isRawRequest(request) && request.bodyCache.formData)
|
|
78184
78381
|
return convertFormDataToBodyData(await request.bodyCache.formData, options);
|
|
78185
|
-
}
|
|
78186
78382
|
const headers = isRawRequest(request) ? request.headers : request.raw.headers;
|
|
78187
78383
|
const arrayBuffer = await request.arrayBuffer();
|
|
78188
78384
|
const formDataPromise = bufferToFormData(arrayBuffer, headers.get("Content-Type") || "");
|
|
78189
|
-
if (!isRawRequest(request))
|
|
78385
|
+
if (!isRawRequest(request))
|
|
78190
78386
|
request.bodyCache.formData = formDataPromise;
|
|
78191
|
-
}
|
|
78192
78387
|
const formData = await formDataPromise;
|
|
78193
|
-
if (formData)
|
|
78388
|
+
if (formData)
|
|
78194
78389
|
return convertFormDataToBodyData(formData, options);
|
|
78195
|
-
}
|
|
78196
78390
|
return {};
|
|
78197
78391
|
}
|
|
78198
78392
|
function convertFormDataToBodyData(formData, options) {
|
|
78199
|
-
const form =
|
|
78393
|
+
const form = Object.create(null);
|
|
78200
78394
|
const nestingState = { count: 0 };
|
|
78201
78395
|
formData.forEach((value, key) => {
|
|
78202
|
-
|
|
78203
|
-
if (!shouldParseAllValues) {
|
|
78396
|
+
if (!(options.all || key.endsWith("[]")))
|
|
78204
78397
|
form[key] = value;
|
|
78205
|
-
|
|
78398
|
+
else
|
|
78206
78399
|
handleParsingAllValues(form, key, value);
|
|
78207
|
-
}
|
|
78208
78400
|
});
|
|
78209
|
-
if (options.dot)
|
|
78401
|
+
if (options.dot)
|
|
78210
78402
|
Object.entries(form).forEach(([key, value]) => {
|
|
78211
|
-
|
|
78212
|
-
if (shouldParseDotValues) {
|
|
78403
|
+
if (key.includes(".")) {
|
|
78213
78404
|
handleParsingNestedValues(form, key, value, nestingState);
|
|
78214
78405
|
delete form[key];
|
|
78215
78406
|
}
|
|
78216
78407
|
});
|
|
78217
|
-
}
|
|
78218
78408
|
return form;
|
|
78219
78409
|
}
|
|
78220
78410
|
var handleParsingAllValues = (form, key, value) => {
|
|
78221
78411
|
if (form[key] !== undefined) {
|
|
78222
|
-
if (Array.isArray(form[key]))
|
|
78412
|
+
if (Array.isArray(form[key]))
|
|
78223
78413
|
form[key].push(value);
|
|
78224
|
-
|
|
78414
|
+
else
|
|
78225
78415
|
form[key] = [form[key], value];
|
|
78226
|
-
|
|
78227
|
-
|
|
78228
|
-
|
|
78229
|
-
|
|
78230
|
-
} else {
|
|
78231
|
-
form[key] = [value];
|
|
78232
|
-
}
|
|
78233
|
-
}
|
|
78416
|
+
} else if (!key.endsWith("[]"))
|
|
78417
|
+
form[key] = value;
|
|
78418
|
+
else
|
|
78419
|
+
form[key] = [value];
|
|
78234
78420
|
};
|
|
78235
78421
|
var handleParsingNestedValues = (form, key, value, state) => {
|
|
78236
|
-
if (/(?:^|\.)__proto__\./.test(key))
|
|
78422
|
+
if (/(?:^|\.)__proto__\./.test(key))
|
|
78237
78423
|
return;
|
|
78238
|
-
}
|
|
78239
78424
|
let nestedForm = form;
|
|
78240
|
-
const keys = key.split(".",
|
|
78241
|
-
if (keys.length >
|
|
78425
|
+
const keys = key.split(".", 34);
|
|
78426
|
+
if (keys.length > 33)
|
|
78242
78427
|
throwNestingLimitExceeded();
|
|
78243
|
-
|
|
78244
|
-
|
|
78245
|
-
|
|
78246
|
-
|
|
78247
|
-
|
|
78248
|
-
|
|
78249
|
-
if (state.count++ >= MAX_NESTED_OBJECTS) {
|
|
78428
|
+
keys.forEach((key, index) => {
|
|
78429
|
+
if (index === keys.length - 1)
|
|
78430
|
+
nestedForm[key] = value;
|
|
78431
|
+
else {
|
|
78432
|
+
if (!nestedForm[key] || typeof nestedForm[key] !== "object" || Array.isArray(nestedForm[key]) || nestedForm[key] instanceof File) {
|
|
78433
|
+
if (state.count++ >= MAX_NESTED_OBJECTS)
|
|
78250
78434
|
throwNestingLimitExceeded();
|
|
78251
|
-
|
|
78252
|
-
nestedForm[key2] = /* @__PURE__ */ Object.create(null);
|
|
78435
|
+
nestedForm[key] = Object.create(null);
|
|
78253
78436
|
}
|
|
78254
|
-
nestedForm = nestedForm[
|
|
78437
|
+
nestedForm = nestedForm[key];
|
|
78255
78438
|
}
|
|
78256
78439
|
});
|
|
78257
78440
|
};
|
|
@@ -78259,12 +78442,11 @@ var throwNestingLimitExceeded = () => {
|
|
|
78259
78442
|
throw new Error("Nesting limit exceeded");
|
|
78260
78443
|
};
|
|
78261
78444
|
|
|
78262
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
78445
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/utils/url.js
|
|
78263
78446
|
var splitPath = (path) => {
|
|
78264
78447
|
const paths = path.split("/");
|
|
78265
|
-
if (paths[0] === "")
|
|
78448
|
+
if (paths[0] === "")
|
|
78266
78449
|
paths.shift();
|
|
78267
|
-
}
|
|
78268
78450
|
return paths;
|
|
78269
78451
|
};
|
|
78270
78452
|
var splitRoutingPath = (routePath) => {
|
|
@@ -78279,34 +78461,46 @@ var extractGroupsFromPath = (path) => {
|
|
|
78279
78461
|
groups.push([mark, match]);
|
|
78280
78462
|
return mark;
|
|
78281
78463
|
});
|
|
78282
|
-
return {
|
|
78464
|
+
return {
|
|
78465
|
+
groups,
|
|
78466
|
+
path
|
|
78467
|
+
};
|
|
78283
78468
|
};
|
|
78284
78469
|
var replaceGroupMarks = (paths, groups) => {
|
|
78285
78470
|
for (let i = groups.length - 1;i >= 0; i--) {
|
|
78286
78471
|
const [mark] = groups[i];
|
|
78287
|
-
for (let j = paths.length - 1;j >= 0; j--)
|
|
78472
|
+
for (let j = paths.length - 1;j >= 0; j--)
|
|
78288
78473
|
if (paths[j].includes(mark)) {
|
|
78289
78474
|
paths[j] = paths[j].replace(mark, groups[i][1]);
|
|
78290
78475
|
break;
|
|
78291
78476
|
}
|
|
78292
|
-
}
|
|
78293
78477
|
}
|
|
78294
78478
|
return paths;
|
|
78295
78479
|
};
|
|
78296
78480
|
var patternCache = {};
|
|
78297
78481
|
var getPattern = (label, next) => {
|
|
78298
|
-
if (label === "*")
|
|
78482
|
+
if (label === "*")
|
|
78299
78483
|
return "*";
|
|
78300
|
-
}
|
|
78301
78484
|
const match = label.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
|
|
78302
78485
|
if (match) {
|
|
78303
78486
|
const cacheKey = `${label}#${next}`;
|
|
78304
78487
|
if (!patternCache[cacheKey]) {
|
|
78305
|
-
if (match[2])
|
|
78306
|
-
patternCache[cacheKey] = next && next[0] !== ":" && next[0] !== "*" ? [
|
|
78307
|
-
|
|
78308
|
-
|
|
78309
|
-
|
|
78488
|
+
if (match[2])
|
|
78489
|
+
patternCache[cacheKey] = next && next[0] !== ":" && next[0] !== "*" ? [
|
|
78490
|
+
cacheKey,
|
|
78491
|
+
match[1],
|
|
78492
|
+
new RegExp(`^${match[2]}(?=/${next})`)
|
|
78493
|
+
] : [
|
|
78494
|
+
label,
|
|
78495
|
+
match[1],
|
|
78496
|
+
new RegExp(`^${match[2]}$`)
|
|
78497
|
+
];
|
|
78498
|
+
else
|
|
78499
|
+
patternCache[cacheKey] = [
|
|
78500
|
+
label,
|
|
78501
|
+
match[1],
|
|
78502
|
+
true
|
|
78503
|
+
];
|
|
78310
78504
|
}
|
|
78311
78505
|
return patternCache[cacheKey];
|
|
78312
78506
|
}
|
|
@@ -78338,9 +78532,8 @@ var getPath = (request) => {
|
|
|
78338
78532
|
const end = queryIndex === -1 ? hashIndex === -1 ? undefined : hashIndex : hashIndex === -1 ? queryIndex : Math.min(queryIndex, hashIndex);
|
|
78339
78533
|
const path = url.slice(start, end);
|
|
78340
78534
|
return tryDecodeURI2(path.includes("%25") ? path.replace(/%25/g, "%2525") : path);
|
|
78341
|
-
} else if (charCode === 63 || charCode === 35)
|
|
78535
|
+
} else if (charCode === 63 || charCode === 35)
|
|
78342
78536
|
break;
|
|
78343
|
-
}
|
|
78344
78537
|
}
|
|
78345
78538
|
return url.slice(start, i);
|
|
78346
78539
|
};
|
|
@@ -78349,109 +78542,93 @@ var getPathNoStrict = (request) => {
|
|
|
78349
78542
|
return result.length > 1 && result.at(-1) === "/" ? result.slice(0, -1) : result;
|
|
78350
78543
|
};
|
|
78351
78544
|
var mergePath = (base, sub, ...rest) => {
|
|
78352
|
-
if (rest.length)
|
|
78545
|
+
if (rest.length)
|
|
78353
78546
|
sub = mergePath(sub, ...rest);
|
|
78354
|
-
}
|
|
78355
78547
|
return `${base?.[0] === "/" ? "" : "/"}${base}${sub === "/" ? "" : `${base?.at(-1) === "/" ? "" : "/"}${sub?.[0] === "/" ? sub.slice(1) : sub}`}`;
|
|
78356
78548
|
};
|
|
78357
78549
|
var checkOptionalParameter = (path) => {
|
|
78358
|
-
if (path.charCodeAt(path.length - 1) !== 63 || !path.includes(":"))
|
|
78550
|
+
if (path.charCodeAt(path.length - 1) !== 63 || !path.includes(":"))
|
|
78359
78551
|
return null;
|
|
78360
|
-
}
|
|
78361
78552
|
const segments = path.split("/");
|
|
78362
78553
|
const results = [];
|
|
78363
78554
|
let basePath = "";
|
|
78364
78555
|
segments.forEach((segment) => {
|
|
78365
|
-
if (segment !== "" && !/\:/.test(segment))
|
|
78556
|
+
if (segment !== "" && !/\:/.test(segment))
|
|
78366
78557
|
basePath += "/" + segment;
|
|
78367
|
-
|
|
78558
|
+
else if (/\:/.test(segment)) {
|
|
78368
78559
|
if (segment.charCodeAt(segment.length - 1) === 63) {
|
|
78369
|
-
if (results.length === 0 && basePath === "")
|
|
78560
|
+
if (results.length === 0 && basePath === "")
|
|
78370
78561
|
results.push("/");
|
|
78371
|
-
|
|
78562
|
+
else
|
|
78372
78563
|
results.push(basePath);
|
|
78373
|
-
}
|
|
78374
78564
|
const optionalSegment = segment.slice(0, -1);
|
|
78375
78565
|
basePath += "/" + optionalSegment;
|
|
78376
78566
|
results.push(basePath);
|
|
78377
|
-
} else
|
|
78567
|
+
} else
|
|
78378
78568
|
basePath += "/" + segment;
|
|
78379
|
-
}
|
|
78380
78569
|
}
|
|
78381
78570
|
});
|
|
78382
78571
|
return results.filter((v, i, a) => a.indexOf(v) === i);
|
|
78383
78572
|
};
|
|
78384
78573
|
var tryDecodeURIComponent = (str) => str.indexOf("%") !== -1 ? tryDecode2(str, decodeURIComponent_) : str;
|
|
78385
78574
|
var _decodeURI = (value) => {
|
|
78386
|
-
if (value.indexOf("+") !== -1)
|
|
78575
|
+
if (value.indexOf("+") !== -1)
|
|
78387
78576
|
value = value.replace(/\+/g, " ");
|
|
78388
|
-
}
|
|
78389
78577
|
return tryDecodeURIComponent(value);
|
|
78390
78578
|
};
|
|
78391
78579
|
var _getQueryParam = (url, key, multiple) => {
|
|
78392
78580
|
const hashIndex = url.indexOf("#", 8);
|
|
78393
|
-
if (hashIndex !== -1)
|
|
78581
|
+
if (hashIndex !== -1)
|
|
78394
78582
|
url = url.slice(0, hashIndex);
|
|
78395
|
-
}
|
|
78396
78583
|
let encoded;
|
|
78397
78584
|
if (!multiple && key && key.indexOf("%") === -1 && key.indexOf("+") === -1) {
|
|
78398
|
-
let
|
|
78399
|
-
if (
|
|
78585
|
+
let keyIndex = url.indexOf("?", 8);
|
|
78586
|
+
if (keyIndex === -1)
|
|
78400
78587
|
return;
|
|
78401
|
-
|
|
78402
|
-
|
|
78403
|
-
|
|
78404
|
-
|
|
78405
|
-
while (keyIndex2 !== -1) {
|
|
78406
|
-
const trailingKeyCode = url.charCodeAt(keyIndex2 + key.length + 1);
|
|
78588
|
+
if (!url.startsWith(key, keyIndex + 1))
|
|
78589
|
+
keyIndex = url.indexOf(`&${key}`, keyIndex + 1);
|
|
78590
|
+
while (keyIndex !== -1) {
|
|
78591
|
+
const trailingKeyCode = url.charCodeAt(keyIndex + key.length + 1);
|
|
78407
78592
|
if (trailingKeyCode === 61) {
|
|
78408
|
-
const valueIndex =
|
|
78593
|
+
const valueIndex = keyIndex + key.length + 2;
|
|
78409
78594
|
const endIndex = url.indexOf("&", valueIndex);
|
|
78410
78595
|
return _decodeURI(url.slice(valueIndex, endIndex === -1 ? undefined : endIndex));
|
|
78411
|
-
} else if (trailingKeyCode == 38 || isNaN(trailingKeyCode))
|
|
78596
|
+
} else if (trailingKeyCode == 38 || isNaN(trailingKeyCode))
|
|
78412
78597
|
return "";
|
|
78413
|
-
}
|
|
78414
|
-
keyIndex2 = url.indexOf(`&${key}`, keyIndex2 + 1);
|
|
78598
|
+
keyIndex = url.indexOf(`&${key}`, keyIndex + 1);
|
|
78415
78599
|
}
|
|
78416
78600
|
encoded = /[%+]/.test(url);
|
|
78417
|
-
if (!encoded)
|
|
78601
|
+
if (!encoded)
|
|
78418
78602
|
return;
|
|
78419
|
-
}
|
|
78420
78603
|
}
|
|
78421
|
-
const results =
|
|
78604
|
+
const results = Object.create(null);
|
|
78422
78605
|
encoded ??= /[%+]/.test(url);
|
|
78423
78606
|
let keyIndex = url.indexOf("?", 8);
|
|
78424
78607
|
while (keyIndex !== -1) {
|
|
78425
78608
|
const nextKeyIndex = url.indexOf("&", keyIndex + 1);
|
|
78426
78609
|
let valueIndex = url.indexOf("=", keyIndex);
|
|
78427
|
-
if (valueIndex > nextKeyIndex && nextKeyIndex !== -1)
|
|
78610
|
+
if (valueIndex > nextKeyIndex && nextKeyIndex !== -1)
|
|
78428
78611
|
valueIndex = -1;
|
|
78429
|
-
}
|
|
78430
78612
|
let name = url.slice(keyIndex + 1, valueIndex === -1 ? nextKeyIndex === -1 ? undefined : nextKeyIndex : valueIndex);
|
|
78431
|
-
if (encoded)
|
|
78613
|
+
if (encoded)
|
|
78432
78614
|
name = _decodeURI(name);
|
|
78433
|
-
}
|
|
78434
78615
|
keyIndex = nextKeyIndex;
|
|
78435
|
-
if (name === "")
|
|
78616
|
+
if (name === "")
|
|
78436
78617
|
continue;
|
|
78437
|
-
}
|
|
78438
78618
|
let value;
|
|
78439
|
-
if (valueIndex === -1)
|
|
78619
|
+
if (valueIndex === -1)
|
|
78440
78620
|
value = "";
|
|
78441
|
-
|
|
78621
|
+
else {
|
|
78442
78622
|
value = url.slice(valueIndex + 1, nextKeyIndex === -1 ? undefined : nextKeyIndex);
|
|
78443
|
-
if (encoded)
|
|
78623
|
+
if (encoded)
|
|
78444
78624
|
value = _decodeURI(value);
|
|
78445
|
-
}
|
|
78446
78625
|
}
|
|
78447
78626
|
if (multiple) {
|
|
78448
|
-
if (!(results[name] && Array.isArray(results[name])))
|
|
78627
|
+
if (!(results[name] && Array.isArray(results[name])))
|
|
78449
78628
|
results[name] = [];
|
|
78450
|
-
}
|
|
78451
78629
|
results[name].push(value);
|
|
78452
|
-
} else
|
|
78630
|
+
} else
|
|
78453
78631
|
results[name] ??= value;
|
|
78454
|
-
}
|
|
78455
78632
|
}
|
|
78456
78633
|
return key ? results[key] : results;
|
|
78457
78634
|
};
|
|
@@ -78461,7 +78638,7 @@ var getQueryParams = (url, key) => {
|
|
|
78461
78638
|
};
|
|
78462
78639
|
var decodeURIComponent_ = decodeURIComponent;
|
|
78463
78640
|
|
|
78464
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
78641
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/request.js
|
|
78465
78642
|
var HonoRequest = class {
|
|
78466
78643
|
raw;
|
|
78467
78644
|
#validatedData;
|
|
@@ -78487,9 +78664,8 @@ var HonoRequest = class {
|
|
|
78487
78664
|
const keys = Object.keys(this.#matchResult[0][this.routeIndex]?.[1] ?? {});
|
|
78488
78665
|
for (const key of keys) {
|
|
78489
78666
|
const value = this.#getParamValue(this.#matchResult[0][this.routeIndex][1][key]);
|
|
78490
|
-
if (value !== undefined)
|
|
78667
|
+
if (value !== undefined)
|
|
78491
78668
|
decoded[key] = tryDecodeURIComponent(value);
|
|
78492
|
-
}
|
|
78493
78669
|
}
|
|
78494
78670
|
return decoded;
|
|
78495
78671
|
}
|
|
@@ -78503,10 +78679,9 @@ var HonoRequest = class {
|
|
|
78503
78679
|
return getQueryParams(this.url, key);
|
|
78504
78680
|
}
|
|
78505
78681
|
header(name) {
|
|
78506
|
-
if (name)
|
|
78682
|
+
if (name)
|
|
78507
78683
|
return this.raw.headers.get(name) ?? undefined;
|
|
78508
|
-
|
|
78509
|
-
const headerData = /* @__PURE__ */ Object.create(null);
|
|
78684
|
+
const headerData = Object.create(null);
|
|
78510
78685
|
this.raw.headers.forEach((value, key) => {
|
|
78511
78686
|
headerData[key] = value;
|
|
78512
78687
|
});
|
|
@@ -78518,17 +78693,15 @@ var HonoRequest = class {
|
|
|
78518
78693
|
#cachedBody = (key) => {
|
|
78519
78694
|
const { bodyCache, raw } = this;
|
|
78520
78695
|
const cachedBody = bodyCache[key];
|
|
78521
|
-
if (cachedBody)
|
|
78696
|
+
if (cachedBody)
|
|
78522
78697
|
return cachedBody;
|
|
78523
|
-
|
|
78524
|
-
for (const anyCachedKey in bodyCache) {
|
|
78698
|
+
for (const anyCachedKey in bodyCache)
|
|
78525
78699
|
return bodyCache[anyCachedKey].then((body) => {
|
|
78526
|
-
if (anyCachedKey === "json")
|
|
78700
|
+
if (anyCachedKey === "json")
|
|
78527
78701
|
body = JSON.stringify(body);
|
|
78528
|
-
|
|
78529
|
-
return new Response(body)[key]();
|
|
78702
|
+
const contentType = anyCachedKey === "formData" ? undefined : raw.headers.get("content-type");
|
|
78703
|
+
return new Response(body, { headers: contentType ? { "Content-Type": contentType } : undefined })[key]();
|
|
78530
78704
|
});
|
|
78531
|
-
}
|
|
78532
78705
|
return bodyCache[key] = raw[key]();
|
|
78533
78706
|
};
|
|
78534
78707
|
json() {
|
|
@@ -78572,7 +78745,7 @@ var HonoRequest = class {
|
|
|
78572
78745
|
}
|
|
78573
78746
|
};
|
|
78574
78747
|
|
|
78575
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
78748
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/utils/html.js
|
|
78576
78749
|
var HtmlEscapedCallbackPhase = {
|
|
78577
78750
|
Stringify: 1,
|
|
78578
78751
|
BeforeStream: 2,
|
|
@@ -78586,31 +78759,30 @@ var raw = (value, callbacks) => {
|
|
|
78586
78759
|
};
|
|
78587
78760
|
var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => {
|
|
78588
78761
|
if (typeof str === "object" && !(str instanceof String)) {
|
|
78589
|
-
if (!(str instanceof Promise))
|
|
78762
|
+
if (!(str instanceof Promise))
|
|
78590
78763
|
str = str.toString();
|
|
78591
|
-
|
|
78592
|
-
if (str instanceof Promise) {
|
|
78764
|
+
if (str instanceof Promise)
|
|
78593
78765
|
str = await str;
|
|
78594
|
-
}
|
|
78595
78766
|
}
|
|
78596
78767
|
const callbacks = str.callbacks;
|
|
78597
|
-
if (!callbacks?.length)
|
|
78768
|
+
if (!callbacks?.length)
|
|
78598
78769
|
return Promise.resolve(str);
|
|
78599
|
-
|
|
78600
|
-
if (buffer) {
|
|
78770
|
+
if (buffer)
|
|
78601
78771
|
buffer[0] += str;
|
|
78602
|
-
|
|
78772
|
+
else
|
|
78603
78773
|
buffer = [str];
|
|
78604
|
-
|
|
78605
|
-
|
|
78606
|
-
|
|
78774
|
+
const resStr = Promise.all(callbacks.map((c) => c({
|
|
78775
|
+
phase,
|
|
78776
|
+
buffer,
|
|
78777
|
+
context
|
|
78778
|
+
}))).then((res) => Promise.all(res.filter(Boolean).map((str) => resolveCallback(str, phase, false, context, buffer))).then(() => buffer[0]));
|
|
78779
|
+
if (preserveCallbacks)
|
|
78607
78780
|
return raw(await resStr, callbacks);
|
|
78608
|
-
|
|
78781
|
+
else
|
|
78609
78782
|
return resStr;
|
|
78610
|
-
}
|
|
78611
78783
|
};
|
|
78612
78784
|
|
|
78613
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
78785
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/context.js
|
|
78614
78786
|
var TEXT_PLAIN = "text/plain; charset=UTF-8";
|
|
78615
78787
|
var setDefaultContentType = (contentType, headers) => {
|
|
78616
78788
|
return {
|
|
@@ -78650,40 +78822,33 @@ var Context = class {
|
|
|
78650
78822
|
return this.#req;
|
|
78651
78823
|
}
|
|
78652
78824
|
get event() {
|
|
78653
|
-
if (this.#executionCtx && "respondWith" in this.#executionCtx)
|
|
78825
|
+
if (this.#executionCtx && "respondWith" in this.#executionCtx)
|
|
78654
78826
|
return this.#executionCtx;
|
|
78655
|
-
|
|
78827
|
+
else
|
|
78656
78828
|
throw Error("This context has no FetchEvent");
|
|
78657
|
-
}
|
|
78658
78829
|
}
|
|
78659
78830
|
get executionCtx() {
|
|
78660
|
-
if (this.#executionCtx)
|
|
78831
|
+
if (this.#executionCtx)
|
|
78661
78832
|
return this.#executionCtx;
|
|
78662
|
-
|
|
78833
|
+
else
|
|
78663
78834
|
throw Error("This context has no ExecutionContext");
|
|
78664
|
-
}
|
|
78665
78835
|
}
|
|
78666
78836
|
get res() {
|
|
78667
|
-
return this.#res ||= createResponseInstance(null, {
|
|
78668
|
-
headers: this.#preparedHeaders ??= new Headers
|
|
78669
|
-
});
|
|
78837
|
+
return this.#res ||= createResponseInstance(null, { headers: this.#preparedHeaders ??= new Headers });
|
|
78670
78838
|
}
|
|
78671
78839
|
set res(_res) {
|
|
78672
78840
|
if (this.#res && _res) {
|
|
78673
78841
|
_res = createResponseInstance(_res.body, _res);
|
|
78674
78842
|
for (const [k, v] of this.#res.headers.entries()) {
|
|
78675
|
-
if (k === "content-type")
|
|
78843
|
+
if (k === "content-type")
|
|
78676
78844
|
continue;
|
|
78677
|
-
}
|
|
78678
78845
|
if (k === "set-cookie") {
|
|
78679
78846
|
const cookies = this.#res.headers.getSetCookie();
|
|
78680
78847
|
_res.headers.delete("set-cookie");
|
|
78681
|
-
for (const cookie of cookies)
|
|
78848
|
+
for (const cookie of cookies)
|
|
78682
78849
|
_res.headers.append("set-cookie", cookie);
|
|
78683
|
-
|
|
78684
|
-
} else {
|
|
78850
|
+
} else
|
|
78685
78851
|
_res.headers.set(k, v);
|
|
78686
|
-
}
|
|
78687
78852
|
}
|
|
78688
78853
|
}
|
|
78689
78854
|
this.#res = _res;
|
|
@@ -78699,17 +78864,15 @@ var Context = class {
|
|
|
78699
78864
|
this.#renderer = renderer;
|
|
78700
78865
|
};
|
|
78701
78866
|
header = (name, value, options) => {
|
|
78702
|
-
if (this.finalized)
|
|
78867
|
+
if (this.finalized)
|
|
78703
78868
|
this.#res = createResponseInstance(this.#res.body, this.#res);
|
|
78704
|
-
}
|
|
78705
78869
|
const headers = this.#res ? this.#res.headers : this.#preparedHeaders ??= new Headers;
|
|
78706
|
-
if (value === undefined)
|
|
78870
|
+
if (value === undefined)
|
|
78707
78871
|
headers.delete(name);
|
|
78708
|
-
|
|
78872
|
+
else if (options?.append)
|
|
78709
78873
|
headers.append(name, value);
|
|
78710
|
-
|
|
78874
|
+
else
|
|
78711
78875
|
headers.set(name, value);
|
|
78712
|
-
}
|
|
78713
78876
|
};
|
|
78714
78877
|
status = (status) => {
|
|
78715
78878
|
this.#status = status;
|
|
@@ -78722,46 +78885,40 @@ var Context = class {
|
|
|
78722
78885
|
return this.#var ? this.#var.get(key) : undefined;
|
|
78723
78886
|
};
|
|
78724
78887
|
get var() {
|
|
78725
|
-
if (!this.#var)
|
|
78888
|
+
if (!this.#var)
|
|
78726
78889
|
return {};
|
|
78727
|
-
}
|
|
78728
78890
|
return Object.fromEntries(this.#var);
|
|
78729
78891
|
}
|
|
78730
78892
|
#newResponse(data, arg, headers) {
|
|
78731
78893
|
let responseHeaders = this.#res ? new Headers(this.#res.headers) : this.#preparedHeaders;
|
|
78732
78894
|
if (typeof arg === "object" && arg.headers) {
|
|
78733
78895
|
responseHeaders ??= new Headers;
|
|
78734
|
-
for (const [key, value] of new Headers(arg.headers))
|
|
78735
|
-
if (key === "set-cookie")
|
|
78896
|
+
for (const [key, value] of new Headers(arg.headers))
|
|
78897
|
+
if (key === "set-cookie")
|
|
78736
78898
|
responseHeaders.append(key, value);
|
|
78737
|
-
|
|
78899
|
+
else
|
|
78738
78900
|
responseHeaders.set(key, value);
|
|
78739
|
-
}
|
|
78740
|
-
}
|
|
78741
78901
|
}
|
|
78742
78902
|
if (headers) {
|
|
78743
78903
|
if (!responseHeaders) {
|
|
78744
78904
|
let count = 0;
|
|
78745
|
-
for (const k in headers)
|
|
78905
|
+
for (const k in headers)
|
|
78746
78906
|
if (++count > 1 || typeof headers[k] !== "string") {
|
|
78747
78907
|
responseHeaders = new Headers;
|
|
78748
78908
|
break;
|
|
78749
78909
|
}
|
|
78750
|
-
}
|
|
78751
78910
|
}
|
|
78752
|
-
if (responseHeaders)
|
|
78911
|
+
if (responseHeaders)
|
|
78753
78912
|
for (const k in headers) {
|
|
78754
78913
|
const v = headers[k];
|
|
78755
|
-
if (typeof v === "string")
|
|
78914
|
+
if (typeof v === "string")
|
|
78756
78915
|
responseHeaders.set(k, v);
|
|
78757
|
-
|
|
78916
|
+
else {
|
|
78758
78917
|
responseHeaders.delete(k);
|
|
78759
|
-
for (const v2 of v)
|
|
78918
|
+
for (const v2 of v)
|
|
78760
78919
|
responseHeaders.append(k, v2);
|
|
78761
|
-
}
|
|
78762
78920
|
}
|
|
78763
78921
|
}
|
|
78764
|
-
}
|
|
78765
78922
|
}
|
|
78766
78923
|
const status = typeof arg === "number" ? arg : arg?.status ?? this.#status;
|
|
78767
78924
|
return createResponseInstance(data, {
|
|
@@ -78792,18 +78949,61 @@ var Context = class {
|
|
|
78792
78949
|
};
|
|
78793
78950
|
};
|
|
78794
78951
|
|
|
78795
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
78796
|
-
var
|
|
78797
|
-
|
|
78798
|
-
|
|
78952
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/compose.js
|
|
78953
|
+
var compose = (middleware, onError, onNotFound) => {
|
|
78954
|
+
return (context, next) => {
|
|
78955
|
+
let index = -1;
|
|
78956
|
+
return dispatch(0);
|
|
78957
|
+
async function dispatch(i) {
|
|
78958
|
+
if (i <= index)
|
|
78959
|
+
throw new Error("next() called multiple times");
|
|
78960
|
+
index = i;
|
|
78961
|
+
let res;
|
|
78962
|
+
let isError = false;
|
|
78963
|
+
let handler;
|
|
78964
|
+
if (middleware[i]) {
|
|
78965
|
+
handler = middleware[i][0][0];
|
|
78966
|
+
context.req.routeIndex = i;
|
|
78967
|
+
} else
|
|
78968
|
+
handler = i === middleware.length && next || undefined;
|
|
78969
|
+
if (handler)
|
|
78970
|
+
try {
|
|
78971
|
+
res = await handler(context, () => dispatch(i + 1));
|
|
78972
|
+
} catch (err) {
|
|
78973
|
+
if (err instanceof Error && onError) {
|
|
78974
|
+
context.error = err;
|
|
78975
|
+
res = await onError(err, context);
|
|
78976
|
+
isError = true;
|
|
78977
|
+
} else
|
|
78978
|
+
throw err;
|
|
78979
|
+
}
|
|
78980
|
+
else if (context.finalized === false && onNotFound)
|
|
78981
|
+
res = await onNotFound(context);
|
|
78982
|
+
if (res && (context.finalized === false || isError))
|
|
78983
|
+
context.res = res;
|
|
78984
|
+
return context;
|
|
78985
|
+
}
|
|
78986
|
+
};
|
|
78987
|
+
};
|
|
78988
|
+
|
|
78989
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/router.js
|
|
78990
|
+
var METHODS = [
|
|
78991
|
+
"get",
|
|
78992
|
+
"post",
|
|
78993
|
+
"put",
|
|
78994
|
+
"delete",
|
|
78995
|
+
"options",
|
|
78996
|
+
"patch",
|
|
78997
|
+
"query"
|
|
78998
|
+
];
|
|
78799
78999
|
var MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is already built.";
|
|
78800
79000
|
var UnsupportedPathError = class extends Error {
|
|
78801
79001
|
};
|
|
78802
79002
|
|
|
78803
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
79003
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/utils/constants.js
|
|
78804
79004
|
var COMPOSED_HANDLER = "__COMPOSED_HANDLER";
|
|
78805
79005
|
|
|
78806
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
79006
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/hono-base.js
|
|
78807
79007
|
var notFoundHandler = (c) => {
|
|
78808
79008
|
return c.text("404 Not Found", 404);
|
|
78809
79009
|
};
|
|
@@ -78815,7 +79015,7 @@ var errorHandler = (err, c) => {
|
|
|
78815
79015
|
console.error(err);
|
|
78816
79016
|
return c.text("Internal Server Error", 500);
|
|
78817
79017
|
};
|
|
78818
|
-
var Hono = class
|
|
79018
|
+
var Hono = class Hono {
|
|
78819
79019
|
get;
|
|
78820
79020
|
post;
|
|
78821
79021
|
put;
|
|
@@ -78832,15 +79032,13 @@ var Hono = class _Hono {
|
|
|
78832
79032
|
#path = "/";
|
|
78833
79033
|
routes = [];
|
|
78834
79034
|
constructor(options = {}) {
|
|
78835
|
-
|
|
78836
|
-
allMethods.forEach((method) => {
|
|
79035
|
+
[...METHODS, "all"].forEach((method) => {
|
|
78837
79036
|
this[method] = (args1, ...args) => {
|
|
78838
79037
|
const methodName = method.toUpperCase();
|
|
78839
|
-
if (typeof args1 === "string")
|
|
79038
|
+
if (typeof args1 === "string")
|
|
78840
79039
|
this.#path = args1;
|
|
78841
|
-
|
|
79040
|
+
else
|
|
78842
79041
|
this.#addRoute(methodName, this.#path, args1);
|
|
78843
|
-
}
|
|
78844
79042
|
args.forEach((handler) => {
|
|
78845
79043
|
this.#addRoute(methodName, this.#path, handler);
|
|
78846
79044
|
});
|
|
@@ -78852,22 +79050,21 @@ var Hono = class _Hono {
|
|
|
78852
79050
|
this.#path = p;
|
|
78853
79051
|
for (const m of [method].flat()) {
|
|
78854
79052
|
const methodName = m.toUpperCase();
|
|
78855
|
-
for (const handler of handlers)
|
|
79053
|
+
for (const handler of handlers)
|
|
78856
79054
|
this.#addRoute(methodName, this.#path, handler);
|
|
78857
|
-
}
|
|
78858
79055
|
}
|
|
78859
79056
|
}
|
|
78860
79057
|
return this;
|
|
78861
79058
|
};
|
|
78862
79059
|
this.use = (arg1, ...handlers) => {
|
|
78863
|
-
if (typeof arg1 === "string")
|
|
79060
|
+
if (typeof arg1 === "string")
|
|
78864
79061
|
this.#path = arg1;
|
|
78865
|
-
|
|
79062
|
+
else {
|
|
78866
79063
|
this.#path = "*";
|
|
78867
79064
|
handlers.unshift(arg1);
|
|
78868
79065
|
}
|
|
78869
79066
|
handlers.forEach((handler) => {
|
|
78870
|
-
this.#addRoute(
|
|
79067
|
+
this.#addRoute("ALL", this.#path, handler);
|
|
78871
79068
|
});
|
|
78872
79069
|
return this;
|
|
78873
79070
|
};
|
|
@@ -78876,7 +79073,7 @@ var Hono = class _Hono {
|
|
|
78876
79073
|
this.getPath = strict ?? true ? options.getPath ?? getPath : getPathNoStrict;
|
|
78877
79074
|
}
|
|
78878
79075
|
#clone() {
|
|
78879
|
-
const clone = new
|
|
79076
|
+
const clone = new Hono({
|
|
78880
79077
|
router: this.router,
|
|
78881
79078
|
getPath: this.getPath
|
|
78882
79079
|
});
|
|
@@ -78891,9 +79088,9 @@ var Hono = class _Hono {
|
|
|
78891
79088
|
const subApp = this.basePath(path);
|
|
78892
79089
|
app.routes.map((r) => {
|
|
78893
79090
|
let handler;
|
|
78894
|
-
if (app.errorHandler === errorHandler)
|
|
79091
|
+
if (app.errorHandler === errorHandler)
|
|
78895
79092
|
handler = r.handler;
|
|
78896
|
-
|
|
79093
|
+
else {
|
|
78897
79094
|
handler = async (c, next) => (await compose([], app.errorHandler)(c, () => r.handler(c, next))).res;
|
|
78898
79095
|
handler[COMPOSED_HANDLER] = r.handler;
|
|
78899
79096
|
}
|
|
@@ -78918,20 +79115,19 @@ var Hono = class _Hono {
|
|
|
78918
79115
|
let replaceRequest;
|
|
78919
79116
|
let optionHandler;
|
|
78920
79117
|
if (options) {
|
|
78921
|
-
if (typeof options === "function")
|
|
79118
|
+
if (typeof options === "function")
|
|
78922
79119
|
optionHandler = options;
|
|
78923
|
-
|
|
79120
|
+
else {
|
|
78924
79121
|
optionHandler = options.optionHandler;
|
|
78925
|
-
if (options.replaceRequest === false)
|
|
79122
|
+
if (options.replaceRequest === false)
|
|
78926
79123
|
replaceRequest = (request) => request;
|
|
78927
|
-
|
|
79124
|
+
else
|
|
78928
79125
|
replaceRequest = options.replaceRequest;
|
|
78929
|
-
}
|
|
78930
79126
|
}
|
|
78931
79127
|
}
|
|
78932
79128
|
const getOptions = optionHandler ? (c) => {
|
|
78933
|
-
const
|
|
78934
|
-
return Array.isArray(
|
|
79129
|
+
const options = optionHandler(c);
|
|
79130
|
+
return Array.isArray(options) ? options : [options];
|
|
78935
79131
|
} : (c) => {
|
|
78936
79132
|
let executionContext = undefined;
|
|
78937
79133
|
try {
|
|
@@ -78950,12 +79146,11 @@ var Hono = class _Hono {
|
|
|
78950
79146
|
})();
|
|
78951
79147
|
const handler = async (c, next) => {
|
|
78952
79148
|
const res = await applicationHandler(replaceRequest(c.req.raw), ...getOptions(c));
|
|
78953
|
-
if (res)
|
|
79149
|
+
if (res)
|
|
78954
79150
|
return res;
|
|
78955
|
-
}
|
|
78956
79151
|
await next();
|
|
78957
79152
|
};
|
|
78958
|
-
this.#addRoute(
|
|
79153
|
+
this.#addRoute("ALL", mergePath(path, "*"), handler);
|
|
78959
79154
|
return this;
|
|
78960
79155
|
}
|
|
78961
79156
|
#addRoute(method, path, handler, baseRoutePath) {
|
|
@@ -78970,15 +79165,13 @@ var Hono = class _Hono {
|
|
|
78970
79165
|
this.routes.push(r);
|
|
78971
79166
|
}
|
|
78972
79167
|
#handleError(err, c) {
|
|
78973
|
-
if (err instanceof Error)
|
|
79168
|
+
if (err instanceof Error)
|
|
78974
79169
|
return this.errorHandler(err, c);
|
|
78975
|
-
}
|
|
78976
79170
|
throw err;
|
|
78977
79171
|
}
|
|
78978
79172
|
#dispatch(request, executionCtx, env, method) {
|
|
78979
|
-
if (method === "HEAD")
|
|
79173
|
+
if (method === "HEAD")
|
|
78980
79174
|
return (async () => new Response(null, await this.#dispatch(request, executionCtx, env, "GET")))();
|
|
78981
|
-
}
|
|
78982
79175
|
const path = this.getPath(request, { env });
|
|
78983
79176
|
const matchResult = this.router.match(method, path);
|
|
78984
79177
|
const c = new Context(request, {
|
|
@@ -79003,9 +79196,8 @@ var Hono = class _Hono {
|
|
|
79003
79196
|
return (async () => {
|
|
79004
79197
|
try {
|
|
79005
79198
|
const context = await composed(c);
|
|
79006
|
-
if (!context.finalized)
|
|
79199
|
+
if (!context.finalized)
|
|
79007
79200
|
throw new Error("Context is not finalized. Did you forget to return a Response object or `await next()`?");
|
|
79008
|
-
}
|
|
79009
79201
|
return context.res;
|
|
79010
79202
|
} catch (err) {
|
|
79011
79203
|
return this.#handleError(err, c);
|
|
@@ -79016,9 +79208,8 @@ var Hono = class _Hono {
|
|
|
79016
79208
|
return this.#dispatch(request, rest[1], rest[0], request.method);
|
|
79017
79209
|
};
|
|
79018
79210
|
request = (input, requestInit, Env, executionCtx) => {
|
|
79019
|
-
if (input instanceof Request)
|
|
79211
|
+
if (input instanceof Request)
|
|
79020
79212
|
return this.fetch(requestInit ? new Request(input, requestInit) : input, Env, executionCtx);
|
|
79021
|
-
}
|
|
79022
79213
|
input = input.toString();
|
|
79023
79214
|
return this.fetch(new Request(/^https?:\/\//.test(input) ? input : `http://localhost${mergePath("/", input)}`, requestInit), Env, executionCtx);
|
|
79024
79215
|
};
|
|
@@ -79029,56 +79220,49 @@ var Hono = class _Hono {
|
|
|
79029
79220
|
};
|
|
79030
79221
|
};
|
|
79031
79222
|
|
|
79032
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
79033
|
-
var createNullObject = () =>
|
|
79223
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/router/utils.js
|
|
79224
|
+
var createNullObject = () => Object.create(null);
|
|
79034
79225
|
|
|
79035
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
79226
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/router/reg-exp-router/matcher.js
|
|
79036
79227
|
var emptyParam = [];
|
|
79037
79228
|
function match(method, path) {
|
|
79038
79229
|
const matchers = this.buildAllMatchers();
|
|
79039
|
-
const
|
|
79040
|
-
const matcher = matchers[
|
|
79041
|
-
const staticMatch = matcher[2][
|
|
79042
|
-
if (staticMatch)
|
|
79230
|
+
const match = (method, path) => {
|
|
79231
|
+
const matcher = matchers[method] || matchers["ALL"];
|
|
79232
|
+
const staticMatch = matcher[2][path];
|
|
79233
|
+
if (staticMatch)
|
|
79043
79234
|
return staticMatch;
|
|
79044
|
-
|
|
79045
|
-
|
|
79046
|
-
if (!match3) {
|
|
79235
|
+
const match = path.match(matcher[0]);
|
|
79236
|
+
if (!match)
|
|
79047
79237
|
return [[], emptyParam];
|
|
79048
|
-
|
|
79049
|
-
|
|
79050
|
-
return [matcher[1][index], match3];
|
|
79238
|
+
const index = match.indexOf("", 1);
|
|
79239
|
+
return [matcher[1][index], match];
|
|
79051
79240
|
};
|
|
79052
|
-
this.match =
|
|
79053
|
-
return
|
|
79241
|
+
this.match = match;
|
|
79242
|
+
return match(method, path);
|
|
79054
79243
|
}
|
|
79055
79244
|
|
|
79056
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
79245
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/router/reg-exp-router/node.js
|
|
79057
79246
|
var LABEL_REG_EXP_STR = "[^/]+";
|
|
79058
|
-
var ONLY_WILDCARD_REG_EXP_STR = ".*";
|
|
79059
79247
|
var TAIL_WILDCARD_REG_EXP_STR = "(?:|/.*)";
|
|
79060
|
-
var PATH_ERROR =
|
|
79061
|
-
var regExpMetaChars = new Set(".\\+*[^]$()");
|
|
79248
|
+
var PATH_ERROR = Symbol();
|
|
79249
|
+
var regExpMetaChars = /* @__PURE__ */ new Set(".\\+*[^]$()");
|
|
79062
79250
|
function compareKey(a, b) {
|
|
79063
|
-
if (a.length === 1)
|
|
79251
|
+
if (a.length === 1)
|
|
79064
79252
|
return b.length === 1 ? a < b ? -1 : 1 : -1;
|
|
79065
|
-
|
|
79066
|
-
if (b.length === 1) {
|
|
79253
|
+
if (b.length === 1)
|
|
79067
79254
|
return 1;
|
|
79068
|
-
|
|
79069
|
-
|
|
79070
|
-
|
|
79071
|
-
} else if (b === ONLY_WILDCARD_REG_EXP_STR || b === TAIL_WILDCARD_REG_EXP_STR) {
|
|
79255
|
+
if (a === ".*" || a === "(?:|/.*)")
|
|
79256
|
+
return b === "(?:|/.*)" ? -1 : 1;
|
|
79257
|
+
else if (b === ".*" || b === "(?:|/.*)")
|
|
79072
79258
|
return -1;
|
|
79073
|
-
|
|
79074
|
-
if (a === LABEL_REG_EXP_STR) {
|
|
79259
|
+
if (a === "[^/]+")
|
|
79075
79260
|
return 1;
|
|
79076
|
-
|
|
79261
|
+
else if (b === "[^/]+")
|
|
79077
79262
|
return -1;
|
|
79078
|
-
}
|
|
79079
79263
|
return a.length === b.length ? a < b ? -1 : 1 : b.length - a.length;
|
|
79080
79264
|
}
|
|
79081
|
-
var Node = class
|
|
79265
|
+
var Node = class Node {
|
|
79082
79266
|
#index;
|
|
79083
79267
|
#varIndex;
|
|
79084
79268
|
#children = createNullObject();
|
|
@@ -79086,33 +79270,40 @@ var Node = class _Node {
|
|
|
79086
79270
|
let node = this;
|
|
79087
79271
|
for (let i = 0, len = tokens.length;i < len; i++) {
|
|
79088
79272
|
const token = tokens[i];
|
|
79089
|
-
const pattern = token.length === 1 ? token === "*" ? i === len - 1 ? [
|
|
79273
|
+
const pattern = token.length === 1 ? token === "*" ? i === len - 1 ? [
|
|
79274
|
+
"",
|
|
79275
|
+
"",
|
|
79276
|
+
".*"
|
|
79277
|
+
] : [
|
|
79278
|
+
"",
|
|
79279
|
+
"",
|
|
79280
|
+
LABEL_REG_EXP_STR
|
|
79281
|
+
] : null : token === "/*" ? [
|
|
79282
|
+
"",
|
|
79283
|
+
"",
|
|
79284
|
+
TAIL_WILDCARD_REG_EXP_STR
|
|
79285
|
+
] : token.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
|
|
79090
79286
|
let nextNode;
|
|
79091
79287
|
if (pattern) {
|
|
79092
79288
|
const name = pattern[1];
|
|
79093
|
-
let regexpStr = pattern[2] ||
|
|
79289
|
+
let regexpStr = pattern[2] || "[^/]+";
|
|
79094
79290
|
if (name && pattern[2]) {
|
|
79095
|
-
if (regexpStr === ".*")
|
|
79291
|
+
if (regexpStr === ".*")
|
|
79096
79292
|
throw PATH_ERROR;
|
|
79097
|
-
}
|
|
79098
79293
|
regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:");
|
|
79099
|
-
if (/\((?!\?:)/.test(regexpStr))
|
|
79294
|
+
if (/\((?!\?:)/.test(regexpStr))
|
|
79100
79295
|
throw PATH_ERROR;
|
|
79101
|
-
|
|
79102
|
-
if (regexpStr.length === 1 && regExpMetaChars.has(regexpStr)) {
|
|
79296
|
+
if (regexpStr.length === 1 && regExpMetaChars.has(regexpStr))
|
|
79103
79297
|
throw PATH_ERROR;
|
|
79104
|
-
}
|
|
79105
79298
|
}
|
|
79106
79299
|
nextNode = node.#children[regexpStr];
|
|
79107
79300
|
if (!nextNode) {
|
|
79108
|
-
if (regexpStr !==
|
|
79109
|
-
for (const k in node.#children)
|
|
79110
|
-
if ((regexpStr.length > 1 || k.length > 1) && k !==
|
|
79301
|
+
if (regexpStr !== ".*" && regexpStr !== "(?:|/.*)") {
|
|
79302
|
+
for (const k in node.#children)
|
|
79303
|
+
if ((regexpStr.length > 1 || k.length > 1) && k !== ".*" && k !== "(?:|/.*)")
|
|
79111
79304
|
throw PATH_ERROR;
|
|
79112
|
-
}
|
|
79113
|
-
}
|
|
79114
79305
|
}
|
|
79115
|
-
nextNode = node.#children[regexpStr] = new
|
|
79306
|
+
nextNode = node.#children[regexpStr] = new Node;
|
|
79116
79307
|
}
|
|
79117
79308
|
if (name !== "") {
|
|
79118
79309
|
nextNode.#varIndex ??= context.varIndex++;
|
|
@@ -79121,42 +79312,35 @@ var Node = class _Node {
|
|
|
79121
79312
|
} else {
|
|
79122
79313
|
nextNode = node.#children[token];
|
|
79123
79314
|
if (!nextNode) {
|
|
79124
|
-
for (const k in node.#children)
|
|
79125
|
-
if (k.length > 1 && k !==
|
|
79315
|
+
for (const k in node.#children)
|
|
79316
|
+
if (k.length > 1 && k !== ".*" && k !== "(?:|/.*)")
|
|
79126
79317
|
throw PATH_ERROR;
|
|
79127
|
-
|
|
79128
|
-
}
|
|
79129
|
-
nextNode = node.#children[token] = new _Node;
|
|
79318
|
+
nextNode = node.#children[token] = new Node;
|
|
79130
79319
|
}
|
|
79131
79320
|
}
|
|
79132
79321
|
node = nextNode;
|
|
79133
79322
|
}
|
|
79134
|
-
if (node.#index !== undefined)
|
|
79323
|
+
if (node.#index !== undefined)
|
|
79135
79324
|
throw PATH_ERROR;
|
|
79136
|
-
}
|
|
79137
79325
|
node.#index = isStatic ? -1 : index;
|
|
79138
79326
|
}
|
|
79139
79327
|
buildRegExpStr() {
|
|
79140
|
-
const
|
|
79141
|
-
const strList = childKeys.map((k) => {
|
|
79328
|
+
const strList = Object.keys(this.#children).sort(compareKey).map((k) => {
|
|
79142
79329
|
const c = this.#children[k];
|
|
79143
79330
|
const childStr = c.buildRegExpStr();
|
|
79144
79331
|
return childStr === "" ? "" : (typeof c.#varIndex === "number" ? `(${k})@${c.#varIndex}` : regExpMetaChars.has(k) ? `\\${k}` : k) + childStr;
|
|
79145
79332
|
}).filter(Boolean);
|
|
79146
|
-
if (typeof this.#index === "number" && this.#index !== -1)
|
|
79333
|
+
if (typeof this.#index === "number" && this.#index !== -1)
|
|
79147
79334
|
strList.unshift(`#${this.#index}`);
|
|
79148
|
-
|
|
79149
|
-
if (strList.length === 0) {
|
|
79335
|
+
if (strList.length === 0)
|
|
79150
79336
|
return "";
|
|
79151
|
-
|
|
79152
|
-
if (strList.length === 1) {
|
|
79337
|
+
if (strList.length === 1)
|
|
79153
79338
|
return strList[0];
|
|
79154
|
-
}
|
|
79155
79339
|
return "(?:" + strList.join("|") + ")";
|
|
79156
79340
|
}
|
|
79157
79341
|
};
|
|
79158
79342
|
|
|
79159
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
79343
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/router/reg-exp-router/trie.js
|
|
79160
79344
|
var Trie = class {
|
|
79161
79345
|
#context = { varIndex: 0 };
|
|
79162
79346
|
#root = new Node;
|
|
@@ -79179,28 +79363,29 @@ var Trie = class {
|
|
|
79179
79363
|
replaced = true;
|
|
79180
79364
|
return mark;
|
|
79181
79365
|
});
|
|
79182
|
-
if (!replaced)
|
|
79366
|
+
if (!replaced)
|
|
79183
79367
|
break;
|
|
79184
|
-
}
|
|
79185
79368
|
}
|
|
79186
79369
|
const tokens = markedPath.match(/(?::[^\/]+)|(?:\/\*$)|./g) || [];
|
|
79187
79370
|
for (let i = groups.length - 1;i >= 0; i--) {
|
|
79188
79371
|
const [mark] = groups[i];
|
|
79189
|
-
for (let j = tokens.length - 1;j >= 0; j--)
|
|
79372
|
+
for (let j = tokens.length - 1;j >= 0; j--)
|
|
79190
79373
|
if (tokens[j].indexOf(mark) !== -1) {
|
|
79191
79374
|
tokens[j] = tokens[j].replace(mark, groups[i][1]);
|
|
79192
79375
|
break;
|
|
79193
79376
|
}
|
|
79194
|
-
}
|
|
79195
79377
|
}
|
|
79196
79378
|
this.#root.insert(tokens, this.#index, paramAssoc, this.#context, false);
|
|
79197
79379
|
this.paths[path] = [this.#index++, paramAssoc];
|
|
79198
79380
|
}
|
|
79199
79381
|
buildRegExp() {
|
|
79200
79382
|
let regexp = this.#root.buildRegExpStr();
|
|
79201
|
-
if (regexp === "")
|
|
79202
|
-
return [
|
|
79203
|
-
|
|
79383
|
+
if (regexp === "")
|
|
79384
|
+
return [
|
|
79385
|
+
/^$/,
|
|
79386
|
+
[],
|
|
79387
|
+
[]
|
|
79388
|
+
];
|
|
79204
79389
|
let captureIndex = 0;
|
|
79205
79390
|
const indexReplacementMap = [];
|
|
79206
79391
|
const paramReplacementMap = [];
|
|
@@ -79215,22 +79400,23 @@ var Trie = class {
|
|
|
79215
79400
|
}
|
|
79216
79401
|
return "";
|
|
79217
79402
|
});
|
|
79218
|
-
return [
|
|
79403
|
+
return [
|
|
79404
|
+
new RegExp(`^${regexp}`),
|
|
79405
|
+
indexReplacementMap,
|
|
79406
|
+
paramReplacementMap
|
|
79407
|
+
];
|
|
79219
79408
|
}
|
|
79220
79409
|
};
|
|
79221
79410
|
|
|
79222
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
79411
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/router/reg-exp-router/router.js
|
|
79223
79412
|
var wildcardRegExpCache = createNullObject();
|
|
79224
79413
|
function buildWildcardRegExp(path) {
|
|
79225
|
-
return wildcardRegExpCache[path] ??= new RegExp(`^${path.replace(/\/:[^/{}]+(?:\{\[\^\/]\+})?(?=[/{]|$)|\/?\*$|([.\\+*[^\]$()?{}|])/g, (
|
|
79414
|
+
return wildcardRegExpCache[path] ??= new RegExp(`^${path.replace(/\/:[^/{}]+(?:\{\[\^\/]\+})?(?=[/{]|$)|\/?\*$|([.\\+*[^\]$()?{}|])/g, (match, metaChar) => metaChar ? `\\${metaChar}` : match === "/*" ? TAIL_WILDCARD_REG_EXP_STR : match === "*" ? ".*" : `/:${LABEL_REG_EXP_STR}`)}$`);
|
|
79226
79415
|
}
|
|
79227
79416
|
function findMiddleware(middleware, path) {
|
|
79228
|
-
for (const k of Object.keys(middleware).sort((a, b) => b.length - a.length))
|
|
79229
|
-
if (buildWildcardRegExp(k).test(path))
|
|
79417
|
+
for (const k of Object.keys(middleware).sort((a, b) => b.length - a.length))
|
|
79418
|
+
if (buildWildcardRegExp(k).test(path))
|
|
79230
79419
|
return [...middleware[k]];
|
|
79231
|
-
}
|
|
79232
|
-
}
|
|
79233
|
-
return;
|
|
79234
79420
|
}
|
|
79235
79421
|
var RegExpRouter = class {
|
|
79236
79422
|
name = "RegExpRouter";
|
|
@@ -79238,9 +79424,9 @@ var RegExpRouter = class {
|
|
|
79238
79424
|
#routes;
|
|
79239
79425
|
#tries;
|
|
79240
79426
|
constructor() {
|
|
79241
|
-
this.#middleware = { [
|
|
79242
|
-
this.#routes = { [
|
|
79243
|
-
this.#tries = { [
|
|
79427
|
+
this.#middleware = { ["ALL"]: createNullObject() };
|
|
79428
|
+
this.#routes = { ["ALL"]: createNullObject() };
|
|
79429
|
+
this.#tries = { ["ALL"]: new Trie };
|
|
79244
79430
|
}
|
|
79245
79431
|
#insertPath(method, path) {
|
|
79246
79432
|
try {
|
|
@@ -79252,57 +79438,49 @@ var RegExpRouter = class {
|
|
|
79252
79438
|
add(method, path, handler) {
|
|
79253
79439
|
const middleware = this.#middleware;
|
|
79254
79440
|
const routes = this.#routes;
|
|
79255
|
-
if (!middleware)
|
|
79441
|
+
if (!middleware)
|
|
79256
79442
|
throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
|
|
79257
|
-
}
|
|
79258
79443
|
if (!middleware[method]) {
|
|
79259
79444
|
this.#tries[method] = new Trie;
|
|
79260
79445
|
for (const handlerMap of [middleware, routes]) {
|
|
79261
79446
|
handlerMap[method] = createNullObject();
|
|
79262
|
-
for (const p in handlerMap[
|
|
79263
|
-
handlerMap[method][p] = [...handlerMap[
|
|
79447
|
+
for (const p in handlerMap["ALL"]) {
|
|
79448
|
+
handlerMap[method][p] = [...handlerMap["ALL"][p]];
|
|
79264
79449
|
this.#insertPath(method, p);
|
|
79265
79450
|
}
|
|
79266
79451
|
}
|
|
79267
79452
|
}
|
|
79268
|
-
if (path === "/*")
|
|
79453
|
+
if (path === "/*")
|
|
79269
79454
|
path = "*";
|
|
79270
|
-
|
|
79271
|
-
const methods = method === METHOD_NAME_ALL ? Object.keys(middleware) : [method];
|
|
79455
|
+
const methods = method === "ALL" ? Object.keys(middleware) : [method];
|
|
79272
79456
|
if (/\*$/.test(path)) {
|
|
79273
79457
|
const re = buildWildcardRegExp(path);
|
|
79274
|
-
for (const m of methods)
|
|
79458
|
+
for (const m of methods)
|
|
79275
79459
|
if (!middleware[m][path]) {
|
|
79276
79460
|
this.#insertPath(m, path);
|
|
79277
|
-
middleware[m][path] = findMiddleware(middleware[m], path) || findMiddleware(middleware[
|
|
79461
|
+
middleware[m][path] = findMiddleware(middleware[m], path) || findMiddleware(middleware["ALL"], path) || [];
|
|
79278
79462
|
}
|
|
79279
|
-
|
|
79280
|
-
|
|
79281
|
-
|
|
79282
|
-
for (const p in handlerMap[m]) {
|
|
79463
|
+
for (const handlerMap of [middleware, routes])
|
|
79464
|
+
for (const m of methods)
|
|
79465
|
+
for (const p in handlerMap[m])
|
|
79283
79466
|
re.test(p) && handlerMap[m][p].push([handler, path]);
|
|
79284
|
-
}
|
|
79285
|
-
}
|
|
79286
|
-
}
|
|
79287
79467
|
return;
|
|
79288
79468
|
}
|
|
79289
79469
|
const paths = checkOptionalParameter(path) || [path];
|
|
79290
|
-
for (const
|
|
79470
|
+
for (const path of paths)
|
|
79291
79471
|
for (const m of methods) {
|
|
79292
|
-
if (!routes[m][
|
|
79293
|
-
this.#insertPath(m,
|
|
79294
|
-
routes[m][
|
|
79472
|
+
if (!routes[m][path]) {
|
|
79473
|
+
this.#insertPath(m, path);
|
|
79474
|
+
routes[m][path] = findMiddleware(middleware[m], path) || findMiddleware(middleware["ALL"], path) || [];
|
|
79295
79475
|
}
|
|
79296
|
-
routes[m][
|
|
79476
|
+
routes[m][path].push([handler, path]);
|
|
79297
79477
|
}
|
|
79298
|
-
}
|
|
79299
79478
|
}
|
|
79300
79479
|
match = match;
|
|
79301
79480
|
buildAllMatchers() {
|
|
79302
79481
|
const matchers = createNullObject();
|
|
79303
|
-
for (const method of Object.keys(this.#routes))
|
|
79482
|
+
for (const method of Object.keys(this.#routes))
|
|
79304
79483
|
matchers[method] = this.#buildMatcher(method);
|
|
79305
|
-
}
|
|
79306
79484
|
this.#middleware = this.#routes = this.#tries = undefined;
|
|
79307
79485
|
wildcardRegExpCache = createNullObject();
|
|
79308
79486
|
return matchers;
|
|
@@ -79314,7 +79492,7 @@ var RegExpRouter = class {
|
|
|
79314
79492
|
const staticMap = createNullObject();
|
|
79315
79493
|
const handlerData = [];
|
|
79316
79494
|
const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp();
|
|
79317
|
-
for (const r of [middleware, routes])
|
|
79495
|
+
for (const r of [middleware, routes])
|
|
79318
79496
|
for (const path in r) {
|
|
79319
79497
|
const handlers = r[path];
|
|
79320
79498
|
const pathData = trie.paths[path];
|
|
@@ -79322,20 +79500,20 @@ var RegExpRouter = class {
|
|
|
79322
79500
|
staticMap[path] = [handlers.map(([h]) => [h, createNullObject()]), emptyParam];
|
|
79323
79501
|
continue;
|
|
79324
79502
|
}
|
|
79325
|
-
handlerData[pathData[0]] = handlers.map(([h, handlerPath]) => [
|
|
79326
|
-
|
|
79327
|
-
|
|
79328
|
-
|
|
79329
|
-
return map;
|
|
79330
|
-
}, createNullObject())
|
|
79331
|
-
]);
|
|
79503
|
+
handlerData[pathData[0]] = handlers.map(([h, handlerPath]) => [h, trie.paths[handlerPath][1].reduceRight((map, [key], i) => {
|
|
79504
|
+
map[key] = paramReplacementMap[pathData[1][i][1]];
|
|
79505
|
+
return map;
|
|
79506
|
+
}, createNullObject())]);
|
|
79332
79507
|
}
|
|
79333
|
-
|
|
79334
|
-
|
|
79508
|
+
return [
|
|
79509
|
+
regexp,
|
|
79510
|
+
indexReplacementMap.map((i) => handlerData[i]),
|
|
79511
|
+
staticMap
|
|
79512
|
+
];
|
|
79335
79513
|
}
|
|
79336
79514
|
};
|
|
79337
79515
|
|
|
79338
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
79516
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/router/smart-router/router.js
|
|
79339
79517
|
var SmartRouter = class {
|
|
79340
79518
|
name = "SmartRouter";
|
|
79341
79519
|
#routers = [];
|
|
@@ -79344,15 +79522,17 @@ var SmartRouter = class {
|
|
|
79344
79522
|
this.#routers = init.routers;
|
|
79345
79523
|
}
|
|
79346
79524
|
add(method, path, handler) {
|
|
79347
|
-
if (!this.#routes)
|
|
79525
|
+
if (!this.#routes)
|
|
79348
79526
|
throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
|
|
79349
|
-
|
|
79350
|
-
|
|
79527
|
+
this.#routes.push([
|
|
79528
|
+
method,
|
|
79529
|
+
path,
|
|
79530
|
+
handler
|
|
79531
|
+
]);
|
|
79351
79532
|
}
|
|
79352
79533
|
match(method, path) {
|
|
79353
|
-
if (!this.#routes)
|
|
79534
|
+
if (!this.#routes)
|
|
79354
79535
|
throw new Error("Fatal error");
|
|
79355
|
-
}
|
|
79356
79536
|
const routers = this.#routers;
|
|
79357
79537
|
const routes = this.#routes;
|
|
79358
79538
|
const len = routers.length;
|
|
@@ -79361,14 +79541,12 @@ var SmartRouter = class {
|
|
|
79361
79541
|
for (;i < len; i++) {
|
|
79362
79542
|
const router = routers[i];
|
|
79363
79543
|
try {
|
|
79364
|
-
for (let
|
|
79365
|
-
router.add(...routes[
|
|
79366
|
-
}
|
|
79544
|
+
for (let i = 0, len = routes.length;i < len; i++)
|
|
79545
|
+
router.add(...routes[i]);
|
|
79367
79546
|
res = router.match(method, path);
|
|
79368
79547
|
} catch (e) {
|
|
79369
|
-
if (e instanceof UnsupportedPathError)
|
|
79548
|
+
if (e instanceof UnsupportedPathError)
|
|
79370
79549
|
continue;
|
|
79371
|
-
}
|
|
79372
79550
|
throw e;
|
|
79373
79551
|
}
|
|
79374
79552
|
this.match = router.match.bind(router);
|
|
@@ -79376,24 +79554,22 @@ var SmartRouter = class {
|
|
|
79376
79554
|
this.#routes = undefined;
|
|
79377
79555
|
break;
|
|
79378
79556
|
}
|
|
79379
|
-
if (i === len)
|
|
79557
|
+
if (i === len)
|
|
79380
79558
|
throw new Error("Fatal error");
|
|
79381
|
-
}
|
|
79382
79559
|
this.name = `SmartRouter + ${this.activeRouter.name}`;
|
|
79383
79560
|
return res;
|
|
79384
79561
|
}
|
|
79385
79562
|
get activeRouter() {
|
|
79386
|
-
if (this.#routes || this.#routers.length !== 1)
|
|
79563
|
+
if (this.#routes || this.#routers.length !== 1)
|
|
79387
79564
|
throw new Error("No active router has been determined yet.");
|
|
79388
|
-
}
|
|
79389
79565
|
return this.#routers[0];
|
|
79390
79566
|
}
|
|
79391
79567
|
};
|
|
79392
79568
|
|
|
79393
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
79569
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/router/trie-router/node.js
|
|
79394
79570
|
var emptyParams = createNullObject();
|
|
79395
79571
|
var order = 0;
|
|
79396
|
-
var Node2 = class
|
|
79572
|
+
var Node2 = class Node {
|
|
79397
79573
|
#methods = [];
|
|
79398
79574
|
#children = createNullObject();
|
|
79399
79575
|
#patterns = [];
|
|
@@ -79409,34 +79585,31 @@ var Node2 = class _Node {
|
|
|
79409
79585
|
const pattern = getPattern(p, nextP) || (nextP === undefined && p && p.indexOf("*") === p.length - 1 ? p : null);
|
|
79410
79586
|
const isParam = Array.isArray(pattern);
|
|
79411
79587
|
const key = isParam ? pattern[0] : pattern || p;
|
|
79412
|
-
const child = curNode.#children[key] ||= new
|
|
79588
|
+
const child = curNode.#children[key] ||= new Node;
|
|
79413
79589
|
if (pattern && !child.#pattern) {
|
|
79414
79590
|
child.#pattern = pattern;
|
|
79415
79591
|
curNode.#patterns.push(child);
|
|
79416
79592
|
}
|
|
79417
79593
|
curNode = child;
|
|
79418
|
-
if (isParam)
|
|
79594
|
+
if (isParam)
|
|
79419
79595
|
possibleKeys.add(pattern[1]);
|
|
79420
|
-
}
|
|
79421
79596
|
}
|
|
79422
|
-
curNode.#methods.push({
|
|
79423
|
-
|
|
79424
|
-
|
|
79425
|
-
|
|
79426
|
-
|
|
79427
|
-
}
|
|
79428
|
-
});
|
|
79597
|
+
curNode.#methods.push({ [method]: {
|
|
79598
|
+
handler,
|
|
79599
|
+
possibleKeys: [...possibleKeys],
|
|
79600
|
+
score: ++order
|
|
79601
|
+
} });
|
|
79429
79602
|
}
|
|
79430
79603
|
#pushHandlerSets(handlerSets, node, method, nodeParams, params) {
|
|
79431
79604
|
for (let i = 0, len = node.#methods.length;i < len; i++) {
|
|
79432
79605
|
const m = node.#methods[i];
|
|
79433
|
-
const handlerSet = m[method] || m[
|
|
79606
|
+
const handlerSet = m[method] || m["ALL"];
|
|
79434
79607
|
if (handlerSet) {
|
|
79435
79608
|
handlerSet.params = createNullObject();
|
|
79436
79609
|
handlerSets.push(handlerSet);
|
|
79437
|
-
for (let
|
|
79438
|
-
const key = handlerSet.possibleKeys[
|
|
79439
|
-
handlerSet.params[key] = params?.[key] && !
|
|
79610
|
+
for (let i = 0, len = handlerSet.possibleKeys.length;i < len; i++) {
|
|
79611
|
+
const key = handlerSet.possibleKeys[i];
|
|
79612
|
+
handlerSet.params[key] = params?.[key] && !i ? params[key] : nodeParams[key] ?? params?.[key];
|
|
79440
79613
|
}
|
|
79441
79614
|
}
|
|
79442
79615
|
}
|
|
@@ -79444,8 +79617,7 @@ var Node2 = class _Node {
|
|
|
79444
79617
|
search(method, path) {
|
|
79445
79618
|
const handlerSets = [];
|
|
79446
79619
|
this.#params = emptyParams;
|
|
79447
|
-
|
|
79448
|
-
let curNodes = [curNode];
|
|
79620
|
+
let curNodes = [this];
|
|
79449
79621
|
const parts = splitPath(path);
|
|
79450
79622
|
const curNodesQueue = [];
|
|
79451
79623
|
const len = parts.length;
|
|
@@ -79460,13 +79632,11 @@ var Node2 = class _Node {
|
|
|
79460
79632
|
if (nextNode) {
|
|
79461
79633
|
nextNode.#params = node.#params;
|
|
79462
79634
|
if (isLast) {
|
|
79463
|
-
if (nextNode.#children["*"])
|
|
79635
|
+
if (nextNode.#children["*"])
|
|
79464
79636
|
this.#pushHandlerSets(handlerSets, nextNode.#children["*"], method, node.#params);
|
|
79465
|
-
}
|
|
79466
79637
|
this.#pushHandlerSets(handlerSets, nextNode, method, node.#params);
|
|
79467
|
-
} else
|
|
79638
|
+
} else
|
|
79468
79639
|
tempNodes.push(nextNode);
|
|
79469
|
-
}
|
|
79470
79640
|
}
|
|
79471
79641
|
for (const child of node.#patterns) {
|
|
79472
79642
|
const pattern = child.#pattern;
|
|
@@ -79482,9 +79652,8 @@ var Node2 = class _Node {
|
|
|
79482
79652
|
continue;
|
|
79483
79653
|
}
|
|
79484
79654
|
const [, name, matcher] = pattern;
|
|
79485
|
-
if (!part && matcher === true)
|
|
79655
|
+
if (!part && matcher === true)
|
|
79486
79656
|
continue;
|
|
79487
|
-
}
|
|
79488
79657
|
if (matcher !== true) {
|
|
79489
79658
|
if (!partOffsets) {
|
|
79490
79659
|
partOffsets = [];
|
|
@@ -79499,14 +79668,12 @@ var Node2 = class _Node {
|
|
|
79499
79668
|
if (m) {
|
|
79500
79669
|
params[name] = m[0];
|
|
79501
79670
|
this.#pushHandlerSets(handlerSets, child, method, node.#params, params);
|
|
79502
|
-
if (m[0].length === restPathString.length && child.#children["*"])
|
|
79671
|
+
if (m[0].length === restPathString.length && child.#children["*"])
|
|
79503
79672
|
this.#pushHandlerSets(handlerSets, child.#children["*"], method, node.#params, params);
|
|
79504
|
-
}
|
|
79505
79673
|
for (const _ in child.#children) {
|
|
79506
79674
|
child.#params = params;
|
|
79507
79675
|
const componentCount = m[0].match(/\//g)?.length ?? 0;
|
|
79508
|
-
|
|
79509
|
-
targetCurNodes.push(child);
|
|
79676
|
+
(curNodesQueue[componentCount] ||= []).push(child);
|
|
79510
79677
|
break;
|
|
79511
79678
|
}
|
|
79512
79679
|
continue;
|
|
@@ -79516,9 +79683,8 @@ var Node2 = class _Node {
|
|
|
79516
79683
|
params[name] = part;
|
|
79517
79684
|
if (isLast) {
|
|
79518
79685
|
this.#pushHandlerSets(handlerSets, child, method, params, node.#params);
|
|
79519
|
-
if (child.#children["*"])
|
|
79686
|
+
if (child.#children["*"])
|
|
79520
79687
|
this.#pushHandlerSets(handlerSets, child.#children["*"], method, params, node.#params);
|
|
79521
|
-
}
|
|
79522
79688
|
} else {
|
|
79523
79689
|
child.#params = params;
|
|
79524
79690
|
tempNodes.push(child);
|
|
@@ -79529,71 +79695,63 @@ var Node2 = class _Node {
|
|
|
79529
79695
|
const shifted = curNodesQueue.shift();
|
|
79530
79696
|
curNodes = shifted ? tempNodes.concat(shifted) : tempNodes;
|
|
79531
79697
|
}
|
|
79532
|
-
if (handlerSets[1])
|
|
79698
|
+
if (handlerSets[1])
|
|
79533
79699
|
handlerSets.sort((a, b) => {
|
|
79534
79700
|
return a.score - b.score;
|
|
79535
79701
|
});
|
|
79536
|
-
}
|
|
79537
79702
|
return [handlerSets.map(({ handler, params }) => [handler, params])];
|
|
79538
79703
|
}
|
|
79539
79704
|
};
|
|
79540
79705
|
|
|
79541
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
79706
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/router/trie-router/router.js
|
|
79542
79707
|
var TrieRouter = class {
|
|
79543
79708
|
name = "TrieRouter";
|
|
79544
79709
|
#node = new Node2;
|
|
79545
79710
|
add(method, path, handler) {
|
|
79546
|
-
for (const result of checkOptionalParameter(path) || [path])
|
|
79711
|
+
for (const result of checkOptionalParameter(path) || [path])
|
|
79547
79712
|
this.#node.insert(method, result, handler);
|
|
79548
|
-
}
|
|
79549
79713
|
}
|
|
79550
79714
|
match(method, path) {
|
|
79551
79715
|
return this.#node.search(method, path);
|
|
79552
79716
|
}
|
|
79553
79717
|
};
|
|
79554
79718
|
|
|
79555
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
79719
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/hono.js
|
|
79556
79720
|
var Hono2 = class extends Hono {
|
|
79557
79721
|
constructor(options = {}) {
|
|
79558
79722
|
super(options);
|
|
79559
|
-
this.router = options.router ?? new SmartRouter({
|
|
79560
|
-
routers: [new RegExpRouter, new TrieRouter]
|
|
79561
|
-
});
|
|
79723
|
+
this.router = options.router ?? new SmartRouter({ routers: [new RegExpRouter, new TrieRouter] });
|
|
79562
79724
|
}
|
|
79563
79725
|
};
|
|
79564
79726
|
|
|
79565
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
79727
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/utils/color.js
|
|
79566
79728
|
function getColorEnabled() {
|
|
79567
79729
|
const { process: process2, Deno: Deno2 } = globalThis;
|
|
79568
|
-
|
|
79569
|
-
return !isNoColor;
|
|
79730
|
+
return !(typeof Deno2?.noColor === "boolean" ? Deno2.noColor : process2 !== undefined ? "NO_COLOR" in process2?.env : false);
|
|
79570
79731
|
}
|
|
79571
79732
|
async function getColorEnabledAsync() {
|
|
79572
79733
|
const { navigator: navigator2 } = globalThis;
|
|
79573
79734
|
const cfWorkers = "cloudflare:workers";
|
|
79574
|
-
|
|
79735
|
+
return !(navigator2 !== undefined && navigator2.userAgent === "Cloudflare-Workers" ? await (async () => {
|
|
79575
79736
|
try {
|
|
79576
79737
|
return "NO_COLOR" in ((await import(cfWorkers)).env ?? {});
|
|
79577
79738
|
} catch {
|
|
79578
79739
|
return false;
|
|
79579
79740
|
}
|
|
79580
|
-
})() : !getColorEnabled();
|
|
79581
|
-
return !isNoColor;
|
|
79741
|
+
})() : !getColorEnabled());
|
|
79582
79742
|
}
|
|
79583
79743
|
|
|
79584
|
-
// ../../node_modules/.bun/hono@4.13.
|
|
79744
|
+
// ../../node_modules/.bun/hono@4.13.13/node_modules/hono/dist/middleware/logger/index.js
|
|
79585
79745
|
var humanize = (times) => {
|
|
79586
79746
|
const [delimiter, separator] = [",", "."];
|
|
79587
|
-
|
|
79588
|
-
return orderTimes.join(separator);
|
|
79747
|
+
return times.map((v) => v.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1" + delimiter)).join(separator);
|
|
79589
79748
|
};
|
|
79590
79749
|
var time2 = (start) => {
|
|
79591
79750
|
const delta = Date.now() - start;
|
|
79592
79751
|
return humanize([delta < 1000 ? delta + "ms" : Math.round(delta / 1000) + "s"]);
|
|
79593
79752
|
};
|
|
79594
79753
|
var colorStatus = async (status) => {
|
|
79595
|
-
|
|
79596
|
-
if (colorEnabled) {
|
|
79754
|
+
if (await getColorEnabledAsync())
|
|
79597
79755
|
switch (status / 100 | 0) {
|
|
79598
79756
|
case 5:
|
|
79599
79757
|
return `\x1B[31m${status}\x1B[0m`;
|
|
@@ -79604,15 +79762,13 @@ var colorStatus = async (status) => {
|
|
|
79604
79762
|
case 2:
|
|
79605
79763
|
return `\x1B[32m${status}\x1B[0m`;
|
|
79606
79764
|
}
|
|
79607
|
-
}
|
|
79608
79765
|
return `${status}`;
|
|
79609
79766
|
};
|
|
79610
79767
|
async function log(fn, prefix, method, path, status = 0, elapsed) {
|
|
79611
|
-
|
|
79612
|
-
fn(out);
|
|
79768
|
+
fn(prefix === "<--" ? `${prefix} ${method} ${path}` : `${prefix} ${method} ${path} ${await colorStatus(status)} ${elapsed}`);
|
|
79613
79769
|
}
|
|
79614
79770
|
var logger = (fn = console.log) => {
|
|
79615
|
-
return async function
|
|
79771
|
+
return async function logger(c, next) {
|
|
79616
79772
|
const { method, url } = c.req;
|
|
79617
79773
|
const path = url.slice(url.indexOf("/", 8));
|
|
79618
79774
|
await log(fn, "<--", method, path);
|
|
@@ -79700,7 +79856,9 @@ function registerAuditUsageRoutes(app, ctx) {
|
|
|
79700
79856
|
size_before: e.size_before ?? null,
|
|
79701
79857
|
size_after: e.size_after ?? null,
|
|
79702
79858
|
description: e.description ?? "",
|
|
79703
|
-
created_at: e.created_at ?? ""
|
|
79859
|
+
created_at: e.created_at ?? "",
|
|
79860
|
+
metadata_before: e.metadata_before ?? null,
|
|
79861
|
+
metadata_after: e.metadata_after ?? null
|
|
79704
79862
|
})));
|
|
79705
79863
|
});
|
|
79706
79864
|
app.get("/api/v1/usage-log", async (c) => {
|
|
@@ -80677,6 +80835,7 @@ function registerDocumentReadRoutes(app, ctx) {
|
|
|
80677
80835
|
updated_at: meta ? meta.updated_at ?? null : null,
|
|
80678
80836
|
deleted_at: meta ? meta.deleted_at ?? null : null,
|
|
80679
80837
|
content_hash: meta ? meta.content_hash ?? null : null,
|
|
80838
|
+
metadata_revision: meta ? meta.metadata_revision ?? null : null,
|
|
80680
80839
|
versions: versions.map((v) => ({
|
|
80681
80840
|
version_id: v.version_id,
|
|
80682
80841
|
version_number: v.version_number,
|
|
@@ -80797,11 +80956,13 @@ var EDIT_FIELDS = new Set([
|
|
|
80797
80956
|
"project_ids",
|
|
80798
80957
|
"metadata",
|
|
80799
80958
|
"expected_content_hash",
|
|
80959
|
+
"expected_metadata_revision",
|
|
80800
80960
|
"last_write_wins",
|
|
80801
80961
|
"author",
|
|
80802
80962
|
"requestor",
|
|
80803
80963
|
"author_type"
|
|
80804
80964
|
]);
|
|
80965
|
+
var METADATA_TOKEN_DEPRECATION = "deprecated: metadata was replaced without expected_metadata_revision, as last-write-wins, " + "so a concurrent metadata change may have been overwritten. Send the metadata_revision " + "you read (GET /api/v1/documents/{id}); a future release will require it.";
|
|
80805
80966
|
var TRASHED_MESSAGE = "This document was moved to the trash while you were editing. " + "Restore it from the Trash page first, then save again.";
|
|
80806
80967
|
function conflictBody(currentHash) {
|
|
80807
80968
|
const message = "This document changed while you were editing it (another writer saved a newer version). " + "Open it again in a new tab, merge your changes, and save from there.";
|
|
@@ -80813,6 +80974,10 @@ function conflictBody(currentHash) {
|
|
|
80813
80974
|
...currentHash ? { current_hash: currentHash } : {}
|
|
80814
80975
|
};
|
|
80815
80976
|
}
|
|
80977
|
+
function metadataConflictBody() {
|
|
80978
|
+
const message = "This document's metadata changed while you were editing it (another writer changed its tags). " + "Open it again in a new tab, reapply your changes, and save from there.";
|
|
80979
|
+
return { success: false, error: "metadata_conflict", message, detail: message };
|
|
80980
|
+
}
|
|
80816
80981
|
function registerDocumentWriteRoutes(app, ctx) {
|
|
80817
80982
|
app.post("/api/v1/documents/:document_id/edit", async (c) => {
|
|
80818
80983
|
const documentId = c.req.param("document_id");
|
|
@@ -80863,6 +81028,11 @@ function registerDocumentWriteRoutes(app, ctx) {
|
|
|
80863
81028
|
if (expectedHash !== null && !lastWriteWins && currentHash !== null && expectedHash !== currentHash) {
|
|
80864
81029
|
return c.json(conflictBody(currentHash), 409);
|
|
80865
81030
|
}
|
|
81031
|
+
const metadataCarried = body.metadata != null;
|
|
81032
|
+
const sentRevision = typeof body.expected_metadata_revision === "number" && Number.isInteger(body.expected_metadata_revision) ? body.expected_metadata_revision : null;
|
|
81033
|
+
const metadataTokenMissing = metadataCarried && sentRevision === null && !lastWriteWins;
|
|
81034
|
+
const warnings = metadataTokenMissing ? [METADATA_TOKEN_DEPRECATION] : undefined;
|
|
81035
|
+
const expectedMetadataRevision = sentRevision ?? (doc.metadata_revision ?? null);
|
|
80866
81036
|
const proposedHash = content.trim() ? contentHash(content) : null;
|
|
80867
81037
|
const contentChanged = proposedHash !== null && currentHash !== null && proposedHash !== currentHash;
|
|
80868
81038
|
if (contentChanged) {
|
|
@@ -80884,17 +81054,22 @@ function registerDocumentWriteRoutes(app, ctx) {
|
|
|
80884
81054
|
title: title || doc.title,
|
|
80885
81055
|
source: "manual",
|
|
80886
81056
|
projectIds: Array.isArray(body.project_ids) ? body.project_ids : undefined,
|
|
80887
|
-
metadata:
|
|
81057
|
+
metadata: metadataCarried ? metadata : undefined,
|
|
81058
|
+
replaceMetadata: metadataCarried && doc.metadata_revision != null,
|
|
81059
|
+
expectedMetadataRevision: metadataCarried ? expectedMetadataRevision : null,
|
|
80888
81060
|
author: who.identity.author,
|
|
80889
81061
|
authorType: who.identity.authorType,
|
|
80890
81062
|
expectedContentHash: expectedHash,
|
|
80891
81063
|
lastWriteWins
|
|
80892
81064
|
});
|
|
80893
|
-
return c.json({ success: true, reindexed: result.reindexed });
|
|
81065
|
+
return c.json({ success: true, reindexed: result.reindexed, ...warnings ? { warnings } : {} });
|
|
80894
81066
|
} catch (err) {
|
|
80895
81067
|
if (err instanceof ConcurrencyConflictError) {
|
|
80896
81068
|
return c.json(conflictBody(err.currentHash), 409);
|
|
80897
81069
|
}
|
|
81070
|
+
if (err instanceof MetadataConcurrencyError) {
|
|
81071
|
+
return err.tokenRequired ? c.json({ success: false, error: "expected_metadata_revision required", message: err.message, detail: err.message }, 400) : c.json(metadataConflictBody(), 409);
|
|
81072
|
+
}
|
|
80898
81073
|
if (err instanceof ConcurrencyTokenRequiredError) {
|
|
80899
81074
|
return c.json({
|
|
80900
81075
|
success: false,
|
|
@@ -80924,13 +81099,15 @@ function registerDocumentWriteRoutes(app, ctx) {
|
|
|
80924
81099
|
const facets = await updateDocumentFacets(ctx.supabase, {
|
|
80925
81100
|
documentId,
|
|
80926
81101
|
title: body.title !== undefined && title !== doc.title ? title : undefined,
|
|
80927
|
-
metadata:
|
|
81102
|
+
metadata: metadataCarried ? metadata : undefined,
|
|
81103
|
+
expectedMetadataRevision: metadataTokenMissing ? null : expectedMetadataRevision,
|
|
81104
|
+
metadataLastWriteWins: lastWriteWins || metadataTokenMissing,
|
|
80928
81105
|
projectIds: Array.isArray(body.project_ids) ? projectIds : undefined,
|
|
80929
81106
|
author: who.identity.author,
|
|
80930
81107
|
authorType: who.identity.authorType,
|
|
80931
81108
|
accessPath: who.identity.accessPath
|
|
80932
81109
|
});
|
|
80933
|
-
return c.json({ success: true, reindexed: false, ...facets });
|
|
81110
|
+
return c.json({ success: true, reindexed: false, ...facets, ...warnings ? { warnings } : {} });
|
|
80934
81111
|
} catch (err) {
|
|
80935
81112
|
const cause = err instanceof FacetUpdateError ? err.cause : err;
|
|
80936
81113
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -80940,6 +81117,9 @@ function registerDocumentWriteRoutes(app, ctx) {
|
|
|
80940
81117
|
if (cause instanceof FacetValidationError) {
|
|
80941
81118
|
return c.json({ success: false, error: msg, detail: msg }, 400);
|
|
80942
81119
|
}
|
|
81120
|
+
if (cause instanceof MetadataConcurrencyError) {
|
|
81121
|
+
return cause.tokenRequired ? c.json({ success: false, error: "expected_metadata_revision required", message: msg, detail: msg }, 400) : c.json(metadataConflictBody(), 409);
|
|
81122
|
+
}
|
|
80943
81123
|
return c.json({ success: false, error: msg, detail: msg }, 500);
|
|
80944
81124
|
}
|
|
80945
81125
|
});
|
|
@@ -81112,6 +81292,9 @@ function ingestFailure(err) {
|
|
|
81112
81292
|
if (err instanceof ConcurrencyTokenRequiredError) {
|
|
81113
81293
|
return [notReady(err.message), 400];
|
|
81114
81294
|
}
|
|
81295
|
+
if (err instanceof MetadataConcurrencyError) {
|
|
81296
|
+
return [notReady(err.message), err.tokenRequired ? 400 : 409];
|
|
81297
|
+
}
|
|
81115
81298
|
const msg = err instanceof Error ? err.message : String(err);
|
|
81116
81299
|
if (/^Document (.* )?not found/.test(msg))
|
|
81117
81300
|
return [notReady(msg), 404];
|
|
@@ -81126,6 +81309,7 @@ var INGEST_FIELDS = new Set([
|
|
|
81126
81309
|
"content",
|
|
81127
81310
|
"document_id",
|
|
81128
81311
|
"expected_content_hash",
|
|
81312
|
+
"expected_metadata_revision",
|
|
81129
81313
|
"last_write_wins",
|
|
81130
81314
|
"update_existing",
|
|
81131
81315
|
"update_if_exists",
|
|
@@ -81156,6 +81340,9 @@ function ingestShapeError(body) {
|
|
|
81156
81340
|
if (body[k] != null && typeof body[k] !== "boolean")
|
|
81157
81341
|
return `${k} must be a boolean.`;
|
|
81158
81342
|
}
|
|
81343
|
+
if (body.expected_metadata_revision != null && !Number.isInteger(body.expected_metadata_revision)) {
|
|
81344
|
+
return "expected_metadata_revision must be an integer.";
|
|
81345
|
+
}
|
|
81159
81346
|
return null;
|
|
81160
81347
|
}
|
|
81161
81348
|
function registerIngestRoutes(app, ctx) {
|
|
@@ -81203,7 +81390,8 @@ function registerIngestRoutes(app, ctx) {
|
|
|
81203
81390
|
author: who.identity.author,
|
|
81204
81391
|
authorType: who.identity.authorType,
|
|
81205
81392
|
expectedContentHash: typeof body.expected_content_hash === "string" && body.expected_content_hash.trim() !== "" ? body.expected_content_hash.trim() : null,
|
|
81206
|
-
lastWriteWins: body.last_write_wins === true
|
|
81393
|
+
lastWriteWins: body.last_write_wins === true,
|
|
81394
|
+
expectedMetadataRevision: body.expected_metadata_revision ?? null
|
|
81207
81395
|
});
|
|
81208
81396
|
const skipped = result.action === "skipped";
|
|
81209
81397
|
const resp = {
|