wiki-plugin-shoppe 0.0.20 → 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/CLAUDE.md CHANGED
@@ -68,6 +68,16 @@ my-shoppe.zip
68
68
  01-T-Shirt/ ← numeric prefix sets display order
69
69
  hero.jpg ← main product image (hero.jpg or hero.png)
70
70
  info.json
71
+ appointments/
72
+ Therapy Session/ ← subfolder per bookable service
73
+ cover.jpg ← optional cover image
74
+ info.json ← required (see format below)
75
+ subscriptions/
76
+ Bronze Tier/ ← subfolder per membership tier
77
+ cover.jpg ← optional cover image
78
+ info.json ← required (see format below)
79
+ bonus-track.mp3 ← any other files become exclusive member content
80
+ chapter-draft.pdf
71
81
  ```
72
82
 
73
83
  ### manifest.json
@@ -141,6 +151,43 @@ preview = "ocean.jpg"
141
151
 
142
152
  The hero image is resolved automatically: `hero.jpg` or `hero.png` is used if present, otherwise the first image in the folder. Folder numeric prefix (`01-`, `02-`, …) sets display order.
143
153
 
154
+ ### appointments/*/info.json
155
+
156
+ ```json
157
+ {
158
+ "title": "60-Minute Therapy Session",
159
+ "description": "One-on-one counseling",
160
+ "price": 15000,
161
+ "duration": 60,
162
+ "timezone": "America/New_York",
163
+ "advanceDays": 30,
164
+ "availability": [
165
+ { "day": "Monday", "slots": ["09:00", "10:00", "11:00", "14:00", "15:00"] },
166
+ { "day": "Wednesday", "slots": ["09:00", "10:00", "14:00"] }
167
+ ]
168
+ }
169
+ ```
170
+
171
+ `price` is in cents. `duration` is minutes per slot. `timezone` is any IANA timezone string. `advanceDays` limits how far ahead slots are shown. `availability` lists days of the week with start times for each slot.
172
+
173
+ ### subscriptions/*/info.json
174
+
175
+ ```json
176
+ {
177
+ "title": "Bronze Supporter",
178
+ "description": "Support the work and get exclusive content",
179
+ "price": 500,
180
+ "renewalDays": 30,
181
+ "benefits": [
182
+ "Early access to new releases",
183
+ "Monthly exclusive track",
184
+ "Name in credits"
185
+ ]
186
+ }
187
+ ```
188
+
189
+ `price` is in cents per period. `renewalDays` is the billing period length (default 30). `benefits` are bullet points shown on the subscribe page. All non-`info.json`, non-image files in the subfolder are uploaded as exclusive artifacts downloadable by active subscribers.
190
+
144
191
  ## Routes
145
192
 
146
193
  | Method | Path | Auth | Description |
@@ -151,6 +198,15 @@ The hero image is resolved automatically: `hero.jpg` or `hero.png` is used if pr
151
198
  | `GET` | `/plugin/shoppe/:id` | Public | Shoppe HTML page |
152
199
  | `GET` | `/plugin/shoppe/:id/goods` | Public | Goods JSON |
153
200
  | `GET` | `/plugin/shoppe/:id/goods?category=books` | Public | Filtered goods JSON |
201
+ | `GET` | `/plugin/shoppe/:id/book/:title` | Public | Appointment booking page |
202
+ | `GET` | `/plugin/shoppe/:id/book/:title/slots` | Public | Available slots JSON |
203
+ | `GET` | `/plugin/shoppe/:id/subscribe/:title` | Public | Subscription sign-up page |
204
+ | `GET` | `/plugin/shoppe/:id/membership` | Public | Membership portal |
205
+ | `POST` | `/plugin/shoppe/:id/membership/check` | Public | Check subscription status |
206
+ | `POST` | `/plugin/shoppe/:id/purchase/intent` | Public | Create Stripe payment intent |
207
+ | `POST` | `/plugin/shoppe/:id/purchase/complete` | Public | Record completed purchase |
208
+ | `GET` | `/plugin/shoppe/:id/download/:title` | Public | Ebook download page |
209
+ | `GET` | `/plugin/shoppe/:id/post/:title` | Public | Post reader |
154
210
 
155
211
  `:id` accepts either UUID or emojicode.
156
212
 
package/client/shoppe.js CHANGED
@@ -239,11 +239,13 @@
239
239
 
240
240
  const r = result.results;
241
241
  const counts = [
242
- r.books.length && `📚 ${r.books.length} book${r.books.length !== 1 ? 's' : ''}`,
243
- r.music.length && `🎵 ${r.music.length} music item${r.music.length !== 1 ? 's' : ''}`,
244
- r.posts.length && `📝 ${r.posts.length} post${r.posts.length !== 1 ? 's' : ''}`,
245
- r.albums.length && `🖼️ ${r.albums.length} album${r.albums.length !== 1 ? 's' : ''}`,
246
- r.products.length && `📦 ${r.products.length} product${r.products.length !== 1 ? 's' : ''}`
242
+ r.books.length && `📚 ${r.books.length} book${r.books.length !== 1 ? 's' : ''}`,
243
+ r.music.length && `🎵 ${r.music.length} music item${r.music.length !== 1 ? 's' : ''}`,
244
+ r.posts.length && `📝 ${r.posts.length} post${r.posts.length !== 1 ? 's' : ''}`,
245
+ r.albums.length && `🖼️ ${r.albums.length} album${r.albums.length !== 1 ? 's' : ''}`,
246
+ r.products.length && `📦 ${r.products.length} product${r.products.length !== 1 ? 's' : ''}`,
247
+ r.appointments && r.appointments.length && `📅 ${r.appointments.length} appointment${r.appointments.length !== 1 ? 's' : ''}`,
248
+ r.subscriptions && r.subscriptions.length && `🎁 ${r.subscriptions.length} subscription tier${r.subscriptions.length !== 1 ? 's' : ''}`
247
249
  ].filter(Boolean).join(' · ') || 'no items found';
248
250
 
249
251
  const warnings = (r.warnings && r.warnings.length > 0)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wiki-plugin-shoppe",
3
- "version": "0.0.20",
3
+ "version": "0.0.21",
4
4
  "description": "Multi-tenant digital goods shoppe for federated wiki, powered by Sanora",
5
5
  "keywords": [
6
6
  "wiki",
@@ -15,7 +15,11 @@
15
15
  "type": "commonjs",
16
16
  "main": "index.js",
17
17
  "scripts": {
18
- "test": "echo \"Error: no test specified\" && exit 1"
18
+ "test": "mocha test/test.js --timeout 30000 --exit"
19
+ },
20
+ "devDependencies": {
21
+ "chai": "^4.5.0",
22
+ "mocha": "^10.8.2"
19
23
  },
20
24
  "dependencies": {
21
25
  "adm-zip": "^0.5.10",