@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 +4 -29
- package/package.json +1 -1
- package/template/.examples/automation-example.ts +60 -0
- package/template/README.md +55 -1
- package/template/src/index.ts +36 -2
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
|
|
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
|
|
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
|
@@ -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
|
+
}
|
package/template/README.md
CHANGED
|
@@ -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,
|
|
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
|
package/template/src/index.ts
CHANGED
|
@@ -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
|
+
});
|