@nacre.work/api 0.0.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.
Files changed (46) hide show
  1. package/README.md +3 -0
  2. package/dist/__tests__/admin-surface.test.d.ts +2 -0
  3. package/dist/__tests__/admin-surface.test.d.ts.map +1 -0
  4. package/dist/__tests__/admin-surface.test.js +431 -0
  5. package/dist/__tests__/admin-surface.test.js.map +1 -0
  6. package/dist/__tests__/init.test.d.ts +2 -0
  7. package/dist/__tests__/init.test.d.ts.map +1 -0
  8. package/dist/__tests__/init.test.js +125 -0
  9. package/dist/__tests__/init.test.js.map +1 -0
  10. package/dist/__tests__/service-keys.test.d.ts +2 -0
  11. package/dist/__tests__/service-keys.test.d.ts.map +1 -0
  12. package/dist/__tests__/service-keys.test.js +204 -0
  13. package/dist/__tests__/service-keys.test.js.map +1 -0
  14. package/dist/adapters.d.ts +197 -0
  15. package/dist/adapters.d.ts.map +1 -0
  16. package/dist/adapters.js +672 -0
  17. package/dist/adapters.js.map +1 -0
  18. package/dist/auth.d.ts +42 -0
  19. package/dist/auth.d.ts.map +1 -0
  20. package/dist/auth.js +106 -0
  21. package/dist/auth.js.map +1 -0
  22. package/dist/errors.d.ts +43 -0
  23. package/dist/errors.d.ts.map +1 -0
  24. package/dist/errors.js +101 -0
  25. package/dist/errors.js.map +1 -0
  26. package/dist/index.d.ts +10 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +6 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/init.d.ts +49 -0
  31. package/dist/init.d.ts.map +1 -0
  32. package/dist/init.js +201 -0
  33. package/dist/init.js.map +1 -0
  34. package/dist/main.d.ts +2 -0
  35. package/dist/main.d.ts.map +1 -0
  36. package/dist/main.js +113 -0
  37. package/dist/main.js.map +1 -0
  38. package/dist/server.d.ts +239 -0
  39. package/dist/server.d.ts.map +1 -0
  40. package/dist/server.js +543 -0
  41. package/dist/server.js.map +1 -0
  42. package/dist/service-keys.d.ts +82 -0
  43. package/dist/service-keys.d.ts.map +1 -0
  44. package/dist/service-keys.js +158 -0
  45. package/dist/service-keys.js.map +1 -0
  46. package/package.json +40 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
package/dist/main.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":""}
package/dist/main.js ADDED
@@ -0,0 +1,113 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { collectDatabaseGauges, createMetrics, createPool, loadConfig, Registry, VectorStore, vectorName, withOrg, ConfigError, } from '@nacre.work/core';
3
+ import { HttpEmbedder, NacreIngest, NacreSearchService, PostgresAudit, PostgresDocuments, PostgresGrants, PostgresJobs, PostgresLayers, } from './adapters.js';
4
+ import { PostgresServiceAccounts, PostgresServiceKeys } from './service-keys.js';
5
+ import { createApi } from './server.js';
6
+ /**
7
+ * The REST API process.
8
+ *
9
+ * Configuration is read and validated before anything is constructed, so a
10
+ * missing variable is a refusal to start rather than an error rate. Nothing
11
+ * below this line has a fallback.
12
+ */
13
+ const APP_ROLE = 'nacre_app';
14
+ function jwtKey(config) {
15
+ // Development uses a symmetric secret. Production is meant to load an Ed25519
16
+ // key through NACRE_JWT_PRIVATE_KEY_REF; until that lands, refusing is the
17
+ // honest behaviour — a hardcoded fallback here would be a signing key anyone
18
+ // reading the source can forge tokens with.
19
+ const secret = process.env.NACRE_JWT_SECRET;
20
+ if (secret === undefined || secret.length < 32) {
21
+ throw new ConfigError([
22
+ 'NACRE_JWT_SECRET is not set, or is shorter than 32 bytes. ' +
23
+ 'Asymmetric keys through NACRE_JWT_PRIVATE_KEY_REF are not implemented yet; ' +
24
+ 'until they are, this is required and there is no default.',
25
+ ]);
26
+ }
27
+ void config;
28
+ return new TextEncoder().encode(secret);
29
+ }
30
+ async function main() {
31
+ const config = loadConfig();
32
+ const key = jwtKey({});
33
+ const pool = createPool({ connectionString: config.pgUrl, max: config.pgPoolMax });
34
+ const vectors = new VectorStore(config.qdrantApiKey === undefined
35
+ ? { url: config.qdrantUrl }
36
+ : { url: config.qdrantUrl, apiKey: config.qdrantApiKey });
37
+ const embedder = new HttpEmbedder(config.embeddingEndpoint, config.embeddingModel, config.embeddingDim);
38
+ // Slugs change rarely and are read on every search. A tiny cache keyed on the
39
+ // organization keeps a search from costing an extra round trip; it is not
40
+ // permission data, so staleness here cannot widen access.
41
+ const slugs = new Map();
42
+ const orgSlug = async (orgId) => {
43
+ const cached = slugs.get(orgId);
44
+ if (cached !== undefined)
45
+ return cached;
46
+ const found = await withOrg(pool, orgId, async (client) => {
47
+ const { rows } = await client.query('SELECT slug FROM organizations WHERE id = $1 AND deleted_at IS NULL', [orgId]);
48
+ return rows[0]?.slug;
49
+ }, { role: APP_ROLE });
50
+ if (found !== undefined)
51
+ slugs.set(orgId, found);
52
+ return found;
53
+ };
54
+ const registry = new Registry();
55
+ const metrics = createMetrics(registry);
56
+ registry.collect(collectDatabaseGauges(pool, metrics, APP_ROLE));
57
+ const server = createApi({
58
+ verify: {
59
+ key,
60
+ issuer: config.jwtIssuer,
61
+ audience: config.jwtAudience,
62
+ serviceKeys: new PostgresServiceKeys(pool, APP_ROLE),
63
+ },
64
+ metrics: registry,
65
+ documents: new PostgresDocuments(pool, APP_ROLE),
66
+ search: new NacreSearchService({
67
+ pool,
68
+ vectors,
69
+ embedder,
70
+ orgSlug,
71
+ vectorName: vectorName(config.embeddingModel, config.embeddingDim),
72
+ role: APP_ROLE,
73
+ }),
74
+ ingest: new NacreIngest({ pool, tombstone: vectors, orgSlug, role: APP_ROLE }),
75
+ audit: new PostgresAudit(pool, APP_ROLE),
76
+ jobs: new PostgresJobs(pool, APP_ROLE),
77
+ layers: new PostgresLayers(pool, APP_ROLE),
78
+ grants: new PostgresGrants(pool, APP_ROLE),
79
+ serviceAccounts: new PostgresServiceAccounts(pool, APP_ROLE),
80
+ });
81
+ const port = Number(process.env.PORT ?? 8080);
82
+ server.listen(port, () => {
83
+ // The fingerprint, never the secret. An operator needs to know which key is
84
+ // in use when two environments disagree; nobody needs the key in a log.
85
+ const fingerprint = createHash('sha256').update(key).digest('hex').slice(0, 12);
86
+ console.log(JSON.stringify({
87
+ msg: 'api listening',
88
+ port,
89
+ env: config.env,
90
+ issuer: config.jwtIssuer,
91
+ jwt_key: `sha256:${fingerprint}`,
92
+ }));
93
+ });
94
+ const shutdown = (signal) => {
95
+ console.log(JSON.stringify({ msg: 'shutting down', signal }));
96
+ // Stop accepting, let in-flight requests finish, then release the pool.
97
+ // Dropping a request mid-flight would leave its audit event unwritten.
98
+ server.close(() => {
99
+ void pool.end().then(() => process.exit(0));
100
+ });
101
+ };
102
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
103
+ process.on('SIGINT', () => shutdown('SIGINT'));
104
+ }
105
+ main().catch((error) => {
106
+ if (error instanceof ConfigError) {
107
+ console.error(error.message);
108
+ process.exit(2);
109
+ }
110
+ console.error(JSON.stringify({ msg: 'failed to start', error: String(error) }));
111
+ process.exit(1);
112
+ });
113
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,239 @@
1
+ import { type Server } from 'node:http';
2
+ import { type AuthContext, type VerifyOptions } from './auth.js';
3
+ /**
4
+ * What the API needs from the rest of the system, as ports.
5
+ *
6
+ * Injected rather than imported so the surface can be tested without a
7
+ * database or a vector store. The parts that must be tested here — the token is
8
+ * the only source of the organization, and invisible is indistinguishable from
9
+ * absent — are properties of this layer, and a test that has to stand up
10
+ * Postgres to check them is a test nobody runs.
11
+ */
12
+ export interface Documents {
13
+ /**
14
+ * The document, or undefined.
15
+ *
16
+ * **Undefined must mean the same thing for every reason it can be
17
+ * undefined** — absent, another organization's, or one this caller has no
18
+ * grant reaching. If this ever grows a second answer, the 403/404
19
+ * distinction leaks through whatever the caller does with it.
20
+ *
21
+ * It takes the whole `AuthContext` and not an `orgId`, and that is the
22
+ * point: with an organization alone the implementation is structurally
23
+ * incapable of consulting the resolver, and the first version of this
24
+ * signature was exactly that. Search filtered correctly while
25
+ * `GET /v1/documents/{id}` returned the title of any document in the
26
+ * organization to anyone holding any token for it — including a caller whose
27
+ * grant had been revoked, and a service account with `write` and no `read`.
28
+ */
29
+ read(auth: AuthContext, documentId: string): Promise<DocumentView | undefined>;
30
+ }
31
+ /**
32
+ * A document, as a caller sees it.
33
+ *
34
+ * It was `{ id, title }`, which is not enough to do anything with: no layer, no
35
+ * status, no size. A client that got a `202` from ingest and then wanted to
36
+ * know whether the document had indexed had to go to `/v1/jobs/{id}` and knew
37
+ * to only because the two ids happen to be the same value.
38
+ *
39
+ * Nothing here is permission data — the caller has already been resolved
40
+ * against this document, so every field describes something they may see. The
41
+ * text is not included: chunks are what search returns, and a whole-document
42
+ * body on this endpoint would be a second, unpaginated way to read everything.
43
+ */
44
+ export interface DocumentView {
45
+ readonly document_id: string;
46
+ readonly layer: string;
47
+ readonly title: string | null;
48
+ readonly status: string;
49
+ readonly chunk_count: number;
50
+ readonly updated_at: string;
51
+ }
52
+ /**
53
+ * One result, as the contract describes it.
54
+ *
55
+ * Not the vector store's hit. That carried the raw payload — `acl_tags`,
56
+ * `acl_version`, `org_id`, `layer_id` — straight to the client, and carried no
57
+ * text at all, so the product's central operation answered with identifiers and
58
+ * a score and nothing a caller could read. `docs/openapi.yaml` had said
59
+ * otherwise since before there was a server.
60
+ *
61
+ * The tags are the part worth naming: an acl tag is a hash over the grant set
62
+ * reaching a document, so publishing it lets a client group documents by which
63
+ * permissions they share. Not a cross-tenant leak, and still the shape of the
64
+ * organization's access structure handed to anyone who can search.
65
+ */
66
+ export interface SearchHit {
67
+ readonly chunk_id: string;
68
+ readonly doc_id: string;
69
+ readonly layer: string;
70
+ readonly title: string | null;
71
+ readonly score: number;
72
+ readonly text: string;
73
+ }
74
+ export interface SearchService {
75
+ search(auth: AuthContext, query: string, topK: number): Promise<readonly SearchHit[]>;
76
+ }
77
+ export interface IngestRequest {
78
+ readonly layer: string;
79
+ readonly externalId: string;
80
+ readonly title?: string;
81
+ readonly content?: string;
82
+ readonly url?: string;
83
+ }
84
+ export interface IngestOutcome {
85
+ readonly documentId: string;
86
+ readonly jobId: string;
87
+ /** True when the idempotency key and content hash both matched. */
88
+ readonly unchanged: boolean;
89
+ }
90
+ export interface Ingest {
91
+ /**
92
+ * Queue a document, or refuse.
93
+ *
94
+ * `undefined` means the caller may not write to that layer — and it must mean
95
+ * the same for a layer that does not exist. Ingest is the cheapest oracle in
96
+ * the system otherwise: a caller with no read access could enumerate layer
97
+ * names by watching which ones accept a document.
98
+ */
99
+ queue(auth: AuthContext, request: IngestRequest): Promise<IngestOutcome | undefined>;
100
+ /** Tombstone. `false` for absent and for not-permitted alike. */
101
+ remove(auth: AuthContext, documentId: string): Promise<boolean>;
102
+ }
103
+ export interface Job {
104
+ readonly jobId: string;
105
+ readonly documentId: string;
106
+ readonly status: 'queued' | 'parsing' | 'embedding' | 'indexed' | 'failed';
107
+ readonly progress: number;
108
+ readonly error?: string;
109
+ }
110
+ export interface Jobs {
111
+ /**
112
+ * `undefined` for absent, for another organization's, and for one the caller
113
+ * has no grant reaching — a job names a document and carries its error
114
+ * string, so it is exactly as much of an oracle as the document is.
115
+ */
116
+ read(auth: AuthContext, jobId: string): Promise<Job | undefined>;
117
+ }
118
+ export interface Layer {
119
+ readonly id: string;
120
+ readonly slug: string;
121
+ readonly name: string;
122
+ readonly workspaceId: string;
123
+ readonly description: string;
124
+ /**
125
+ * Live documents in the layer.
126
+ *
127
+ * Not "documents this caller may read": layer-scoped grants are all this
128
+ * build has, so anyone who can see the layer reaches everything in it. When
129
+ * document-level grants exist this stops being true, and the number has to be
130
+ * computed per caller or removed — a count is a small disclosure and still a
131
+ * disclosure.
132
+ */
133
+ readonly documentCount: number;
134
+ }
135
+ /**
136
+ * Three outcomes, not two.
137
+ *
138
+ * `denied` covers "may not administer this workspace" and "no such workspace"
139
+ * together, which is the usual rule. `conflict` is deliberately separate: the
140
+ * caller has already proved admin on the target workspace by the time it can
141
+ * happen, so the answer is about the resource rather than about what they can
142
+ * see.
143
+ *
144
+ * Folding it into `denied` was the first shape and it makes the endpoint
145
+ * unusable — an administrator who picks a name already in use gets a 404 and
146
+ * cannot tell it from having no permission, so the next move is to guess. It
147
+ * discloses exactly one bit, that the slug is taken somewhere in their own
148
+ * organization, and slugs are organization-unique by design (migration 0006).
149
+ */
150
+ export type LayerOutcome = {
151
+ readonly kind: 'created';
152
+ readonly layer: Layer;
153
+ } | {
154
+ readonly kind: 'denied';
155
+ } | {
156
+ readonly kind: 'conflict';
157
+ };
158
+ export interface Layers {
159
+ /** Only the layers this caller may read. The plan decides, not the caller. */
160
+ list(auth: AuthContext): Promise<readonly Layer[]>;
161
+ create(auth: AuthContext, input: {
162
+ workspaceId: string;
163
+ slug: string;
164
+ name: string;
165
+ }): Promise<LayerOutcome>;
166
+ }
167
+ export interface GrantInput {
168
+ readonly principalType: 'user' | 'group' | 'service_account';
169
+ readonly principalId: string;
170
+ readonly scopeType: 'workspace' | 'layer';
171
+ readonly scopeId: string;
172
+ readonly permission: 'read' | 'write' | 'admin';
173
+ }
174
+ export interface GrantRecord extends GrantInput {
175
+ readonly id: string;
176
+ readonly effect: 'allow' | 'deny';
177
+ readonly source: string;
178
+ }
179
+ export interface Grants {
180
+ /** Grants in the caller's organization. Admin only; the caller is checked above. */
181
+ list(auth: AuthContext): Promise<readonly GrantRecord[]>;
182
+ /** `undefined` when the caller may not administer the scope, or it does not exist. */
183
+ issue(auth: AuthContext, input: GrantInput): Promise<GrantRecord | undefined>;
184
+ /**
185
+ * Withdraw a grant. `false` when it is absent, in another organization, or on
186
+ * a scope this caller may not administer — one answer for all three.
187
+ *
188
+ * This is the operation `nacre_acl_propagation_lag_seconds` measures and the
189
+ * one docs/authz.md builds its SLA around, and there was no way to perform it
190
+ * through the API at all. Three documents described revocation; the only
191
+ * implementation was a DELETE against the table by hand.
192
+ */
193
+ revoke(auth: AuthContext, grantId: string): Promise<boolean>;
194
+ }
195
+ export interface ServiceAccountView {
196
+ readonly id: string;
197
+ readonly name: string;
198
+ readonly keyPrefix: string;
199
+ readonly createdAt: string;
200
+ readonly lastUsedAt: string | null;
201
+ readonly revokedAt: string | null;
202
+ }
203
+ export interface ServiceAccountPort {
204
+ list(auth: AuthContext): Promise<readonly ServiceAccountView[]>;
205
+ create(auth: AuthContext, name: string): Promise<{
206
+ account: ServiceAccountView;
207
+ key: string;
208
+ }>;
209
+ revoke(auth: AuthContext, id: string): Promise<boolean>;
210
+ }
211
+ export interface AuditEvent {
212
+ readonly orgId: string;
213
+ readonly actor: string;
214
+ readonly action: string;
215
+ readonly result: 'allow' | 'deny' | 'error';
216
+ readonly detail: Record<string, unknown>;
217
+ readonly requestId: string;
218
+ }
219
+ export interface AuditSink {
220
+ /** Awaited before the response goes out. A lost event is worse than a slow response. */
221
+ write(event: AuditEvent): Promise<void>;
222
+ }
223
+ export interface ApiOptions {
224
+ readonly verify: VerifyOptions;
225
+ /** Rendered at /metrics. Absent means the endpoint answers 404. */
226
+ readonly metrics?: {
227
+ render(): Promise<string>;
228
+ };
229
+ readonly documents: Documents;
230
+ readonly search: SearchService;
231
+ readonly ingest: Ingest;
232
+ readonly audit: AuditSink;
233
+ readonly jobs?: Jobs;
234
+ readonly layers?: Layers;
235
+ readonly grants?: Grants;
236
+ readonly serviceAccounts?: ServiceAccountPort;
237
+ }
238
+ export declare function createApi(options: ApiOptions): Server;
239
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}