pubky-app-specs 0.5.0 → 0.5.1-rc1
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/README.md +321 -166
- package/example.js +295 -0
- package/index.js +2889 -0
- package/package.json +52 -11
- package/pubky_app_specs_bg.wasm +0 -0
- package/validationLimits.cjs +9 -0
- package/validationLimits.js +5 -0
- package/validationLimits.json +40 -0
- /package/{pubky_app_specs.js → index.cjs} +0 -0
package/README.md
CHANGED
|
@@ -1,254 +1,409 @@
|
|
|
1
|
-
# Pubky
|
|
1
|
+
# Pubky App Specs · `pubky-app-specs`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/pubky-app-specs)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
> This specification is in an **early development phase** and is evolving quickly. Expect frequent changes and updates as the system matures. Consider this a **v0 draft**.
|
|
7
|
-
>
|
|
8
|
-
> When we reach the first stable, long-term support version of the schemas, paths will adopt the format: `pubky.app/v1/` to indicate compatibility and stability.
|
|
6
|
+
A WASM library for building and validating structured JSON models compatible with Pubky.App social powered by [`@synonymdev/pubky`](https://www.npmjs.com/package/@synonymdev/pubky). It handles domain objects like **Users**, **Posts**, **Feeds**, **Bookmarks**, **Tags**, and more. Each object is:
|
|
9
7
|
|
|
10
|
-
|
|
8
|
+
- **Sanitized** and **Validated** via Rust logic.
|
|
9
|
+
- **Auto-ID’ed** and **Auto-Pathed** according to your domain rules.
|
|
10
|
+
- **Exported** to JavaScript/TypeScript with minimal overhead.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
## 🤔 Why Use This Crate Instead of [Manual JSONs](https://github.com/pubky/pubky-app-specs?tab=readme-ov-file#data-models)?
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
- **Validation Consistency**: Ensures your app uses the same sanitization and validation rules as [Pubky indexers](https://github.com/pubky/pubky-nexus), avoiding errors.
|
|
15
|
+
- **Schema Versioning**: Automatically stay up-to-date with schema changes, reducing maintenance overhead.
|
|
16
|
+
- **Auto IDs & Paths**: Generates unique IDs, paths, and URLs according to Pubky standards.
|
|
17
|
+
- **Rust-to-JavaScript Compatibility**: Type-safe models that work seamlessly across Rust and JavaScript/TypeScript.
|
|
18
|
+
- **Future-Proof**: Easily adapt to new Pubky object types without rewriting JSON manually.
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
cd pkg
|
|
23
|
-
npm run install
|
|
24
|
-
npm run test
|
|
25
|
-
```
|
|
20
|
+
---
|
|
26
21
|
|
|
27
|
-
|
|
22
|
+
## ⚙️ Installation
|
|
28
23
|
|
|
29
24
|
```bash
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
npm install pubky-app-specs
|
|
26
|
+
# or
|
|
27
|
+
yarn add pubky-app-specs
|
|
32
28
|
```
|
|
33
29
|
|
|
30
|
+
> **Note**: This package uses WASM with embedded bytes for automatic initialization. No manual WASM loading required - just import and use!
|
|
31
|
+
|
|
34
32
|
---
|
|
35
33
|
|
|
36
|
-
##
|
|
37
|
-
|
|
38
|
-
- [Pubky.app Data Model Specification](#pubkyapp-data-model-specification)
|
|
39
|
-
- [JS package](#js-package)
|
|
40
|
-
- [Table of Contents](#table-of-contents)
|
|
41
|
-
- [Introduction](#introduction)
|
|
42
|
-
- [Quick Start](#quick-start)
|
|
43
|
-
- [Concepts:](#concepts)
|
|
44
|
-
- [Data Models](#data-models)
|
|
45
|
-
- [PubkyAppUser](#pubkyappuser)
|
|
46
|
-
- [PubkyAppFile](#pubkyappfile)
|
|
47
|
-
- [PubkyAppPost](#pubkyapppost)
|
|
48
|
-
- [PubkyAppTag](#pubkyapptag)
|
|
49
|
-
- [PubkyAppBookmark](#pubkyappbookmark)
|
|
50
|
-
- [PubkyAppFollow](#pubkyappfollow)
|
|
51
|
-
- [PubkyAppFeed](#pubkyappfeed)
|
|
52
|
-
- [Validation Rules](#validation-rules)
|
|
53
|
-
- [Common Rules](#common-rules)
|
|
54
|
-
- [License](#license)
|
|
34
|
+
## 🚀 Quick Start
|
|
55
35
|
|
|
56
|
-
|
|
36
|
+
1. **Import** the library.
|
|
37
|
+
2. **Construct** a `PubkySpecsBuilder(pubkyId)` object.
|
|
38
|
+
3. **Create** validated domain objects (User, Post, Tag, etc.).
|
|
39
|
+
4. **Store** them on the [PubKy homeserver](https://github.com/synonymdev/pubky) or any distributed storage solution you prefer.
|
|
40
|
+
|
|
41
|
+
### Import & Usage
|
|
57
42
|
|
|
58
|
-
|
|
43
|
+
```js
|
|
44
|
+
// ES Modules
|
|
45
|
+
import { PubkySpecsBuilder } from "pubky-app-specs";
|
|
59
46
|
|
|
60
|
-
|
|
47
|
+
// OR CommonJS
|
|
48
|
+
const { PubkySpecsBuilder } = require("pubky-app-specs");
|
|
61
49
|
|
|
62
|
-
|
|
50
|
+
function loadSpecs(pubkyId) {
|
|
51
|
+
// Create a specs builder instance - WASM is already initialized
|
|
52
|
+
const specs = new PubkySpecsBuilder(pubkyId);
|
|
53
|
+
return specs;
|
|
54
|
+
}
|
|
55
|
+
```
|
|
63
56
|
|
|
64
57
|
---
|
|
65
58
|
|
|
66
|
-
##
|
|
59
|
+
## 🎨 Example Usage
|
|
67
60
|
|
|
68
|
-
|
|
61
|
+
Below are **succinct** examples to illustrate how to create or update data using **`pubky-app-specs`** and then **store** it with [`@synonymdev/pubky`](https://www.npmjs.com/package/@synonymdev/pubky).
|
|
69
62
|
|
|
70
|
-
###
|
|
63
|
+
### 1) Creating a New User
|
|
71
64
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
65
|
+
```js
|
|
66
|
+
import { Client, PublicKey } from "@synonymdev/pubky";
|
|
67
|
+
import { PubkySpecsBuilder } from "pubky-app-specs";
|
|
75
68
|
|
|
76
|
-
|
|
69
|
+
async function createUser(pubkyId) {
|
|
70
|
+
const client = new Client();
|
|
71
|
+
const specs = new PubkySpecsBuilder(pubkyId);
|
|
72
|
+
|
|
73
|
+
// Create user object with minimal fields
|
|
74
|
+
const { user, meta } = specs.createUser(
|
|
75
|
+
"Alice", // Name
|
|
76
|
+
"Hello from WASM", // Bio
|
|
77
|
+
null, // Image URL or File
|
|
78
|
+
null, // Links
|
|
79
|
+
"active", // Status
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
// meta contains { id, path, url }.
|
|
83
|
+
// user is the Rust "PubkyAppUser" object.
|
|
77
84
|
|
|
78
|
-
|
|
85
|
+
// We bring the Rust object to JS using the .toJson() method.
|
|
86
|
+
const userJson = user.toJson();
|
|
79
87
|
|
|
80
|
-
|
|
88
|
+
// Store in homeserver via pubky
|
|
89
|
+
const response = await client.fetch(meta.url, {
|
|
90
|
+
method: "PUT",
|
|
91
|
+
body: JSON.stringify(userJson),
|
|
92
|
+
credentials: "include",
|
|
93
|
+
});
|
|
81
94
|
|
|
82
|
-
|
|
95
|
+
if (!response.ok) {
|
|
96
|
+
throw new Error(`Failed to store user: ${response.statusText}`);
|
|
97
|
+
}
|
|
83
98
|
|
|
84
|
-
|
|
99
|
+
console.log("User stored at:", meta.url);
|
|
100
|
+
return { user, meta };
|
|
101
|
+
}
|
|
102
|
+
```
|
|
85
103
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
104
|
+
### 2) Creating a Post
|
|
105
|
+
|
|
106
|
+
```js
|
|
107
|
+
import { Client } from "@synonymdev/pubky";
|
|
108
|
+
import { PubkySpecsBuilder, PubkyAppPostKind } from "pubky-app-specs";
|
|
109
|
+
|
|
110
|
+
async function createPost(pubkyId, content) {
|
|
111
|
+
const client = new Client();
|
|
112
|
+
const specs = new PubkySpecsBuilder(pubkyId);
|
|
113
|
+
|
|
114
|
+
// Create the Post object
|
|
115
|
+
const { post, meta } = specs.createPost(
|
|
116
|
+
content,
|
|
117
|
+
PubkyAppPostKind.Short,
|
|
118
|
+
null, // parent post URI (for replies)
|
|
119
|
+
null, // embed object (for reposts)
|
|
120
|
+
null, // attachments (array of file URLs, max 3)
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
// Store the post
|
|
124
|
+
const postJson = post.toJson();
|
|
125
|
+
await client.fetch(meta.url, {
|
|
126
|
+
method: "PUT",
|
|
127
|
+
body: JSON.stringify(postJson),
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
console.log("Post stored at:", meta.url);
|
|
131
|
+
return { post, meta };
|
|
132
|
+
}
|
|
133
|
+
```
|
|
93
134
|
|
|
94
|
-
|
|
135
|
+
### 3) Creating a Post with Attachments
|
|
95
136
|
|
|
96
|
-
|
|
97
|
-
|
|
137
|
+
```js
|
|
138
|
+
import { Client } from "@synonymdev/pubky";
|
|
139
|
+
import { PubkySpecsBuilder, PubkyAppPostKind } from "pubky-app-specs";
|
|
98
140
|
|
|
99
|
-
|
|
141
|
+
async function createPostWithAttachments(pubkyId, content, fileUrls) {
|
|
142
|
+
const client = new Client();
|
|
143
|
+
const specs = new PubkySpecsBuilder(pubkyId);
|
|
100
144
|
|
|
101
|
-
|
|
102
|
-
{
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
145
|
+
// Create post with attachments (max 3 allowed)
|
|
146
|
+
const { post, meta } = specs.createPost(
|
|
147
|
+
content,
|
|
148
|
+
PubkyAppPostKind.Image,
|
|
149
|
+
null, // parent
|
|
150
|
+
null, // embed
|
|
151
|
+
fileUrls, // e.g. ["pubky://user/pub/pubky.app/files/abc123"]
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
const postJson = post.toJson();
|
|
155
|
+
console.log("Attachments:", postJson.attachments);
|
|
156
|
+
|
|
157
|
+
await client.fetch(meta.url, {
|
|
158
|
+
method: "PUT",
|
|
159
|
+
body: JSON.stringify(postJson),
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
console.log("Post with attachments stored at:", meta.url);
|
|
163
|
+
return { post, meta };
|
|
113
164
|
}
|
|
114
165
|
```
|
|
115
166
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
### PubkyAppFile
|
|
167
|
+
### 4) Following a User
|
|
119
168
|
|
|
120
|
-
|
|
169
|
+
```js
|
|
170
|
+
import { Client } from "@synonymdev/pubky";
|
|
171
|
+
import { PubkySpecsBuilder } from "pubky-app-specs";
|
|
121
172
|
|
|
122
|
-
|
|
173
|
+
async function followUser(myPubkyId, userToFollow) {
|
|
174
|
+
const client = new Client();
|
|
175
|
+
const specs = new PubkySpecsBuilder(myPubkyId);
|
|
123
176
|
|
|
124
|
-
|
|
125
|
-
| -------------- | -------- | --------------------------- | ---------------------------------------------- |
|
|
126
|
-
| `name` | String | Name of the file. | Required. Must be 1-255 characters |
|
|
127
|
-
| `created_at` | Integer | Unix timestamp of creation. | Required. |
|
|
128
|
-
| `src` | String | File blob URL | Required. must be a valid URL. Max length 1024 |
|
|
129
|
-
| `content_type` | String | MIME type of the file. | Required. Valid IANA mime types |
|
|
130
|
-
| `size` | Integer | Size of the file in bytes. | Required. Positive integer. Max size is 10Mb |
|
|
177
|
+
const { follow, meta } = specs.createFollow(userToFollow);
|
|
131
178
|
|
|
132
|
-
|
|
179
|
+
// We only need to store the JSON in the homeserver
|
|
180
|
+
await client.fetch(meta.url, {
|
|
181
|
+
method: "PUT",
|
|
182
|
+
body: JSON.stringify(follow.toJson()),
|
|
183
|
+
});
|
|
133
184
|
|
|
134
|
-
|
|
185
|
+
console.log(`Successfully followed: ${userToFollow}`);
|
|
186
|
+
}
|
|
187
|
+
```
|
|
135
188
|
|
|
136
189
|
---
|
|
137
190
|
|
|
138
|
-
|
|
191
|
+
## 📁 Additional Models
|
|
139
192
|
|
|
140
|
-
|
|
193
|
+
This library supports many more domain objects beyond `User` and `Post`. Here are a few more you can explore:
|
|
141
194
|
|
|
142
|
-
**
|
|
195
|
+
- **Feeds**: `createFeed(...)`
|
|
196
|
+
- **Bookmarks**: `createBookmark(...)`
|
|
197
|
+
- **Tags**: `createTag(...)`
|
|
198
|
+
- **Mutes**: `createMute(...)`
|
|
199
|
+
- **Follows**: `createFollow(...)`
|
|
200
|
+
- **LastRead**: `createLastRead(...)`
|
|
201
|
+
- **Blobs**: `createBlob(...)`
|
|
202
|
+
- **Files**: `createFile(...)`
|
|
143
203
|
|
|
144
|
-
|
|
145
|
-
| ------------- | -------- | ------------------------------------ | -------------------------------------------------------------------------- |
|
|
146
|
-
| `content` | String | Content of the post. | Required. Max length: 2000 (short), 50000 (long). Cannot be `"[DELETED]"`. |
|
|
147
|
-
| `kind` | String | Type of post. | Required. Must be a valid `PubkyAppPostKind` value. |
|
|
148
|
-
| `parent` | String | URI of the parent post (if a reply). | Optional. Must be a valid URI if present. |
|
|
149
|
-
| `embed` | Object | Reposted content (type + URI). | Optional. URI must be valid if present. |
|
|
150
|
-
| `attachments` | Array | List of attachment URIs. | Optional. Each must be a valid URI. |
|
|
204
|
+
Each has a `meta` field for storing relevant IDs/paths and a typed data object.
|
|
151
205
|
|
|
152
|
-
|
|
206
|
+
### Creating a File with Blob
|
|
153
207
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
-
|
|
157
|
-
- `video`
|
|
158
|
-
- `link`
|
|
159
|
-
- `file`
|
|
208
|
+
```js
|
|
209
|
+
import { Client } from "@synonymdev/pubky";
|
|
210
|
+
import { PubkySpecsBuilder, getValidMimeTypes } from "pubky-app-specs";
|
|
160
211
|
|
|
161
|
-
|
|
212
|
+
async function uploadFile(pubkyId, fileData, fileName, contentType, fileSize) {
|
|
213
|
+
const client = new Client();
|
|
214
|
+
const specs = new PubkySpecsBuilder(pubkyId);
|
|
162
215
|
|
|
163
|
-
|
|
164
|
-
{
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
216
|
+
// First, create and store the blob (raw binary data)
|
|
217
|
+
const { blob, meta: blobMeta } = specs.createBlob(fileData);
|
|
218
|
+
|
|
219
|
+
await client.fetch(blobMeta.url, {
|
|
220
|
+
method: "PUT",
|
|
221
|
+
body: JSON.stringify(blob.toJson()),
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// Then create the file metadata pointing to the blob
|
|
225
|
+
const { file, meta: fileMeta } = specs.createFile(
|
|
226
|
+
fileName, // e.g. "vacation-photo.jpg"
|
|
227
|
+
blobMeta.url, // Reference to the blob
|
|
228
|
+
contentType, // e.g. "image/jpeg"
|
|
229
|
+
fileSize, // Size in bytes
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
await client.fetch(fileMeta.url, {
|
|
233
|
+
method: "PUT",
|
|
234
|
+
body: JSON.stringify(file.toJson()),
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
console.log("File stored at:", fileMeta.url);
|
|
238
|
+
return { file, meta: fileMeta };
|
|
173
239
|
}
|
|
174
240
|
```
|
|
175
241
|
|
|
176
242
|
---
|
|
177
243
|
|
|
178
|
-
|
|
244
|
+
## ✅ Validating File MIME Types
|
|
245
|
+
|
|
246
|
+
Use `getValidMimeTypes()` to get the list of allowed MIME types for file attachments. This helps validate files before upload without duplicating the validation list.
|
|
179
247
|
|
|
180
|
-
|
|
248
|
+
```js
|
|
249
|
+
import { getValidMimeTypes } from "pubky-app-specs";
|
|
181
250
|
|
|
182
|
-
|
|
251
|
+
// Get the list of valid MIME types
|
|
252
|
+
const validMimeTypes = getValidMimeTypes();
|
|
253
|
+
// Returns: ["application/javascript", "application/json", "application/pdf", "image/png", ...]
|
|
183
254
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
| `created_at` | Integer | Unix timestamp of creation. | Required. |
|
|
255
|
+
// Validate a file before upload
|
|
256
|
+
function isValidFileType(mimeType) {
|
|
257
|
+
return validMimeTypes.includes(mimeType);
|
|
258
|
+
}
|
|
189
259
|
|
|
190
|
-
|
|
260
|
+
// Example usage
|
|
261
|
+
if (isValidFileType(file.type)) {
|
|
262
|
+
// Proceed with upload
|
|
263
|
+
} else {
|
|
264
|
+
console.error(`Invalid file type: ${file.type}`);
|
|
265
|
+
}
|
|
266
|
+
```
|
|
191
267
|
|
|
192
|
-
|
|
268
|
+
## 🔗 URI Builder Utilities
|
|
269
|
+
|
|
270
|
+
These helper functions construct properly formatted Pubky URIs:
|
|
271
|
+
|
|
272
|
+
```js
|
|
273
|
+
import {
|
|
274
|
+
userUriBuilder,
|
|
275
|
+
postUriBuilder,
|
|
276
|
+
bookmarkUriBuilder,
|
|
277
|
+
followUriBuilder,
|
|
278
|
+
tagUriBuilder,
|
|
279
|
+
muteUriBuilder,
|
|
280
|
+
lastReadUriBuilder,
|
|
281
|
+
blobUriBuilder,
|
|
282
|
+
fileUriBuilder,
|
|
283
|
+
feedUriBuilder,
|
|
284
|
+
} from "pubky-app-specs";
|
|
285
|
+
|
|
286
|
+
const userId = "8kkppkmiubfq4pxn6f73nqrhhhgkb5xyfprntc9si3np9ydbotto";
|
|
287
|
+
const targetUserId = "dzswkfy7ek3bqnoc89jxuqqfbzhjrj6mi8qthgbxxcqkdugm3rio";
|
|
288
|
+
|
|
289
|
+
// Build URIs for different resources
|
|
290
|
+
userUriBuilder(userId); // pubky://{userId}/pub/pubky.app/profile.json
|
|
291
|
+
postUriBuilder(userId, "0033SSE3B1FQ0"); // pubky://{userId}/pub/pubky.app/posts/{postId}
|
|
292
|
+
bookmarkUriBuilder(userId, "ABC123"); // pubky://{userId}/pub/pubky.app/bookmarks/{bookmarkId}
|
|
293
|
+
followUriBuilder(userId, targetUserId); // pubky://{userId}/pub/pubky.app/follows/{targetUserId}
|
|
294
|
+
tagUriBuilder(userId, "XYZ789"); // pubky://{userId}/pub/pubky.app/tags/{tagId}
|
|
295
|
+
muteUriBuilder(userId, targetUserId); // pubky://{userId}/pub/pubky.app/mutes/{targetUserId}
|
|
296
|
+
lastReadUriBuilder(userId); // pubky://{userId}/pub/pubky.app/last_read
|
|
297
|
+
blobUriBuilder(userId, "BLOB123"); // pubky://{userId}/pub/pubky.app/blobs/{blobId}
|
|
298
|
+
fileUriBuilder(userId, "FILE456"); // pubky://{userId}/pub/pubky.app/files/{fileId}
|
|
299
|
+
feedUriBuilder(userId, "FEED789"); // pubky://{userId}/pub/pubky.app/feeds/{feedId}
|
|
300
|
+
```
|
|
193
301
|
|
|
194
302
|
---
|
|
195
303
|
|
|
196
|
-
|
|
304
|
+
## 📌 Parsing a Pubky URI
|
|
305
|
+
|
|
306
|
+
The `parse_uri()` function converts a Pubky URI string into a strongly typed object.
|
|
197
307
|
|
|
198
|
-
**
|
|
308
|
+
**Usage:**
|
|
199
309
|
|
|
200
|
-
|
|
310
|
+
```js
|
|
311
|
+
import { parse_uri } from "pubky-app-specs";
|
|
312
|
+
|
|
313
|
+
try {
|
|
314
|
+
const result = parse_uri("pubky://userID/pub/pubky.app/posts/postID");
|
|
315
|
+
console.log(result.user_id); // "userID"
|
|
316
|
+
console.log(result.resource); // e.g. "posts"
|
|
317
|
+
console.log(result.resource_id); // "postID" or null
|
|
318
|
+
} catch (error) {
|
|
319
|
+
console.error("URI parse error:", error);
|
|
320
|
+
}
|
|
321
|
+
```
|
|
201
322
|
|
|
202
|
-
|
|
203
|
-
| ------------ | -------- | ---------------------- | ------------------------------ |
|
|
204
|
-
| `uri` | String | URI of the bookmark. | Required. Must be a valid URI. |
|
|
205
|
-
| `created_at` | Integer | Timestamp of creation. | Required. |
|
|
323
|
+
**Returns:**
|
|
206
324
|
|
|
207
|
-
|
|
325
|
+
A `ParsedUriResult` object with:
|
|
208
326
|
|
|
209
|
-
-
|
|
327
|
+
- **user_id:** The parsed user identifier.
|
|
328
|
+
- **resource:** A string indicating the resource type.
|
|
329
|
+
- **resource_id:** An optional resource identifier.
|
|
210
330
|
|
|
211
331
|
---
|
|
212
332
|
|
|
213
|
-
|
|
333
|
+
## Validation limits
|
|
214
334
|
|
|
215
|
-
|
|
335
|
+
Validation limits are published as JSON so UIs and tests can reuse the
|
|
336
|
+
canonical rules without WASM, plus optional WASM accessors when needed.
|
|
216
337
|
|
|
217
|
-
|
|
338
|
+
### ✅ Recommended (no WASM)
|
|
218
339
|
|
|
219
|
-
|
|
220
|
-
| ------------ | -------- | ---------------------- | -------------------- |
|
|
221
|
-
| `created_at` | Integer | Timestamp of creation. | Required. |
|
|
340
|
+
**Named export from the package root:**
|
|
222
341
|
|
|
223
|
-
|
|
342
|
+
```js
|
|
343
|
+
import { validationLimits, getValidationLimits } from "pubky-app-specs";
|
|
224
344
|
|
|
225
|
-
|
|
345
|
+
console.log(validationLimits);
|
|
346
|
+
const copy = getValidationLimits();
|
|
347
|
+
```
|
|
226
348
|
|
|
227
|
-
**
|
|
349
|
+
**Direct subpath import (ESM):**
|
|
228
350
|
|
|
229
|
-
|
|
351
|
+
```js
|
|
352
|
+
import limits from "pubky-app-specs/validationLimits";
|
|
353
|
+
// or
|
|
354
|
+
import limitsJson from "pubky-app-specs/validationLimits.json";
|
|
355
|
+
```
|
|
230
356
|
|
|
231
|
-
|
|
232
|
-
| --------- | -------- | ----------------------------------------- | ---------------------------------- |
|
|
233
|
-
| `tags` | Array | List of tags for filtering. | Optional. Strings must be trimmed. |
|
|
234
|
-
| `reach` | String | Feed visibility (e.g., `all`, `friends`). | Required. Must be a valid reach. |
|
|
235
|
-
| `layout` | String | Feed layout style (e.g., `columns`). | Required. Must be valid layout. |
|
|
236
|
-
| `sort` | String | Sort order (e.g., `recent`). | Required. Must be valid sort. |
|
|
237
|
-
| `content` | String | Type of content filtered. | Optional. |
|
|
238
|
-
| `name` | String | Name of the feed. | Required. |
|
|
357
|
+
**Direct subpath import (CJS):**
|
|
239
358
|
|
|
240
|
-
|
|
359
|
+
```js
|
|
360
|
+
const { validationLimits, getValidationLimits } = require("pubky-app-specs");
|
|
361
|
+
// or
|
|
362
|
+
const limits = require("pubky-app-specs/validationLimits");
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### WASM accessors
|
|
241
366
|
|
|
242
|
-
|
|
367
|
+
```js
|
|
368
|
+
import { PubkySpecsBuilder, getValidationLimits } from "pubky-app-specs";
|
|
243
369
|
|
|
244
|
-
|
|
370
|
+
const limitsFromWasm = getValidationLimits();
|
|
245
371
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
372
|
+
const builder = new PubkySpecsBuilder("pubky_id_here");
|
|
373
|
+
const limitsFromBuilder = builder.validationLimits;
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Example output shape:
|
|
377
|
+
|
|
378
|
+
```json
|
|
379
|
+
{
|
|
380
|
+
"maxBlobSizeBytes": 104857600,
|
|
381
|
+
"maxFileSizeBytes": 104857600,
|
|
382
|
+
"tagLabelMinLength": 1,
|
|
383
|
+
"tagLabelMaxLength": 20,
|
|
384
|
+
"tagInvalidChars": [",", ":", " ", "\t", "\n", "\r"],
|
|
385
|
+
"userNameMinLength": 3,
|
|
386
|
+
"userNameMaxLength": 50,
|
|
387
|
+
"userBioMaxLength": 160,
|
|
388
|
+
"userImageUrlMaxLength": 300,
|
|
389
|
+
"userLinksMaxCount": 5,
|
|
390
|
+
"userLinkTitleMaxLength": 100,
|
|
391
|
+
"userLinkUrlMaxLength": 300,
|
|
392
|
+
"userStatusMaxLength": 50,
|
|
393
|
+
"postShortContentMaxLength": 2000,
|
|
394
|
+
"postLongContentMaxLength": 50000,
|
|
395
|
+
"postAttachmentsMaxCount": 4,
|
|
396
|
+
"postAttachmentUrlMaxLength": 200,
|
|
397
|
+
"postAllowedAttachmentProtocols": ["pubky", "http", "https"],
|
|
398
|
+
"fileNameMinLength": 1,
|
|
399
|
+
"fileNameMaxLength": 255,
|
|
400
|
+
"fileSrcMaxLength": 1024,
|
|
401
|
+
"feedTagsMaxCount": 5
|
|
402
|
+
}
|
|
403
|
+
```
|
|
249
404
|
|
|
250
405
|
---
|
|
251
406
|
|
|
252
|
-
## License
|
|
407
|
+
## 📄 License
|
|
253
408
|
|
|
254
|
-
|
|
409
|
+
MIT
|