@nacre.work/api 0.6.0 → 0.8.0

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.
@@ -1,7 +1,7 @@
1
1
  import { buildFilter, VectorStore, type CacheStore, type Metadata } from '@nacre.work/core';
2
2
  import type { Pool } from 'pg';
3
3
  import { type Reranker } from './rerank.js';
4
- import type { Reindex, ReindexOutcome, ReindexStatus, ReferenceQueries, ReferenceQuery, AuditEvent, AuditQuery, AuditReader, AuditRecord, AuditWriter, Documents, GrantInput, GrantRecord, Grants, Ingest, IngestOutcome, IngestRefused, IngestRequest, Job, Jobs, Layer, LayerOutcome, DocumentView, Layers, Page, PageResult, Workspace, WorkspaceOutcome, Workspaces, SearchHit, SearchOptions, SearchService } from './server.js';
4
+ import type { Reindex, ReindexOutcome, ReindexStatus, ReferenceQueries, ReferenceQuery, AuditEvent, AuditQuery, AuditReader, AuditRecord, AuditWriter, Documents, GrantInput, GrantRecord, Grants, Ingest, IngestOutcome, IngestRefused, IngestRequest, Job, Jobs, Layer, LayerOutcome, DocumentView, Layers, Page, PageResult, EmbeddingProvider as EmbeddingProviderView, EmbeddingProviderOutcome, EmbeddingProviders, Workspace, WorkspaceOutcome, Workspaces, SearchHit, SearchOptions, SearchService } from './server.js';
5
5
  import { type AuthContext } from './auth.js';
6
6
  /**
7
7
  * The adapters that put the permission model on the request path.
@@ -407,6 +407,34 @@ export declare class PostgresLayers implements Layers {
407
407
  * who closed that terminal had no way forward that did not involve reading the
408
408
  * database directly.
409
409
  */
410
+ /**
411
+ * Embedding providers, which had no API at all.
412
+ *
413
+ * `init` wrote one row and nothing else ever did, so a deployment had exactly
414
+ * one model and the documented way to add a second was `psql` — the shape this
415
+ * repository has closed twice before, at the workspace listing and at
416
+ * `/v1/users`. The capability was already built everywhere else: the schema has
417
+ * carried `embedding_providers.org_id` since migration 0001, and the search
418
+ * path, the worker and the reindex machinery were all taught to honour it.
419
+ *
420
+ * The **database** narrows both operations and this class does not repeat it.
421
+ * `org_isolation` (0002) shows a caller their own organization's rows and the
422
+ * installation default; the three restrictive policies from 0019 require a
423
+ * write to name the caller's own organization, so a tenant cannot create,
424
+ * change or remove the global row whatever this code passes.
425
+ */
426
+ export declare class PostgresEmbeddingProviders implements EmbeddingProviders {
427
+ private readonly pool;
428
+ private readonly role?;
429
+ constructor(pool: Pool, role?: string | undefined);
430
+ list(auth: AuthContext): Promise<readonly EmbeddingProviderView[]>;
431
+ create(auth: AuthContext, input: {
432
+ name: string;
433
+ endpoint: string;
434
+ model: string;
435
+ dimensions: number;
436
+ }): Promise<EmbeddingProviderOutcome>;
437
+ }
410
438
  export declare class PostgresWorkspaces implements Workspaces {
411
439
  private readonly pool;
412
440
  private readonly role?;
@@ -1 +1 @@
1
- {"version":3,"file":"adapters.d.ts","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"adapters.d.ts","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"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"}
package/dist/adapters.js CHANGED
@@ -2,7 +2,7 @@ import { buildFilter, cachedEffectivePrincipals, documentKey, effectivePrincipal
2
2
  import { createHash } from 'node:crypto';
3
3
  import { encodeCursor, pageOf } from './pagination.js';
4
4
  import { applyRanking } from './rerank.js';
5
- import { withinDelegation } from './auth.js';
5
+ import { administers, delegatedLayers, withinDelegation } from './auth.js';
6
6
  export class PostgresDocuments {
7
7
  pool;
8
8
  payload;
@@ -58,7 +58,7 @@ export class PostgresDocuments {
58
58
  if (plan.kind === 'none')
59
59
  return undefined;
60
60
  const { rows } = await client.query(`SELECT d.id, d.title, d.layer_id, l.slug AS layer, d.status, d.chunk_count,
61
- d.updated_at, d.metadata, d.source_type, d.source_ref
61
+ d.updated_at, d.metadata, d.source_type, d.source_ref, d.error
62
62
  FROM documents d
63
63
  JOIN layers l ON l.id = d.layer_id AND l.org_id = d.org_id
64
64
  WHERE d.org_id = $1 AND d.id = $2 AND d.deleted_at IS NULL`, [orgId, documentId]);
@@ -71,7 +71,7 @@ export class PostgresDocuments {
71
71
  // the layer and this would hand over the same document a request later.
72
72
  // `undefined` here becomes the 404 an unreachable document gets, which
73
73
  // is invariant 6 — the caller learns nothing about why.
74
- if (!withinDelegation(auth, row.layer_id))
74
+ if (!withinDelegation(auth, row.layer_id, 'read'))
75
75
  return undefined;
76
76
  // `all` is org_admin, which reaches everything by rule 3. Otherwise the
77
77
  // document has to sit in a layer the plan reached, or be named
@@ -94,6 +94,15 @@ export class PostgresDocuments {
94
94
  // tag has no way to tell a successful write from a dropped one — and
95
95
  // this field was dropped by the handler for as long as it existed.
96
96
  metadata: (row.metadata ?? {}),
97
+ // Why it failed, which the worker has always written and nothing has
98
+ // ever read back. An operator with five failed documents and this
99
+ // field empty has one route left, and it is `docker logs` — so the
100
+ // answer was reachable only by whoever holds the host.
101
+ //
102
+ // Only on `failed`. The column keeps the last error across a retry
103
+ // that succeeded, and reporting that beside `indexed` would describe
104
+ // a document that is fine as a document with a problem.
105
+ error: row.status === 'failed' ? row.error : null,
97
106
  // Minted here and nowhere earlier: everything above this line is the
98
107
  // permission check, so a link exists only for a caller who has just
99
108
  // been found to hold `read` on this document. `write` alone does not
@@ -145,7 +154,7 @@ export class PostgresDocuments {
145
154
  if (layerId === undefined)
146
155
  return false;
147
156
  // The narrowing, same as everywhere a layer id and a document meet.
148
- if (!withinDelegation(auth, layerId))
157
+ if (!withinDelegation(auth, layerId, 'write'))
149
158
  return false;
150
159
  if (plan.kind === 'scoped') {
151
160
  // deniedDocs first, as on the delete path: a deny beats an allow at
@@ -186,7 +195,7 @@ export class NacreSearchService {
186
195
  const principals = await principalsFor(client, auth, this.deps.principalsCache);
187
196
  const grants = await loadGrants(client, auth.orgId, principals);
188
197
  const tree = await loadScopeTree(client, auth.orgId, grants.filter((g) => g.scope.type === 'document').map((g) => g.scope.id));
189
- const plan = activeResolver().resolve({ orgId: auth.orgId, role: auth.role, principals, grants, tree }, 'read');
198
+ const plan = activeResolver().resolve({ orgId: auth.orgId, role: auth.role, principals, grants, tree, ...ceilingOf(auth) }, 'read');
190
199
  // Every live layer with the model it is on. Small — an installation
191
200
  // runs tens of layers per organization, not thousands — and it is what
192
201
  // decides how many branches the query has.
@@ -262,7 +271,12 @@ export class NacreSearchService {
262
271
  // beside the permission constraint the index answers that exactly, which is
263
272
  // also why this is not a post-filter — invariant 2 holds because the clause
264
273
  // is inside the traversal and `top_k` still returns k permitted results.
265
- const delegated = auth.delegation?.layers;
274
+ // `read`, because this is the search path and there is no other verb it
275
+ // could be asking about. A layer the person gave the application `write`
276
+ // and not `read` is absent from this set, which is exactly rule 6: an
277
+ // ingest-only layer is not searchable, and it never was for a principal
278
+ // holding `write` alone either.
279
+ const delegated = delegatedLayers(auth, 'read');
266
280
  if (delegated !== undefined) {
267
281
  const both = narrow?.layers === undefined ? [...delegated] : narrow.layers.filter((id) => delegated.includes(id));
268
282
  // The caller named layers and none of them survive the narrowing. Empty,
@@ -645,7 +659,7 @@ export class NacreIngest {
645
659
  const principals = await principalsFor(client, auth, this.deps.principalsCache);
646
660
  const grants = await loadGrants(client, auth.orgId, principals);
647
661
  const tree = await loadScopeTree(client, auth.orgId, grants.filter((g) => g.scope.type === 'document').map((g) => g.scope.id));
648
- const plan = activeResolver().resolve({ orgId: auth.orgId, role: auth.role, principals, grants, tree }, 'write');
662
+ const plan = activeResolver().resolve({ orgId: auth.orgId, role: auth.role, principals, grants, tree, ...ceilingOf(auth) }, 'write');
649
663
  if (plan.kind === 'none')
650
664
  return undefined;
651
665
  const { rows } = await client.query(`SELECT id FROM layers WHERE org_id = $1 AND slug = $2 AND deleted_at IS NULL`, [auth.orgId, layerSlug]);
@@ -657,7 +671,7 @@ export class NacreIngest {
657
671
  // restricted an application to one layer restricted what it can *put*
658
672
  // there too, and an ingest is the one verb where the layer arrives named
659
673
  // rather than being discovered by a query.
660
- if (!withinDelegation(auth, id))
674
+ if (!withinDelegation(auth, id, 'write'))
661
675
  return undefined;
662
676
  // A layer that exists but is not writable and a layer that does not exist
663
677
  // return the same thing, so the caller cannot tell them apart.
@@ -802,7 +816,7 @@ export class NacreIngest {
802
816
  const principals = await principalsFor(client, auth, this.deps.principalsCache);
803
817
  const grants = await loadGrants(client, auth.orgId, principals);
804
818
  const tree = await loadScopeTree(client, auth.orgId, [documentId]);
805
- const plan = activeResolver().resolve({ orgId: auth.orgId, role: auth.role, principals, grants, tree }, 'write');
819
+ const plan = activeResolver().resolve({ orgId: auth.orgId, role: auth.role, principals, grants, tree, ...ceilingOf(auth) }, 'write');
806
820
  if (plan.kind === 'none')
807
821
  return false;
808
822
  const { rows } = await client.query(`SELECT layer_id FROM documents
@@ -813,7 +827,7 @@ export class NacreIngest {
813
827
  // The narrowing. A delegation restricted to one layer must not be able
814
828
  // to delete out of another, and this is a `write` path so rule 6 does
815
829
  // not help: the person's own `read` never came into it.
816
- if (!withinDelegation(auth, layerId))
830
+ if (!withinDelegation(auth, layerId, 'write'))
817
831
  return false;
818
832
  if (plan.kind === 'scoped') {
819
833
  // deniedDocs first. `resolve` populates it precisely so a deny beats
@@ -933,7 +947,21 @@ async function contextFor(client, auth, cache) {
933
947
  const principals = await principalsFor(client, auth, cache);
934
948
  const grants = await loadGrants(client, auth.orgId, principals);
935
949
  const tree = await loadScopeTree(client, auth.orgId, grants.filter((g) => g.scope.type === 'document').map((g) => g.scope.id));
936
- return { orgId: auth.orgId, role: auth.role, principals, grants, tree };
950
+ return { orgId: auth.orgId, role: auth.role, principals, grants, tree, ...ceilingOf(auth) };
951
+ }
952
+ /**
953
+ * The delegation's permission ceiling, in the shape `ResolveInput` takes it.
954
+ *
955
+ * One function so the three places that build a resolve input cannot disagree,
956
+ * and so adding a fourth is a compile error rather than a silently unbounded
957
+ * token. `resolve` applies it before rule 3, which is the part that matters:
958
+ * an `org_admin` reaches everything by role and by no grant at all, so a
959
+ * ceiling consulted after that line would not bound the one principal it
960
+ * exists for.
961
+ */
962
+ function ceilingOf(auth) {
963
+ const ceiling = auth.delegation?.permissions;
964
+ return ceiling === undefined ? {} : { ceiling };
937
965
  }
938
966
  export class PostgresLayers {
939
967
  pool;
@@ -994,7 +1022,10 @@ export class PostgresLayers {
994
1022
  const projection = `l.id, l.slug, l.name, l.workspace_id, l.description, l.created_at,
995
1023
  l.created_at::text AS created_at_text,
996
1024
  (SELECT count(*) FROM documents d
997
- WHERE d.layer_id = l.id AND d.deleted_at IS NULL) AS document_count`;
1025
+ WHERE d.layer_id = l.id AND d.deleted_at IS NULL) AS document_count,
1026
+ (SELECT count(*) FROM documents d
1027
+ WHERE d.layer_id = l.id AND d.deleted_at IS NULL
1028
+ AND d.status = 'failed') AS failed_count`;
998
1029
  // Ordered by (created_at, id) rather than by slug, because that is the
999
1030
  // cursor's sort key and a page has to be stable under inserts. Sorting
1000
1031
  // by a mutable column would move rows between pages when one is renamed.
@@ -1018,6 +1049,7 @@ export class PostgresLayers {
1018
1049
  workspaceId: r.workspace_id,
1019
1050
  description: r.description ?? '',
1020
1051
  documentCount: Number(r.document_count),
1052
+ failedCount: Number(r.failed_count),
1021
1053
  createdAt: r.created_at.toISOString(),
1022
1054
  }));
1023
1055
  return pageOf(layers, page, (l, i) => ({
@@ -1186,6 +1218,8 @@ export class PostgresLayers {
1186
1218
  description: row.description ?? '',
1187
1219
  // Just created, so this is a fact rather than a query.
1188
1220
  documentCount: 0,
1221
+ // A layer created a moment ago has nothing in it to have failed.
1222
+ failedCount: 0,
1189
1223
  createdAt: row.created_at.toISOString(),
1190
1224
  },
1191
1225
  };
@@ -1202,6 +1236,77 @@ export class PostgresLayers {
1202
1236
  * who closed that terminal had no way forward that did not involve reading the
1203
1237
  * database directly.
1204
1238
  */
1239
+ /**
1240
+ * Embedding providers, which had no API at all.
1241
+ *
1242
+ * `init` wrote one row and nothing else ever did, so a deployment had exactly
1243
+ * one model and the documented way to add a second was `psql` — the shape this
1244
+ * repository has closed twice before, at the workspace listing and at
1245
+ * `/v1/users`. The capability was already built everywhere else: the schema has
1246
+ * carried `embedding_providers.org_id` since migration 0001, and the search
1247
+ * path, the worker and the reindex machinery were all taught to honour it.
1248
+ *
1249
+ * The **database** narrows both operations and this class does not repeat it.
1250
+ * `org_isolation` (0002) shows a caller their own organization's rows and the
1251
+ * installation default; the three restrictive policies from 0019 require a
1252
+ * write to name the caller's own organization, so a tenant cannot create,
1253
+ * change or remove the global row whatever this code passes.
1254
+ */
1255
+ export class PostgresEmbeddingProviders {
1256
+ pool;
1257
+ role;
1258
+ constructor(pool, role) {
1259
+ this.pool = pool;
1260
+ this.role = role;
1261
+ }
1262
+ async list(auth) {
1263
+ return withOrg(this.pool, auth.orgId, async (client) => {
1264
+ // The installation default last. It is the one every layer starts on,
1265
+ // so it is the least interesting entry in a list somebody opened to
1266
+ // find the model they added.
1267
+ const { rows } = await client.query(`SELECT id, name, model, dimensions, org_id
1268
+ FROM embedding_providers
1269
+ ORDER BY org_id IS NULL, name`);
1270
+ return rows.map((r) => ({
1271
+ id: r.id,
1272
+ name: r.name,
1273
+ model: r.model,
1274
+ dimensions: Number(r.dimensions),
1275
+ isDefault: r.org_id === null,
1276
+ }));
1277
+ }, this.role === undefined ? {} : { role: this.role });
1278
+ }
1279
+ async create(auth, input) {
1280
+ if (!administers(auth))
1281
+ return { kind: 'denied' };
1282
+ return withOrg(this.pool, auth.orgId, async (client) => {
1283
+ // `auth.orgId` and never NULL, so a tenant cannot write the global
1284
+ // default. The restrictive policy refuses it anyway — this is the
1285
+ // application saying the same thing, because a statement that relies
1286
+ // only on a policy is one nobody reading it can check.
1287
+ const { rows } = await client.query(`INSERT INTO embedding_providers (org_id, name, endpoint, model, dimensions)
1288
+ VALUES ($1,$2,$3,$4,$5)
1289
+ ON CONFLICT DO NOTHING
1290
+ RETURNING id, name, model, dimensions`, [auth.orgId, input.name, input.endpoint, input.model, input.dimensions]);
1291
+ const row = rows[0];
1292
+ // By here the caller has proved they administer the organization, so
1293
+ // there is nothing about visibility left to protect: a name already in
1294
+ // use is a fact about the resource, and 409 says so.
1295
+ if (row === undefined)
1296
+ return { kind: 'conflict' };
1297
+ return {
1298
+ kind: 'created',
1299
+ provider: {
1300
+ id: row.id,
1301
+ name: row.name,
1302
+ model: row.model,
1303
+ dimensions: Number(row.dimensions),
1304
+ isDefault: false,
1305
+ },
1306
+ };
1307
+ }, this.role === undefined ? {} : { role: this.role });
1308
+ }
1309
+ }
1205
1310
  export class PostgresWorkspaces {
1206
1311
  pool;
1207
1312
  role;
@@ -1282,6 +1387,37 @@ export class PostgresWorkspaces {
1282
1387
  // for a workspace with nothing in it yet.
1283
1388
  return referenceAllows(context, { type: 'workspace', id: w.id }, 'read');
1284
1389
  });
1390
+ /**
1391
+ * What this caller holds on **this workspace**, asked per request and
1392
+ * never derived from `users.role`.
1393
+ *
1394
+ * Authority over a workspace comes from a grant placed on the workspace
1395
+ * scope, or from the role, and `referenceAllows` is the one thing that
1396
+ * answers that — the same function the filter above uses for its third
1397
+ * branch.
1398
+ *
1399
+ * The plan is deliberately *not* consulted. `resolve` flattens a grant
1400
+ * set to the layers it reaches, so a workspace grant and a grant on a
1401
+ * layer inside that workspace produce the same scoped plan: asking the
1402
+ * plan cannot tell "admin on the workspace" from "admin on one layer in
1403
+ * it", and reporting the second as the first would put "New layer" in
1404
+ * front of a principal the server refuses. That was the first shape of
1405
+ * this function, and the T-case is what caught it.
1406
+ *
1407
+ * `read` is added rather than asked, and that is the one thing here
1408
+ * taken on trust from the filter above: a row only reaches this point
1409
+ * because the caller can see the workspace — through a grant on it, or
1410
+ * through a layer inside it, or by role. Either way `read` is true.
1411
+ */
1412
+ const permissionsOn = (w) => {
1413
+ const held = new Set(['read']);
1414
+ for (const permission of ['write', 'admin']) {
1415
+ if (referenceAllows(context, { type: 'workspace', id: w.id }, permission)) {
1416
+ held.add(permission);
1417
+ }
1418
+ }
1419
+ return ['read', 'write', 'admin'].filter((p) => held.has(p));
1420
+ };
1285
1421
  const fetched = page === undefined ? rows : rows.slice(0, page.limit);
1286
1422
  const items = reachable
1287
1423
  .filter((w) => fetched.some((f) => f.id === w.id))
@@ -1291,6 +1427,7 @@ export class PostgresWorkspaces {
1291
1427
  name: w.name,
1292
1428
  layerCount: (w.layer_ids ?? []).length,
1293
1429
  createdAt: w.created_at.toISOString(),
1430
+ permissions: permissionsOn(w),
1294
1431
  }));
1295
1432
  // From the last row **fetched**, not the last returned — the same rule
1296
1433
  // the grant listing follows and for the same reason: the filter above
@@ -1320,7 +1457,7 @@ export class PostgresWorkspaces {
1320
1457
  * documents live.
1321
1458
  */
1322
1459
  async create(auth, input) {
1323
- if (auth.role !== 'org_admin')
1460
+ if (!administers(auth))
1324
1461
  return { kind: 'denied' };
1325
1462
  return withOrg(this.pool, auth.orgId, async (client) => {
1326
1463
  const { rows } = await client.query(`INSERT INTO workspaces (org_id, slug, name) VALUES ($1,$2,$3)
@@ -1342,6 +1479,10 @@ export class PostgresWorkspaces {
1342
1479
  name: row.name,
1343
1480
  layerCount: 0,
1344
1481
  createdAt: row.created_at.toISOString(),
1482
+ // Creating one is `org_admin`, and an `org_admin` reaches
1483
+ // everything by role — so this is the whole set rather than a
1484
+ // resolve call that could only agree with the check just made.
1485
+ permissions: ['read', 'write', 'admin'],
1345
1486
  },
1346
1487
  };
1347
1488
  }, this.scope);