@project-ajax/create 0.0.19 → 0.0.21

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/dist/index.js CHANGED
@@ -18,38 +18,25 @@ ${err.message}`));
18
18
  process.exit(1);
19
19
  });
20
20
  async function run() {
21
- console.log(chalk.bold.cyan("\n\u{1F680} Create a new Project Ajax worker\n"));
21
+ console.log(chalk.bold.cyan("\n\u{1F680} Create a new worker\n"));
22
22
  const { values } = parseArgs({
23
23
  options: {
24
24
  directory: {
25
25
  type: "string",
26
26
  short: "d"
27
- },
28
- project: {
29
- type: "string",
30
- short: "p"
31
27
  }
32
28
  }
33
29
  });
34
30
  let directoryName = values.directory;
35
- let projectName = values.project;
36
31
  if (!directoryName) {
37
32
  directoryName = await safePrompt({
38
33
  message: "Path to the new worker project:",
39
34
  default: ".",
40
35
  required: true,
41
- noTTY: "Provide the path to the new project with --directory"
42
- });
43
- }
44
- if (!projectName) {
45
- projectName = await safePrompt({
46
- message: "Project name:",
47
- default: "my-worker",
48
- required: true,
49
- noTTY: "Provide the project name with --project"
36
+ noTTY: "Provide the path to the new worker project with --directory"
50
37
  });
51
38
  }
52
- if (!directoryName || !projectName) {
39
+ if (!directoryName) {
53
40
  console.log(chalk.red("Cancelled."));
54
41
  process.exit(1);
55
42
  }
@@ -60,12 +47,10 @@ async function run() {
60
47
  spinner.text = "Copying template files...";
61
48
  const templatePath = getTemplatePath();
62
49
  copyTemplate(templatePath, destPath);
63
- spinner.text = "Customizing package.json...";
64
- customizePackageJson(destPath, projectName);
65
50
  spinner.succeed(chalk.green("Worker project created successfully!"));
66
51
  printNextSteps(directoryName);
67
52
  } catch (err) {
68
- spinner.fail("Failed to create project.");
53
+ spinner.fail("Failed to create worker project.");
69
54
  console.error(
70
55
  chalk.red(`
71
56
  ${err instanceof Error ? err.message : String(err)}`)
@@ -103,16 +88,6 @@ function copyTemplate(templatePath, destPath) {
103
88
  fs.cpSync(srcPath, destFilePath, { recursive: true });
104
89
  }
105
90
  }
106
- function customizePackageJson(destPath, projectName) {
107
- const packageJsonPath = path.join(destPath, "package.json");
108
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
109
- packageJson.name = projectName;
110
- fs.writeFileSync(
111
- packageJsonPath,
112
- `${JSON.stringify(packageJson, null, 2)}
113
- `
114
- );
115
- }
116
91
  function printNextSteps(directoryName) {
117
92
  console.log(chalk.cyan(`
118
93
  \u2728 Next steps:`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@project-ajax/create",
3
- "version": "0.0.19",
3
+ "version": "0.0.21",
4
4
  "description": "Initialize a new Notion Project Ajax extensions repo.",
5
5
  "bin": {
6
6
  "create-ajax": "dist/index.js"
@@ -0,0 +1,60 @@
1
+ import { Client } from "@notionhq/client";
2
+ import { automation } from "@project-ajax/sdk";
3
+
4
+ // Initialize the Notion client with OAuth token from environment
5
+ const notion = new Client({
6
+ auth: process.env.NOTION_API_TOKEN,
7
+ });
8
+
9
+ type RichTextProperty = {
10
+ type: "rich_text";
11
+ rich_text: Array<{ plain_text: string }>;
12
+ };
13
+
14
+ /**
15
+ * Example automation that processes questions from database pages.
16
+ *
17
+ * This automation:
18
+ * 1. Reads a question from a page property
19
+ * 2. Processes it (calls an API, performs logic, etc.)
20
+ * 3. Updates the page with the answer
21
+ */
22
+ export const questionAnswerAutomation = automation({
23
+ title: "Question Answer Automation",
24
+ description:
25
+ "Reads questions from database pages and updates them with answers",
26
+ execute: async ({ pageId, pageData }) => {
27
+ // Extract email from the page dat
28
+ const emailProperty = pageData?.properties?.Email as
29
+ | RichTextProperty
30
+ | undefined;
31
+
32
+ // Extract text content from the property
33
+ let emailValue = "";
34
+ if (emailProperty?.type === "rich_text") {
35
+ emailValue = emailProperty.rich_text.map((rt) => rt.plain_text).join("");
36
+ }
37
+
38
+ // Handle empty email
39
+ if (!emailValue) {
40
+ return;
41
+ }
42
+
43
+ await sendEmail(emailValue);
44
+
45
+ // Update the page to indicate the email has been sent
46
+ await notion.pages.update({
47
+ page_id: pageId,
48
+ properties: {
49
+ EmailSent: {
50
+ // Notion has a 2000 character limit for rich_text
51
+ checkbox: true,
52
+ },
53
+ },
54
+ });
55
+ },
56
+ });
57
+
58
+ async function sendEmail(email: string): Promise<void> {
59
+ console.log(`Sending email to ${email}`);
60
+ }
@@ -2,7 +2,7 @@
2
2
 
3
3
  Use this repo to write workers to enhance Notion. With Notion Workers, you can
4
4
  write JavaScript that syncs data into Notion collections, provides tools to
5
- Custom Agents, or runs automation tasks.
5
+ Custom Agents, and powers database automations.
6
6
 
7
7
  ## Prerequisites
8
8
 
@@ -76,6 +76,7 @@ The sample worker installs three capabilities:
76
76
 
77
77
  - [Synced database](#try-the-synced-database)
78
78
  - [Agent tool](#try-the-agent-tool)
79
+ - [Automation](#try-the-automation)
79
80
 
80
81
  #### Try the synced database
81
82
 
@@ -108,6 +109,19 @@ Save settings, then navigate to the **chat** tab. Our sample tool call allows
108
109
  for searching tasks by id or keyword - try asking Agent to find tasks related to
109
110
  "Ajax" or "worker".
110
111
 
112
+ #### Try the automation
113
+
114
+ Add a column to your Sample Tasks synced database with type Button. Modify the button automation to `Run Worker` and then choose your worker and the `Mark Task Complete` automation.
115
+
116
+ Once configured, click the button.
117
+
118
+ You will see `Button automation ran successfully`.
119
+
120
+ The automation only prints to console. To see the logs:
121
+ 1. Navigate to the `Workers` tab
122
+ 2. Select your worker
123
+ 3. In `Recent runs` click `automation:completeTaskAutomation`
124
+
111
125
  ## How-to build your own
112
126
 
113
127
  Begin by using `npm init @project-ajax`, and then customize `index.ts` with
@@ -127,6 +141,13 @@ your Notion workspace.
127
141
 
128
142
  See the [tool example](./.examples/tool-example.ts) for a complete example.
129
143
 
144
+ ### Writing an automation
145
+
146
+ [Automations](#automations) provide custom actions that can be triggered from
147
+ database automations in your Notion workspace.
148
+
149
+ See the [automation example](./.examples/automation-example.ts) for a complete example.
150
+
130
151
  ## Secrets
131
152
 
132
153
  Your function might require sensitive values, like API tokens, to run. You can
@@ -239,6 +260,39 @@ npx workers exec myTool
239
260
  # To test tools with specific inputs, use them with a custom agent in Notion.
240
261
  ```
241
262
 
263
+ ### Automations
264
+
265
+ The **automation** capability allows you to create custom actions that can be
266
+ triggered from database automations in your Notion workspace. When you create a
267
+ database automation and select "Run worker" as an action, you can choose from
268
+ your deployed automation capabilities.
269
+
270
+ #### Properties
271
+
272
+ - **`title`** (string, required): The name of the automation shown in the UI when selecting automations.
273
+ - **`description`** (string, required): A brief description of what this automation does.
274
+ - **`execute`** (function, required): Async function that runs when the automation is triggered.
275
+ - **Parameters**: `context` (AutomationContext) - Context about the trigger, including:
276
+ - `actionType` (string): The type of automation action
277
+ - `pageId` (string, optional): ID of the page that triggered the automation
278
+ - `pageData` (object, optional): Full page object from Notion's Public API, including all properties
279
+ - **Returns**: Promise that resolves when the automation completes.
280
+
281
+ #### Example
282
+
283
+ ```typescript
284
+ automation({
285
+ title: "Send Welcome Email",
286
+ description: "Sends a welcome email when a user is added",
287
+ execute: async ({ pageData }) => {
288
+ if (pageData) {
289
+ const email = pageData.properties.Email;
290
+ await sendEmail(email);
291
+ }
292
+ },
293
+ })
294
+ ```
295
+
242
296
  ## CLI reference
243
297
 
244
298
  The `workers` CLI provides commands to authenticate, deploy, execute, and manage
@@ -1,7 +1,6 @@
1
- import { tool } from "@project-ajax/sdk";
1
+ import { automation, sync, tool } from "@project-ajax/sdk";
2
2
  import * as Builder from "@project-ajax/sdk/builder";
3
3
  import * as Schema from "@project-ajax/sdk/schema";
4
- import { sync } from "@project-ajax/sdk/sync";
5
4
 
6
5
  // Sample data for demonstration
7
6
  const sampleTasks = [
@@ -149,3 +148,38 @@ export const taskSearchTool = tool({
149
148
  };
150
149
  },
151
150
  });
151
+
152
+ // Example automation that runs when triggered from a database automation
153
+ export const completeTaskAutomation = automation({
154
+ title: "Mark Task Complete",
155
+ description: "Automatically marks a task as complete when triggered",
156
+ execute: async ({ pageId, actionType, pageData }) => {
157
+ // The pageData parameter contains the full page object from Notion's Public API
158
+ // with all the database properties already encoded and ready to use.
159
+
160
+ console.log(`Automation triggered for page: ${pageId}`);
161
+ console.log(`Action type: ${actionType}`);
162
+
163
+ if (pageData) {
164
+ // Access all page properties directly
165
+ console.log("Page properties:", pageData.properties);
166
+
167
+ // Example: Access specific properties by their name
168
+ // const taskName = pageData.properties.Name;
169
+ // const status = pageData.properties.Status;
170
+ // const assignee = pageData.properties.Assignee;
171
+
172
+ // The properties are in Notion's Public API format
173
+ // See: https://developers.notion.com/reference/property-value-object
174
+ }
175
+
176
+ // In a real implementation, you would:
177
+ // 1. Use the page properties to determine what action to take
178
+ // 2. Update the task status in your system
179
+ // 3. Call external APIs, send notifications, etc.
180
+
181
+ // Example: You could call an external API, update a database, send notifications, etc.
182
+ // For this demo, we just log the execution
183
+ console.log("Task marked as complete!");
184
+ },
185
+ });