@abloatai/transaction 0.55.0 → 0.57.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 (213) hide show
  1. package/CONVENTIONS.md +34 -0
  2. package/dist/auth/hostedEndpoints.d.ts +21 -5
  3. package/dist/auth/hostedEndpoints.d.ts.map +1 -1
  4. package/dist/auth/hostedEndpoints.js +21 -5
  5. package/dist/auth/hostedEndpoints.js.map +1 -1
  6. package/dist/auth/index.d.ts +1 -1
  7. package/dist/auth/index.d.ts.map +1 -1
  8. package/dist/auth/index.js +1 -1
  9. package/dist/auth/index.js.map +1 -1
  10. package/dist/coordination/index.d.ts +2 -2
  11. package/dist/coordination/index.d.ts.map +1 -1
  12. package/dist/coordination/index.js +1 -1
  13. package/dist/coordination/index.js.map +1 -1
  14. package/dist/coordination/schema.d.ts +0 -3
  15. package/dist/coordination/schema.d.ts.map +1 -1
  16. package/dist/coordination/schema.js +4 -5
  17. package/dist/coordination/schema.js.map +1 -1
  18. package/dist/errorCodes.d.ts +1 -0
  19. package/dist/errorCodes.d.ts.map +1 -1
  20. package/dist/errorCodes.js +1 -0
  21. package/dist/errorCodes.js.map +1 -1
  22. package/dist/errors.d.ts.map +1 -1
  23. package/dist/errors.js +4 -1
  24. package/dist/errors.js.map +1 -1
  25. package/dist/log/syncDeltaRow.d.ts +3 -3
  26. package/dist/readSetContext.d.ts.map +1 -1
  27. package/dist/readSetContext.js +8 -3
  28. package/dist/readSetContext.js.map +1 -1
  29. package/dist/resources/httpResources.d.ts +43 -22
  30. package/dist/resources/httpResources.d.ts.map +1 -1
  31. package/dist/resources/httpResources.js +81 -4
  32. package/dist/resources/httpResources.js.map +1 -1
  33. package/dist/resources/modelCreate.d.ts +21 -0
  34. package/dist/resources/modelCreate.d.ts.map +1 -0
  35. package/dist/resources/modelCreate.js +49 -0
  36. package/dist/resources/modelCreate.js.map +1 -0
  37. package/dist/resources/modelOperations.d.ts +24 -2
  38. package/dist/resources/modelOperations.d.ts.map +1 -1
  39. package/dist/resources/modelOperations.js.map +1 -1
  40. package/dist/resources/writeOptionsSchema.d.ts +14 -0
  41. package/dist/resources/writeOptionsSchema.d.ts.map +1 -1
  42. package/dist/resources/writeOptionsSchema.js +23 -2
  43. package/dist/resources/writeOptionsSchema.js.map +1 -1
  44. package/dist/schema/audit.d.ts +15 -0
  45. package/dist/schema/audit.d.ts.map +1 -0
  46. package/dist/schema/audit.js +90 -0
  47. package/dist/schema/audit.js.map +1 -0
  48. package/dist/schema/ddl.d.ts.map +1 -1
  49. package/dist/schema/ddl.js +68 -1
  50. package/dist/schema/ddl.js.map +1 -1
  51. package/dist/schema/index.d.ts +3 -1
  52. package/dist/schema/index.d.ts.map +1 -1
  53. package/dist/schema/index.js +3 -1
  54. package/dist/schema/index.js.map +1 -1
  55. package/dist/schema/model.d.ts +14 -0
  56. package/dist/schema/model.d.ts.map +1 -1
  57. package/dist/schema/model.js +2 -0
  58. package/dist/schema/model.js.map +1 -1
  59. package/dist/schema/openapi.d.ts.map +1 -1
  60. package/dist/schema/openapi.js +104 -2
  61. package/dist/schema/openapi.js.map +1 -1
  62. package/dist/schema/roles.d.ts +27 -0
  63. package/dist/schema/roles.d.ts.map +1 -1
  64. package/dist/schema/roles.js +40 -0
  65. package/dist/schema/roles.js.map +1 -1
  66. package/dist/schema/schema.d.ts +23 -4
  67. package/dist/schema/schema.d.ts.map +1 -1
  68. package/dist/schema/schema.js +30 -1
  69. package/dist/schema/schema.js.map +1 -1
  70. package/dist/schema/serialize.d.ts +4 -1
  71. package/dist/schema/serialize.d.ts.map +1 -1
  72. package/dist/schema/serialize.js +5 -1
  73. package/dist/schema/serialize.js.map +1 -1
  74. package/dist/schema/subject.d.ts +18 -0
  75. package/dist/schema/subject.d.ts.map +1 -0
  76. package/dist/schema/subject.js +27 -0
  77. package/dist/schema/subject.js.map +1 -0
  78. package/dist/server/adapter.d.ts +2 -0
  79. package/dist/server/adapter.d.ts.map +1 -1
  80. package/dist/server/readConfig.d.ts +3 -0
  81. package/dist/server/readConfig.d.ts.map +1 -1
  82. package/dist/server/readConfig.js +0 -21
  83. package/dist/server/readConfig.js.map +1 -1
  84. package/dist/source/adapters/drizzle.d.ts.map +1 -1
  85. package/dist/source/adapters/drizzle.js +37 -6
  86. package/dist/source/adapters/drizzle.js.map +1 -1
  87. package/dist/source/adapters/kysely.d.ts +2 -0
  88. package/dist/source/adapters/kysely.d.ts.map +1 -1
  89. package/dist/source/adapters/kysely.js +33 -5
  90. package/dist/source/adapters/kysely.js.map +1 -1
  91. package/dist/source/adapters/kyselyMutationCore.d.ts +4 -1
  92. package/dist/source/adapters/kyselyMutationCore.d.ts.map +1 -1
  93. package/dist/source/adapters/kyselyMutationCore.js +17 -8
  94. package/dist/source/adapters/kyselyMutationCore.js.map +1 -1
  95. package/dist/source/adapters/memory.d.ts.map +1 -1
  96. package/dist/source/adapters/memory.js +1 -0
  97. package/dist/source/adapters/memory.js.map +1 -1
  98. package/dist/source/adapters/prisma.d.ts.map +1 -1
  99. package/dist/source/adapters/prisma.js +59 -7
  100. package/dist/source/adapters/prisma.js.map +1 -1
  101. package/dist/source/contract.d.ts +14 -0
  102. package/dist/source/contract.d.ts.map +1 -1
  103. package/dist/source/contract.js +10 -0
  104. package/dist/source/contract.js.map +1 -1
  105. package/dist/source/factory.d.ts +7 -1
  106. package/dist/source/factory.d.ts.map +1 -1
  107. package/dist/source/factory.js +116 -5
  108. package/dist/source/factory.js.map +1 -1
  109. package/dist/source/index.d.ts +2 -1
  110. package/dist/source/index.d.ts.map +1 -1
  111. package/dist/source/index.js +1 -0
  112. package/dist/source/index.js.map +1 -1
  113. package/dist/source/migrations.d.ts.map +1 -1
  114. package/dist/source/migrations.js +21 -0
  115. package/dist/source/migrations.js.map +1 -1
  116. package/dist/source/subjectAuthorization.d.ts +16 -0
  117. package/dist/source/subjectAuthorization.d.ts.map +1 -0
  118. package/dist/source/subjectAuthorization.js +126 -0
  119. package/dist/source/subjectAuthorization.js.map +1 -0
  120. package/dist/source/types.d.ts +52 -2
  121. package/dist/source/types.d.ts.map +1 -1
  122. package/dist/source/types.js +1 -0
  123. package/dist/source/types.js.map +1 -1
  124. package/dist/syncLog/contract.d.ts +45 -3
  125. package/dist/syncLog/contract.d.ts.map +1 -1
  126. package/dist/syncLog/contract.js +46 -4
  127. package/dist/syncLog/contract.js.map +1 -1
  128. package/dist/testing/fixtures/httpResponses.d.ts +6 -0
  129. package/dist/testing/fixtures/httpResponses.d.ts.map +1 -1
  130. package/dist/testing/fixtures/httpResponses.js +1 -0
  131. package/dist/testing/fixtures/httpResponses.js.map +1 -1
  132. package/dist/transport/httpClient.d.ts +8 -1
  133. package/dist/transport/httpClient.d.ts.map +1 -1
  134. package/dist/transport/httpClient.js +51 -20
  135. package/dist/transport/httpClient.js.map +1 -1
  136. package/dist/transport/httpCommitRequest.d.ts +45 -0
  137. package/dist/transport/httpCommitRequest.d.ts.map +1 -0
  138. package/dist/transport/httpCommitRequest.js +67 -0
  139. package/dist/transport/httpCommitRequest.js.map +1 -0
  140. package/dist/transport/httpTransport.d.ts.map +1 -1
  141. package/dist/transport/httpTransport.js +69 -106
  142. package/dist/transport/httpTransport.js.map +1 -1
  143. package/dist/transport/httpTransportHelpers.d.ts +10 -0
  144. package/dist/transport/httpTransportHelpers.d.ts.map +1 -0
  145. package/dist/transport/httpTransportHelpers.js +46 -0
  146. package/dist/transport/httpTransportHelpers.js.map +1 -0
  147. package/dist/wire/apiLifecycle.d.ts +63 -0
  148. package/dist/wire/apiLifecycle.d.ts.map +1 -0
  149. package/dist/wire/apiLifecycle.js +89 -0
  150. package/dist/wire/apiLifecycle.js.map +1 -0
  151. package/dist/wire/auth.d.ts.map +1 -1
  152. package/dist/wire/auth.js +6 -3
  153. package/dist/wire/auth.js.map +1 -1
  154. package/dist/wire/commit.d.ts +74 -9
  155. package/dist/wire/commit.d.ts.map +1 -1
  156. package/dist/wire/commit.js +18 -5
  157. package/dist/wire/commit.js.map +1 -1
  158. package/dist/wire/index.d.ts +5 -2
  159. package/dist/wire/index.d.ts.map +1 -1
  160. package/dist/wire/index.js +12 -1
  161. package/dist/wire/index.js.map +1 -1
  162. package/dist/wire/modelMutations.js +3 -2
  163. package/dist/wire/modelMutations.js.map +1 -1
  164. package/dist/wire/rateLimit.d.ts +82 -0
  165. package/dist/wire/rateLimit.d.ts.map +1 -0
  166. package/dist/wire/rateLimit.js +142 -0
  167. package/dist/wire/rateLimit.js.map +1 -0
  168. package/package.json +1 -1
  169. package/src/auth/hostedEndpoints.ts +23 -5
  170. package/src/auth/index.ts +2 -0
  171. package/src/coordination/index.ts +0 -2
  172. package/src/coordination/schema.ts +4 -7
  173. package/src/errorCodes.ts +6 -0
  174. package/src/errors.ts +4 -1
  175. package/src/readSetContext.ts +8 -2
  176. package/src/resources/httpResources.ts +116 -25
  177. package/src/resources/modelCreate.ts +73 -0
  178. package/src/resources/modelOperations.ts +29 -2
  179. package/src/resources/writeOptionsSchema.ts +30 -2
  180. package/src/schema/audit.ts +121 -0
  181. package/src/schema/ddl.ts +71 -1
  182. package/src/schema/index.ts +16 -0
  183. package/src/schema/model.ts +17 -0
  184. package/src/schema/openapi.ts +123 -2
  185. package/src/schema/roles.ts +53 -0
  186. package/src/schema/schema.ts +68 -3
  187. package/src/schema/serialize.ts +8 -1
  188. package/src/schema/subject.ts +43 -0
  189. package/src/server/adapter.ts +2 -0
  190. package/src/server/readConfig.ts +4 -0
  191. package/src/source/adapters/drizzle.ts +50 -6
  192. package/src/source/adapters/kysely.ts +47 -4
  193. package/src/source/adapters/kyselyMutationCore.ts +21 -9
  194. package/src/source/adapters/memory.ts +1 -0
  195. package/src/source/adapters/prisma.ts +70 -7
  196. package/src/source/contract.ts +11 -0
  197. package/src/source/factory.ts +141 -5
  198. package/src/source/index.ts +6 -0
  199. package/src/source/migrations.ts +21 -0
  200. package/src/source/subjectAuthorization.ts +182 -0
  201. package/src/source/types.ts +56 -2
  202. package/src/syncLog/contract.ts +47 -5
  203. package/src/testing/fixtures/httpResponses.ts +7 -0
  204. package/src/transport/httpClient.ts +85 -23
  205. package/src/transport/httpCommitRequest.ts +104 -0
  206. package/src/transport/httpTransport.ts +92 -142
  207. package/src/transport/httpTransportHelpers.ts +63 -0
  208. package/src/wire/apiLifecycle.ts +94 -0
  209. package/src/wire/auth.ts +6 -3
  210. package/src/wire/commit.ts +20 -5
  211. package/src/wire/index.ts +31 -0
  212. package/src/wire/modelMutations.ts +2 -2
  213. package/src/wire/rateLimit.ts +155 -0
@@ -0,0 +1,155 @@
1
+ /**
2
+ * How a rate limit is stated on the wire, so a caller can pace itself instead
3
+ * of discovering the ceiling by hitting it.
4
+ *
5
+ * Two fields, from "RateLimit header fields for HTTP"
6
+ * (draft-ietf-httpapi-ratelimit-headers), and they answer different questions:
7
+ *
8
+ * - `RateLimit-Policy` is the STANDING allowance — the quota and the window
9
+ * the server allocates. It does not move between responses, so it can be
10
+ * stated on any response, including one that carried no credential. This is
11
+ * the field an agent reads once and paces against.
12
+ * - `RateLimit` is the LIVE position within that allowance — what is left and
13
+ * when it refills. It is per caller, so it appears only once a request has
14
+ * been attributed to a credential.
15
+ *
16
+ * Both are Structured Field Lists whose members are Strings naming the policy,
17
+ * carrying `q`/`w` (quota, window seconds) and `r`/`t` (remaining, seconds to
18
+ * reset) as parameters. Serializing them by hand is the reason this module
19
+ * exists: the field names and the parameter spellings were previously written
20
+ * out at each producer, so a change had to be made in every one of them and
21
+ * nothing failed when it was not.
22
+ *
23
+ * `Retry-After` is not defined here — it is plain HTTP (RFC 9110 § 10.2.3) and
24
+ * the value is a count of seconds. Its NAME lives here so a producer emitting
25
+ * the 429 triple names all three fields from one place.
26
+ */
27
+
28
+ import { z } from 'zod';
29
+
30
+ /** The standing-allowance field. Safe on any response; independent of caller. */
31
+ export const RATE_LIMIT_POLICY_HEADER = 'RateLimit-Policy';
32
+
33
+ /** The live-position field. Per caller, so only on an attributed request. */
34
+ export const RATE_LIMIT_HEADER = 'RateLimit';
35
+
36
+ /** Seconds to wait before retrying, on a 429 or a 503 (RFC 9110 § 10.2.3). */
37
+ export const RETRY_AFTER_HEADER = 'Retry-After';
38
+
39
+ /**
40
+ * A policy name as it appears inside the fields. Constrained to characters that
41
+ * need no Structured-Fields escaping, which is what lets the serializers below
42
+ * be a template rather than a String encoder — and what makes an unquotable
43
+ * name a thrown error at the definition site rather than a malformed header on
44
+ * the wire.
45
+ */
46
+ const POLICY_NAME = /^[A-Za-z0-9_-]{1,64}$/;
47
+
48
+ /**
49
+ * One allocation of server capacity: how much, over how long.
50
+ *
51
+ * `quotaUnit` is omitted for the default unit, requests. A limiter that meters
52
+ * something else — bytes, operations — names it, and a client that does not
53
+ * recognize the unit knows to leave the number alone rather than read it as a
54
+ * request count.
55
+ */
56
+ export const quotaPolicySchema = z.object({
57
+ /** Identifier the matching {@link ServiceLimit} refers back to. */
58
+ name: z.string(),
59
+ /** `q` — the allocation, in `quotaUnit`. */
60
+ quota: z.number(),
61
+ /** `w` — the window the allocation applies over, in whole seconds. */
62
+ windowSeconds: z.number().optional(),
63
+ /** `qu` — the unit `quota` counts. Omit for the default, requests. */
64
+ quotaUnit: z.string().optional(),
65
+ });
66
+ export type QuotaPolicy = Readonly<z.infer<typeof quotaPolicySchema>>;
67
+
68
+ /** Where this caller currently stands against one {@link QuotaPolicy}. */
69
+ export const serviceLimitSchema = z.object({
70
+ /** The {@link QuotaPolicy} name this position is measured against. */
71
+ policy: z.string(),
72
+ /** `r` — units left in the current window. */
73
+ remaining: z.number(),
74
+ /** `t` — seconds until the allocation refills. */
75
+ resetSeconds: z.number().optional(),
76
+ });
77
+ export type ServiceLimit = Readonly<z.infer<typeof serviceLimitSchema>>;
78
+
79
+ function assertName(name: string, field: string): void {
80
+ if (!POLICY_NAME.test(name)) {
81
+ throw new Error(
82
+ `${field} policy name ${JSON.stringify(name)} must match ${String(POLICY_NAME)}`,
83
+ );
84
+ }
85
+ }
86
+
87
+ /**
88
+ * A non-negative whole number, which is what both fields' numeric parameters
89
+ * are. A fractional or negative value is a producer bug; clamping it here keeps
90
+ * one malformed reading from making the whole field unparseable for the client.
91
+ */
92
+ function integer(value: number): number {
93
+ if (!Number.isFinite(value)) return 0;
94
+ return Math.max(0, Math.floor(value));
95
+ }
96
+
97
+ /** Serialize {@link QuotaPolicy} values into a `RateLimit-Policy` field value. */
98
+ export function rateLimitPolicyField(policies: readonly QuotaPolicy[]): string {
99
+ if (policies.length === 0) {
100
+ throw new Error(`${RATE_LIMIT_POLICY_HEADER} must name at least one policy`);
101
+ }
102
+ return policies
103
+ .map((policy) => {
104
+ assertName(policy.name, RATE_LIMIT_POLICY_HEADER);
105
+ let item = `"${policy.name}";q=${integer(policy.quota)}`;
106
+ if (policy.quotaUnit !== undefined) item += `;qu="${policy.quotaUnit}"`;
107
+ if (policy.windowSeconds !== undefined) item += `;w=${integer(policy.windowSeconds)}`;
108
+ return item;
109
+ })
110
+ .join(', ');
111
+ }
112
+
113
+ /** Serialize {@link ServiceLimit} values into a `RateLimit` field value. */
114
+ export function rateLimitField(limits: readonly ServiceLimit[]): string {
115
+ if (limits.length === 0) {
116
+ throw new Error(`${RATE_LIMIT_HEADER} must name at least one policy`);
117
+ }
118
+ return limits
119
+ .map((limit) => {
120
+ assertName(limit.policy, RATE_LIMIT_HEADER);
121
+ let item = `"${limit.policy}";r=${integer(limit.remaining)}`;
122
+ if (limit.resetSeconds !== undefined) item += `;t=${integer(limit.resetSeconds)}`;
123
+ return item;
124
+ })
125
+ .join(', ');
126
+ }
127
+
128
+ /** What a producer knows about the limit at the moment it writes the response. */
129
+ export const rateLimitSignalSchema = z.object({
130
+ /** The standing allowance. Always known; stated on every response. */
131
+ policies: z.array(quotaPolicySchema).readonly(),
132
+ /** This caller's position, once the request has been attributed to one. */
133
+ limits: z.array(serviceLimitSchema).readonly().optional(),
134
+ /** Present only on a rejection, and only when a wait is what resolves it. */
135
+ retryAfterSeconds: z.number().optional(),
136
+ });
137
+ export type RateLimitSignal = Readonly<z.infer<typeof rateLimitSignalSchema>>;
138
+
139
+ /**
140
+ * The header map for one response. This is the single call every producer
141
+ * makes, so the three fields cannot be emitted in one place and forgotten in
142
+ * the next.
143
+ */
144
+ export function rateLimitHeaders(signal: RateLimitSignal): Record<string, string> {
145
+ const headers: Record<string, string> = {
146
+ [RATE_LIMIT_POLICY_HEADER]: rateLimitPolicyField(signal.policies),
147
+ };
148
+ if (signal.limits && signal.limits.length > 0) {
149
+ headers[RATE_LIMIT_HEADER] = rateLimitField(signal.limits);
150
+ }
151
+ if (signal.retryAfterSeconds !== undefined) {
152
+ headers[RETRY_AFTER_HEADER] = String(Math.max(1, integer(signal.retryAfterSeconds)));
153
+ }
154
+ return headers;
155
+ }