freshjots 0.2.1 → 0.3.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.
- checksums.yaml +4 -4
- data/README.md +12 -5
- data/lib/freshjots/version.rb +1 -1
- data/lib/freshjots.rb +59 -2
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7674ef20013fb9165dcc54d15c0f7b1b99c4ec1967a11e3646d5b72ed605ff3b
|
|
4
|
+
data.tar.gz: d4663a22426bfcf413a48d0d0e5b00c12d08d291ed388c9cbc5dcac33f4b98d1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bb91c405637119e815517dec72db163c65d3a3b58b317cd51fd156eb3fccf08a3967547a8b661fbb3c7c4477756844b4ad08d7e07463df4435ec21a8f0c297b4
|
|
7
|
+
data.tar.gz: 8f240df1b1b9bb8d69aa0d294e74efa2ae47bfcafa980488fd898bbb368e02016acf96cb97aec9d187848f0f4ec8a815682e73043dfa7448c52a066926f2643c
|
data/README.md
CHANGED
|
@@ -34,16 +34,23 @@ client.append("cron-jobs-prod", "backup ok #{Time.now.utc.iso8601}")
|
|
|
34
34
|
# Read a note's body.
|
|
35
35
|
puts client.note("cron-jobs-prod")[:plain_body]
|
|
36
36
|
|
|
37
|
-
# List your notes.
|
|
38
|
-
client.notes.each
|
|
37
|
+
# List your notes (most recent activity first). Sort and filter with options:
|
|
38
|
+
client.notes(sort: "created", folder_id: 3, limit: 20).each do |note|
|
|
39
|
+
puts "#{note[:id]}\t#{note[:filename]}\t#{note[:title]}"
|
|
40
|
+
end
|
|
39
41
|
|
|
40
42
|
# Create a note. The API derives the filename from the title — for a
|
|
41
43
|
# note addressable by an exact filename, use append instead.
|
|
42
44
|
created = client.create(title: "Research 2026 Q2", body: "Initial outline.")
|
|
43
45
|
puts created[:filename] # server-derived stream name
|
|
46
|
+
|
|
47
|
+
# Organize: move into a folder (by id or name), delete (by id or filename), list folders.
|
|
48
|
+
client.move("cron-jobs-prod", folder: "Ops")
|
|
49
|
+
client.delete("old-note")
|
|
50
|
+
client.folders.each { |f| puts "#{f[:id]}\t#{f[:name]}" }
|
|
44
51
|
```
|
|
45
52
|
|
|
46
|
-
|
|
53
|
+
Client methods: `notes(sort:, folder_id:, limit:, offset:)`, `note(filename)`, `note_by_id(id)`, `create(title:, body:)`, `append(filename, text)`, `delete(id_or_filename)`, `move(id_or_filename, folder:)`, and `folders`. `note`/`note_by_id`/`create` return the note hash directly (no `{ note: … }` wrapper); `notes` and `folders` return arrays. For `notes`, `sort` is `created|updated|appended` and `folder_id` may be a folder id or `"none"` (un-foldered only).
|
|
47
54
|
|
|
48
55
|
## Errors
|
|
49
56
|
|
|
@@ -67,8 +74,8 @@ Stable error codes: `unauthenticated`, `forbidden`, `not_found`,
|
|
|
67
74
|
|
|
68
75
|
## Auth
|
|
69
76
|
|
|
70
|
-
Mint a token at <https://freshjots.com/settings/api_tokens> (
|
|
71
|
-
|
|
77
|
+
Mint a token at <https://freshjots.com/settings/api_tokens> (Pro or
|
|
78
|
+
Team tier required). Set it once:
|
|
72
79
|
|
|
73
80
|
```sh
|
|
74
81
|
export FRESHJOTS_TOKEN=<your-token>
|
data/lib/freshjots/version.rb
CHANGED
data/lib/freshjots.rb
CHANGED
|
@@ -40,8 +40,18 @@ module Freshjots
|
|
|
40
40
|
@token, @base_url = token, base_url
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
# List notes (summary projection). Keyword options mirror the API
|
|
44
|
+
# query params: sort (created|updated|appended, default updated),
|
|
45
|
+
# folder_id (a folder id, or "none" for un-foldered notes only), and
|
|
46
|
+
# limit/offset for pagination (the server caps a page at 200).
|
|
47
|
+
def notes(sort: nil, folder_id: nil, limit: nil, offset: nil)
|
|
48
|
+
query = {}
|
|
49
|
+
query[:sort] = sort if sort
|
|
50
|
+
query[:folder_id] = folder_id unless folder_id.nil? || folder_id.to_s.empty?
|
|
51
|
+
query[:limit] = limit unless limit.nil?
|
|
52
|
+
query[:offset] = offset unless offset.nil?
|
|
53
|
+
path = query.empty? ? "/notes" : "/notes?#{URI.encode_www_form(query)}"
|
|
54
|
+
request(:get, path)[:notes]
|
|
45
55
|
end
|
|
46
56
|
|
|
47
57
|
# show-by-filename renders the serializer at the top level (no
|
|
@@ -50,6 +60,11 @@ module Freshjots
|
|
|
50
60
|
request(:get, "/notes/by-filename/#{escape(filename)}")
|
|
51
61
|
end
|
|
52
62
|
|
|
63
|
+
# Full note by numeric id (GET /notes/:id) — top-level serializer.
|
|
64
|
+
def note_by_id(id)
|
|
65
|
+
request(:get, "/notes/#{escape(id)}")
|
|
66
|
+
end
|
|
67
|
+
|
|
53
68
|
# Create a note. The API permits note[title, plain_body, format, ...]
|
|
54
69
|
# — NOT filename: the server DERIVES the filename from the title. For
|
|
55
70
|
# a note addressable by an exact, caller-chosen filename, use append
|
|
@@ -71,8 +86,50 @@ module Freshjots
|
|
|
71
86
|
true
|
|
72
87
|
end
|
|
73
88
|
|
|
89
|
+
# Delete a note. Accepts a numeric id or a filename (resolved to its
|
|
90
|
+
# id via the by-filename lookup). Locked (append-only) notes are
|
|
91
|
+
# refused by the API with note_locked. Returns true on success.
|
|
92
|
+
def delete(id_or_filename)
|
|
93
|
+
request(:delete, "/notes/#{resolve_note_id(id_or_filename)}")
|
|
94
|
+
true
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Move a note into a folder. `folder` may be a folder id, a folder
|
|
98
|
+
# name (resolved via /folders), or nil / "none" / "root" to send the
|
|
99
|
+
# note back to the root.
|
|
100
|
+
def move(id_or_filename, folder: nil)
|
|
101
|
+
id = resolve_note_id(id_or_filename)
|
|
102
|
+
request(:post, "/notes/#{id}/move", { folder_id: resolve_folder_id(folder) })
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# List folders ({ folders: [...] } envelope).
|
|
106
|
+
def folders
|
|
107
|
+
request(:get, "/folders")[:folders]
|
|
108
|
+
end
|
|
109
|
+
|
|
74
110
|
private
|
|
75
111
|
|
|
112
|
+
# A note reference is either a numeric id (used as-is) or a
|
|
113
|
+
# filename/title resolved to an id via the by-filename lookup.
|
|
114
|
+
def resolve_note_id(value)
|
|
115
|
+
return value if value.is_a?(Integer) || value.to_s.match?(/\A\d+\z/)
|
|
116
|
+
|
|
117
|
+
note(value.to_s)[:id]
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# A folder reference resolves to an id (or nil for the root). Names go
|
|
121
|
+
# through /folders; an unknown or ambiguous name is an ArgumentError.
|
|
122
|
+
def resolve_folder_id(value)
|
|
123
|
+
return nil if value.nil? || %w[none root null].include?(value.to_s.downcase)
|
|
124
|
+
return value if value.is_a?(Integer) || value.to_s.match?(/\A\d+\z/)
|
|
125
|
+
|
|
126
|
+
matches = folders.select { |f| f[:name] == value.to_s }
|
|
127
|
+
raise ArgumentError, "no folder named '#{value}'" if matches.empty?
|
|
128
|
+
raise ArgumentError, "ambiguous folder name '#{value}' — use its id" if matches.size > 1
|
|
129
|
+
|
|
130
|
+
matches.first[:id]
|
|
131
|
+
end
|
|
132
|
+
|
|
76
133
|
def request(method, path, body = nil)
|
|
77
134
|
uri = URI("#{@base_url}#{path}")
|
|
78
135
|
req = Net::HTTP.const_get(method.to_s.capitalize).new(uri)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: freshjots
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Goran Arsov
|
|
@@ -10,7 +10,7 @@ cert_chain: []
|
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies: []
|
|
12
12
|
description: Append-only notebooks for cron jobs, deploy scripts, and bots. Wraps
|
|
13
|
-
the
|
|
13
|
+
the plain-text REST API at freshjots.com/api/v1.
|
|
14
14
|
email:
|
|
15
15
|
- arsphy@yahoo.com
|
|
16
16
|
executables: []
|