@nacre.work/core 0.0.0 → 0.2.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 (89) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +9 -0
  3. package/dist/audit.d.ts +41 -0
  4. package/dist/audit.d.ts.map +1 -0
  5. package/dist/audit.js +18 -0
  6. package/dist/audit.js.map +1 -0
  7. package/dist/authz/cache.d.ts +20 -0
  8. package/dist/authz/cache.d.ts.map +1 -1
  9. package/dist/authz/cache.js +29 -0
  10. package/dist/authz/cache.js.map +1 -1
  11. package/dist/authz/filter.d.ts +54 -3
  12. package/dist/authz/filter.d.ts.map +1 -1
  13. package/dist/authz/filter.js +45 -9
  14. package/dist/authz/filter.js.map +1 -1
  15. package/dist/authz/index.d.ts +3 -3
  16. package/dist/authz/index.d.ts.map +1 -1
  17. package/dist/authz/index.js +2 -2
  18. package/dist/authz/index.js.map +1 -1
  19. package/dist/config.d.ts +55 -1
  20. package/dist/config.d.ts.map +1 -1
  21. package/dist/config.js +245 -7
  22. package/dist/config.js.map +1 -1
  23. package/dist/db/client.d.ts +39 -0
  24. package/dist/db/client.d.ts.map +1 -1
  25. package/dist/db/client.js +82 -0
  26. package/dist/db/client.js.map +1 -1
  27. package/dist/db/migrate.d.ts.map +1 -1
  28. package/dist/db/migrate.js +49 -0
  29. package/dist/db/migrate.js.map +1 -1
  30. package/dist/index.d.ts +21 -3
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +12 -3
  33. package/dist/index.js.map +1 -1
  34. package/dist/lifecycle.d.ts +57 -0
  35. package/dist/lifecycle.d.ts.map +1 -0
  36. package/dist/lifecycle.js +84 -0
  37. package/dist/lifecycle.js.map +1 -0
  38. package/dist/logging.d.ts +46 -0
  39. package/dist/logging.d.ts.map +1 -0
  40. package/dist/logging.js +110 -0
  41. package/dist/logging.js.map +1 -0
  42. package/dist/metadata.d.ts +50 -0
  43. package/dist/metadata.d.ts.map +1 -0
  44. package/dist/metadata.js +127 -0
  45. package/dist/metadata.js.map +1 -0
  46. package/dist/metrics.d.ts +19 -1
  47. package/dist/metrics.d.ts.map +1 -1
  48. package/dist/metrics.js +84 -2
  49. package/dist/metrics.js.map +1 -1
  50. package/dist/migrations/0008_authenticating_lookup.sql +124 -0
  51. package/dist/migrations/0009_refresh_tokens.sql +73 -0
  52. package/dist/migrations/0010_definer_search_path.sql +22 -0
  53. package/dist/migrations/0011_sweep_lease.sql +36 -0
  54. package/dist/migrations/0012_prune.sql +118 -0
  55. package/dist/migrations/0013_reindex.sql +65 -0
  56. package/dist/migrations/0014_retired_collections.sql +68 -0
  57. package/dist/oauth.d.ts +45 -0
  58. package/dist/oauth.d.ts.map +1 -0
  59. package/dist/oauth.js +53 -0
  60. package/dist/oauth.js.map +1 -0
  61. package/dist/observability.d.ts.map +1 -1
  62. package/dist/observability.js +100 -13
  63. package/dist/observability.js.map +1 -1
  64. package/dist/passwords.d.ts +37 -0
  65. package/dist/passwords.d.ts.map +1 -0
  66. package/dist/passwords.js +234 -0
  67. package/dist/passwords.js.map +1 -0
  68. package/dist/redis.d.ts +46 -0
  69. package/dist/redis.d.ts.map +1 -0
  70. package/dist/redis.js +234 -0
  71. package/dist/redis.js.map +1 -0
  72. package/dist/reindex.d.ts +87 -0
  73. package/dist/reindex.d.ts.map +1 -0
  74. package/dist/reindex.js +97 -0
  75. package/dist/reindex.js.map +1 -0
  76. package/dist/s3.d.ts +111 -0
  77. package/dist/s3.d.ts.map +1 -0
  78. package/dist/s3.js +242 -0
  79. package/dist/s3.js.map +1 -0
  80. package/dist/tsconfig.tsbuildinfo +1 -1
  81. package/dist/vector/query.d.ts +49 -4
  82. package/dist/vector/query.d.ts.map +1 -1
  83. package/dist/vector/query.js +43 -10
  84. package/dist/vector/query.js.map +1 -1
  85. package/dist/vector/search.d.ts +175 -4
  86. package/dist/vector/search.d.ts.map +1 -1
  87. package/dist/vector/search.js +320 -7
  88. package/dist/vector/search.js.map +1 -1
  89. package/package.json +26 -8
@@ -3,6 +3,19 @@ import { join } from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
4
  import { Client } from 'pg';
5
5
  const MIGRATIONS_DIR = fileURLToPath(new URL('../migrations/', import.meta.url));
6
+ /**
7
+ * How long a migration may wait for a lock before giving up. See the call site.
8
+ *
9
+ * A migration that needs longer can say so: `SET LOCAL lock_timeout` inside the
10
+ * file overrides this for the rest of that transaction, and it is the right
11
+ * place for the exception because the migration is what knows it is unusual.
12
+ *
13
+ * `statement_timeout` is deliberately not touched. Some managed platforms set
14
+ * one globally and a long index build will hit it — but that is the operator's
15
+ * configuration, the failure rolls back cleanly, and quietly overriding a bound
16
+ * somebody chose is worse than failing where they can see it.
17
+ */
18
+ const LOCK_TIMEOUT = '10s';
6
19
  /**
7
20
  * Migrations in filename order. Numbered prefixes are compared as numbers, so
8
21
  * `0010` sorts after `0009` rather than between `0001` and `0002`.
@@ -81,6 +94,30 @@ export async function migrate(connectionString, migrations = loadMigrations()) {
81
94
  }
82
95
  await client.query('BEGIN');
83
96
  try {
97
+ // Bounded waiting, set inside the transaction so it reverts on its own.
98
+ //
99
+ // `ALTER TABLE` takes ACCESS EXCLUSIVE, which conflicts with everything
100
+ // including a plain SELECT. With no timeout the sequence on a busy
101
+ // database is: the ALTER waits behind one long-running query, and every
102
+ // statement arriving afterwards queues behind the ALTER — because a
103
+ // lock request is not overtaken by weaker ones. One slow reporting
104
+ // query therefore stops the entire application for as long as it runs,
105
+ // and the migration that appeared to be "just adding a column" is what
106
+ // the outage gets blamed on.
107
+ //
108
+ // `lock_timeout`, not `statement_timeout`: the two failures are not
109
+ // alike. Waiting for a lock is a scheduling problem and retrying in a
110
+ // quieter minute fixes it, so failing fast is free. Doing the work is
111
+ // not — a backfill or an index build on a large table legitimately
112
+ // takes longer than any bound worth setting, and killing it halfway
113
+ // achieves nothing except a rollback. So the wait is capped and the
114
+ // work is not.
115
+ //
116
+ // Ten seconds because it is far longer than any lock this schema takes
117
+ // when the queue is empty, and far shorter than a deploy timeout — the
118
+ // migration fails with `55P03 lock_not_available`, which names the
119
+ // problem, instead of hanging until someone kills it and has to guess.
120
+ await client.query(`SET LOCAL lock_timeout = '${LOCK_TIMEOUT}'`);
84
121
  await client.query(migration.sql);
85
122
  await client.query('INSERT INTO schema_migrations (name, checksum) VALUES ($1, $2)', [
86
123
  migration.name,
@@ -91,6 +128,18 @@ export async function migrate(connectionString, migrations = loadMigrations()) {
91
128
  }
92
129
  catch (cause) {
93
130
  await client.query('ROLLBACK');
131
+ // 55P03 is `lock_not_available`, and it is worth naming: it is the one
132
+ // failure here that says nothing about the migration. The SQL is fine,
133
+ // something else was holding the table, and the fix is to look at
134
+ // pg_stat_activity rather than at the file.
135
+ if (cause.code === '55P03') {
136
+ throw new Error(`migration ${migration.name} gave up waiting for a lock after ${LOCK_TIMEOUT} ` +
137
+ 'and was rolled back. Something else is holding the table — a long query, an ' +
138
+ 'idle-in-transaction session, another migration — so this is not a problem with ' +
139
+ 'the migration itself and re-running it once the holder is gone will work. ' +
140
+ 'The wait is capped deliberately: an ALTER queued behind one slow query blocks ' +
141
+ 'every statement that arrives after it, which takes the application down.', { cause });
142
+ }
94
143
  throw new Error(`migration ${migration.name} failed and was rolled back`, { cause });
95
144
  }
96
145
  }
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../db/migrate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../db/migrate.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,16 +1,34 @@
1
1
  export * from './types.js';
2
2
  export * from './authz/index.js';
3
- export { loadConfig, ConfigError } from './config.js';
3
+ export { parseFilters, parseMetadata, MetadataError, MAX_METADATA_KEYS, MAX_METADATA_KEY_LENGTH, MAX_METADATA_LIST, MAX_METADATA_VALUE_LENGTH, } from './metadata.js';
4
+ export type { Metadata } from './metadata.js';
5
+ export { loadConfig, loadJwtKeys, ConfigError } from './config.js';
6
+ export { protectedResourceMetadata, PROTECTED_RESOURCE_PATH } from './oauth.js';
7
+ export type { ProtectedResourceMetadata } from './oauth.js';
8
+ export type { JwtKeys } from './config.js';
4
9
  export type { Config } from './config.js';
5
- export { createPool, withOrg } from './db/client.js';
10
+ export { acrossOrganizations, createPool, whileAuthenticating, withOrg } from './db/client.js';
6
11
  export type { DbOptions, WithOrgOptions } from './db/client.js';
7
12
  export { migrate, loadMigrations } from './db/migrate.js';
8
13
  export { loadGrants, loadGroupsVersion, loadScopeTree, PostgresGroupGraph } from './authz/store.js';
9
- export { VectorStore } from './vector/search.js';
14
+ export { explainQdrant, MetadataIndexer, METADATA_INDEX_LIMIT, VectorStore } from './vector/search.js';
15
+ export { MAX_AUDITED_QUERY, queryAudit } from './audit.js';
16
+ export type { QueryAudit } from './audit.js';
17
+ export { configureLogging, createLogger, logger } from './logging.js';
18
+ export type { Logger, LoggerOptions, LogFormat, LogLevel } from './logging.js';
19
+ export { documentKey, S3, S3Error } from './s3.js';
20
+ export type { S3Options } from './s3.js';
10
21
  export type { Hit, SearchRequest, VectorStoreOptions } from './vector/search.js';
11
22
  export { buildHybridQuery, collectionConfig, collectionName, PAYLOAD_INDEXES, vectorName } from './vector/query.js';
12
23
  export type { Branch, HybridQuery } from './vector/query.js';
13
24
  export { Counter, Gauge, Histogram, Registry, createMetrics } from './metrics.js';
14
25
  export type { Labels, Metrics } from './metrics.js';
15
26
  export { collectDatabaseGauges } from './observability.js';
27
+ export { Redis, RedisError } from './redis.js';
28
+ export type { RedisOptions } from './redis.js';
29
+ export { reindexProgress, toStateJson, fromStateJson } from './reindex.js';
30
+ export type { ReindexState } from './reindex.js';
31
+ export { hashingLoad, hashPassword, needsRehash, spendVerificationTime, TooBusy, verifyPassword, } from './passwords.js';
32
+ export { installGuards, onListenError } from './lifecycle.js';
33
+ export type { Guards } from './lifecycle.js';
16
34
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACrD,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACpD,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC/D,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACnG,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,YAAY,EAAE,GAAG,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAChF,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnH,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC5D,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACjF,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,OAAO,EACL,YAAY,EACZ,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,uBAAuB,EACvB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,eAAe,CAAA;AACtB,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAClE,OAAO,EAAE,yBAAyB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AAC/E,YAAY,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAA;AAC3D,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAC1C,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAC9F,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC/D,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACnG,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACtG,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC1D,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAC9E,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAClD,YAAY,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACxC,YAAY,EAAE,GAAG,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAChF,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnH,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC5D,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACjF,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAC1D,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC9C,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC1E,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,EACL,WAAW,EACX,YAAY,EACZ,WAAW,EACX,qBAAqB,EACrB,OAAO,EACP,cAAc,GACf,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAC7D,YAAY,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA"}
package/dist/index.js CHANGED
@@ -1,11 +1,20 @@
1
1
  export * from './types.js';
2
2
  export * from './authz/index.js';
3
- export { loadConfig, ConfigError } from './config.js';
4
- export { createPool, withOrg } from './db/client.js';
3
+ export { parseFilters, parseMetadata, MetadataError, MAX_METADATA_KEYS, MAX_METADATA_KEY_LENGTH, MAX_METADATA_LIST, MAX_METADATA_VALUE_LENGTH, } from './metadata.js';
4
+ export { loadConfig, loadJwtKeys, ConfigError } from './config.js';
5
+ export { protectedResourceMetadata, PROTECTED_RESOURCE_PATH } from './oauth.js';
6
+ export { acrossOrganizations, createPool, whileAuthenticating, withOrg } from './db/client.js';
5
7
  export { migrate, loadMigrations } from './db/migrate.js';
6
8
  export { loadGrants, loadGroupsVersion, loadScopeTree, PostgresGroupGraph } from './authz/store.js';
7
- export { VectorStore } from './vector/search.js';
9
+ export { explainQdrant, MetadataIndexer, METADATA_INDEX_LIMIT, VectorStore } from './vector/search.js';
10
+ export { MAX_AUDITED_QUERY, queryAudit } from './audit.js';
11
+ export { configureLogging, createLogger, logger } from './logging.js';
12
+ export { documentKey, S3, S3Error } from './s3.js';
8
13
  export { buildHybridQuery, collectionConfig, collectionName, PAYLOAD_INDEXES, vectorName } from './vector/query.js';
9
14
  export { Counter, Gauge, Histogram, Registry, createMetrics } from './metrics.js';
10
15
  export { collectDatabaseGauges } from './observability.js';
16
+ export { Redis, RedisError } from './redis.js';
17
+ export { reindexProgress, toStateJson, fromStateJson } from './reindex.js';
18
+ export { hashingLoad, hashPassword, needsRehash, spendVerificationTime, TooBusy, verifyPassword, } from './passwords.js';
19
+ export { installGuards, onListenError } from './lifecycle.js';
11
20
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAErD,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAEpD,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACnG,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAEhD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAEnH,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAEjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,OAAO,EACL,YAAY,EACZ,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,uBAAuB,EACvB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,eAAe,CAAA;AAEtB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAClE,OAAO,EAAE,yBAAyB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AAI/E,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAE9F,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACnG,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACtG,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE1D,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAErE,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAGlD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAEnH,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAEjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAC1D,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE9C,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAE1E,OAAO,EACL,WAAW,EACX,YAAY,EACZ,WAAW,EACX,qBAAqB,EACrB,OAAO,EACP,cAAc,GACf,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * What every process does when it is asked to stop, and when it is about to
3
+ * die for a reason nobody wrote down.
4
+ *
5
+ * Three processes ship here — api, mcp, worker — and none of them had any of
6
+ * this. The consequences were all of the same shape: a failure that produced no
7
+ * log line, so the operator saw a container restart and had nothing to read.
8
+ *
9
+ * - **No `unhandledRejection` handler.** Node terminates the process on one,
10
+ * with a raw stack on stderr and no service name, no timestamp in the format
11
+ * every other line uses, and nothing to join to a request.
12
+ * - **No `error` listener on `listen`.** `EADDRINUSE` is emitted on the server
13
+ * *after* `main()` has already resolved, so `main().catch` never sees it and
14
+ * the careful ConfigError path — which exits 2 with an explanation — is
15
+ * bypassed by the one startup failure an operator hits most.
16
+ * - **No deadline on shutdown.** `server.close()` waits for in-flight requests
17
+ * with no upper bound. One request blocked on a slow dependency means the
18
+ * callback never runs, the pool is never released, and the orchestrator
19
+ * SIGKILLs at the end of its grace period — turning every rolling deploy into
20
+ * an abrupt one, silently.
21
+ */
22
+ export interface Guards {
23
+ /** Named in every line, so two processes in one log stream are tellable apart. */
24
+ readonly service: string;
25
+ /**
26
+ * Release what the process holds. Called once, with a deadline.
27
+ *
28
+ * Whatever it does, it must not be the only thing standing between the
29
+ * process and exiting: if it hangs, the deadline below exits anyway.
30
+ */
31
+ readonly shutdown?: () => Promise<void> | void;
32
+ /** How long `shutdown` gets. Shorter than any orchestrator's grace period. */
33
+ readonly graceMs?: number;
34
+ /** Injected in tests. Nothing else should be replacing this. */
35
+ readonly exit?: (code: number) => void;
36
+ }
37
+ /**
38
+ * Install the handlers. Returns a `stop` to call from a signal handler.
39
+ *
40
+ * Idempotent: a second SIGTERM while shutting down is ignored rather than
41
+ * starting a second shutdown, because an orchestrator that sends one and then
42
+ * loses patience sends another.
43
+ */
44
+ export declare function installGuards(guards: Guards): {
45
+ stop: (signal: string) => void;
46
+ };
47
+ /**
48
+ * Fail a `listen` the way every other startup failure fails.
49
+ *
50
+ * `server.listen(port, cb)` reports a bound port through the callback and a
51
+ * refusal through an `error` event — which arrives after `main()` has resolved,
52
+ * so nothing was catching it.
53
+ */
54
+ export declare function onListenError(server: {
55
+ on(event: 'error', listener: (error: NodeJS.ErrnoException) => void): unknown;
56
+ }, service: string, port: number, exit?: (code: number) => void): void;
57
+ //# sourceMappingURL=lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../lifecycle.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,WAAW,MAAM;IACrB,kFAAkF;IAClF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAC9C,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,gEAAgE;IAChE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACvC;AAkBD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,CAmDhF;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE;IAAE,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,cAAc,KAAK,IAAI,GAAG,OAAO,CAAA;CAAE,EACzF,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAmC,GAC1D,IAAI,CAWN"}
@@ -0,0 +1,84 @@
1
+ import { logger } from './logging.js';
2
+ /**
3
+ * Through the process logger, so `NACRE_LOG_FORMAT` reaches these too.
4
+ *
5
+ * The level is a parameter rather than always `error`: a clean shutdown is not
6
+ * a failure, and reporting it as one is how a dashboard counting errors turns
7
+ * every deploy into an incident. What is an error stays an error.
8
+ */
9
+ const log = (level, service, msg, extra = {}) => {
10
+ logger[level](msg, { service, ...extra });
11
+ };
12
+ /**
13
+ * Install the handlers. Returns a `stop` to call from a signal handler.
14
+ *
15
+ * Idempotent: a second SIGTERM while shutting down is ignored rather than
16
+ * starting a second shutdown, because an orchestrator that sends one and then
17
+ * loses patience sends another.
18
+ */
19
+ export function installGuards(guards) {
20
+ const { service, shutdown, graceMs = 10_000, exit = (code) => process.exit(code) } = guards;
21
+ let stopping = false;
22
+ process.on('unhandledRejection', (reason) => {
23
+ // Logged and then rethrown by exiting, rather than swallowed. A promise
24
+ // nobody awaited failing means the process is in a state its author did not
25
+ // plan for, and continuing from there is how one bad request becomes a
26
+ // corrupt one.
27
+ log('error', service, 'unhandled rejection; exiting', { error: String(reason).slice(0, 500) });
28
+ exit(1);
29
+ });
30
+ process.on('uncaughtException', (error) => {
31
+ log('error', service, 'uncaught exception; exiting', {
32
+ error: String(error).slice(0, 500),
33
+ stack: error.stack?.split('\n').slice(1, 6).join(' | '),
34
+ });
35
+ exit(1);
36
+ });
37
+ const stop = (signal) => {
38
+ if (stopping)
39
+ return;
40
+ stopping = true;
41
+ log('info', service, 'shutting down', { signal });
42
+ // The deadline runs whatever happens, and `unref` keeps it from being the
43
+ // thing that holds the process open once everything else has let go.
44
+ const deadline = setTimeout(() => {
45
+ log('error', service, 'shutdown did not finish in time; exiting anyway', { grace_ms: graceMs });
46
+ exit(1);
47
+ }, graceMs);
48
+ deadline.unref();
49
+ void (async () => {
50
+ try {
51
+ await shutdown?.();
52
+ clearTimeout(deadline);
53
+ exit(0);
54
+ }
55
+ catch (error) {
56
+ log('error', service, 'shutdown failed', { error: String(error).slice(0, 500) });
57
+ clearTimeout(deadline);
58
+ exit(1);
59
+ }
60
+ })();
61
+ };
62
+ process.on('SIGTERM', () => stop('SIGTERM'));
63
+ process.on('SIGINT', () => stop('SIGINT'));
64
+ return { stop };
65
+ }
66
+ /**
67
+ * Fail a `listen` the way every other startup failure fails.
68
+ *
69
+ * `server.listen(port, cb)` reports a bound port through the callback and a
70
+ * refusal through an `error` event — which arrives after `main()` has resolved,
71
+ * so nothing was catching it.
72
+ */
73
+ export function onListenError(server, service, port, exit = (code) => process.exit(code)) {
74
+ server.on('error', (error) => {
75
+ const detail = error.code === 'EADDRINUSE'
76
+ ? `port ${port} is already in use`
77
+ : error.code === 'EACCES'
78
+ ? `port ${port} needs privileges this process does not have`
79
+ : String(error);
80
+ log('error', service, 'could not listen', { port, detail });
81
+ exit(2);
82
+ });
83
+ }
84
+ //# sourceMappingURL=lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../lifecycle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Logging, at the level and in the format the deployment asked for.
3
+ *
4
+ * `NACRE_LOG_LEVEL` and `NACRE_LOG_FORMAT` were validated at startup and read
5
+ * by nothing: every process wrote structured JSON at one level, so an operator
6
+ * setting `warn` still got every `info` line and one setting `text` still got
7
+ * JSON. Both are among the first variables anyone sets.
8
+ *
9
+ * ─── what does not go through here ───
10
+ *
11
+ * **Configuration errors.** They happen before a configuration exists, so there
12
+ * is nothing to ask about the level, and a process that cannot start must say
13
+ * why whatever anyone configured. Those stay on `console.error`.
14
+ *
15
+ * **`init` and `migrate` output.** Those are commands a person runs and reads —
16
+ * the printed org id, the applied migrations. That is program output, like
17
+ * `--help`, and putting it behind a level would mean `NACRE_LOG_LEVEL=warn`
18
+ * silently swallows the one line the command exists to produce.
19
+ *
20
+ * ─── what a field may hold ───
21
+ *
22
+ * The same rule as everywhere else in this repository: no document contents and
23
+ * no full query text. This module cannot enforce that — it takes what it is
24
+ * given — so it is stated where the fields are named rather than here.
25
+ */
26
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
27
+ export type LogFormat = 'json' | 'text';
28
+ export interface Logger {
29
+ debug(message: string, fields?: Record<string, unknown>): void;
30
+ info(message: string, fields?: Record<string, unknown>): void;
31
+ warn(message: string, fields?: Record<string, unknown>): void;
32
+ error(message: string, fields?: Record<string, unknown>): void;
33
+ }
34
+ export interface LoggerOptions {
35
+ readonly level: LogLevel;
36
+ readonly format: LogFormat;
37
+ /** Injected so a test can assert on a line rather than on a moving timestamp. */
38
+ readonly now?: () => Date;
39
+ /** Injected for the same reason. Defaults to the console. */
40
+ readonly write?: (level: LogLevel, line: string) => void;
41
+ }
42
+ export declare function createLogger(options: LoggerOptions): Logger;
43
+ export declare function configureLogging(options: LoggerOptions): void;
44
+ /** Delegates on every call, so a module may hold this and still see the change. */
45
+ export declare const logger: Logger;
46
+ //# sourceMappingURL=logging.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../logging.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AAC1D,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,CAAA;AAIvC,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IAC9D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IAC7D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IAC7D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;CAC/D;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;IAC1B,iFAAiF;IACjF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;IACzB,6DAA6D;IAC7D,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACzD;AA+BD,wBAAgB,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CA6B3D;AAiBD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAE7D;AAED,mFAAmF;AACnF,eAAO,MAAM,MAAM,EAAE,MAKpB,CAAA"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Logging, at the level and in the format the deployment asked for.
3
+ *
4
+ * `NACRE_LOG_LEVEL` and `NACRE_LOG_FORMAT` were validated at startup and read
5
+ * by nothing: every process wrote structured JSON at one level, so an operator
6
+ * setting `warn` still got every `info` line and one setting `text` still got
7
+ * JSON. Both are among the first variables anyone sets.
8
+ *
9
+ * ─── what does not go through here ───
10
+ *
11
+ * **Configuration errors.** They happen before a configuration exists, so there
12
+ * is nothing to ask about the level, and a process that cannot start must say
13
+ * why whatever anyone configured. Those stay on `console.error`.
14
+ *
15
+ * **`init` and `migrate` output.** Those are commands a person runs and reads —
16
+ * the printed org id, the applied migrations. That is program output, like
17
+ * `--help`, and putting it behind a level would mean `NACRE_LOG_LEVEL=warn`
18
+ * silently swallows the one line the command exists to produce.
19
+ *
20
+ * ─── what a field may hold ───
21
+ *
22
+ * The same rule as everywhere else in this repository: no document contents and
23
+ * no full query text. This module cannot enforce that — it takes what it is
24
+ * given — so it is stated where the fields are named rather than here.
25
+ */
26
+ const ORDER = { debug: 10, info: 20, warn: 30, error: 40 };
27
+ /**
28
+ * `warn` and `error` to stderr, the rest to stdout.
29
+ *
30
+ * Not a style choice: a container that pipes stdout into a log shipper and
31
+ * leaves stderr on the terminal is a real deployment, and a failure that went
32
+ * to stdout with everything else is a failure nobody saw at 3am.
33
+ */
34
+ function toConsole(level, line) {
35
+ if (level === 'warn')
36
+ console.warn(line);
37
+ else if (level === 'error')
38
+ console.error(line);
39
+ else
40
+ console.log(line);
41
+ }
42
+ /**
43
+ * `key=value`, with anything ambiguous quoted.
44
+ *
45
+ * Text format is for a person reading a terminal, so it is optimised for
46
+ * scanning rather than for parsing — but a value containing a space or a quote
47
+ * still has to survive, or two fields read as one.
48
+ */
49
+ function render(value) {
50
+ if (value === null)
51
+ return 'null';
52
+ if (typeof value === 'string') {
53
+ return /[\s"=]/.test(value) ? JSON.stringify(value) : value;
54
+ }
55
+ if (typeof value === 'number' || typeof value === 'boolean')
56
+ return String(value);
57
+ return JSON.stringify(value);
58
+ }
59
+ export function createLogger(options) {
60
+ const threshold = ORDER[options.level];
61
+ const now = options.now ?? (() => new Date());
62
+ const write = options.write ?? toConsole;
63
+ const emit = (level, message, fields) => {
64
+ if (ORDER[level] < threshold)
65
+ return;
66
+ const ts = now().toISOString();
67
+ if (options.format === 'json') {
68
+ // `msg` first and named the same as before, because every existing line
69
+ // was `{"msg": ...}` and anything already grepping for it should keep
70
+ // working. The level and timestamp are additions, not a replacement.
71
+ write(level, JSON.stringify({ level, ts, msg: message, ...fields }));
72
+ return;
73
+ }
74
+ const rest = Object.entries(fields ?? {})
75
+ .map(([key, value]) => ` ${key}=${render(value)}`)
76
+ .join('');
77
+ write(level, `${ts} ${level.toUpperCase().padEnd(5)} ${message}${rest}`);
78
+ };
79
+ return {
80
+ debug: (m, f) => emit('debug', m, f),
81
+ info: (m, f) => emit('info', m, f),
82
+ warn: (m, f) => emit('warn', m, f),
83
+ error: (m, f) => emit('error', m, f),
84
+ };
85
+ }
86
+ /**
87
+ * The process-wide logger.
88
+ *
89
+ * A module-level default that `configureLogging` replaces once the
90
+ * configuration is read. Deliberately the one piece of global state in this
91
+ * repository, and it is safe to be: it carries no authorization semantics, the
92
+ * worst a wrong one does is print at the wrong level, and the alternative —
93
+ * threading a logger through every adapter and port — buys nothing a reader of
94
+ * those signatures would want.
95
+ *
96
+ * The default is `info`/`json`, so a module that logs before `configureLogging`
97
+ * runs behaves exactly as the whole system did before this existed.
98
+ */
99
+ let current = createLogger({ level: 'info', format: 'json' });
100
+ export function configureLogging(options) {
101
+ current = createLogger(options);
102
+ }
103
+ /** Delegates on every call, so a module may hold this and still see the change. */
104
+ export const logger = {
105
+ debug: (m, f) => current.debug(m, f),
106
+ info: (m, f) => current.info(m, f),
107
+ warn: (m, f) => current.warn(m, f),
108
+ error: (m, f) => current.error(m, f),
109
+ };
110
+ //# sourceMappingURL=logging.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logging.js","sourceRoot":"","sources":["../logging.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import type { MetadataValue } from './authz/filter.js';
2
+ /**
3
+ * Document metadata: what a caller may write, and what they may narrow a search
4
+ * by.
5
+ *
6
+ * One module for both ends on purpose. Ingest and search accept the same shape
7
+ * from the same untrusted place, and two validators would drift — the ingest
8
+ * side would grow a type the search side could not express, or the search side
9
+ * would accept a key ingest had refused, and a caller would be filtering on a
10
+ * field that can never exist.
11
+ *
12
+ * Everything here is a bound. Metadata is written into the vector payload of
13
+ * *every chunk of a document*, so a key is stored once per point and a
14
+ * thousand-chunk document multiplies whatever arrives here by a thousand. The
15
+ * limits are deliberately small; a knowledge index wants `source`, `team`,
16
+ * `updated_at`, not a document's worth of JSON a second time.
17
+ */
18
+ /** Keys per document. */
19
+ export declare const MAX_METADATA_KEYS = 32;
20
+ export declare const MAX_METADATA_KEY_LENGTH = 64;
21
+ /** A string value, and every string inside a list value. */
22
+ export declare const MAX_METADATA_VALUE_LENGTH = 256;
23
+ /** Values in one list. */
24
+ export declare const MAX_METADATA_LIST = 32;
25
+ export type Metadata = Readonly<Record<string, MetadataValue>>;
26
+ export declare class MetadataError extends Error {
27
+ constructor(message: string);
28
+ }
29
+ /**
30
+ * Validate and normalise metadata arriving from a request.
31
+ *
32
+ * Raises rather than dropping what it does not like. A silently discarded key
33
+ * is a document a caller believes is tagged and a filter that will never match
34
+ * it — the same class of failure as a search parameter read by nothing, and the
35
+ * reason `filters` answered 400 rather than being ignored.
36
+ */
37
+ export declare function parseMetadata(raw: unknown, what?: string): Metadata;
38
+ /**
39
+ * The same bounds, plus the one rule that belongs only to filtering.
40
+ *
41
+ * An empty list is a legitimate *value* — a document may be tagged with no
42
+ * teams — and an impossible *restriction*: "team is one of nothing" matches
43
+ * nothing at all. `buildFilter` refuses to encode it, deliberately, so that
44
+ * what an impossible restriction means stays the caller's decision rather than
45
+ * the query builder's. This is where that decision is made for a request: a 400
46
+ * naming the key, because a client that built a list and put nothing in it has
47
+ * a bug, and answering with an empty result would hide it.
48
+ */
49
+ export declare function parseFilters(raw: unknown): Metadata;
50
+ //# sourceMappingURL=metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../metadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEtD;;;;;;;;;;;;;;;GAeG;AAEH,yBAAyB;AACzB,eAAO,MAAM,iBAAiB,KAAK,CAAA;AACnC,eAAO,MAAM,uBAAuB,KAAK,CAAA;AACzC,4DAA4D;AAC5D,eAAO,MAAM,yBAAyB,MAAM,CAAA;AAC5C,0BAA0B;AAC1B,eAAO,MAAM,iBAAiB,KAAK,CAAA;AAanC,MAAM,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAA;AAE9D,qBAAa,aAAc,SAAQ,KAAK;gBAC1B,OAAO,EAAE,MAAM;CAI5B;AA6BD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,SAAa,GAAG,QAAQ,CAsCvE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,CAWnD"}