ocel 0.0.1-alpha.0 → 0.0.1

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 (271) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +2 -0
  3. package/README.md +98 -0
  4. package/dist/binding/binding.d.ts +22 -0
  5. package/dist/binding/binding.js +60 -0
  6. package/dist/binding/unprovisioned.d.ts +17 -0
  7. package/dist/binding/unprovisioned.js +25 -0
  8. package/dist/bucket/bucket-client.d.ts +4 -0
  9. package/dist/bucket/bucket-client.js +5 -0
  10. package/dist/bucket/bucket-context.d.ts +8 -0
  11. package/dist/bucket/bucket-context.js +10 -0
  12. package/dist/bucket/bucket.d.ts +60 -0
  13. package/dist/bucket/bucket.js +91 -0
  14. package/dist/bucket/client.d.ts +49 -0
  15. package/dist/bucket/client.js +95 -0
  16. package/dist/bucket/errors.d.ts +12 -0
  17. package/dist/bucket/errors.js +20 -0
  18. package/dist/bucket/express.d.ts +10 -0
  19. package/dist/bucket/express.js +24 -0
  20. package/dist/bucket/hono.d.ts +18 -0
  21. package/dist/bucket/hono.js +13 -0
  22. package/dist/bucket/index.d.ts +8 -0
  23. package/dist/bucket/index.js +6 -0
  24. package/dist/bucket/keys.d.ts +5 -0
  25. package/dist/bucket/keys.js +24 -0
  26. package/dist/bucket/metadata.d.ts +6 -0
  27. package/dist/bucket/metadata.js +6 -0
  28. package/dist/bucket/next.d.ts +15 -0
  29. package/dist/bucket/next.js +11 -0
  30. package/dist/bucket/objects.d.ts +130 -0
  31. package/dist/bucket/objects.js +350 -0
  32. package/dist/bucket/route.d.ts +13 -0
  33. package/dist/bucket/route.js +247 -0
  34. package/dist/bucket/server-only.js +5 -0
  35. package/dist/bucket/types.d.ts +63 -0
  36. package/dist/bucket/uploader.d.ts +3 -0
  37. package/dist/bucket/uploader.js +6 -0
  38. package/dist/build-env.d.ts +17 -0
  39. package/dist/build-env.js +41 -0
  40. package/dist/config.d.ts +30 -0
  41. package/dist/config.js +9 -0
  42. package/dist/declaration/callsite.d.ts +15 -0
  43. package/dist/declaration/callsite.js +43 -0
  44. package/dist/declaration/component.d.ts +4 -0
  45. package/dist/declaration/component.js +1 -0
  46. package/dist/declaration/defer.d.ts +5 -0
  47. package/dist/declaration/defer.js +9 -0
  48. package/dist/delivery/duration.d.ts +13 -0
  49. package/dist/delivery/duration.js +36 -0
  50. package/dist/delivery/lane.d.ts +4 -0
  51. package/dist/delivery/lane.js +15 -0
  52. package/dist/delivery/payload.d.ts +6 -0
  53. package/dist/delivery/payload.js +14 -0
  54. package/dist/delivery/retry.d.ts +16 -0
  55. package/dist/delivery/retry.js +10 -0
  56. package/dist/delivery/schema.d.ts +10 -0
  57. package/dist/delivery/schema.js +20 -0
  58. package/dist/dns.d.ts +11 -0
  59. package/dist/dns.js +4 -0
  60. package/dist/edge.d.ts +4 -0
  61. package/dist/edge.js +4 -0
  62. package/dist/env/access.d.ts +22 -0
  63. package/dist/env/access.js +49 -0
  64. package/dist/env/client.d.ts +5 -0
  65. package/dist/env/client.js +10 -0
  66. package/dist/env/declare.d.ts +2 -0
  67. package/dist/env/declare.js +83 -0
  68. package/dist/env/definition.d.ts +46 -0
  69. package/dist/env/definition.js +164 -0
  70. package/dist/env/deployment.d.ts +23 -0
  71. package/dist/env/deployment.js +13 -0
  72. package/dist/env/edge.d.ts +10 -0
  73. package/dist/env/edge.js +30 -0
  74. package/dist/env/errors.d.ts +9 -0
  75. package/dist/env/errors.js +9 -0
  76. package/dist/env/file.d.ts +1 -0
  77. package/dist/env/file.js +27 -0
  78. package/dist/env/index.d.ts +10 -0
  79. package/dist/env/index.js +63 -0
  80. package/dist/env/live.d.ts +3 -0
  81. package/dist/env/live.js +12 -0
  82. package/dist/env/schema.d.ts +27 -0
  83. package/dist/env/schema.js +43 -0
  84. package/dist/env/scope.d.ts +7 -0
  85. package/dist/env/scope.js +45 -0
  86. package/dist/env/standard.d.ts +10 -0
  87. package/dist/env/standard.js +21 -0
  88. package/dist/env/value.d.ts +5 -0
  89. package/dist/env/value.js +26 -0
  90. package/dist/env-source.d.ts +17 -0
  91. package/dist/env-source.js +16 -0
  92. package/dist/gen/proto/app/bucket/v1/bucket_pb.d.ts +911 -0
  93. package/dist/gen/proto/app/bucket/v1/bucket_pb.js +253 -0
  94. package/dist/gen/proto/app/realtime/v1/realtime_pb.d.ts +50 -0
  95. package/dist/gen/proto/app/realtime/v1/realtime_pb.js +23 -0
  96. package/dist/gen/proto/app/resources/v1/resources_pb.d.ts +554 -0
  97. package/dist/gen/proto/app/resources/v1/resources_pb.js +214 -0
  98. package/dist/gen/proto/app/resources/v1/variables_pb.d.ts +231 -0
  99. package/dist/gen/proto/app/resources/v1/variables_pb.js +101 -0
  100. package/dist/gen/proto/app/task/v1/task_pb.d.ts +498 -0
  101. package/dist/gen/proto/app/task/v1/task_pb.js +151 -0
  102. package/dist/gen/proto/app/topic/v1/topic_pb.d.ts +456 -0
  103. package/dist/gen/proto/app/topic/v1/topic_pb.js +125 -0
  104. package/dist/gen/proto/buf/validate/validate_pb.d.ts +4833 -0
  105. package/dist/gen/proto/buf/validate/validate_pb.js +356 -0
  106. package/dist/gen/proto/common/bindings/v1/bindings_pb.d.ts +378 -0
  107. package/dist/gen/proto/common/bindings/v1/bindings_pb.js +140 -0
  108. package/dist/generated/config.d.ts +428 -0
  109. package/dist/generated/config.js +2 -0
  110. package/dist/kv/entries.d.ts +193 -0
  111. package/dist/kv/entries.js +325 -0
  112. package/dist/kv/errors.d.ts +12 -0
  113. package/dist/kv/errors.js +14 -0
  114. package/dist/kv/index.d.ts +6 -0
  115. package/dist/kv/index.js +3 -0
  116. package/dist/kv/ioredis.d.ts +2 -0
  117. package/dist/kv/ioredis.js +20 -0
  118. package/dist/kv/kv.d.ts +84 -0
  119. package/dist/kv/kv.js +177 -0
  120. package/dist/kv/pattern.d.ts +27 -0
  121. package/dist/kv/pattern.js +73 -0
  122. package/dist/kv/ttl.d.ts +22 -0
  123. package/dist/kv/ttl.js +21 -0
  124. package/dist/postgres/index.d.ts +21 -2
  125. package/dist/postgres/index.js +73 -2
  126. package/dist/postgres/pg.d.ts +5 -4
  127. package/dist/postgres/pg.js +16 -12
  128. package/dist/providers/aws/dns.d.ts +11 -0
  129. package/dist/providers/aws/dns.js +4 -0
  130. package/dist/providers/aws/edge.d.ts +6 -0
  131. package/dist/providers/aws/edge.js +8 -0
  132. package/dist/providers/aws/index.d.ts +4 -0
  133. package/dist/providers/aws/index.js +4 -0
  134. package/dist/providers/gcp/edge.d.ts +14 -0
  135. package/dist/providers/gcp/edge.js +14 -0
  136. package/dist/providers/gcp/index.d.ts +9 -0
  137. package/dist/providers/gcp/index.js +9 -0
  138. package/dist/providers/vps/index.d.ts +4 -0
  139. package/dist/providers/vps/index.js +4 -0
  140. package/dist/realtime/client-error.d.ts +30 -0
  141. package/dist/realtime/client-error.js +17 -0
  142. package/dist/realtime/client-event-socket.d.ts +8 -0
  143. package/dist/realtime/client-event-socket.js +169 -0
  144. package/dist/realtime/client-transport.d.ts +29 -0
  145. package/dist/realtime/client-transport.js +13 -0
  146. package/dist/realtime/client.d.ts +150 -0
  147. package/dist/realtime/client.js +345 -0
  148. package/dist/realtime/express.d.ts +18 -0
  149. package/dist/realtime/express.js +83 -0
  150. package/dist/realtime/handler.d.ts +56 -0
  151. package/dist/realtime/handler.js +287 -0
  152. package/dist/realtime/hono.d.ts +19 -0
  153. package/dist/realtime/hono.js +24 -0
  154. package/dist/realtime/index.d.ts +2 -0
  155. package/dist/realtime/index.js +2 -0
  156. package/dist/realtime/next.d.ts +26 -0
  157. package/dist/realtime/next.js +16 -0
  158. package/dist/realtime/realtime.d.ts +181 -0
  159. package/dist/realtime/realtime.js +205 -0
  160. package/dist/realtime/token.d.ts +20 -0
  161. package/dist/realtime/token.js +45 -0
  162. package/dist/realtime/transport.d.ts +11 -0
  163. package/dist/realtime/transport.js +15 -0
  164. package/dist/realtime/wire.d.ts +30 -0
  165. package/dist/realtime/wire.js +104 -0
  166. package/dist/runtime/dev-server.d.ts +8 -0
  167. package/dist/runtime/dev-server.js +8 -0
  168. package/dist/runtime/rpc.d.ts +23 -0
  169. package/dist/runtime/rpc.js +24 -0
  170. package/dist/runtime/transport.d.ts +11 -0
  171. package/dist/runtime/transport.js +35 -0
  172. package/dist/task/errors.d.ts +7 -0
  173. package/dist/task/errors.js +7 -0
  174. package/dist/task/hooks.d.ts +57 -0
  175. package/dist/task/hooks.js +1 -0
  176. package/dist/task/index.d.ts +9 -0
  177. package/dist/task/index.js +4 -0
  178. package/dist/task/runs.d.ts +74 -0
  179. package/dist/task/runs.js +82 -0
  180. package/dist/task/task.d.ts +117 -0
  181. package/dist/task/task.js +109 -0
  182. package/dist/topic/dead-letters.d.ts +53 -0
  183. package/dist/topic/dead-letters.js +62 -0
  184. package/dist/topic/index.d.ts +8 -0
  185. package/dist/topic/index.js +4 -0
  186. package/dist/topic/topic.d.ts +85 -0
  187. package/dist/topic/topic.js +117 -0
  188. package/dist/version.d.ts +2 -0
  189. package/dist/version.js +2 -0
  190. package/dist/worker/context.d.ts +36 -0
  191. package/dist/worker/context.js +1 -0
  192. package/dist/worker/deliver.d.ts +13 -0
  193. package/dist/worker/deliver.js +258 -0
  194. package/dist/worker/index.d.ts +4 -0
  195. package/dist/worker/index.js +2 -0
  196. package/dist/worker/registry.d.ts +28 -0
  197. package/dist/worker/registry.js +22 -0
  198. package/dist/worker/semaphore.d.ts +7 -0
  199. package/dist/worker/semaphore.js +36 -0
  200. package/dist/worker/worker.d.ts +21 -0
  201. package/dist/worker/worker.js +32 -0
  202. package/package.json +158 -57
  203. package/bin/run.js +0 -39
  204. package/dist/blob/bucket.d.ts +0 -55
  205. package/dist/blob/bucket.js +0 -65
  206. package/dist/blob/index.d.ts +0 -8
  207. package/dist/blob/index.js +0 -13
  208. package/dist/blob/integrations/client.d.ts +0 -25
  209. package/dist/blob/integrations/client.js +0 -71
  210. package/dist/blob/integrations/hono.d.ts +0 -31
  211. package/dist/blob/integrations/hono.js +0 -11
  212. package/dist/blob/mime-types.d.ts +0 -1
  213. package/dist/blob/parse.d.ts +0 -16
  214. package/dist/blob/parse.js +0 -69
  215. package/dist/blob/s3-listener.d.ts +0 -7
  216. package/dist/blob/s3-listener.js +0 -35
  217. package/dist/blob/types.d.ts +0 -128
  218. package/dist/blob/types.js +0 -1
  219. package/dist/blob/upload-error.d.ts +0 -35
  220. package/dist/blob/upload-error.js +0 -54
  221. package/dist/blob/uploader.d.ts +0 -67
  222. package/dist/blob/uploader.js +0 -323
  223. package/dist/internal/db/index.d.ts +0 -68
  224. package/dist/internal/db/index.js +0 -73
  225. package/dist/lambda/index.d.ts +0 -2
  226. package/dist/lambda/index.js +0 -4
  227. package/dist/lambda/integrations/express.d.ts +0 -3
  228. package/dist/lambda/integrations/express.js +0 -13
  229. package/dist/lambda/integrations/hono.d.ts +0 -3
  230. package/dist/lambda/integrations/hono.js +0 -13
  231. package/dist/lambda/lambda.d.ts +0 -43
  232. package/dist/lambda/lambda.js +0 -30
  233. package/dist/utils/component.d.ts +0 -3
  234. package/dist/utils/constants.d.ts +0 -2
  235. package/dist/utils/constants.js +0 -2
  236. package/dist/utils/nanoid.d.ts +0 -1
  237. package/dist/utils/nanoid.js +0 -6
  238. package/dist/utils/rpc.d.ts +0 -11
  239. package/dist/utils/rpc.js +0 -17
  240. package/dist/utils/stack.d.ts +0 -4
  241. package/dist/utils/stack.js +0 -23
  242. package/dist/workflow/index.d.ts +0 -3
  243. package/dist/workflow/index.js +0 -4
  244. package/dist/workflow/workflow.d.ts +0 -34
  245. package/dist/workflow/workflow.js +0 -146
  246. package/src/blob/bucket.ts +0 -92
  247. package/src/blob/index.ts +0 -34
  248. package/src/blob/integrations/client.ts +0 -127
  249. package/src/blob/integrations/hono.ts +0 -16
  250. package/src/blob/mime-types.ts +0 -68
  251. package/src/blob/parse.ts +0 -93
  252. package/src/blob/s3-listener.ts +0 -48
  253. package/src/blob/types.ts +0 -142
  254. package/src/blob/upload-error.ts +0 -67
  255. package/src/blob/uploader.ts +0 -426
  256. package/src/internal/db/index.ts +0 -78
  257. package/src/lambda/index.ts +0 -8
  258. package/src/lambda/integrations/express.ts +0 -25
  259. package/src/lambda/integrations/hono.ts +0 -25
  260. package/src/lambda/lambda.ts +0 -94
  261. package/src/postgres/index.ts +0 -5
  262. package/src/postgres/pg.ts +0 -33
  263. package/src/utils/component.ts +0 -3
  264. package/src/utils/constants.ts +0 -2
  265. package/src/utils/nanoid.ts +0 -9
  266. package/src/utils/rpc.ts +0 -28
  267. package/src/utils/stack.ts +0 -26
  268. package/src/workflow/index.ts +0 -9
  269. package/src/workflow/workflow.ts +0 -235
  270. /package/dist/{blob/mime-types.js → bucket/server-only.d.ts} +0 -0
  271. /package/dist/{utils/component.js → bucket/types.js} +0 -0
@@ -0,0 +1,73 @@
1
+ const literalSegment = /^[A-Za-z0-9._-]+$/;
2
+ const parameterSegment = /^:[A-Za-z_][A-Za-z0-9_]*$/;
3
+ export function parsePattern(written) {
4
+ if (written === "") {
5
+ throw new Error("the pattern is empty: write one or more segments joined by /, each a literal or a :parameter");
6
+ }
7
+ if (/[{}]/.test(written)) {
8
+ throw new Error(`pattern "${written}" holds { or }, which a store reserves as the hash tag syntax`);
9
+ }
10
+ const segments = [];
11
+ const named = new Set();
12
+ for (const part of written.split("/")) {
13
+ if (part === "") {
14
+ throw new Error(`pattern "${written}" has an empty segment: it neither starts nor ends with /, and no two / are adjacent`);
15
+ }
16
+ if (part.startsWith(":")) {
17
+ if (!parameterSegment.test(part)) {
18
+ throw new Error(`pattern "${written}" has segment "${part}", which is no parameter: a parameter is : and a name of letters, digits and _ that starts with a letter or _`);
19
+ }
20
+ const name = part.slice(1);
21
+ if (named.has(name)) {
22
+ throw new Error(`pattern "${written}" names parameter "${name}" twice, so a key could not say which value is which`);
23
+ }
24
+ named.add(name);
25
+ segments.push({ parameter: name });
26
+ continue;
27
+ }
28
+ if (!literalSegment.test(part)) {
29
+ throw new Error(`pattern "${written}" has segment "${part}", which is no literal: a literal is letters, digits, ., _ and -`);
30
+ }
31
+ segments.push({ literal: part });
32
+ }
33
+ return { written, segments };
34
+ }
35
+ export function patternsOverlap(a, b) {
36
+ if (a.segments.length !== b.segments.length)
37
+ return false;
38
+ return a.segments.every((mine, i) => {
39
+ const theirs = b.segments[i];
40
+ return !("literal" in mine && "literal" in theirs) || mine.literal === theirs.literal;
41
+ });
42
+ }
43
+ export function hasParameters(pattern) {
44
+ return pattern.segments.some((segment) => "parameter" in segment);
45
+ }
46
+ const unreserved = /[A-Za-z0-9\-._~]/;
47
+ export function encodeParameter(value) {
48
+ let encoded = "";
49
+ for (const byte of new TextEncoder().encode(value)) {
50
+ const char = String.fromCharCode(byte);
51
+ encoded +=
52
+ byte < 0x80 && unreserved.test(char)
53
+ ? char
54
+ : `%${byte.toString(16).toUpperCase().padStart(2, "0")}`;
55
+ }
56
+ return encoded;
57
+ }
58
+ export function buildKey(pattern, key) {
59
+ return pattern.segments
60
+ .map((segment) => {
61
+ if ("literal" in segment)
62
+ return segment.literal;
63
+ const value = key?.[segment.parameter];
64
+ if (typeof value === "number" && !Number.isSafeInteger(value)) {
65
+ throw new TypeError(`the key of pattern "${pattern.written}" gives :${segment.parameter} the number ${value}, which is no safe integer: give a string or an integer within ±(2^53 - 1)`);
66
+ }
67
+ if (typeof value !== "string" && typeof value !== "number") {
68
+ throw new TypeError(`the key of pattern "${pattern.written}" has no value for :${segment.parameter}: give a string or an integer`);
69
+ }
70
+ return encodeParameter(String(value));
71
+ })
72
+ .join("/");
73
+ }
@@ -0,0 +1,22 @@
1
+ /** A length of time written with its unit, such as `"500ms"`, `"10s"`, `"5m"`, `"2h"` or `"30d"`. */
2
+ export type KVDuration = `${number}ms` | `${number}s` | `${number}m` | `${number}h` | `${number}d`;
3
+ /**
4
+ * How long a write leaves its key to live: a duration replaces the TTL, `"keep"` keeps the
5
+ * one the key has, and `null` clears it so the key lives until it is deleted or evicted.
6
+ */
7
+ export type WriteTTL = KVDuration | "keep" | null;
8
+ /** How one write treats its key's TTL. */
9
+ export interface WriteOptions {
10
+ /** The TTL this write sets instead of the entry's own; without it, the entry's own. */
11
+ ttl?: WriteTTL;
12
+ }
13
+ export type TTL = {
14
+ kind: "expire";
15
+ milliseconds: number;
16
+ } | {
17
+ kind: "keep";
18
+ } | {
19
+ kind: "clear";
20
+ };
21
+ export declare function parseTTL(duration: unknown): number;
22
+ export declare function resolveTTL(declared: number | undefined, written: WriteTTL | undefined): TTL;
package/dist/kv/ttl.js ADDED
@@ -0,0 +1,21 @@
1
+ import { parseDurationMilliseconds } from "../delivery/duration.js";
2
+ export function parseTTL(duration) {
3
+ if (typeof duration !== "string") {
4
+ throw new Error(`a ttl is a duration written with its unit, such as "10s", "5m" or "30d", not ${String(duration)}`);
5
+ }
6
+ const milliseconds = Math.round(parseDurationMilliseconds(duration));
7
+ if (milliseconds < 1) {
8
+ throw new Error(`a ttl is at least 1ms, and "${duration}" is shorter`);
9
+ }
10
+ return milliseconds;
11
+ }
12
+ export function resolveTTL(declared, written) {
13
+ if (written === undefined) {
14
+ return declared === undefined ? { kind: "clear" } : { kind: "expire", milliseconds: declared };
15
+ }
16
+ if (written === null)
17
+ return { kind: "clear" };
18
+ if (written === "keep")
19
+ return { kind: "keep" };
20
+ return { kind: "expire", milliseconds: parseTTL(written) };
21
+ }
@@ -1,2 +1,21 @@
1
- import { Postgres, type PostgresConfig } from "./pg";
2
- export declare function postgres(id: string, config: PostgresConfig): Postgres;
1
+ import { Pool } from "pg";
2
+ import { type PostgresConfig } from "./pg.js";
3
+ export { UnprovisionedResourceError } from "../binding/unprovisioned.js";
4
+ type PgReturn = Pool & {
5
+ connectionString: string;
6
+ };
7
+ /**
8
+ * Declares a postgres database named `id` and returns a `pg` pool connected to it.
9
+ *
10
+ * At deploy the database is provisioned in your account, or bound to the record
11
+ * `bindings` names; the pool connects through the record's url when it has
12
+ * one, reading its `sslmode` as libpq does, and otherwise through its host, port,
13
+ * database, username and password, encrypted as its tls mode asks.
14
+ * `connectionString` is the same connection as a URL, for tools that take one.
15
+ */
16
+ export declare function postgres(id: string, config?: PostgresConfig): PgReturn;
17
+ /**
18
+ * Renders a postgres connection URL from its parts, percent-encoding the
19
+ * username and password so any character in either survives.
20
+ */
21
+ export declare function connectionStringFor(host: string, port: number, database: string, username: string, password: string): string;
@@ -1,4 +1,75 @@
1
- import { Postgres } from "./pg";
1
+ import { Pool } from "pg";
2
+ import { unprovisionedPhase, unprovisionedProxy } from "../binding/unprovisioned.js";
3
+ import { PostgresTlsMode, } from "../gen/proto/common/bindings/v1/bindings_pb.js";
4
+ import { Postgres } from "./pg.js";
5
+ export { UnprovisionedResourceError } from "../binding/unprovisioned.js";
6
+ /**
7
+ * Declares a postgres database named `id` and returns a `pg` pool connected to it.
8
+ *
9
+ * At deploy the database is provisioned in your account, or bound to the record
10
+ * `bindings` names; the pool connects through the record's url when it has
11
+ * one, reading its `sslmode` as libpq does, and otherwise through its host, port,
12
+ * database, username and password, encrypted as its tls mode asks.
13
+ * `connectionString` is the same connection as a URL, for tools that take one.
14
+ */
2
15
  export function postgres(id, config) {
3
- return new Postgres(id, config);
16
+ const pg = new Postgres(id, config);
17
+ if (unprovisionedPhase()) {
18
+ return unprovisionedProxy(`postgres("${id}")`);
19
+ }
20
+ const properties = pg.__config();
21
+ const client = new Pool(poolConfig(properties));
22
+ return Object.assign(client, { connectionString: connectionStringOf(properties) });
23
+ }
24
+ function poolConfig(properties) {
25
+ if (properties.url) {
26
+ return { connectionString: withLibpqSslmodes(properties.url) };
27
+ }
28
+ const { host, port, database, username, password } = properties;
29
+ const config = { host, port, database, user: username, password };
30
+ switch (properties.tlsMode) {
31
+ case PostgresTlsMode.REQUIRE:
32
+ config.ssl = { rejectUnauthorized: false };
33
+ break;
34
+ case PostgresTlsMode.VERIFY_FULL:
35
+ config.ssl = properties.tlsCa
36
+ ? { rejectUnauthorized: true, ca: properties.tlsCa }
37
+ : { rejectUnauthorized: true };
38
+ break;
39
+ }
40
+ return config;
41
+ }
42
+ function withLibpqSslmodes(url) {
43
+ if (/[?&]uselibpqcompat=/.test(url)) {
44
+ return url;
45
+ }
46
+ return `${url}${url.includes("?") ? "&" : "?"}uselibpqcompat=true`;
47
+ }
48
+ const sslmodes = {
49
+ [PostgresTlsMode.UNSPECIFIED]: undefined,
50
+ [PostgresTlsMode.REQUIRE]: "require",
51
+ [PostgresTlsMode.VERIFY_FULL]: "verify-full",
52
+ };
53
+ function connectionStringOf(properties) {
54
+ if (properties.url) {
55
+ return properties.url;
56
+ }
57
+ const { host, port, database, username, password } = properties;
58
+ const url = new URL(connectionStringFor(host, port, database, username, password));
59
+ const sslmode = sslmodes[properties.tlsMode];
60
+ if (sslmode) {
61
+ url.searchParams.set("sslmode", sslmode);
62
+ }
63
+ return url.toString();
64
+ }
65
+ /**
66
+ * Renders a postgres connection URL from its parts, percent-encoding the
67
+ * username and password so any character in either survives.
68
+ */
69
+ export function connectionStringFor(host, port, database, username, password) {
70
+ const url = new URL(`postgres://${host}:${port}/`);
71
+ url.pathname = `/${database}`;
72
+ url.username = username;
73
+ url.password = password;
74
+ return url.toString();
4
75
  }
@@ -1,11 +1,12 @@
1
- import type { Component } from "../utils/component";
1
+ import type { Component } from "../declaration/component.js";
2
+ import type { PostgresProperties } from "../gen/proto/common/bindings/v1/bindings_pb.js";
2
3
  export interface PostgresConfig {
3
4
  version?: string;
4
- migrations?: string;
5
5
  }
6
6
  export declare class Postgres implements Component {
7
7
  id: string;
8
- constructor(id: string, config: PostgresConfig);
8
+ private type;
9
+ constructor(id: string, config?: PostgresConfig);
9
10
  __id(): string;
10
- sql(query: string): Promise<{}>;
11
+ __config(): PostgresProperties;
11
12
  }
@@ -1,24 +1,28 @@
1
- import { rpc } from "../utils/rpc";
2
- import { getCallerFile } from "../utils/stack";
1
+ import { getConfig } from "../binding/binding.js";
2
+ import { declarationSite } from "../declaration/callsite.js";
3
+ import { defer } from "../declaration/defer.js";
4
+ import { ResourceType } from "../gen/proto/app/resources/v1/resources_pb.js";
5
+ import { rpc } from "../runtime/rpc.js";
3
6
  export class Postgres {
4
7
  id;
8
+ type = ResourceType.POSTGRES;
5
9
  constructor(id, config) {
6
- // remove non-serializable stuff
7
10
  this.id = id;
8
11
  if (process.env.OCEL_PHASE === "discovery") {
9
- const source = getCallerFile();
10
- rpc.register({
11
- id: this.id,
12
- type: "postgres",
13
- source: source || "unknown",
14
- config: {},
15
- });
12
+ defer(rpc.resource.declare({
13
+ resource: { name: id, type: this.type },
14
+ config: {
15
+ case: "postgres",
16
+ value: { version: config?.version ?? "17" },
17
+ },
18
+ source: declarationSite(),
19
+ }));
16
20
  }
17
21
  }
18
22
  __id() {
19
23
  return this.id;
20
24
  }
21
- async sql(query) {
22
- return {};
25
+ __config() {
26
+ return getConfig(this.id, "postgres");
23
27
  }
24
28
  }
@@ -0,0 +1,11 @@
1
+ import type { DNSDescriptor } from "../../generated/config.js";
2
+ /** Options for Route 53. */
3
+ export interface Route53Options {
4
+ /**
5
+ * The hosted zone the records are written into. Omit it and ocel picks the
6
+ * zone that covers the hostname.
7
+ */
8
+ zone?: string;
9
+ }
10
+ /** Declares Route 53 as the DNS the project's records are written into. */
11
+ export declare function route53(options?: Route53Options): DNSDescriptor;
@@ -0,0 +1,4 @@
1
+ /** Declares Route 53 as the DNS the project's records are written into. */
2
+ export function route53(options = {}) {
3
+ return { route53: options };
4
+ }
@@ -0,0 +1,6 @@
1
+ import type { ApiGatewayEdgeOptions, CloudFrontEdgeOptions, EdgeDescriptor } from "../../generated/config.js";
2
+ export type { ApiGatewayEdgeOptions, CloudFrontEdgeOptions } from "../../generated/config.js";
3
+ /** Declares CloudFront as the edge the project's hostnames are served from. */
4
+ export declare function cloudfront(options?: CloudFrontEdgeOptions): EdgeDescriptor;
5
+ /** Declares API Gateway as the edge the project's hostnames are served from. */
6
+ export declare function apiGateway(options?: ApiGatewayEdgeOptions): EdgeDescriptor;
@@ -0,0 +1,8 @@
1
+ /** Declares CloudFront as the edge the project's hostnames are served from. */
2
+ export function cloudfront(options = {}) {
3
+ return { cloudfront: options };
4
+ }
5
+ /** Declares API Gateway as the edge the project's hostnames are served from. */
6
+ export function apiGateway(options = {}) {
7
+ return { "api-gateway": options };
8
+ }
@@ -0,0 +1,4 @@
1
+ import type { AwsProviderOptions, ProviderDescriptor } from "../../generated/config.js";
2
+ export type { AwsProviderOptions };
3
+ /** Declares AWS as the provider `ocel deploy` provisions into. */
4
+ export default function awsProvider(options?: AwsProviderOptions): ProviderDescriptor;
@@ -0,0 +1,4 @@
1
+ /** Declares AWS as the provider `ocel deploy` provisions into. */
2
+ export default function awsProvider(options = {}) {
3
+ return { aws: options };
4
+ }
@@ -0,0 +1,14 @@
1
+ import type { AlbEdgeOptions, EdgeDescriptor } from "../../generated/config.js";
2
+ export type { AlbEdgeOptions } from "../../generated/config.js";
3
+ /**
4
+ * Declares a global external Application Load Balancer, with Cloud CDN in
5
+ * front of Cloud Run, as the edge the project's hostnames are served from.
6
+ *
7
+ * One load balancer runs per bootstrap tier and every project in that tier
8
+ * is answered by it. It is the only piece of GCP infrastructure ocel provisions
9
+ * that costs money while it serves no traffic — roughly $18 a month per tier
10
+ * plus Premium-tier egress — so it is never the default: a project that names
11
+ * no edge is answered on the URL Cloud Run gives each service, and binds no
12
+ * hostname.
13
+ */
14
+ export declare function alb(options?: AlbEdgeOptions): EdgeDescriptor;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Declares a global external Application Load Balancer, with Cloud CDN in
3
+ * front of Cloud Run, as the edge the project's hostnames are served from.
4
+ *
5
+ * One load balancer runs per bootstrap tier and every project in that tier
6
+ * is answered by it. It is the only piece of GCP infrastructure ocel provisions
7
+ * that costs money while it serves no traffic — roughly $18 a month per tier
8
+ * plus Premium-tier egress — so it is never the default: a project that names
9
+ * no edge is answered on the URL Cloud Run gives each service, and binds no
10
+ * hostname.
11
+ */
12
+ export function alb(options = {}) {
13
+ return { alb: options };
14
+ }
@@ -0,0 +1,9 @@
1
+ import type { GcpProviderOptions, ProviderDescriptor } from "../../generated/config.js";
2
+ export type { GcpProviderOptions };
3
+ /**
4
+ * Declares Google Cloud as the provider `ocel deploy` provisions into.
5
+ *
6
+ * Credentials are read from Application Default Credentials in the environment
7
+ * the provider runs in: `gcloud auth application-default login`.
8
+ */
9
+ export default function gcpProvider(options: GcpProviderOptions): ProviderDescriptor;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Declares Google Cloud as the provider `ocel deploy` provisions into.
3
+ *
4
+ * Credentials are read from Application Default Credentials in the environment
5
+ * the provider runs in: `gcloud auth application-default login`.
6
+ */
7
+ export default function gcpProvider(options) {
8
+ return { gcp: options };
9
+ }
@@ -0,0 +1,4 @@
1
+ import type { ProviderDescriptor, VpsProviderOptions, VpsProxy, VpsTarget } from "../../generated/config.js";
2
+ export type { VpsProviderOptions, VpsProxy, VpsTarget };
3
+ /** Declares a VPS as the provider `ocel deploy` provisions into. */
4
+ export default function vpsProvider(options: VpsProviderOptions): ProviderDescriptor;
@@ -0,0 +1,4 @@
1
+ /** Declares a VPS as the provider `ocel deploy` provisions into. */
2
+ export default function vpsProvider(options) {
3
+ return { vps: options };
4
+ }
@@ -0,0 +1,30 @@
1
+ import type { RealtimeDenial } from "./handler.js";
2
+ /**
3
+ * Why the realtime handler or the transport refused an operation, or why it could not be
4
+ * attempted: one of the handler's denial codes, or one the client names itself.
5
+ *
6
+ * - `headers-failed`: the `headers` function threw.
7
+ * - `handler-unreachable`: the handler could not be reached, did not answer in time, or
8
+ * answered without JSON.
9
+ * - `handler-refused`: the handler answered with an HTTP error status.
10
+ * - `invalid-grant`: the handler granted a subscribe without the token it takes.
11
+ * - `connection-failed`: the socket could not be opened, or was not accepted in time.
12
+ * - `connection-lost`: the open socket dropped or went silent.
13
+ * - `subscribe-refused`: the transport refused a subscription the handler granted.
14
+ * - `unsupported-transport`: the handler named a transport this client does not speak.
15
+ * - `closed`: the client was closed.
16
+ */
17
+ export type RealtimeErrorCode = RealtimeDenial | "headers-failed" | "handler-unreachable" | "handler-refused" | "invalid-grant" | "connection-failed" | "connection-lost" | "subscribe-refused" | "unsupported-transport" | "closed";
18
+ /** An operation the realtime client could not complete. */
19
+ export declare class RealtimeError extends Error {
20
+ name: string;
21
+ /** What refused the operation, or why it could not be attempted. */
22
+ readonly code: RealtimeErrorCode;
23
+ /**
24
+ * Whether the same operation may succeed if tried again: true for a network failure, a
25
+ * dropped connection or a failing rule, false for a denial that would be answered the
26
+ * same way. A subscription the client keeps retrying on its own reports `true`.
27
+ */
28
+ readonly retriable: boolean;
29
+ constructor(code: RealtimeErrorCode, retriable: boolean, message: string);
30
+ }
@@ -0,0 +1,17 @@
1
+ /** An operation the realtime client could not complete. */
2
+ export class RealtimeError extends Error {
3
+ name = "RealtimeError";
4
+ /** What refused the operation, or why it could not be attempted. */
5
+ code;
6
+ /**
7
+ * Whether the same operation may succeed if tried again: true for a network failure, a
8
+ * dropped connection or a failing rule, false for a denial that would be answered the
9
+ * same way. A subscription the client keeps retrying on its own reports `true`.
10
+ */
11
+ retriable;
12
+ constructor(code, retriable, message) {
13
+ super(message);
14
+ this.code = code;
15
+ this.retriable = retriable;
16
+ }
17
+ }
@@ -0,0 +1,8 @@
1
+ import type { ClientTransport } from "./client-transport.js";
2
+ /** The Ocel gateway's socket, which speaks the AppSync Events protocol. */
3
+ export declare const gatewayTransport: ClientTransport;
4
+ /**
5
+ * AppSync Events' socket. AppSync ends a connection after 24 hours, which reaches the
6
+ * client as a drop, so every live subscription is authorized again on the next socket.
7
+ */
8
+ export declare const appSyncTransport: ClientTransport;
@@ -0,0 +1,169 @@
1
+ import { RealtimeError } from "./client-error.js";
2
+ const subprotocol = "aws-appsync-event-ws";
3
+ const answerDeadlineMilliseconds = 10_000;
4
+ function encodeBase64url(text) {
5
+ let binary = "";
6
+ for (const byte of new TextEncoder().encode(text))
7
+ binary += String.fromCharCode(byte);
8
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
9
+ }
10
+ function describeErrors(frame) {
11
+ return (frame.errors ?? []).map((error) => error.message ?? error.errorType ?? "").join("; ");
12
+ }
13
+ function readEnvelopes(event) {
14
+ const texts = Array.isArray(event) ? event : [event];
15
+ return texts.flatMap((text) => {
16
+ if (typeof text !== "string")
17
+ return [];
18
+ try {
19
+ const decoded = JSON.parse(text);
20
+ return [typeof decoded === "string" ? decoded : text];
21
+ }
22
+ catch {
23
+ return [text];
24
+ }
25
+ });
26
+ }
27
+ function createEventSocketTransport(peer) {
28
+ return {
29
+ connect(grant, onDrop) {
30
+ return new Promise((resolve, reject) => {
31
+ const authorize = (token) => grant.host === undefined
32
+ ? { Authorization: token }
33
+ : { host: grant.host, Authorization: token };
34
+ const socket = new WebSocket(grant.url, [
35
+ subprotocol,
36
+ `header-${encodeBase64url(JSON.stringify(authorize(grant.token)))}`,
37
+ ]);
38
+ const pending = new Map();
39
+ const listeners = new Map();
40
+ let isOpen = false;
41
+ let hasEnded = false;
42
+ let isClosedByClient = false;
43
+ let silenceTimer;
44
+ let silenceLimitMilliseconds = 0;
45
+ const send = (frame) => {
46
+ if (socket.readyState === WebSocket.OPEN)
47
+ socket.send(JSON.stringify(frame));
48
+ };
49
+ const end = (error) => {
50
+ if (hasEnded)
51
+ return;
52
+ hasEnded = true;
53
+ clearTimeout(handshakeDeadline);
54
+ clearTimeout(silenceTimer);
55
+ for (const waiting of pending.values()) {
56
+ clearTimeout(waiting.deadline);
57
+ waiting.reject(error);
58
+ }
59
+ pending.clear();
60
+ listeners.clear();
61
+ if (!isOpen) {
62
+ reject(error);
63
+ return;
64
+ }
65
+ isOpen = false;
66
+ if (!isClosedByClient)
67
+ onDrop(error);
68
+ };
69
+ const abandon = (error) => {
70
+ socket.close();
71
+ end(error);
72
+ };
73
+ const handshakeDeadline = setTimeout(() => abandon(new RealtimeError("connection-failed", true, `${peer} did not accept the connection within ${answerDeadlineMilliseconds}ms`)), answerDeadlineMilliseconds);
74
+ const watchSilence = () => {
75
+ if (silenceLimitMilliseconds <= 0)
76
+ return;
77
+ clearTimeout(silenceTimer);
78
+ silenceTimer = setTimeout(() => abandon(new RealtimeError("connection-lost", true, `${peer} sent nothing for ${silenceLimitMilliseconds}ms`)), silenceLimitMilliseconds);
79
+ };
80
+ const settleSubscribe = (id) => {
81
+ const waiting = pending.get(id);
82
+ pending.delete(id);
83
+ if (waiting)
84
+ clearTimeout(waiting.deadline);
85
+ return waiting;
86
+ };
87
+ const connection = {
88
+ subscribe(id, channel, token, onEvent) {
89
+ if (!isOpen) {
90
+ return Promise.reject(new RealtimeError("connection-lost", true, "the connection is no longer open"));
91
+ }
92
+ return new Promise((subscribed, refused) => {
93
+ const waiting = {
94
+ resolve: () => {
95
+ if (waiting.isCancelled)
96
+ send({ type: "unsubscribe", id });
97
+ else
98
+ listeners.set(id, onEvent);
99
+ subscribed();
100
+ },
101
+ reject: refused,
102
+ deadline: setTimeout(() => abandon(new RealtimeError("connection-lost", true, `${peer} did not answer a subscribe within ${answerDeadlineMilliseconds}ms`)), answerDeadlineMilliseconds),
103
+ isCancelled: false,
104
+ };
105
+ pending.set(id, waiting);
106
+ send({ type: "subscribe", id, channel, authorization: authorize(token) });
107
+ });
108
+ },
109
+ unsubscribe(id) {
110
+ const waiting = pending.get(id);
111
+ if (waiting)
112
+ waiting.isCancelled = true;
113
+ if (listeners.delete(id))
114
+ send({ type: "unsubscribe", id });
115
+ },
116
+ close() {
117
+ isClosedByClient = true;
118
+ socket.close(1000);
119
+ end(new RealtimeError("closed", false, "the realtime client was closed"));
120
+ },
121
+ };
122
+ socket.addEventListener("open", () => send({ type: "connection_init" }));
123
+ socket.addEventListener("message", (message) => {
124
+ let frame;
125
+ try {
126
+ frame = JSON.parse(String(message.data));
127
+ }
128
+ catch {
129
+ return;
130
+ }
131
+ watchSilence();
132
+ switch (frame.type) {
133
+ case "connection_ack":
134
+ clearTimeout(handshakeDeadline);
135
+ isOpen = true;
136
+ silenceLimitMilliseconds = frame.connectionTimeoutMs ?? 0;
137
+ watchSilence();
138
+ resolve(connection);
139
+ return;
140
+ case "connection_error":
141
+ abandon(new RealtimeError("connection-failed", true, `${peer} refused the connection: ${describeErrors(frame)}`));
142
+ return;
143
+ case "subscribe_success":
144
+ settleSubscribe(frame.id ?? "")?.resolve();
145
+ return;
146
+ case "subscribe_error":
147
+ settleSubscribe(frame.id ?? "")?.reject(new RealtimeError("subscribe-refused", false, `${peer} refused the subscription: ${describeErrors(frame)}`));
148
+ return;
149
+ case "data": {
150
+ const listener = listeners.get(frame.id ?? "");
151
+ if (listener)
152
+ for (const envelope of readEnvelopes(frame.event))
153
+ listener(envelope);
154
+ return;
155
+ }
156
+ }
157
+ });
158
+ socket.addEventListener("close", () => end(new RealtimeError(isOpen ? "connection-lost" : "connection-failed", true, isOpen ? `the connection to ${peer} closed` : `${peer} could not be reached`)));
159
+ });
160
+ },
161
+ };
162
+ }
163
+ /** The Ocel gateway's socket, which speaks the AppSync Events protocol. */
164
+ export const gatewayTransport = createEventSocketTransport("the gateway");
165
+ /**
166
+ * AppSync Events' socket. AppSync ends a connection after 24 hours, which reaches the
167
+ * client as a drop, so every live subscription is authorized again on the next socket.
168
+ */
169
+ export const appSyncTransport = createEventSocketTransport("AppSync");
@@ -0,0 +1,29 @@
1
+ import { RealtimeError } from "./client-error.js";
2
+ import type { Transport } from "./transport.js";
3
+ /** What the realtime handler answered a connect with: where the socket is and its token. */
4
+ export interface ConnectGrant {
5
+ url: string;
6
+ host?: string;
7
+ token: string;
8
+ }
9
+ /** One open socket to a transport, carrying any number of subscriptions. */
10
+ export interface TransportConnection {
11
+ /**
12
+ * Subscribes `id` to `channel` with its subscribe token, resolving once the transport
13
+ * accepts it and rejecting with a {@link RealtimeError} when it refuses; each event
14
+ * then reaches `onEvent` as the envelope's JSON text.
15
+ */
16
+ subscribe(id: string, channel: string, token: string, onEvent: (envelope: string) => void): Promise<void>;
17
+ unsubscribe(id: string): void;
18
+ close(): void;
19
+ }
20
+ /** How a browser reaches one kind of transport. */
21
+ export interface ClientTransport {
22
+ /**
23
+ * Opens a socket with `grant`, resolving once the transport accepts it. `onDrop` hears
24
+ * of a socket that ended without `close` being called.
25
+ */
26
+ connect(grant: ConnectGrant, onDrop: (error: RealtimeError) => void): Promise<TransportConnection>;
27
+ }
28
+ /** Loads the transport the realtime handler named, so a bundle carries only the one it uses. */
29
+ export declare function loadTransport(name: Transport["name"]): Promise<ClientTransport>;