This project is an experiment in using Apple Notes as a storage layer for a web application.
It is not meant to be practical, it is a creative exercise.
Run PORT=3000 node .
to run the server.
The UI is at /
and allows listing notes and reading and writing notes by ID.
There is also a to-do list sample running at /todo.html
.
Entity/type approximates a database table and is implemented using Apple Notes folders.
There is an encompassing folder for the application named after appName.js
.
-
GET type
- list the IDs of entities of the given typeThe ID can be any string of characters except for a line break and a comma.
-
GET type/id
- get the content of the entity of the given type by its IDThe return value is a JSON object literal with string key-value pairs.
-
POST type/id
- set the content of the entity of the given type by its IDThe expected body is of the same format as the corresponding GET method. There is no return value.
-
DELETE type/id
- delete the note of the given type.There is no return value.
The app uses Playwright for E2E testing.
Run the tests using npm test
.
The test runner will start the app server itself.
We want to refresh it every once in a while, but every test run seems too much. Let's see if I can use the GitHub Actions cache to do this.
I got help making the AppleScript work for macOS 13: actions/runner-images#8214
This image is in beta though. I should find a way to do this in macOS 12 and only switch to macOS 13 once it it latest.
Maybe I should respect the semantics for POST
being for creating new items and
PUT
being for updating existing items and erroring if the item doesn't exist.
In this scenario, POST
would be a single-component path of just POST /type
and would automatically assign a unique ID or it could optionally have a
two-component path variant POST /type/id
with suggested ID (based on say a
friendly name) which would be checked for uniqueness.
PUT
would always require the ID: PUT /type/id
.
This will bring parity to ID-less multi-retrival at GET /type?full
.
It will be useful for building file-system-like experiences on top of the notes.
It should be accompanied with a method for creating a folder (different from
indirectly via GET /type
or GET /type?full
through ensureTypeFolder
) so
that the folder CRUD actions can be carried out end to end over the API.
I need to test this feature more as well, it seems kind of unreliable and I had trouble putting together the AppleScript for it. In some versions which I attempted to make slicker I would get seemingly racy errors, sometimes it would delete the notes successfully, sometimes it would error with unhelpful vague error messages. The current version when passed a set of IDs sometimes succeeds but doesn't actually seem to delete the notes? I might need to craft better AppleScript or add checks after the command with retry logic maybe?