@samebase/alchemy-convex 0.8.0 → 0.9.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.
package/README.md CHANGED
@@ -135,11 +135,20 @@ is set must be the slug of that team, checked against its projects, and a token
135
135
  fails the run. The Convex CLI login needs the slug or the id. The first run of a team creates
136
136
  the project `alchemy-state` and pushes the store functions to its
137
137
  production deployment with the Convex CLI of the app; a later version of this package pushes a
138
- newer store when it finds an older one, and never an older one over a newer one. Each run makes a
138
+ newer store when it finds an older one. A store that is newer than the package fails the run with
139
+ both versions, so the repositories of a team upgrade the package together. Each run makes a
139
140
  deploy key of that deployment that can only run the store's internal functions, and deletes it at
140
141
  the end. Rows are in the tables `resources` and `outputs` in the dashboard, under the stack name.
141
142
  The store has no lock: run one deploy of a stage at a time, such as with a CI concurrency group.
142
- The names of the store functions are a wire contract: never renamed or removed.
143
+ The store and its readers (Samebase) are released and upgraded together.
144
+
145
+ Store version 3 supports native subscriptions. A trusted server checks repository access, then
146
+ calls internal `reader:authorize({ repository, subject })` with a deployment credential. It gives
147
+ the returned token to a separate `ConvexClient` connected to the state deployment. The client
148
+ subscribes to `reader:repository({})`; the verified token selects the repository. The token has a
149
+ five-minute lifetime and permits redacted reads only. The server checks access again on renewal.
150
+ The store uses its own native signing key and JWKS, so no extra signing secret is required.
151
+ See [the reader contract](docs/design/convex-state.md#repository-subscriptions-090).
143
152
 
144
153
  ### What the output records about a run
145
154
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/Credentials.ts","../src/ManagementApi.ts","../src/Providers.ts","../src/Push.ts","../src/Deployment.ts","../src/Project.ts","../src/RunRecord.ts","../src/State.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/Credentials.ts","../src/ManagementApi.ts","../src/Providers.ts","../src/Push.ts","../src/Deployment.ts","../src/Project.ts","../src/RunRecord.ts","../src/State.ts"],"mappings":"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"}
package/lib/index.js CHANGED
@@ -1555,8 +1555,18 @@ const makeFunctionApi = (url, key) => ({ call: (path, args) => post(`${url}/api/
1555
1555
  /** The value of a reply, or the Convex message, which names the function and the cause, such as a missing key action. */
1556
1556
  const valueOf = (reply) => reply.status === "success" ? Effect.succeed(reply.value) : Effect.fail(failure(reply.errorMessage.trim()));
1557
1557
  /** The functions of the store with Alchemy's encoding: the JSON text of encodeState. */
1558
- const remoteOf = (api) => {
1558
+ const remoteOf = (api, record) => {
1559
1559
  const run = (name, args) => api.call(`state:${name}`, args).pipe(Effect.flatMap(valueOf));
1560
+ const write = (name, args) => Effect.gen(function* () {
1561
+ const currentRun = record === void 0 ? void 0 : {
1562
+ ...record,
1563
+ recordedAt: new Date(yield* Clock.currentTimeMillis).toISOString()
1564
+ };
1565
+ return yield* run(name, {
1566
+ ...args,
1567
+ run: currentRun
1568
+ });
1569
+ });
1560
1570
  const strings = (name, args) => run(name, args).pipe(Effect.flatMap(decode(Schema.Array(Schema.String), name)));
1561
1571
  const optional = (name, args) => run(name, args).pipe(Effect.flatMap(decode(Schema.NullOr(Schema.String), name)));
1562
1572
  const encode = (value) => JSON.stringify(encodeState(value));
@@ -1580,13 +1590,13 @@ const remoteOf = (api) => {
1580
1590
  stack: r.stack,
1581
1591
  stage: r.stage
1582
1592
  }).pipe(Effect.map((text) => text === null ? void 0 : JSON.parse(text, reviveState))),
1583
- set: (r) => run("set", {
1593
+ set: (r) => write("set", {
1584
1594
  stack: r.stack,
1585
1595
  stage: r.stage,
1586
1596
  fqn: r.fqn,
1587
1597
  value: encode(r.value)
1588
1598
  }),
1589
- delete: (r) => run("remove", {
1599
+ delete: (r) => write("remove", {
1590
1600
  stack: r.stack,
1591
1601
  stage: r.stage,
1592
1602
  fqn: r.fqn
@@ -1595,7 +1605,7 @@ const remoteOf = (api) => {
1595
1605
  stack: r.stack,
1596
1606
  stage: r.stage
1597
1607
  }),
1598
- setOutput: (r) => run("setOutput", {
1608
+ setOutput: (r) => write("setOutput", {
1599
1609
  stack: r.stack,
1600
1610
  stage: r.stage,
1601
1611
  value: encode(r.value)
@@ -1618,7 +1628,7 @@ const storeDirectory = () => join(dirname(fileURLToPath(import.meta.url)), "..",
1618
1628
  */
1619
1629
  const pushStore = (options, deployment) => Effect.gen(function* () {
1620
1630
  const cli = yield* installedCli(join(options.store, ".."));
1621
- yield* Effect.logInfo(`Convex state: pushing the store version 2 to ${deployment.name}`);
1631
+ yield* Effect.logInfo(`Convex state: pushing the store version 3 to ${deployment.name}`);
1622
1632
  yield* withPushKey(options.api, deployment.name, PUSH_KEY_ACTIONS, (key) => push(options.spawner, key, {
1623
1633
  deployment: deployment.name,
1624
1634
  url: deployment.deploymentUrl,
@@ -1681,17 +1691,17 @@ const makeConvexState = (options) => Effect.gen(function* () {
1681
1691
  current = next;
1682
1692
  return next.call(path, args);
1683
1693
  })))) };
1684
- const version = yield* storeVersion(functions);
1685
- if (version === void 0 || version < 2) {
1694
+ let version = yield* storeVersion(functions);
1695
+ if (version === void 0 || version < 3) {
1686
1696
  if (version === void 0 && deployment.lastDeployTime) return yield* failure(`project ${STORE_PROJECT_NAME} (${project.id}) of team ${team} has code that is not the state store, and Convex.state does not push over it. Rename that project in the Convex dashboard.`);
1687
- const now = yield* storeVersion(functions);
1688
- if (now === void 0 || now < 2) {
1697
+ version = yield* storeVersion(functions);
1698
+ if (version === void 0 || version < 3) {
1689
1699
  yield* pushStore(options, deployment);
1690
- const pushed = yield* storeVersion(functions);
1691
- if (pushed === void 0 || pushed < 2) return yield* failure(`${deployment.name} answers store version ${pushed ?? "none"} after the push of version 2.`);
1700
+ version = yield* storeVersion(functions);
1692
1701
  }
1693
- } else if (version > 2) yield* Effect.logInfo(`Convex state: the store of team ${team} is version ${version}, newer than version 2 of this package, and it stays.`);
1694
- const remote = remoteOf(functions);
1702
+ }
1703
+ if (version !== 3) return yield* failure(`${deployment.name} answers store version ${version ?? "none"}, and this package needs store version 3.`);
1704
+ const remote = remoteOf(functions, options.run);
1695
1705
  /** The stack's output plus the record, when the run has one and the output has a place for it. */
1696
1706
  const documentOf = (request) => Effect.gen(function* () {
1697
1707
  const { run } = options;