@utilarium/overcontext 0.0.7 → 0.0.8-dev.20260226040805.d18adcf

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -7,6 +7,8 @@ const fs = require('node:fs/promises');
7
7
  const node_fs = require('node:fs');
8
8
  const path = require('node:path');
9
9
  const yaml = require('js-yaml');
10
+ const libFs = require('@fjell/lib-fs');
11
+ const libGcs = require('@fjell/lib-gcs');
10
12
 
11
13
  function _interopNamespaceDefault(e) {
12
14
  const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } });
@@ -258,7 +260,7 @@ const yaml__namespace = /*#__PURE__*/_interopNamespaceDefault(yaml);
258
260
  }
259
261
  };
260
262
 
261
- function _define_property$1(obj, key, value) {
263
+ function _define_property$5(obj, key, value) {
262
264
  if (key in obj) {
263
265
  Object.defineProperty(obj, key, {
264
266
  value: value,
@@ -273,25 +275,25 @@ function _define_property$1(obj, key, value) {
273
275
  }
274
276
  class StorageError extends Error {
275
277
  constructor(message, code, cause){
276
- super(message), _define_property$1(this, "code", void 0), _define_property$1(this, "cause", void 0), this.code = code, this.cause = cause;
278
+ super(message), _define_property$5(this, "code", void 0), _define_property$5(this, "cause", void 0), this.code = code, this.cause = cause;
277
279
  this.name = 'StorageError';
278
280
  }
279
281
  }
280
282
  class EntityNotFoundError extends StorageError {
281
283
  constructor(entityType, entityId, namespace){
282
- super(`Entity not found: ${entityType}/${entityId}${namespace ? ` in ${namespace}` : ''}`, 'ENTITY_NOT_FOUND'), _define_property$1(this, "entityType", void 0), _define_property$1(this, "entityId", void 0), _define_property$1(this, "namespace", void 0), this.entityType = entityType, this.entityId = entityId, this.namespace = namespace;
284
+ super(`Entity not found: ${entityType}/${entityId}${namespace ? ` in ${namespace}` : ''}`, 'ENTITY_NOT_FOUND'), _define_property$5(this, "entityType", void 0), _define_property$5(this, "entityId", void 0), _define_property$5(this, "namespace", void 0), this.entityType = entityType, this.entityId = entityId, this.namespace = namespace;
283
285
  this.name = 'EntityNotFoundError';
284
286
  }
285
287
  }
286
288
  class SchemaNotRegisteredError extends StorageError {
287
289
  constructor(entityType){
288
- super(`Schema not registered for type: ${entityType}`, 'SCHEMA_NOT_REGISTERED'), _define_property$1(this, "entityType", void 0), this.entityType = entityType;
290
+ super(`Schema not registered for type: ${entityType}`, 'SCHEMA_NOT_REGISTERED'), _define_property$5(this, "entityType", void 0), this.entityType = entityType;
289
291
  this.name = 'SchemaNotRegisteredError';
290
292
  }
291
293
  }
292
294
  class ValidationError extends StorageError {
293
295
  constructor(message, validationErrors){
294
- super(message, 'VALIDATION_ERROR'), _define_property$1(this, "validationErrors", void 0), this.validationErrors = validationErrors;
296
+ super(message, 'VALIDATION_ERROR'), _define_property$5(this, "validationErrors", void 0), this.validationErrors = validationErrors;
295
297
  this.name = 'ValidationError';
296
298
  }
297
299
  }
@@ -309,7 +311,7 @@ class ReadonlyStorageError extends StorageError {
309
311
  }
310
312
  class NamespaceNotFoundError extends StorageError {
311
313
  constructor(namespace){
312
- super(`Namespace not found: ${namespace}`, 'NAMESPACE_NOT_FOUND'), _define_property$1(this, "namespace", void 0), this.namespace = namespace;
314
+ super(`Namespace not found: ${namespace}`, 'NAMESPACE_NOT_FOUND'), _define_property$5(this, "namespace", void 0), this.namespace = namespace;
313
315
  this.name = 'NamespaceNotFoundError';
314
316
  }
315
317
  }
@@ -329,7 +331,15 @@ class NamespaceNotFoundError extends StorageError {
329
331
  });
330
332
  };
331
333
  return {
332
- ...provider,
334
+ get name () {
335
+ return provider.name;
336
+ },
337
+ get location () {
338
+ return provider.location;
339
+ },
340
+ get registry () {
341
+ return provider.registry;
342
+ },
333
343
  subscribe (handler) {
334
344
  handlers.add(handler);
335
345
  return ()=>handlers.delete(handler);
@@ -349,6 +359,24 @@ class NamespaceNotFoundError extends StorageError {
349
359
  handlers.clear(); // Clear all handlers to prevent memory leaks
350
360
  await provider.dispose();
351
361
  },
362
+ async isAvailable () {
363
+ return provider.isAvailable();
364
+ },
365
+ async get (type, id, namespace) {
366
+ return provider.get(type, id, namespace);
367
+ },
368
+ async getAll (type, namespace) {
369
+ return provider.getAll(type, namespace);
370
+ },
371
+ async find (filter) {
372
+ return provider.find(filter);
373
+ },
374
+ async exists (type, id, namespace) {
375
+ return provider.exists(type, id, namespace);
376
+ },
377
+ async count (filter) {
378
+ return provider.count(filter);
379
+ },
352
380
  async save (entity, namespace) {
353
381
  const existing = await provider.get(entity.type, entity.id, namespace);
354
382
  const saved = await provider.save(entity, namespace);
@@ -407,6 +435,15 @@ class NamespaceNotFoundError extends StorageError {
407
435
  deletedCount: count
408
436
  });
409
437
  return count;
438
+ },
439
+ async listNamespaces () {
440
+ return provider.listNamespaces();
441
+ },
442
+ async namespaceExists (namespace) {
443
+ return provider.namespaceExists(namespace);
444
+ },
445
+ async listTypes (namespace) {
446
+ return provider.listTypes(namespace);
410
447
  }
411
448
  };
412
449
  };
@@ -1024,6 +1061,761 @@ const createMemoryProvider = (options)=>{
1024
1061
  };
1025
1062
  };
1026
1063
 
1064
+ function _define_property$4(obj, key, value) {
1065
+ if (key in obj) {
1066
+ Object.defineProperty(obj, key, {
1067
+ value: value,
1068
+ enumerable: true,
1069
+ configurable: true,
1070
+ writable: true
1071
+ });
1072
+ } else {
1073
+ obj[key] = value;
1074
+ }
1075
+ return obj;
1076
+ }
1077
+ /**
1078
+ * StorageProvider backed by a FjellBackendAdapter.
1079
+ * Delegates all persistence to the adapter and handles
1080
+ * entity <-> raw record conversion at the boundary.
1081
+ */ class FjellStorageProvider {
1082
+ async initialize() {
1083
+ return this.adapter.initialize();
1084
+ }
1085
+ async dispose() {
1086
+ return this.adapter.dispose();
1087
+ }
1088
+ async isAvailable() {
1089
+ return this.adapter.isAvailable();
1090
+ }
1091
+ async get(type, id, namespace) {
1092
+ const raw = await this.adapter.get(type, id, namespace);
1093
+ return raw ? this.toEntity(raw) : undefined;
1094
+ }
1095
+ async getAll(type, namespace) {
1096
+ const raws = await this.adapter.getAll(type, namespace);
1097
+ return raws.map((r)=>this.toEntity(r));
1098
+ }
1099
+ async find(filter) {
1100
+ const types = this.resolveFilterTypes(filter);
1101
+ const results = [];
1102
+ for (const type of types){
1103
+ const typeFilter = {
1104
+ ...filter,
1105
+ type
1106
+ };
1107
+ const raws = await this.adapter.find(type, typeFilter, filter.namespace);
1108
+ results.push(...raws.map((r)=>this.toEntity(r)));
1109
+ }
1110
+ if (filter.limit && results.length > filter.limit) {
1111
+ return results.slice(0, filter.limit);
1112
+ }
1113
+ return results;
1114
+ }
1115
+ async exists(type, id, namespace) {
1116
+ return this.adapter.exists(type, id, namespace);
1117
+ }
1118
+ async count(filter) {
1119
+ const types = this.resolveFilterTypes(filter);
1120
+ let total = 0;
1121
+ for (const type of types){
1122
+ const typeFilter = {
1123
+ ...filter,
1124
+ type
1125
+ };
1126
+ total += await this.adapter.count(type, typeFilter, filter.namespace);
1127
+ }
1128
+ return total;
1129
+ }
1130
+ async save(entity, namespace) {
1131
+ const raw = this.toRaw(entity);
1132
+ const entityExists = await this.adapter.exists(entity.type, entity.id, namespace);
1133
+ const result = entityExists ? await this.adapter.update(entity.type, entity.id, raw, namespace) : await this.adapter.create(entity.type, raw, namespace);
1134
+ return this.toEntity(result);
1135
+ }
1136
+ async delete(type, id, namespace) {
1137
+ return this.adapter.remove(type, id, namespace);
1138
+ }
1139
+ async saveBatch(entities, namespace) {
1140
+ return Promise.all(entities.map((e)=>this.save(e, namespace)));
1141
+ }
1142
+ async deleteBatch(refs, namespace) {
1143
+ let deleted = 0;
1144
+ for (const ref of refs){
1145
+ const removed = await this.adapter.remove(ref.type, ref.id, namespace);
1146
+ if (removed) deleted++;
1147
+ }
1148
+ return deleted;
1149
+ }
1150
+ async listNamespaces() {
1151
+ return this.adapter.listNamespaces();
1152
+ }
1153
+ async namespaceExists(namespace) {
1154
+ return this.adapter.namespaceExists(namespace);
1155
+ }
1156
+ async listTypes(namespace) {
1157
+ return this.adapter.listTypes(namespace);
1158
+ }
1159
+ toEntity(raw) {
1160
+ const entity = {
1161
+ ...raw
1162
+ };
1163
+ if (raw.createdAt && typeof raw.createdAt === 'string') {
1164
+ entity.createdAt = new Date(raw.createdAt);
1165
+ }
1166
+ if (raw.updatedAt && typeof raw.updatedAt === 'string') {
1167
+ entity.updatedAt = new Date(raw.updatedAt);
1168
+ }
1169
+ return entity;
1170
+ }
1171
+ toRaw(entity) {
1172
+ const raw = {
1173
+ ...entity
1174
+ };
1175
+ if (entity.createdAt) {
1176
+ raw.createdAt = entity.createdAt.toISOString();
1177
+ }
1178
+ if (entity.updatedAt) {
1179
+ raw.updatedAt = entity.updatedAt.toISOString();
1180
+ }
1181
+ return raw;
1182
+ }
1183
+ resolveFilterTypes(filter) {
1184
+ if (filter.type) {
1185
+ return Array.isArray(filter.type) ? filter.type : [
1186
+ filter.type
1187
+ ];
1188
+ }
1189
+ return this.registry.types();
1190
+ }
1191
+ constructor(adapter, registry, name, location){
1192
+ _define_property$4(this, "name", void 0);
1193
+ _define_property$4(this, "location", void 0);
1194
+ _define_property$4(this, "registry", void 0);
1195
+ _define_property$4(this, "adapter", void 0);
1196
+ this.adapter = adapter;
1197
+ this.registry = registry;
1198
+ this.name = name;
1199
+ this.location = location;
1200
+ }
1201
+ }
1202
+
1203
+ function _define_property$3(obj, key, value) {
1204
+ if (key in obj) {
1205
+ Object.defineProperty(obj, key, {
1206
+ value: value,
1207
+ enumerable: true,
1208
+ configurable: true,
1209
+ writable: true
1210
+ });
1211
+ } else {
1212
+ obj[key] = value;
1213
+ }
1214
+ return obj;
1215
+ }
1216
+ /**
1217
+ * In-memory implementation of FjellBackendAdapter for testing.
1218
+ * Stores entities in a nested Map: namespaceKey:type -> id -> entity data.
1219
+ */ class MemoryFjellAdapter {
1220
+ bucketKey(type, namespace) {
1221
+ return `${namespace !== null && namespace !== void 0 ? namespace : this.defaultNamespace}:${type}`;
1222
+ }
1223
+ getBucket(type, namespace) {
1224
+ const key = this.bucketKey(type, namespace);
1225
+ let bucket = this.store.get(key);
1226
+ if (!bucket) {
1227
+ bucket = new Map();
1228
+ this.store.set(key, bucket);
1229
+ }
1230
+ return bucket;
1231
+ }
1232
+ async initialize() {
1233
+ this.initialized = true;
1234
+ }
1235
+ async dispose() {
1236
+ this.store.clear();
1237
+ this.initialized = false;
1238
+ }
1239
+ async isAvailable() {
1240
+ return this.initialized;
1241
+ }
1242
+ async get(type, id, namespace) {
1243
+ const bucket = this.getBucket(type, namespace);
1244
+ const item = bucket.get(id);
1245
+ return item ? {
1246
+ ...item
1247
+ } : undefined;
1248
+ }
1249
+ async getAll(type, namespace) {
1250
+ const bucket = this.getBucket(type, namespace);
1251
+ return Array.from(bucket.values()).map((item)=>({
1252
+ ...item
1253
+ }));
1254
+ }
1255
+ async create(type, item, namespace) {
1256
+ const bucket = this.getBucket(type, namespace);
1257
+ const id = item.id;
1258
+ const stored = {
1259
+ ...item
1260
+ };
1261
+ bucket.set(id, stored);
1262
+ return {
1263
+ ...stored
1264
+ };
1265
+ }
1266
+ async update(type, id, item, namespace) {
1267
+ const bucket = this.getBucket(type, namespace);
1268
+ const stored = {
1269
+ ...item
1270
+ };
1271
+ bucket.set(id, stored);
1272
+ return {
1273
+ ...stored
1274
+ };
1275
+ }
1276
+ async remove(type, id, namespace) {
1277
+ const bucket = this.getBucket(type, namespace);
1278
+ return bucket.delete(id);
1279
+ }
1280
+ async find(type, filter, namespace) {
1281
+ const all = await this.getAll(type, namespace);
1282
+ let results = all;
1283
+ if (filter.ids) {
1284
+ const idSet = new Set(filter.ids);
1285
+ results = results.filter((item)=>idSet.has(item.id));
1286
+ }
1287
+ if (filter.search) {
1288
+ const term = filter.search.toLowerCase();
1289
+ results = results.filter((item)=>{
1290
+ var _item_name, _item_notes;
1291
+ const name = (_item_name = item.name) !== null && _item_name !== void 0 ? _item_name : '';
1292
+ const notes = (_item_notes = item.notes) !== null && _item_notes !== void 0 ? _item_notes : '';
1293
+ return name.toLowerCase().includes(term) || notes.toLowerCase().includes(term);
1294
+ });
1295
+ }
1296
+ if (filter.offset) {
1297
+ results = results.slice(filter.offset);
1298
+ }
1299
+ if (filter.limit) {
1300
+ results = results.slice(0, filter.limit);
1301
+ }
1302
+ return results;
1303
+ }
1304
+ async exists(type, id, namespace) {
1305
+ const bucket = this.getBucket(type, namespace);
1306
+ return bucket.has(id);
1307
+ }
1308
+ async count(type, filter, namespace) {
1309
+ if (filter) {
1310
+ const results = await this.find(type, filter, namespace);
1311
+ return results.length;
1312
+ }
1313
+ const bucket = this.getBucket(type, namespace);
1314
+ return bucket.size;
1315
+ }
1316
+ async listNamespaces() {
1317
+ const namespaces = new Set();
1318
+ for (const key of this.store.keys()){
1319
+ const ns = key.split(':')[0];
1320
+ if (this.store.get(key).size > 0) {
1321
+ namespaces.add(ns);
1322
+ }
1323
+ }
1324
+ return Array.from(namespaces);
1325
+ }
1326
+ async namespaceExists(namespace) {
1327
+ for (const [key, bucket] of this.store.entries()){
1328
+ if (key.startsWith(`${namespace}:`) && bucket.size > 0) {
1329
+ return true;
1330
+ }
1331
+ }
1332
+ return false;
1333
+ }
1334
+ async listTypes(namespace) {
1335
+ const ns = namespace !== null && namespace !== void 0 ? namespace : this.defaultNamespace;
1336
+ const types = new Set();
1337
+ for (const [key, bucket] of this.store.entries()){
1338
+ if (key.startsWith(`${ns}:`) && bucket.size > 0) {
1339
+ types.add(key.split(':')[1]);
1340
+ }
1341
+ }
1342
+ return Array.from(types);
1343
+ }
1344
+ constructor(){
1345
+ _define_property$3(this, "store", new Map());
1346
+ _define_property$3(this, "initialized", false);
1347
+ _define_property$3(this, "defaultNamespace", 'default');
1348
+ }
1349
+ }
1350
+
1351
+ function _define_property$2(obj, key, value) {
1352
+ if (key in obj) {
1353
+ Object.defineProperty(obj, key, {
1354
+ value: value,
1355
+ enumerable: true,
1356
+ configurable: true,
1357
+ writable: true
1358
+ });
1359
+ } else {
1360
+ obj[key] = value;
1361
+ }
1362
+ return obj;
1363
+ }
1364
+ /**
1365
+ * Filesystem-backed Fjell adapter.
1366
+ * Uses one lib-fs Library instance per namespace/type pair.
1367
+ */ class FjellFsAdapter {
1368
+ async initialize() {
1369
+ await fs__namespace.mkdir(this.config.basePath, {
1370
+ recursive: true
1371
+ });
1372
+ // Prime libraries for known types in the default namespace.
1373
+ for (const type of this.config.registry.types()){
1374
+ this.getLibrary(type);
1375
+ }
1376
+ this.initialized = true;
1377
+ }
1378
+ async dispose() {
1379
+ this.libraries.clear();
1380
+ this.initialized = false;
1381
+ }
1382
+ async isAvailable() {
1383
+ if (!this.initialized) {
1384
+ return false;
1385
+ }
1386
+ try {
1387
+ const stat = await fs__namespace.stat(this.config.basePath);
1388
+ return stat.isDirectory();
1389
+ } catch {
1390
+ return false;
1391
+ }
1392
+ }
1393
+ async get(type, id, namespace) {
1394
+ const library = this.getLibrary(type, namespace);
1395
+ const key = this.toPriKey(type, id);
1396
+ const item = await library.operations.get(key);
1397
+ if (!item) {
1398
+ return undefined;
1399
+ }
1400
+ return this.normalizeFromFjell(item, type, id);
1401
+ }
1402
+ async getAll(type, namespace) {
1403
+ const library = this.getLibrary(type, namespace);
1404
+ const result = await library.operations.all();
1405
+ return result.items.map((item)=>this.normalizeFromFjell(item, type));
1406
+ }
1407
+ async create(type, item, namespace) {
1408
+ var _item_id;
1409
+ const id = String((_item_id = item.id) !== null && _item_id !== void 0 ? _item_id : '');
1410
+ const library = this.getLibrary(type, namespace);
1411
+ const key = this.toPriKey(type, id);
1412
+ const created = await library.operations.create(this.toFjellItem(type, id, item), {
1413
+ key
1414
+ });
1415
+ return this.normalizeFromFjell(created, type, id);
1416
+ }
1417
+ async update(type, id, item, namespace) {
1418
+ const library = this.getLibrary(type, namespace);
1419
+ const key = this.toPriKey(type, id);
1420
+ const updated = await library.operations.update(key, this.toFjellItem(type, id, item));
1421
+ return this.normalizeFromFjell(updated, type, id);
1422
+ }
1423
+ async remove(type, id, namespace) {
1424
+ const existing = await this.get(type, id, namespace);
1425
+ if (!existing) {
1426
+ return false;
1427
+ }
1428
+ const library = this.getLibrary(type, namespace);
1429
+ const key = this.toPriKey(type, id);
1430
+ await library.operations.remove(key);
1431
+ return true;
1432
+ }
1433
+ async find(type, filter, namespace) {
1434
+ let results = await this.getAll(type, namespace);
1435
+ if (filter.ids && filter.ids.length > 0) {
1436
+ const ids = new Set(filter.ids);
1437
+ results = results.filter((item)=>ids.has(String(item.id)));
1438
+ }
1439
+ if (filter.search) {
1440
+ const search = filter.search.toLowerCase();
1441
+ results = results.filter((item)=>{
1442
+ var _item_name, _item_notes;
1443
+ const name = String((_item_name = item.name) !== null && _item_name !== void 0 ? _item_name : '').toLowerCase();
1444
+ const notes = String((_item_notes = item.notes) !== null && _item_notes !== void 0 ? _item_notes : '').toLowerCase();
1445
+ return name.includes(search) || notes.includes(search);
1446
+ });
1447
+ }
1448
+ if (filter.offset && filter.offset > 0) {
1449
+ results = results.slice(filter.offset);
1450
+ }
1451
+ if (filter.limit && filter.limit >= 0) {
1452
+ results = results.slice(0, filter.limit);
1453
+ }
1454
+ return results;
1455
+ }
1456
+ async exists(type, id, namespace) {
1457
+ const existing = await this.get(type, id, namespace);
1458
+ return Boolean(existing);
1459
+ }
1460
+ async count(type, filter, namespace) {
1461
+ if (!filter) {
1462
+ const all = await this.getAll(type, namespace);
1463
+ return all.length;
1464
+ }
1465
+ const results = await this.find(type, filter, namespace);
1466
+ return results.length;
1467
+ }
1468
+ async listNamespaces() {
1469
+ let entries;
1470
+ try {
1471
+ entries = await fs__namespace.readdir(this.config.basePath, {
1472
+ withFileTypes: true
1473
+ });
1474
+ } catch {
1475
+ return [];
1476
+ }
1477
+ const knownTypes = new Set(this.config.registry.types());
1478
+ return entries.filter((entry)=>entry.isDirectory()).map((entry)=>entry.name).filter((name)=>!knownTypes.has(name));
1479
+ }
1480
+ async namespaceExists(namespace) {
1481
+ const nsPath = path__namespace.join(this.config.basePath, namespace);
1482
+ try {
1483
+ const stat = await fs__namespace.stat(nsPath);
1484
+ return stat.isDirectory();
1485
+ } catch {
1486
+ return false;
1487
+ }
1488
+ }
1489
+ async listTypes(namespace) {
1490
+ const ns = this.resolveNamespace(namespace);
1491
+ const nsPath = path__namespace.join(this.config.basePath, ns);
1492
+ let entries;
1493
+ try {
1494
+ entries = await fs__namespace.readdir(nsPath, {
1495
+ withFileTypes: true
1496
+ });
1497
+ } catch {
1498
+ return [];
1499
+ }
1500
+ return entries.filter((entry)=>entry.isDirectory()).map((entry)=>entry.name);
1501
+ }
1502
+ libraryKey(type, namespace) {
1503
+ return `${this.resolveNamespace(namespace)}:${type}`;
1504
+ }
1505
+ resolveNamespace(namespace) {
1506
+ return namespace !== null && namespace !== void 0 ? namespace : this.defaultNamespace;
1507
+ }
1508
+ getLibrary(type, namespace) {
1509
+ const key = this.libraryKey(type, namespace);
1510
+ const existing = this.libraries.get(key);
1511
+ if (existing) {
1512
+ return existing;
1513
+ }
1514
+ const ns = this.resolveNamespace(namespace);
1515
+ const library = libFs.createPrimaryFilesystemLibrary(type, `${ns}/${type}`, this.config.basePath);
1516
+ this.libraries.set(key, library);
1517
+ return library;
1518
+ }
1519
+ toPriKey(type, id) {
1520
+ return {
1521
+ kt: type,
1522
+ pk: id
1523
+ };
1524
+ }
1525
+ toFjellItem(type, id, item) {
1526
+ return {
1527
+ ...item,
1528
+ id,
1529
+ type
1530
+ };
1531
+ }
1532
+ normalizeFromFjell(item, type, idFromKey) {
1533
+ const raw = {
1534
+ ...item
1535
+ };
1536
+ delete raw.key;
1537
+ delete raw.events;
1538
+ delete raw.aggs;
1539
+ delete raw.refs;
1540
+ const key = item.key;
1541
+ const id = idFromKey !== null && idFromKey !== void 0 ? idFromKey : typeof raw.id === 'string' ? raw.id : key === null || key === void 0 ? void 0 : key.pk;
1542
+ return {
1543
+ ...raw,
1544
+ id: id ? String(id) : '',
1545
+ type: typeof raw.type === 'string' ? raw.type : type
1546
+ };
1547
+ }
1548
+ constructor(config){
1549
+ _define_property$2(this, "libraries", new Map());
1550
+ _define_property$2(this, "config", void 0);
1551
+ _define_property$2(this, "defaultNamespace", 'default');
1552
+ _define_property$2(this, "initialized", false);
1553
+ this.config = config;
1554
+ }
1555
+ }
1556
+
1557
+ async function createFjellFsProvider(config) {
1558
+ var _config_name;
1559
+ const adapter = new FjellFsAdapter(config);
1560
+ const provider = new FjellStorageProvider(adapter, config.registry, (_config_name = config.name) !== null && _config_name !== void 0 ? _config_name : 'fjell-fs', config.basePath);
1561
+ await provider.initialize();
1562
+ return provider;
1563
+ }
1564
+
1565
+ function _define_property$1(obj, key, value) {
1566
+ if (key in obj) {
1567
+ Object.defineProperty(obj, key, {
1568
+ value: value,
1569
+ enumerable: true,
1570
+ configurable: true,
1571
+ writable: true
1572
+ });
1573
+ } else {
1574
+ obj[key] = value;
1575
+ }
1576
+ return obj;
1577
+ }
1578
+ /**
1579
+ * GCS-backed Fjell adapter.
1580
+ * Uses one lib-gcs Library instance per namespace/type pair.
1581
+ */ class FjellGcsAdapter {
1582
+ async initialize() {
1583
+ // Prime libraries for known types in the default namespace.
1584
+ for (const type of this.config.registry.types()){
1585
+ this.getLibrary(type);
1586
+ }
1587
+ this.initialized = true;
1588
+ }
1589
+ async dispose() {
1590
+ this.libraries.clear();
1591
+ this.initialized = false;
1592
+ }
1593
+ async isAvailable() {
1594
+ return this.initialized;
1595
+ }
1596
+ async get(type, id, namespace) {
1597
+ const library = this.getLibrary(type, namespace);
1598
+ const key = this.toPriKey(type, id);
1599
+ const item = await library.operations.get(key);
1600
+ if (!item) {
1601
+ return undefined;
1602
+ }
1603
+ return this.normalizeFromFjell(item, type, id);
1604
+ }
1605
+ async getAll(type, namespace) {
1606
+ const library = this.getLibrary(type, namespace);
1607
+ const result = await library.operations.all();
1608
+ return result.items.map((item)=>this.normalizeFromFjell(item, type));
1609
+ }
1610
+ async create(type, item, namespace) {
1611
+ var _item_id;
1612
+ const id = String((_item_id = item.id) !== null && _item_id !== void 0 ? _item_id : '');
1613
+ const library = this.getLibrary(type, namespace);
1614
+ const key = this.toPriKey(type, id);
1615
+ const created = await library.operations.create(this.toFjellItem(type, id, item), {
1616
+ key
1617
+ });
1618
+ return this.normalizeFromFjell(created, type, id);
1619
+ }
1620
+ async update(type, id, item, namespace) {
1621
+ const library = this.getLibrary(type, namespace);
1622
+ const key = this.toPriKey(type, id);
1623
+ const updated = await library.operations.update(key, this.toFjellItem(type, id, item));
1624
+ return this.normalizeFromFjell(updated, type, id);
1625
+ }
1626
+ async remove(type, id, namespace) {
1627
+ const existing = await this.get(type, id, namespace);
1628
+ if (!existing) {
1629
+ return false;
1630
+ }
1631
+ const library = this.getLibrary(type, namespace);
1632
+ const key = this.toPriKey(type, id);
1633
+ await library.operations.remove(key);
1634
+ return true;
1635
+ }
1636
+ async find(type, filter, namespace) {
1637
+ let results = await this.getAll(type, namespace);
1638
+ if (filter.ids && filter.ids.length > 0) {
1639
+ const ids = new Set(filter.ids);
1640
+ results = results.filter((item)=>ids.has(String(item.id)));
1641
+ }
1642
+ if (filter.search) {
1643
+ const search = filter.search.toLowerCase();
1644
+ results = results.filter((item)=>{
1645
+ var _item_name, _item_notes;
1646
+ const name = String((_item_name = item.name) !== null && _item_name !== void 0 ? _item_name : '').toLowerCase();
1647
+ const notes = String((_item_notes = item.notes) !== null && _item_notes !== void 0 ? _item_notes : '').toLowerCase();
1648
+ return name.includes(search) || notes.includes(search);
1649
+ });
1650
+ }
1651
+ if (filter.offset && filter.offset > 0) {
1652
+ results = results.slice(filter.offset);
1653
+ }
1654
+ if (filter.limit && filter.limit >= 0) {
1655
+ results = results.slice(0, filter.limit);
1656
+ }
1657
+ return results;
1658
+ }
1659
+ async exists(type, id, namespace) {
1660
+ const existing = await this.get(type, id, namespace);
1661
+ return Boolean(existing);
1662
+ }
1663
+ async count(type, filter, namespace) {
1664
+ if (!filter) {
1665
+ const all = await this.getAll(type, namespace);
1666
+ return all.length;
1667
+ }
1668
+ const results = await this.find(type, filter, namespace);
1669
+ return results.length;
1670
+ }
1671
+ async listNamespaces() {
1672
+ const names = await this.listObjectNames(this.objectPrefix());
1673
+ const knownTypes = new Set(this.config.registry.types());
1674
+ const namespaces = new Set();
1675
+ for (const name of names){
1676
+ const rel = this.relativeObjectPath(name);
1677
+ if (!rel) {
1678
+ continue;
1679
+ }
1680
+ const [firstSegment] = rel.split('/');
1681
+ if (!firstSegment || knownTypes.has(firstSegment)) {
1682
+ continue;
1683
+ }
1684
+ namespaces.add(firstSegment);
1685
+ }
1686
+ return Array.from(namespaces);
1687
+ }
1688
+ async namespaceExists(namespace) {
1689
+ const prefix = this.objectPrefix(namespace);
1690
+ const names = await this.listObjectNames(prefix);
1691
+ return names.length > 0;
1692
+ }
1693
+ async listTypes(namespace) {
1694
+ const ns = this.resolveNamespace(namespace);
1695
+ const prefix = this.objectPrefix(ns);
1696
+ const names = await this.listObjectNames(prefix);
1697
+ const types = new Set();
1698
+ for (const name of names){
1699
+ const rel = this.relativeObjectPath(name);
1700
+ if (!rel || !rel.startsWith(`${ns}/`)) {
1701
+ continue;
1702
+ }
1703
+ const parts = rel.split('/');
1704
+ if (parts.length >= 2 && parts[1]) {
1705
+ types.add(parts[1]);
1706
+ }
1707
+ }
1708
+ return Array.from(types);
1709
+ }
1710
+ libraryKey(type, namespace) {
1711
+ return `${this.resolveNamespace(namespace)}:${type}`;
1712
+ }
1713
+ resolveNamespace(namespace) {
1714
+ return namespace !== null && namespace !== void 0 ? namespace : this.defaultNamespace;
1715
+ }
1716
+ getLibrary(type, namespace) {
1717
+ const key = this.libraryKey(type, namespace);
1718
+ const existing = this.libraries.get(key);
1719
+ if (existing) {
1720
+ return existing;
1721
+ }
1722
+ const ns = this.resolveNamespace(namespace);
1723
+ const libBasePath = this.joinPath(this.normalizeBasePath(this.config.basePath), ns);
1724
+ const library = libGcs.createPrimaryGCSLibrary(type, type, {
1725
+ bucketName: this.config.bucketName,
1726
+ basePath: libBasePath,
1727
+ storage: this.config.storage,
1728
+ useJsonExtension: true,
1729
+ querySafety: this.config.querySafety
1730
+ });
1731
+ this.libraries.set(key, library);
1732
+ return library;
1733
+ }
1734
+ toPriKey(type, id) {
1735
+ return {
1736
+ kt: type,
1737
+ pk: id
1738
+ };
1739
+ }
1740
+ toFjellItem(type, id, item) {
1741
+ return {
1742
+ ...item,
1743
+ id,
1744
+ type
1745
+ };
1746
+ }
1747
+ normalizeFromFjell(item, type, idFromKey) {
1748
+ const raw = {
1749
+ ...item
1750
+ };
1751
+ delete raw.key;
1752
+ delete raw.events;
1753
+ delete raw.aggs;
1754
+ delete raw.refs;
1755
+ const key = item.key;
1756
+ const id = idFromKey !== null && idFromKey !== void 0 ? idFromKey : typeof raw.id === 'string' ? raw.id : key === null || key === void 0 ? void 0 : key.pk;
1757
+ return {
1758
+ ...raw,
1759
+ id: id ? String(id) : '',
1760
+ type: typeof raw.type === 'string' ? raw.type : type
1761
+ };
1762
+ }
1763
+ objectPrefix(...parts) {
1764
+ const normalizedBase = this.normalizeBasePath(this.config.basePath);
1765
+ const segments = [
1766
+ normalizedBase,
1767
+ ...parts
1768
+ ].filter(Boolean);
1769
+ return segments.length > 0 ? `${segments.join('/')}/` : '';
1770
+ }
1771
+ joinPath(...parts) {
1772
+ return parts.filter(Boolean).join('/');
1773
+ }
1774
+ normalizeBasePath(basePath) {
1775
+ if (!basePath) {
1776
+ return '';
1777
+ }
1778
+ return basePath.replace(/^\/+|\/+$/g, '');
1779
+ }
1780
+ relativeObjectPath(fullName) {
1781
+ const base = this.normalizeBasePath(this.config.basePath);
1782
+ if (!base) {
1783
+ return fullName;
1784
+ }
1785
+ return fullName.startsWith(`${base}/`) ? fullName.slice(base.length + 1) : fullName;
1786
+ }
1787
+ async listObjectNames(prefix) {
1788
+ const storage = this.config.storage;
1789
+ if (!storage) {
1790
+ return [];
1791
+ }
1792
+ const bucket = storage.bucket(this.config.bucketName);
1793
+ const [files] = await bucket.getFiles({
1794
+ prefix
1795
+ });
1796
+ return files.map((file)=>{
1797
+ var _file_name;
1798
+ return (_file_name = file.name) !== null && _file_name !== void 0 ? _file_name : '';
1799
+ }).filter(Boolean);
1800
+ }
1801
+ constructor(config){
1802
+ _define_property$1(this, "libraries", new Map());
1803
+ _define_property$1(this, "config", void 0);
1804
+ _define_property$1(this, "defaultNamespace", 'default');
1805
+ _define_property$1(this, "initialized", false);
1806
+ this.config = config;
1807
+ }
1808
+ }
1809
+
1810
+ async function createFjellGcsProvider(config) {
1811
+ var _config_name;
1812
+ const adapter = new FjellGcsAdapter(config);
1813
+ const location = config.basePath ? `gs://${config.bucketName}/${config.basePath}` : `gs://${config.bucketName}`;
1814
+ const provider = new FjellStorageProvider(adapter, config.registry, (_config_name = config.name) !== null && _config_name !== void 0 ? _config_name : 'fjell-gcs', location);
1815
+ await provider.initialize();
1816
+ return provider;
1817
+ }
1818
+
1027
1819
  /**
1028
1820
  * Generate a slug from a name.
1029
1821
  * "John Doe" -> "john-doe"
@@ -2008,6 +2800,10 @@ const discoverContextRoot = async (options = {})=>{
2008
2800
  exports.BaseEntitySchema = BaseEntitySchema;
2009
2801
  exports.EntityMetadataSchema = EntityMetadataSchema;
2010
2802
  exports.EntityNotFoundError = EntityNotFoundError;
2803
+ exports.FjellFsAdapter = FjellFsAdapter;
2804
+ exports.FjellGcsAdapter = FjellGcsAdapter;
2805
+ exports.FjellStorageProvider = FjellStorageProvider;
2806
+ exports.MemoryFjellAdapter = MemoryFjellAdapter;
2011
2807
  exports.NamespaceNotFoundError = NamespaceNotFoundError;
2012
2808
  exports.QueryBuilder = QueryBuilder;
2013
2809
  exports.ReadonlyStorageError = ReadonlyStorageError;
@@ -2021,6 +2817,8 @@ exports.createContext = createContext;
2021
2817
  exports.createDirectoryWalker = createDirectoryWalker;
2022
2818
  exports.createEntitySchema = createEntitySchema;
2023
2819
  exports.createFileSystemProvider = createFileSystemProvider;
2820
+ exports.createFjellFsProvider = createFjellFsProvider;
2821
+ exports.createFjellGcsProvider = createFjellGcsProvider;
2024
2822
  exports.createHierarchicalProvider = createHierarchicalProvider;
2025
2823
  exports.createMemoryProvider = createMemoryProvider;
2026
2824
  exports.createMultiNamespaceContext = createMultiNamespaceContext;