@nacre.work/api 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 (69) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +9 -0
  3. package/dist/adapters.d.ts +421 -17
  4. package/dist/adapters.d.ts.map +1 -1
  5. package/dist/adapters.js +1092 -72
  6. package/dist/adapters.js.map +1 -1
  7. package/dist/audit-export.d.ts +45 -0
  8. package/dist/audit-export.d.ts.map +1 -0
  9. package/dist/audit-export.js +155 -0
  10. package/dist/audit-export.js.map +1 -0
  11. package/dist/auth.d.ts +17 -0
  12. package/dist/auth.d.ts.map +1 -1
  13. package/dist/auth.js +17 -7
  14. package/dist/auth.js.map +1 -1
  15. package/dist/idempotency.d.ts +62 -0
  16. package/dist/idempotency.d.ts.map +1 -0
  17. package/dist/idempotency.js +147 -0
  18. package/dist/idempotency.js.map +1 -0
  19. package/dist/index.d.ts +12 -3
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +10 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/init.d.ts +9 -0
  24. package/dist/init.d.ts.map +1 -1
  25. package/dist/init.js +50 -5
  26. package/dist/init.js.map +1 -1
  27. package/dist/limits.d.ts +80 -0
  28. package/dist/limits.d.ts.map +1 -0
  29. package/dist/limits.js +63 -0
  30. package/dist/limits.js.map +1 -0
  31. package/dist/login.d.ts +94 -0
  32. package/dist/login.d.ts.map +1 -0
  33. package/dist/login.js +283 -0
  34. package/dist/login.js.map +1 -0
  35. package/dist/main.js +171 -60
  36. package/dist/main.js.map +1 -1
  37. package/dist/pagination.d.ts +72 -0
  38. package/dist/pagination.d.ts.map +1 -0
  39. package/dist/pagination.js +110 -0
  40. package/dist/pagination.js.map +1 -0
  41. package/dist/rerank.d.ts +99 -0
  42. package/dist/rerank.d.ts.map +1 -0
  43. package/dist/rerank.js +138 -0
  44. package/dist/rerank.js.map +1 -0
  45. package/dist/server.d.ts +361 -6
  46. package/dist/server.d.ts.map +1 -1
  47. package/dist/server.js +1050 -31
  48. package/dist/server.js.map +1 -1
  49. package/dist/service-keys.d.ts +13 -5
  50. package/dist/service-keys.d.ts.map +1 -1
  51. package/dist/service-keys.js +54 -31
  52. package/dist/service-keys.js.map +1 -1
  53. package/dist/source.d.ts +53 -0
  54. package/dist/source.d.ts.map +1 -0
  55. package/dist/source.js +109 -0
  56. package/dist/source.js.map +1 -0
  57. package/package.json +28 -10
  58. package/dist/__tests__/admin-surface.test.d.ts +0 -2
  59. package/dist/__tests__/admin-surface.test.d.ts.map +0 -1
  60. package/dist/__tests__/admin-surface.test.js +0 -431
  61. package/dist/__tests__/admin-surface.test.js.map +0 -1
  62. package/dist/__tests__/init.test.d.ts +0 -2
  63. package/dist/__tests__/init.test.d.ts.map +0 -1
  64. package/dist/__tests__/init.test.js +0 -125
  65. package/dist/__tests__/init.test.js.map +0 -1
  66. package/dist/__tests__/service-keys.test.d.ts +0 -2
  67. package/dist/__tests__/service-keys.test.d.ts.map +0 -1
  68. package/dist/__tests__/service-keys.test.js +0 -204
  69. package/dist/__tests__/service-keys.test.js.map +0 -1
@@ -0,0 +1,147 @@
1
+ import { createHash } from 'node:crypto';
2
+ /**
3
+ * `Idempotency-Key`, cached for 24 hours.
4
+ *
5
+ * `POST /v1/documents` does not need this — it is idempotent on
6
+ * `(layer, external_id)` and the content hash, which is a stronger guarantee
7
+ * because it survives the cache expiring. This is for everything else unsafe:
8
+ * issuing a grant, revoking one, creating a service account. A client that
9
+ * times out and retries should not end up with two accounts.
10
+ *
11
+ * ## Scoped to the caller, not to the tenant
12
+ *
13
+ * The cache key mixes the key the caller sent with the organization, **the
14
+ * principal**, the method, the path, and a hash of the body. Three of those are
15
+ * not optional.
16
+ *
17
+ * The organization, because a key is a string the caller chose: without it,
18
+ * `Idempotency-Key: 1` from one tenant hands another tenant's response to
19
+ * whoever asks next.
20
+ *
21
+ * The principal, for the same reason one level down, and this one was missing.
22
+ * Two principals in one organization see different things — that is the whole
23
+ * product — so a cache scoped to the tenant let any of them replay any other's
24
+ * response, verbatim and unchecked, because a replay is sent before any handler
25
+ * runs. It bypassed the pre-filter (invariant 2), handed read results to a
26
+ * `write`-only service account (invariant 6), and kept serving a principal
27
+ * whose grant had been revoked for a further 24 hours (invariant 4).
28
+ *
29
+ * The body, because reusing a key with different content is a client bug, and
30
+ * the useful answer to it is `409` rather than silently replaying the first
31
+ * result. A caller who changes the payload and keeps the key is not asking for
32
+ * the old answer.
33
+ *
34
+ * ## Only responses, and only successful ones
35
+ *
36
+ * A failure is never stored. The point is to stop a retry repeating an
37
+ * **effect**, and a request that failed had none — while a cached `500` makes a
38
+ * transient fault permanent for a day and denies the retry the feature exists
39
+ * to serve.
40
+ *
41
+ * ## Failing open
42
+ *
43
+ * If Redis is unreachable the request is processed normally, uncached. The risk
44
+ * is a duplicate on a retry, which is what the feature exists to prevent — so
45
+ * this is a real degradation, logged as one. The alternative is refusing writes
46
+ * because a cache is down, which trades a rare duplicate for a certain outage.
47
+ */
48
+ const TTL_SECONDS = 24 * 60 * 60;
49
+ /**
50
+ * How long a reservation lives before the key frees itself.
51
+ *
52
+ * The reservation and the stored response used to share the 24-hour TTL, which
53
+ * made a crash permanent: `begin` reserves with `SET NX EX 86400` and only
54
+ * `store` overwrites it, so a process that was OOM-killed or SIGKILLed between
55
+ * the two left `pending: true` sitting there for a full day — and every retry
56
+ * of that exact request got `409 "the first attempt has not finished"`. The one
57
+ * situation the feature exists to serve, made impossible by the feature, with
58
+ * `redis-cli DEL` as the only way out.
59
+ *
60
+ * Sixty seconds is longer than any request this API serves and short enough
61
+ * that a crash costs a minute. The response TTL is untouched: once there is a
62
+ * result to replay, it is worth keeping for the full day.
63
+ */
64
+ const RESERVATION_SECONDS = 60;
65
+ /** Long enough that a collision is not a thing, short enough to read in a log. */
66
+ const digest = (value) => createHash('sha256').update(value).digest('base64url').slice(0, 32);
67
+ export const isReplay = (o) => 'cached' in o;
68
+ export const isConflict = (o) => 'conflict' in o;
69
+ /** Organization, then principal. Both, in that order, so neither can be crossed. */
70
+ const orgId = (p) => `${p.orgId}:${p.type}:${p.id}`;
71
+ export class Idempotency {
72
+ options;
73
+ constructor(options) {
74
+ this.options = options;
75
+ }
76
+ /**
77
+ * Look up a key, or reserve it.
78
+ *
79
+ * `SET NX` is what makes two concurrent retries safe: exactly one reserves
80
+ * the slot and runs the handler, and the other sees a reservation rather than
81
+ * a result. A reservation is reported as a conflict — the honest answer to
82
+ * "the first attempt is still in flight" is not to replay a response that
83
+ * does not exist yet.
84
+ */
85
+ async begin(key, principal, method, path, body) {
86
+ const fingerprint = digest(JSON.stringify({ method, path, body: body ?? null }));
87
+ // The organization AND the principal, and the second one is not optional.
88
+ //
89
+ // Scoped to the organization alone, this was a cross-principal read: the
90
+ // key is a string the caller chose, so any principal in the tenant who
91
+ // presented the same key and the same body was handed whatever the first
92
+ // one got — replayed verbatim, with no permission check on the way out,
93
+ // because the cached response is sent before any handler runs.
94
+ //
95
+ // That is invariant 2 bypassed (the answer comes from a cache rather than
96
+ // from a filtered index traversal), invariant 6 bypassed (a `write`-only
97
+ // service account receives read results), and invariant 4 defeated for
98
+ // 24 hours (a principal whose grant was revoked replays their own key and
99
+ // keeps being served). One convenience feature, four rules.
100
+ const cacheKey = `nacre:idem:${orgId(principal)}:${digest(key)}`;
101
+ try {
102
+ const existing = await this.options.redis.command('GET', cacheKey);
103
+ if (typeof existing === 'string') {
104
+ const record = JSON.parse(existing);
105
+ if (record.fingerprint !== fingerprint)
106
+ return { conflict: true };
107
+ if (record.pending === true)
108
+ return { conflict: true };
109
+ return { cached: { status: record.status, body: record.body } };
110
+ }
111
+ const reserved = await this.options.redis.command('SET', cacheKey, JSON.stringify({ fingerprint, pending: true }), 'NX', 'EX',
112
+ // The reservation, not the answer. See RESERVATION_SECONDS.
113
+ String(RESERVATION_SECONDS));
114
+ // Somebody else reserved it between the GET and the SET.
115
+ if (reserved === null)
116
+ return { conflict: true };
117
+ return {
118
+ proceed: true,
119
+ store: async (status, responseBody) => {
120
+ // Only what succeeded. A cached failure is never useful and is often
121
+ // harmful: the point of this cache is to stop a retry repeating an
122
+ // *effect*, and a request that failed had none to repeat. Storing one
123
+ // makes a transient 500 permanent for 24 hours and turns the retry
124
+ // the feature exists to serve into the one thing it cannot do.
125
+ if (status >= 400) {
126
+ await this.options.redis.command('DEL', cacheKey).catch(() => undefined);
127
+ return;
128
+ }
129
+ try {
130
+ await this.options.redis.command('SET', cacheKey, JSON.stringify({ fingerprint, status, body: responseBody }), 'EX', String(TTL_SECONDS));
131
+ }
132
+ catch (error) {
133
+ // The work is already done and the caller is getting their answer.
134
+ // Losing the cache entry means a retry redoes it, which is the
135
+ // situation before this feature existed.
136
+ this.options.onDegraded?.(error);
137
+ }
138
+ },
139
+ };
140
+ }
141
+ catch (error) {
142
+ this.options.onDegraded?.(error);
143
+ return { proceed: true, store: async () => { } };
144
+ }
145
+ }
146
+ }
147
+ //# sourceMappingURL=idempotency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idempotency.js","sourceRoot":"","sources":["../src/idempotency.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,10 +1,19 @@
1
1
  export { createApi } from './server.js';
2
- export type { ApiOptions, AuditEvent, AuditSink, DocumentView, Documents, GrantInput, GrantRecord, Grants, Ingest, IngestOutcome, IngestRequest, Job, Jobs, Layer, LayerOutcome, Layers, SearchHit, SearchService, ServiceAccountPort, ServiceAccountView, } from './server.js';
2
+ export type { ApiOptions, AuditEvent, AuditQuery, AuditReader, AuditRecord, Reindex, ReindexOutcome, ReindexStatus, AuditSink, DocumentView, Documents, GrantInput, GrantRecord, Grants, Ingest, IngestOutcome, IngestRequest, Job, Jobs, Layer, LayerOutcome, Layers, SearchHit, SearchOptions, SearchService, ServiceAccountPort, ServiceAccountView, } from './server.js';
3
3
  export { authenticate, findTenantOverride, rejectTenantOverride } from './auth.js';
4
4
  export type { AuthContext, VerifyOptions } from './auth.js';
5
5
  export { Problem, badRequest, forbidden, internal, notFound, unauthorized } from './errors.js';
6
- export { HttpEmbedder, NacreIngest, NacreSearchService, PostgresAudit, PostgresDocuments, PostgresGrants, PostgresJobs, PostgresLayers, } from './adapters.js';
7
- export type { DocumentTombstone, Embedder, IngestDeps, SearchDeps } from './adapters.js';
6
+ export { HttpEmbedder, NacreIngest, NacreSearchService, PostgresAudit, PostgresAuditReader, PostgresDocuments, PostgresGrants, PostgresJobs, PostgresLayers, PostgresWorkspaces, PostgresReindex, } from './adapters.js';
7
+ export type { DocumentTombstone, Embedder, IngestDeps, ObjectStore, PrincipalsCache, SearchDeps, } from './adapters.js';
8
+ export { applyRanking, HttpReranker, rerankerFor } from './rerank.js';
9
+ export type { Reranker } from './rerank.js';
8
10
  export { generateKey, hashOf, KEY_PREFIX, looksLikeServiceKey, PostgresServiceAccounts, PostgresServiceKeys, prefixOf, } from './service-keys.js';
9
11
  export type { ServiceAccount, ServiceAccounts, ServiceKeyResolver } from './service-keys.js';
12
+ export { auditFormat, auditJson, readAuditQuery, toCsv, toNdjson } from './audit-export.js';
13
+ export type { AuditFormat } from './audit-export.js';
14
+ export { limitHeaders, RateLimiter } from './limits.js';
15
+ export type { LimitDecision, LimitPolicy, Resource } from './limits.js';
16
+ export { clientSource } from './source.js';
17
+ export { Login } from './login.js';
18
+ export type { LoginDeps, LoginRequest, Tokens } from './login.js';
10
19
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,YAAY,EACV,UAAU,EACV,UAAU,EACV,SAAS,EACT,YAAY,EACZ,SAAS,EACT,UAAU,EACV,WAAW,EACX,MAAM,EACN,MAAM,EACN,aAAa,EACb,aAAa,EACb,GAAG,EACH,IAAI,EACJ,KAAK,EACL,YAAY,EACZ,MAAM,EACN,SAAS,EACT,aAAa,EACb,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAClF,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAC3D,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC9F,OAAO,EACL,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,YAAY,EACZ,cAAc,GACf,MAAM,eAAe,CAAA;AACtB,YAAY,EAAE,iBAAiB,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AACxF,OAAO,EACL,WAAW,EACX,MAAM,EACN,UAAU,EACV,mBAAmB,EACnB,uBAAuB,EACvB,mBAAmB,EACnB,QAAQ,GACT,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,YAAY,EACV,UAAU,EACV,UAAU,EACV,UAAU,EACV,WAAW,EACX,WAAW,EACX,OAAO,EACP,cAAc,EACd,aAAa,EACb,SAAS,EACT,YAAY,EACZ,SAAS,EACT,UAAU,EACV,WAAW,EACX,MAAM,EACN,MAAM,EACN,aAAa,EACb,aAAa,EACb,GAAG,EACH,IAAI,EACJ,KAAK,EACL,YAAY,EACZ,MAAM,EACN,SAAS,EACT,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAClF,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAC3D,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC9F,OAAO,EACL,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,eAAe,GAChB,MAAM,eAAe,CAAA;AACtB,YAAY,EACV,iBAAiB,EACjB,QAAQ,EACR,UAAU,EACV,WAAW,EACX,eAAe,EACf,UAAU,GACX,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACrE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EACL,WAAW,EACX,MAAM,EACN,UAAU,EACV,mBAAmB,EACnB,uBAAuB,EACvB,mBAAmB,EACnB,QAAQ,GACT,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAK5F,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC3F,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACvD,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA"}
package/dist/index.js CHANGED
@@ -1,6 +1,15 @@
1
1
  export { createApi } from './server.js';
2
2
  export { authenticate, findTenantOverride, rejectTenantOverride } from './auth.js';
3
3
  export { Problem, badRequest, forbidden, internal, notFound, unauthorized } from './errors.js';
4
- export { HttpEmbedder, NacreIngest, NacreSearchService, PostgresAudit, PostgresDocuments, PostgresGrants, PostgresJobs, PostgresLayers, } from './adapters.js';
4
+ export { HttpEmbedder, NacreIngest, NacreSearchService, PostgresAudit, PostgresAuditReader, PostgresDocuments, PostgresGrants, PostgresJobs, PostgresLayers, PostgresWorkspaces, PostgresReindex, } from './adapters.js';
5
+ export { applyRanking, HttpReranker, rerankerFor } from './rerank.js';
5
6
  export { generateKey, hashOf, KEY_PREFIX, looksLikeServiceKey, PostgresServiceAccounts, PostgresServiceKeys, prefixOf, } from './service-keys.js';
7
+ // The limiter, so the MCP transport can share it rather than growing a second
8
+ // one. Two limiters would be two buckets, and a caller out of budget on one
9
+ // surface would simply use the other — which is what happened before this was
10
+ // exported: NACRE_RATE_* applied to REST only.
11
+ export { auditFormat, auditJson, readAuditQuery, toCsv, toNdjson } from './audit-export.js';
12
+ export { limitHeaders, RateLimiter } from './limits.js';
13
+ export { clientSource } from './source.js';
14
+ export { Login } from './login.js';
6
15
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAuBvC,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAElF,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC9F,OAAO,EACL,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,YAAY,EACZ,cAAc,GACf,MAAM,eAAe,CAAA;AAEtB,OAAO,EACL,WAAW,EACX,MAAM,EACN,UAAU,EACV,mBAAmB,EACnB,uBAAuB,EACvB,mBAAmB,EACnB,QAAQ,GACT,MAAM,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AA8BvC,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAElF,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC9F,OAAO,EACL,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,eAAe,GAChB,MAAM,eAAe,CAAA;AAStB,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAErE,OAAO,EACL,WAAW,EACX,MAAM,EACN,UAAU,EACV,mBAAmB,EACnB,uBAAuB,EACvB,mBAAmB,EACnB,QAAQ,GACT,MAAM,mBAAmB,CAAA;AAE1B,8EAA8E;AAC9E,4EAA4E;AAC5E,8EAA8E;AAC9E,+CAA+C;AAC/C,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE3F,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA"}
package/dist/init.d.ts CHANGED
@@ -25,6 +25,15 @@ export interface Options {
25
25
  readonly name: string;
26
26
  readonly email: string;
27
27
  readonly workspace: string;
28
+ /**
29
+ * Set on the administrator, when there is one to set.
30
+ *
31
+ * Passed in already hashed rather than as a plaintext to hash here: `init`
32
+ * runs in a terminal and its arguments end up in a shell history and in
33
+ * `ps`, so the password is generated rather than accepted, and the plaintext
34
+ * exists in exactly one place — the line printed at the end.
35
+ */
36
+ readonly passwordHash?: string;
28
37
  }
29
38
  export declare function parseArgs(argv: readonly string[]): Options | string;
30
39
  export interface InitResult {
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAA;AAG9B;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,GAAG,MAAM,CA6BnE;AAMD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAC1B;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,EACjE,UAAU,EAAE,MAAM,EAClB,GAAG,GAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAsB,GAC5E,OAAO,CAAC,UAAU,CAAC,CAsFrB"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAA;AAI9B;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B;;;;;;;OAOG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAC/B;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,GAAG,MAAM,CA6BnE;AAMD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAC1B;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,EACjE,UAAU,EAAE,MAAM,EAClB,GAAG,GAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAsB,GAC5E,OAAO,CAAC,UAAU,CAAC,CA2FrB"}
package/dist/init.js CHANGED
@@ -1,5 +1,6 @@
1
- import { collectionName, ConfigError, createPool, loadConfig, vectorName, VectorStore, } from '@nacre.work/core';
1
+ import { collectionName, ConfigError, createPool, hashPassword, loadConfig, vectorName, VectorStore, } from '@nacre.work/core';
2
2
  import { SignJWT } from 'jose';
3
+ import { randomInt } from 'node:crypto';
3
4
  import { pathToFileURL } from 'node:url';
4
5
  export function parseArgs(argv) {
5
6
  const values = new Map();
@@ -64,9 +65,15 @@ export async function initialize(pool, options, provider, collection, log = () =
64
65
  // the organization in the transaction-local setting. The organizations row
65
66
  // itself is not covered — it is the tenant registry, not tenant data.
66
67
  await client.query('SELECT set_config($1, $2, true)', ['app.current_org', org.id]);
67
- const { rows: users } = await client.query(`INSERT INTO users (org_id, email, role) VALUES ($1,$2,'org_admin')
68
- ON CONFLICT (org_id, email) DO UPDATE SET email = EXCLUDED.email
69
- RETURNING id`, [org.id, options.email]);
68
+ const { rows: users } = await client.query(
69
+ // The password is set only when this run generated one — re-running init
70
+ // against an existing organization must not silently reset the
71
+ // administrator's password and lock them out of their own installation.
72
+ `INSERT INTO users (org_id, email, role, password_hash) VALUES ($1,$2,'org_admin',$3)
73
+ ON CONFLICT (org_id, email) DO UPDATE
74
+ SET email = EXCLUDED.email,
75
+ password_hash = COALESCE(users.password_hash, EXCLUDED.password_hash)
76
+ RETURNING id`, [org.id, options.email, options.passwordHash ?? null]);
70
77
  const userId = users[0]?.id;
71
78
  if (userId === undefined)
72
79
  throw new Error('the user insert returned no row');
@@ -115,6 +122,30 @@ export async function initialize(pool, options, provider, collection, log = () =
115
122
  client.release();
116
123
  }
117
124
  }
125
+ /**
126
+ * Six words and a number, from the CSPRNG.
127
+ *
128
+ * Roughly 70 bits with this list, which is more than a person would choose and
129
+ * still something they can read off a terminal and type into a form once. A
130
+ * base64 string of the same strength gets copied wrong, and the recovery from
131
+ * that is re-running init against a live installation.
132
+ */
133
+ function generatePassword() {
134
+ const words = [
135
+ 'abalone', 'anchor', 'aurora', 'basalt', 'beacon', 'bramble', 'cinder', 'clover',
136
+ 'compass', 'coral', 'crest', 'current', 'delta', 'drift', 'ember', 'estuary',
137
+ 'fathom', 'ferry', 'fjord', 'granite', 'harbor', 'haven', 'iris', 'kelp',
138
+ 'lantern', 'ledger', 'lichen', 'mantle', 'marlin', 'meadow', 'mica', 'nacre',
139
+ 'nautilus', 'obsidian', 'onyx', 'opal', 'orbit', 'pearl', 'pelagic', 'pillar',
140
+ 'plover', 'quarry', 'quartz', 'reef', 'ripple', 'salt', 'sextant', 'shale',
141
+ 'shoal', 'silt', 'slate', 'spindrift', 'stratum', 'tide', 'trawler', 'trench',
142
+ 'vellum', 'wharf', 'willow', 'zephyr',
143
+ ];
144
+ // randomInt rather than Math.random or a modulo of randomBytes: one is not a
145
+ // CSPRNG and the other is biased unless the range divides evenly.
146
+ const chosen = Array.from({ length: 6 }, () => words[randomInt(words.length)]);
147
+ return `${chosen.join('-')}-${String(randomInt(10, 100))}`;
148
+ }
118
149
  async function main() {
119
150
  const parsed = parseArgs(process.argv.slice(2));
120
151
  if (typeof parsed === 'string')
@@ -127,11 +158,17 @@ async function main() {
127
158
  'issue the first token, and the API will refuse to start without it either.',
128
159
  ]);
129
160
  }
161
+ // Generated, never taken from an argument: `init` runs in a terminal, and an
162
+ // argument ends up in the shell history and in `ps` on a shared machine. Six
163
+ // words from the CSPRNG rather than a random string, because this is typed
164
+ // by a person into a sign-in form at least once.
165
+ const password = generatePassword();
166
+ const passwordHash = await hashPassword(password);
130
167
  const pool = createPool({ connectionString: config.pgUrl, max: 2 });
131
168
  const vector = vectorName(config.embeddingModel, config.embeddingDim);
132
169
  const collection = collectionName(parsed.slug);
133
170
  try {
134
- const ids = await initialize(pool, parsed, {
171
+ const ids = await initialize(pool, { ...parsed, passwordHash }, {
135
172
  endpoint: config.embeddingEndpoint,
136
173
  model: config.embeddingModel,
137
174
  dimensions: config.embeddingDim,
@@ -173,6 +210,14 @@ async function main() {
173
210
  console.log('');
174
211
  console.log(` export NACRE_TOKEN=${token}`);
175
212
  console.log('');
213
+ console.log('And a password for signing in, which is not printed again:');
214
+ console.log('');
215
+ console.log(` ${password}`);
216
+ console.log('');
217
+ console.log(` curl -X POST ${config.canonicalUrl}/v1/auth/login \\`);
218
+ console.log(` -H 'Content-Type: application/json' \\`);
219
+ console.log(` -d '{"email":"${parsed.email}","password":"…"}'`);
220
+ console.log('');
176
221
  console.log('Create a layer with it, then follow docs/quickstart.md:');
177
222
  console.log('');
178
223
  console.log(` curl -X POST ${config.canonicalUrl}/v1/layers \\`);
package/dist/init.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,WAAW,EACX,UAAU,EACV,YAAY,EACZ,UAAU,EACV,UAAU,EACV,WAAW,GACZ,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAE9B,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAwCxC,MAAM,UAAU,SAAS,CAAC,IAAuB;IAC/C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAA;IACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;QACnB,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;QACzB,IAAI,GAAG,KAAK,SAAS,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACtE,OAAO,+FAA+F,CAAA;QACxG,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;IACjC,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IACjC,IAAI,IAAI,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC9C,OAAO,+FAA+F,CAAA;IACxG,CAAC;IACD,wEAAwE;IACxE,qCAAqC;IACrC,IAAI,CAAC,mCAAmC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACpD,OAAO,4GAA4G,IAAI,EAAE,CAAA;IAC3H,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,0CAA0C,KAAK,EAAE,CAAA;IAElF,OAAO;QACL,IAAI;QACJ,KAAK;QACL,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI;QAChC,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,SAAS;KAChD,CAAA;AACH,CAAC;AAED,MAAM,GAAG,GAAG,CAAC,GAAW,EAAE,QAAiC,EAAE,EAAQ,EAAE;IACrE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAA;AAChD,CAAC,CAAA;AAUD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAU,EACV,OAAgB,EAChB,QAAiE,EACjE,UAAkB,EAClB,MAA8D,GAAG,EAAE,CAAC,SAAS;IAE7E,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAA;IACnC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAE3B,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK,CACvC;;;;;;;;eAQS,EACT,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,CACzC,CAAA;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;QACnB,IAAI,GAAG,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAA;QACjF,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAAC,CAAC,CAAC,sBAAsB,EAAE;YACzE,MAAM,EAAE,GAAG,CAAC,EAAE;YACd,IAAI,EAAE,OAAO,CAAC,IAAI;SACnB,CAAC,CAAA;QAEF,2EAA2E;QAC3E,2EAA2E;QAC3E,sEAAsE;QACtE,MAAM,MAAM,CAAC,KAAK,CAAC,iCAAiC,EAAE,CAAC,iBAAiB,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;QAElF,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK;QACxC,yEAAyE;QACzE,+DAA+D;QAC/D,wEAAwE;QACxE;;;;oBAIc,EACd,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,YAAY,IAAI,IAAI,CAAC,CACtD,CAAA;QACD,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAA;QAC3B,IAAI,MAAM,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;QAC5E,GAAG,CAAC,kBAAkB,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAA;QAElE,2EAA2E;QAC3E,mEAAmE;QACnE,wDAAwD;QACxD,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK,CAC5C;;;;;;;;;eASS,EACT,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,CACzD,CAAA;QACD,MAAM,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAA;QACnC,IAAI,UAAU,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;QAC9F,GAAG,CAAC,0BAA0B,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;QAEnF,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK,CAC7C;;;;;;;;;;;eAWS,EACT,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,CAC/C,CAAA;QACD,MAAM,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAA;QACrC,IAAI,WAAW,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAA;QACtF,GAAG,CAAC,iBAAiB,EAAE,EAAE,YAAY,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAA;QAE9E,MAAM,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;QAC5B,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,CAAA;IACtE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QAC9C,MAAM,KAAK,CAAA;IACb,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,OAAO,EAAE,CAAA;IAClB,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,gBAAgB;IACvB,MAAM,KAAK,GAAG;QACZ,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ;QAChF,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS;QAC5E,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM;QACxE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO;QAC5E,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ;QAC7E,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO;QAC1E,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ;QAC7E,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ;KAC7B,CAAA;IAEV,6EAA6E;IAC7E,kEAAkE;IAClE,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IAC9E,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,EAAE,CAAA;AAC5D,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IAC/C,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,MAAM,IAAI,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;IAE/D,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;IAC3B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAA;IAC3C,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QAC/C,MAAM,IAAI,WAAW,CAAC;YACpB,4EAA4E;gBAC1E,4EAA4E;SAC/E,CAAC,CAAA;IACJ,CAAC;IAED,6EAA6E;IAC7E,6EAA6E;IAC7E,2EAA2E;IAC3E,iDAAiD;IACjD,MAAM,QAAQ,GAAG,gBAAgB,EAAE,CAAA;IACnC,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAA;IAEjD,MAAM,IAAI,GAAG,UAAU,CAAC,EAAE,gBAAgB,EAAE,MAAM,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAA;IACnE,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,YAAY,CAAC,CAAA;IACrE,MAAM,UAAU,GAAG,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAE9C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,UAAU,CAC1B,IAAI,EACJ,EAAE,GAAG,MAAM,EAAE,YAAY,EAAE,EAC3B;YACE,QAAQ,EAAE,MAAM,CAAC,iBAAiB;YAClC,KAAK,EAAE,MAAM,CAAC,cAAc;YAC5B,UAAU,EAAE,MAAM,CAAC,YAAY;SAChC,EACD,UAAU,EACV,GAAG,CACJ,CAAA;QAED,0EAA0E;QAC1E,2EAA2E;QAC3E,qCAAqC;QACrC,EAAE;QACF,2EAA2E;QAC3E,2EAA2E;QAC3E,mEAAmE;QACnE,MAAM,OAAO,GAAG,IAAI,WAAW,CAC7B,MAAM,CAAC,YAAY,KAAK,SAAS;YAC/B,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,SAAS,EAAE;YAC3B,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,YAAY,EAAE,CAC3D,CAAA;QACD,MAAM,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,YAAY,CAAC,CAAA;QACxE,GAAG,CAAC,kBAAkB,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAA;QAEhF,yEAAyE;QACzE,yEAAyE;QACzE,wEAAwE;QACxE,sCAAsC;QACtC,MAAM,KAAK,GAAG,MAAM,IAAI,OAAO,CAAC;YAC9B,GAAG,EAAE,GAAG,CAAC,KAAK;YACd,cAAc,EAAE,MAAM;YACtB,IAAI,EAAE,WAAW;SAClB,CAAC;aACC,kBAAkB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;aACpC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC;aACtB,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC;aAC3B,WAAW,CAAC,MAAM,CAAC,WAAW,CAAC;aAC/B,iBAAiB,CAAC,IAAI,CAAC;aACvB,IAAI,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAA;QAEzC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACf,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,CAAC,IAAI,YAAY,CAAC,CAAA;QACpD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACf,OAAO,CAAC,GAAG,CAAC,mBAAmB,GAAG,CAAC,WAAW,EAAE,CAAC,CAAA;QACjD,OAAO,CAAC,GAAG,CAAC,mBAAmB,MAAM,CAAC,KAAK,EAAE,CAAC,CAAA;QAC9C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACf,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAA;QAC1D,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACf,OAAO,CAAC,GAAG,CAAC,wBAAwB,KAAK,EAAE,CAAC,CAAA;QAC5C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACf,OAAO,CAAC,GAAG,CAAC,4DAA4D,CAAC,CAAA;QACzE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACf,OAAO,CAAC,GAAG,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAA;QAC5B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACf,OAAO,CAAC,GAAG,CAAC,kBAAkB,MAAM,CAAC,YAAY,mBAAmB,CAAC,CAAA;QACrE,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAA;QACzD,OAAO,CAAC,GAAG,CAAC,qBAAqB,MAAM,CAAC,KAAK,oBAAoB,CAAC,CAAA;QAClE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACf,OAAO,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAA;QACtE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACf,OAAO,CAAC,GAAG,CAAC,kBAAkB,MAAM,CAAC,YAAY,eAAe,CAAC,CAAA;QACjE,OAAO,CAAC,GAAG,CAAC,oFAAoF,CAAC,CAAA;QACjG,OAAO,CAAC,GAAG,CACT,4BAA4B,GAAG,CAAC,WAAW,yCAAyC,CACrF,CAAA;QACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IACjB,CAAC;YAAS,CAAC;QACT,MAAM,IAAI,CAAC,GAAG,EAAE,CAAA;IAClB,CAAC;AACH,CAAC;AAED,6EAA6E;AAC7E,yEAAyE;AACzE,8EAA8E;AAC9E,mCAAmC;AACnC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7F,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QAC9B,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;YACjC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;YAC5B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAA;QAC3E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,80 @@
1
+ import type { Redis } from '@nacre.work/core';
2
+ /**
3
+ * Rate limiting, per organization.
4
+ *
5
+ * **Per organization and not per token**, which is the whole point: a limit
6
+ * counted per credential is bypassed by minting another credential, and this
7
+ * product hands out service account keys through an endpoint.
8
+ *
9
+ * A fixed window rather than a sliding one. The cost is a burst at the
10
+ * boundary — a caller can spend a full window at 11:59:59 and another at
11
+ * 12:00:00 — and the benefit is that the whole thing is one `INCR` against a
12
+ * key whose name contains the window, so there is no set to trim and nothing to
13
+ * clean up. Stated rather than hidden because "60 per minute" is not quite what
14
+ * the boundary delivers.
15
+ *
16
+ * ## Failing open, deliberately
17
+ *
18
+ * If Redis is unreachable the request is **allowed**. That is the opposite of
19
+ * invariant I3, and the difference is the point: I3 is about permissions, where
20
+ * an unanswerable question must deny. A rate limit is availability protection,
21
+ * and failing closed would turn a Redis restart into a total outage of a
22
+ * product whose selling point is that it runs in your own network. The
23
+ * degradation is logged, and `nacre_rate_limit_unavailable_total` is what an
24
+ * operator alerts on.
25
+ */
26
+ /**
27
+ * What a limit is counted against.
28
+ *
29
+ * `search` and `ingest` are counted per organization — a per-token limit is
30
+ * bypassed by issuing another key, and this API hands out keys. Login runs
31
+ * before there is an organization, so it is counted twice, on two different
32
+ * things, because either one alone leaves a hole:
33
+ *
34
+ * - `login` counts per email address, and defends one account against being
35
+ * guessed at. On its own it is nearly useless against the attack people
36
+ * actually run: one password sprayed across ten thousand addresses never
37
+ * repeats a key and never meets the limit.
38
+ * - `login_source` counts per client, and is what bounds that. On its own it
39
+ * over-trusts topology — everyone behind one NAT shares a bucket — which is
40
+ * why it is the looser of the two and why the address limit stays.
41
+ *
42
+ * Failing open matters more on both rather than less: a cache outage that
43
+ * locked everybody out of signing in would be the outage.
44
+ */
45
+ export type Resource = 'search' | 'ingest' | 'login' | 'login_source';
46
+ export interface LimitDecision {
47
+ readonly allowed: boolean;
48
+ /** RFC 9331 `RateLimit-Limit`. */
49
+ readonly limit: number;
50
+ /** RFC 9331 `RateLimit-Remaining`, never negative. */
51
+ readonly remaining: number;
52
+ /** Seconds until the window resets — `RateLimit-Reset` and `Retry-After`. */
53
+ readonly reset: number;
54
+ /** True when the check could not run and the request was let through. */
55
+ readonly degraded: boolean;
56
+ }
57
+ export interface LimitPolicy {
58
+ /** Requests allowed per window. */
59
+ readonly limit: number;
60
+ /** Window length in seconds. */
61
+ readonly windowSeconds: number;
62
+ }
63
+ export interface RateLimiterOptions {
64
+ readonly redis: Redis;
65
+ readonly policies: Readonly<Record<Resource, LimitPolicy>>;
66
+ readonly onDegraded?: (resource: Resource, error: unknown) => void;
67
+ }
68
+ export declare class RateLimiter {
69
+ private readonly options;
70
+ constructor(options: RateLimiterOptions);
71
+ check(orgId: string, resource: Resource): Promise<LimitDecision>;
72
+ }
73
+ /**
74
+ * RFC 9331 headers, plus `Retry-After` when the answer is 429.
75
+ *
76
+ * `RateLimit-Policy` names the window so a client can tell 60/minute from
77
+ * 60/hour without guessing from `Reset`.
78
+ */
79
+ export declare function limitHeaders(decision: LimitDecision, policy: LimitPolicy, resource: Resource): Record<string, string>;
80
+ //# sourceMappingURL=limits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../src/limits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAE7C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,cAAc,CAAA;AAErE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,kCAAkC;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,sDAAsD;IACtD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,mCAAmC;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,gCAAgC;IAChC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;CAC/B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAA;IAC1D,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CACnE;AAED,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,kBAAkB;IAElD,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,aAAa,CAAC;CA4CvE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,aAAa,EACvB,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,QAAQ,GACjB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASxB"}
package/dist/limits.js ADDED
@@ -0,0 +1,63 @@
1
+ export class RateLimiter {
2
+ options;
3
+ constructor(options) {
4
+ this.options = options;
5
+ }
6
+ async check(orgId, resource) {
7
+ const policy = this.options.policies[resource];
8
+ const windowMs = policy.windowSeconds * 1000;
9
+ const now = Date.now();
10
+ const windowStart = Math.floor(now / windowMs) * windowMs;
11
+ const reset = Math.ceil((windowStart + windowMs - now) / 1000);
12
+ // The window is in the key, so a stale key belongs to a window nobody will
13
+ // ask about again and expiry is the only cleanup there is.
14
+ const key = `nacre:rl:${resource}:${orgId}:${windowStart}`;
15
+ try {
16
+ // INCR and PEXPIRE together: one round trip, and the TTL is refreshed on
17
+ // every hit rather than only on the first. Setting it once would leave
18
+ // the key immortal if the process died in between, and refreshing a
19
+ // window-scoped key changes nothing about when it actually expires.
20
+ const [count] = await this.options.redis.pipeline(['INCR', key], ['PEXPIRE', key, String(windowMs + 1000)]);
21
+ const used = typeof count === 'number' ? count : Number(count ?? 0);
22
+ return {
23
+ allowed: used <= policy.limit,
24
+ limit: policy.limit,
25
+ remaining: Math.max(0, policy.limit - used),
26
+ reset,
27
+ degraded: false,
28
+ };
29
+ }
30
+ catch (error) {
31
+ this.options.onDegraded?.(resource, error);
32
+ return {
33
+ allowed: true,
34
+ limit: policy.limit,
35
+ // Reporting the full allowance would claim a budget nothing is
36
+ // counting. Reporting the truth — the check did not run — is what the
37
+ // `degraded` flag is for, and the headers say the limit rather than a
38
+ // remaining figure that would be fiction.
39
+ remaining: policy.limit,
40
+ reset,
41
+ degraded: true,
42
+ };
43
+ }
44
+ }
45
+ }
46
+ /**
47
+ * RFC 9331 headers, plus `Retry-After` when the answer is 429.
48
+ *
49
+ * `RateLimit-Policy` names the window so a client can tell 60/minute from
50
+ * 60/hour without guessing from `Reset`.
51
+ */
52
+ export function limitHeaders(decision, policy, resource) {
53
+ const headers = {
54
+ 'ratelimit-limit': String(decision.limit),
55
+ 'ratelimit-remaining': String(decision.remaining),
56
+ 'ratelimit-reset': String(decision.reset),
57
+ 'ratelimit-policy': `${resource};q=${policy.limit};w=${policy.windowSeconds}`,
58
+ };
59
+ if (!decision.allowed)
60
+ headers['retry-after'] = String(decision.reset);
61
+ return headers;
62
+ }
63
+ //# sourceMappingURL=limits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"limits.js","sourceRoot":"","sources":["../src/limits.ts"],"names":[],"mappings":"AAyEA,MAAM,OAAO,WAAW;IACO;IAA7B,YAA6B,OAA2B;QAA3B,YAAO,GAAP,OAAO,CAAoB;IAAG,CAAC;IAE5D,KAAK,CAAC,KAAK,CAAC,KAAa,EAAE,QAAkB;QAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;QAC9C,MAAM,QAAQ,GAAG,MAAM,CAAC,aAAa,GAAG,IAAI,CAAA;QAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACtB,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,QAAQ,CAAC,GAAG,QAAQ,CAAA;QACzD,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,WAAW,GAAG,QAAQ,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,CAAA;QAE9D,2EAA2E;QAC3E,2DAA2D;QAC3D,MAAM,GAAG,GAAG,YAAY,QAAQ,IAAI,KAAK,IAAI,WAAW,EAAE,CAAA;QAE1D,IAAI,CAAC;YACH,yEAAyE;YACzE,uEAAuE;YACvE,oEAAoE;YACpE,oEAAoE;YACpE,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAC/C,CAAC,MAAM,EAAE,GAAG,CAAC,EACb,CAAC,SAAS,EAAE,GAAG,EAAE,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,CAC1C,CAAA;YAED,MAAM,IAAI,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC,CAAA;YACnE,OAAO;gBACL,OAAO,EAAE,IAAI,IAAI,MAAM,CAAC,KAAK;gBAC7B,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC;gBAC3C,KAAK;gBACL,QAAQ,EAAE,KAAK;aAChB,CAAA;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;YAC1C,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,+DAA+D;gBAC/D,sEAAsE;gBACtE,sEAAsE;gBACtE,0CAA0C;gBAC1C,SAAS,EAAE,MAAM,CAAC,KAAK;gBACvB,KAAK;gBACL,QAAQ,EAAE,IAAI;aACf,CAAA;QACH,CAAC;IACH,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAC1B,QAAuB,EACvB,MAAmB,EACnB,QAAkB;IAElB,MAAM,OAAO,GAA2B;QACtC,iBAAiB,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QACzC,qBAAqB,EAAE,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;QACjD,iBAAiB,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QACzC,kBAAkB,EAAE,GAAG,QAAQ,MAAM,MAAM,CAAC,KAAK,MAAM,MAAM,CAAC,aAAa,EAAE;KAC9E,CAAA;IACD,IAAI,CAAC,QAAQ,CAAC,OAAO;QAAE,OAAO,CAAC,aAAa,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IACtE,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -0,0 +1,94 @@
1
+ import type { Pool } from 'pg';
2
+ export interface LoginRequest {
3
+ readonly email: string;
4
+ readonly password: string;
5
+ /** Optional; see the note on invariant I1 above. */
6
+ readonly organization?: string;
7
+ }
8
+ export interface Tokens {
9
+ readonly accessToken: string;
10
+ readonly refreshToken: string;
11
+ readonly expiresIn: number;
12
+ /**
13
+ * Who this was issued to, so the caller can audit it.
14
+ *
15
+ * The audit log is per-organization, and on a successful sign-in there is one
16
+ * to write to. On a failure there is not — an address that matches no user
17
+ * belongs to no tenant, and inventing an owner for that row would put one
18
+ * organization's failed attempts in another's access log. Failures are logged
19
+ * by the process instead; see the handler.
20
+ */
21
+ readonly orgId: string;
22
+ readonly userId: string;
23
+ }
24
+ export interface LoginDeps {
25
+ readonly pool: Pool;
26
+ readonly key: Uint8Array;
27
+ readonly issuer: string;
28
+ readonly audience: string;
29
+ readonly accessTokenTtl: number;
30
+ readonly refreshTokenTtl: number;
31
+ readonly role?: string;
32
+ /** Injected so tests are not asked to wait for wall-clock expiry. */
33
+ readonly now?: () => Date;
34
+ }
35
+ export declare class Login {
36
+ private readonly deps;
37
+ constructor(deps: LoginDeps);
38
+ private get scope();
39
+ private get clock();
40
+ /**
41
+ * Sign in, or refuse.
42
+ *
43
+ * `undefined` for every reason it can fail. The caller turns it into one
44
+ * `401` with one message.
45
+ */
46
+ login(request: LoginRequest): Promise<Tokens | undefined>;
47
+ /**
48
+ * Find the one user this login is about, without saying how many nearly were.
49
+ *
50
+ * `organizations` carries no row-level security — an organization is not
51
+ * inside one — so the slug resolves on an ordinary connection, and the user
52
+ * is then read through `withOrg` like everything else. That is why the login
53
+ * path needs no cross-tenant read and no escape hatch: it is two scoped
54
+ * queries rather than one unscoped one.
55
+ */
56
+ private find;
57
+ private orgIdForSlug;
58
+ private allOrgIds;
59
+ private userIn;
60
+ /**
61
+ * Exchange a refresh token for a new pair, or refuse.
62
+ *
63
+ * Rotation on every use. A token presented after it has been used is not
64
+ * tolerated as a client retry: the legitimate holder already exchanged it, so
65
+ * a second presentation means two parties hold the same token and one of them
66
+ * took it. Which one is unknowable from here, so the whole family is revoked
67
+ * and both sign in again.
68
+ */
69
+ refresh(token: string): Promise<Tokens | undefined>;
70
+ /** Sign out. Ends the family, not just this token. */
71
+ logout(token: string): Promise<boolean>;
72
+ /**
73
+ * End every token descended from one login.
74
+ *
75
+ * Takes the same advisory lock the rotation path takes, and that is what
76
+ * makes it complete rather than approximately complete. Without it the two
77
+ * interleave badly: a statement's snapshot is fixed when the statement
78
+ * starts, so a revoke that begins before a rotation commits will not see the
79
+ * row that rotation inserts — and the token the racing party just obtained
80
+ * survives the revocation that was supposed to catch it. Serialized on the
81
+ * family, the revoke either runs first (and the rotation then finds the
82
+ * family revoked) or runs second (and sees the new row).
83
+ */
84
+ private revokeFamily;
85
+ /**
86
+ * Mint an access token and the refresh token that succeeds it.
87
+ *
88
+ * `family` carries across a rotation so the whole chain from one login can be
89
+ * revoked together; a fresh login starts a new one, so signing out of one
90
+ * device does not sign out of the others.
91
+ */
92
+ private issue;
93
+ }
94
+ //# sourceMappingURL=login.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../src/login.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,IAAI,CAAA;AAyC1C,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,oDAAoD;IACpD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAC/B;AAED,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B;;;;;;;;OAQG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;IACnB,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,qEAAqE;IACrE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;CAC1B;AAeD,qBAAa,KAAK;IACJ,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,SAAS;IAE5C,OAAO,KAAK,KAAK,GAEhB;IAED,OAAO,KAAK,KAAK,GAEhB;IAED;;;;;OAKG;IACG,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAiC/D;;;;;;;;OAQG;YACW,IAAI;YAuBJ,YAAY;YAaZ,SAAS;YAYT,MAAM;IAgBpB;;;;;;;;OAQG;IACG,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IA+FzD,sDAAsD;IAChD,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAkB7C;;;;;;;;;;;OAWG;YACW,YAAY;IAe1B;;;;;;OAMG;YACW,KAAK;CA+CpB"}