create-feltkit 0.3.12 → 0.3.13

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
@@ -1,7 +1,7 @@
1
1
  <p align="center">
2
2
  <picture>
3
- <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/rkendel1/feltkit/main/docs/assets/feltkit-logo-dark.png">
4
- <img src="https://raw.githubusercontent.com/rkendel1/feltkit/main/docs/assets/feltkit-logo.png" alt="FeltKit" width="160">
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/npm/@feltdb/feltkit/docs/assets/feltkit-logo-dark.png">
4
+ <img src="https://cdn.jsdelivr.net/npm/@feltdb/feltkit/docs/assets/feltkit-logo.png" alt="FeltKit" width="160">
5
5
  </picture>
6
6
  </p>
7
7
 
@@ -29,4 +29,5 @@ npm run managed:setup
29
29
 
30
30
  The managed starter's README walks through setup, deployment and verification.
31
31
 
32
- Documentation: https://github.com/rkendel1/concave#readme
32
+ Documentation: shipped with the package. In a project, run `npx feltkit docs` (or read
33
+ `node_modules/@feltdb/feltkit/docs/`); online: <https://cdn.jsdelivr.net/npm/@feltdb/feltkit/docs/README.md>.
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "create-feltkit",
3
- "version": "0.3.12",
3
+ "version": "0.3.13",
4
4
  "description": "Create a FeltKit application: npm create feltkit@latest my-app (add -- --template managed for Managed FeltDB)",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "git+https://github.com/rkendel1/concave.git",
9
+ "url": "git+https://github.com/rkendel1/feltkit.git",
10
10
  "directory": "packages/create"
11
11
  },
12
12
  "engines": {
@@ -33,5 +33,6 @@
33
33
  "build": "node sync-template.mjs",
34
34
  "prepack": "node sync-template.mjs",
35
35
  "test": "node --test test/*.test.mjs"
36
- }
36
+ },
37
+ "homepage": "https://www.npmjs.com/package/create-feltkit"
37
38
  }
@@ -92,13 +92,21 @@ Configure each one in **Studio → Services**: every service has its own screen,
92
92
  operation there is authorized as the dev user you choose with **Act as**. From a function:
93
93
 
94
94
  ```ts
95
+ // Effects that announce this mutation's change: performed only if it commits (mutations only).
96
+ ctx.afterCommit.webhooks.emit("task.created", { id });
97
+ ctx.afterCommit.notifications.send({ recipient: "grace", type: "task.completed", title: "Done" });
98
+ ctx.afterCommit.jobs.enqueue("projects.clear-completed", {});
99
+ // Reads and stored files, right away:
95
100
  await ctx.services.files.upload({ name: "notes.txt", content: text });
96
- await ctx.services.notifications.send({ recipient: "grace", type: "task.completed", title: "Done" });
97
- await ctx.services.webhooks?.emit("task.created", { id }); // mutations only
98
- await ctx.services.jobs?.enqueue("projects.clear-completed", {}); // mutations only
99
101
  const greeting = await ctx.services.configuration.get("GREETING");
100
102
  ```
101
103
 
104
+ Use `ctx.afterCommit` for anything that tells the world about the mutation's change. The same
105
+ calls on `ctx.services` (`ctx.services.webhooks.emit`, `…notifications.send`, `…jobs.enqueue`)
106
+ happen immediately and stay done even if the mutation then fails (a `CONFLICT` at commit), so
107
+ receivers would hear about a change that never happened. `npx feltkit outbox list` shows every
108
+ after-commit effect and its state.
109
+
102
110
  The starter already uses them: creating and completing a task emits `task.created` and
103
111
  `task.completed` to any registered webhook endpoint; completing someone else's task notifies
104
112
  its creator; and the job `projects.clear-completed` runs `projects:clearCompleted`.
@@ -121,8 +129,12 @@ service off, remove it from `services`.
121
129
 
122
130
  **Studio → Integrations → Connect an API** reads an OpenAPI document (JSON) or lets you
123
131
  describe the operations yourself, then writes `feltkit/<name>.ts` and grants `<name>.*` to the
124
- roles you choose. Each operation becomes a capability your functions, the agent and other apps
125
- can call (`<name>.<operation>`), with its permission, and every call recorded. The API key is
132
+ roles you choose. Each operation becomes an AppPort capability (`<name>.<operation>`) with its
133
+ permission, and every call is recorded. It is called through AppPort, not from a query or
134
+ mutation: by the agent (MCP tools, proposals), by other apps and scripts (`POST /appport`), and by
135
+ your frontend with an AppPort request carrying the session token. To act on the result inside
136
+ your app, name a mutation in the operation's `onOutcome`: it runs as the caller with the call's
137
+ record when the call finishes (success or failure). The API key is
126
138
  stored in FeltKit's custody; in production set `<NAME>_URL` and `FELTKIT_CREDENTIAL_<NAME>`.
127
139
  Then narrow each operation's `output` schema in that file to what the API returns.
128
140
 
@@ -360,4 +372,7 @@ operate this app.
360
372
  - Errors carry a code (`FORBIDDEN`, `INVALID_ARGUMENT`, `NOT_FOUND`, …) and usually a hint with
361
373
  the fix.
362
374
 
363
- FeltKit documentation: <https://github.com/rkendel1/feltkit#readme>
375
+ FeltKit documentation ships with the package: `npx feltkit docs` lists it (guarantees, transactions,
376
+ security, agents, path to production, backup) and `npx feltkit docs <name>` prints one. The same files
377
+ are in `node_modules/@feltdb/feltkit/docs/`, and online at
378
+ <https://cdn.jsdelivr.net/npm/@feltdb/feltkit/docs/README.md>.
@@ -19,7 +19,8 @@ export const app = feltkit({
19
19
  // Viewers read. They can see agent tasks but not start or approve them.
20
20
  viewer: ["projects.read", "tasks.read", "files.read", "notifications.read", "feltkit.agent.read"],
21
21
  // Agents can read, complete tasks, and leave notes. They cannot create or delete.
22
- agent: ["projects.read", "tasks.read", "tasks.complete", "tasks.note", "files.read", "files.write", "notifications.send", "webhooks.emit", "webhooks.deliver"],
22
+ // feltkit.agent.*: discover the app (feltkit_context), work tasks, propose actions; a person approves.
23
+ agent: ["projects.read", "tasks.read", "tasks.complete", "tasks.note", "files.read", "files.write", "notifications.send", "webhooks.emit", "webhooks.deliver", "feltkit.agent.*"],
23
24
  // Admins configure the app in Studio → Services: the model (intelligence.*), stored
24
25
  // credentials (credential.*), configuration, API keys, webhooks, jobs, and schedules.
25
26
  // Credentials are stored by reference; the value never enters FeltDB.
@@ -42,7 +42,8 @@ export const create = app.mutation({
42
42
  createdBy: ctx.auth.requirePrincipal().id,
43
43
  });
44
44
  // Delivered, signed, to every webhook endpoint registered for "task.created" (Studio → Services → Webhooks).
45
- await ctx.services.webhooks?.emit("task.created", { id, projectId, title: title.trim() });
45
+ // ctx.afterCommit: only if this mutation commits (ctx.services.* effects happen even if it does not).
46
+ ctx.afterCommit.webhooks.emit("task.created", { id, projectId, title: title.trim() });
46
47
  return id;
47
48
  },
48
49
  });
@@ -67,10 +68,10 @@ export const setDone = app.mutation({
67
68
  const who = ctx.auth.requirePrincipal().id;
68
69
  const task = await ctx.db.patch(tasks, id, done ? { done: true, completedAt: Date.now(), completedBy: who } : { done: false, completedAt: undefined, completedBy: undefined });
69
70
  if (done) {
70
- await ctx.services.webhooks?.emit("task.completed", { id: task.id, projectId: task.projectId, completedBy: who });
71
+ ctx.afterCommit.webhooks.emit("task.completed", { id: task.id, projectId: task.projectId, completedBy: who });
71
72
  // Tell whoever created the task, when someone else completes it.
72
73
  if (task.createdBy !== who) {
73
- await ctx.services.notifications.send({ recipient: task.createdBy, type: "task.completed", title: `${who} completed "${task.title}"`, data: { taskId: task.id }, idempotencyKey: `task.completed:${task.id}:${task.completedAt}` });
74
+ ctx.afterCommit.notifications.send({ recipient: task.createdBy, type: "task.completed", title: `${who} completed "${task.title}"`, data: { taskId: task.id }, idempotencyKey: `task.completed:${task.id}:${task.completedAt}` });
74
75
  }
75
76
  }
76
77
  return { id: task.id, done: task.done };
@@ -13,7 +13,7 @@
13
13
  "typecheck": "tsc --noEmit"
14
14
  },
15
15
  "dependencies": {
16
- "@feltdb/feltkit": "0.3.12",
16
+ "@feltdb/feltkit": "0.3.13",
17
17
  "react": "19.2.0",
18
18
  "react-dom": "19.2.0"
19
19
  },
@@ -20,10 +20,10 @@
20
20
  "deploy:fly": "node scripts/deploy-fly.mjs"
21
21
  },
22
22
  "dependencies": {
23
- "@feltdb/feltkit": "0.3.12"
23
+ "@feltdb/feltkit": "0.3.13"
24
24
  },
25
25
  "devDependencies": {
26
- "@feltdb/core": ">=0.18.0 <1.0.0",
26
+ "@feltdb/core": ">=0.21.0 <1.0.0",
27
27
  "@types/node": "22.19.1",
28
28
  "typescript": "5.9.3"
29
29
  }