pubky-app-specs 0.5.2 → 0.6.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.
- package/README.md +82 -331
- package/example.js +36 -12
- package/index.cjs +47 -3
- package/index.js +48 -4
- package/package.json +1 -1
- package/pubky_app_specs.d.ts +10 -1
- package/pubky_app_specs_bg.wasm +0 -0
- package/validationLimits.js +40 -1
- package/validationLimits.json +1 -1
package/README.md
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
#
|
|
1
|
+
# pubky-app-specs
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/pubky-app-specs)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
JavaScript and TypeScript bindings for Pubky.app data models, generated from the canonical Rust specs.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
- **Auto-ID’ed** and **Auto-Pathed** according to your domain rules.
|
|
10
|
-
- **Exported** to JavaScript/TypeScript with minimal overhead.
|
|
8
|
+
The package initializes WASM automatically, so no manual `.wasm` loading is required.
|
|
11
9
|
|
|
12
|
-
##
|
|
10
|
+
## Why Use This Package Instead of Manual JSONs?
|
|
13
11
|
|
|
14
12
|
- **Validation Consistency**: Ensures your app uses the same sanitization and validation rules as [Pubky indexers](https://github.com/pubky/pubky-nexus), avoiding errors.
|
|
15
13
|
- **Schema Versioning**: Automatically stay up-to-date with schema changes, reducing maintenance overhead.
|
|
@@ -17,257 +15,67 @@ A WASM library for building and validating structured JSON models compatible wit
|
|
|
17
15
|
- **Rust-to-JavaScript Compatibility**: Type-safe models that work seamlessly across Rust and JavaScript/TypeScript.
|
|
18
16
|
- **Future-Proof**: Easily adapt to new Pubky object types without rewriting JSON manually.
|
|
19
17
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
## ⚙️ Installation
|
|
18
|
+
## Installation
|
|
23
19
|
|
|
24
20
|
```bash
|
|
25
21
|
npm install pubky-app-specs
|
|
26
|
-
# or
|
|
27
|
-
yarn add pubky-app-specs
|
|
28
22
|
```
|
|
29
23
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
---
|
|
33
|
-
|
|
34
|
-
## 🚀 Quick Start
|
|
35
|
-
|
|
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
|
|
42
|
-
|
|
43
|
-
```js
|
|
44
|
-
// ES Modules
|
|
45
|
-
import { PubkySpecsBuilder } from "pubky-app-specs";
|
|
46
|
-
|
|
47
|
-
// OR CommonJS
|
|
48
|
-
const { PubkySpecsBuilder } = require("pubky-app-specs");
|
|
49
|
-
|
|
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
|
-
```
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
## 🎨 Example Usage
|
|
60
|
-
|
|
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).
|
|
62
|
-
|
|
63
|
-
### 1) Creating a New User
|
|
64
|
-
|
|
65
|
-
```js
|
|
66
|
-
import { Client, PublicKey } from "@synonymdev/pubky";
|
|
67
|
-
import { PubkySpecsBuilder } from "pubky-app-specs";
|
|
68
|
-
|
|
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.
|
|
84
|
-
|
|
85
|
-
// We bring the Rust object to JS using the .toJson() method.
|
|
86
|
-
const userJson = user.toJson();
|
|
87
|
-
|
|
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
|
-
});
|
|
94
|
-
|
|
95
|
-
if (!response.ok) {
|
|
96
|
-
throw new Error(`Failed to store user: ${response.statusText}`);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
console.log("User stored at:", meta.url);
|
|
100
|
-
return { user, meta };
|
|
101
|
-
}
|
|
102
|
-
```
|
|
103
|
-
|
|
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
|
-
```
|
|
134
|
-
|
|
135
|
-
### 3) Creating a Post with Attachments
|
|
136
|
-
|
|
137
|
-
```js
|
|
138
|
-
import { Client } from "@synonymdev/pubky";
|
|
139
|
-
import { PubkySpecsBuilder, PubkyAppPostKind } from "pubky-app-specs";
|
|
140
|
-
|
|
141
|
-
async function createPostWithAttachments(pubkyId, content, fileUrls) {
|
|
142
|
-
const client = new Client();
|
|
143
|
-
const specs = new PubkySpecsBuilder(pubkyId);
|
|
144
|
-
|
|
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 };
|
|
164
|
-
}
|
|
24
|
+
```bash
|
|
25
|
+
yarn add pubky-app-specs
|
|
165
26
|
```
|
|
166
27
|
|
|
167
|
-
|
|
28
|
+
## Quick Start
|
|
168
29
|
|
|
169
30
|
```js
|
|
170
|
-
import {
|
|
171
|
-
import { PubkySpecsBuilder } from "pubky-app-specs";
|
|
172
|
-
|
|
173
|
-
async function followUser(myPubkyId, userToFollow) {
|
|
174
|
-
const client = new Client();
|
|
175
|
-
const specs = new PubkySpecsBuilder(myPubkyId);
|
|
176
|
-
|
|
177
|
-
const { follow, meta } = specs.createFollow(userToFollow);
|
|
178
|
-
|
|
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
|
-
});
|
|
184
|
-
|
|
185
|
-
console.log(`Successfully followed: ${userToFollow}`);
|
|
186
|
-
}
|
|
187
|
-
```
|
|
31
|
+
import { PubkyAppPostKind, PubkySpecsBuilder } from "pubky-app-specs";
|
|
188
32
|
|
|
189
|
-
|
|
33
|
+
const pubkyId = "8kkppkmiubfq4pxn6f73nqrhhhgkb5xyfprntc9si3np9ydbotto";
|
|
34
|
+
const specs = new PubkySpecsBuilder(pubkyId);
|
|
190
35
|
|
|
191
|
-
|
|
36
|
+
const { user, meta: userMeta } = specs.createUser(
|
|
37
|
+
"Alice",
|
|
38
|
+
"Building on Pubky",
|
|
39
|
+
null,
|
|
40
|
+
null,
|
|
41
|
+
"active"
|
|
42
|
+
);
|
|
192
43
|
|
|
193
|
-
|
|
44
|
+
console.log(userMeta.url); // pubky://.../pub/pubky.app/profile.json
|
|
45
|
+
console.log(user.toJson());
|
|
194
46
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
- **Follows**: `createFollow(...)`
|
|
200
|
-
- **LastRead**: `createLastRead(...)`
|
|
201
|
-
- **Blobs**: `createBlob(...)`
|
|
202
|
-
- **Files**: `createFile(...)`
|
|
47
|
+
const { post, meta: postMeta } = specs.createPost(
|
|
48
|
+
"Hello, Pubky!",
|
|
49
|
+
PubkyAppPostKind.Short
|
|
50
|
+
);
|
|
203
51
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
### Creating a File with Blob
|
|
207
|
-
|
|
208
|
-
```js
|
|
209
|
-
import { Client } from "@synonymdev/pubky";
|
|
210
|
-
import { PubkySpecsBuilder, getValidMimeTypes } from "pubky-app-specs";
|
|
211
|
-
|
|
212
|
-
async function uploadFile(pubkyId, fileData, fileName, contentType, fileSize) {
|
|
213
|
-
const client = new Client();
|
|
214
|
-
const specs = new PubkySpecsBuilder(pubkyId);
|
|
215
|
-
|
|
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 };
|
|
239
|
-
}
|
|
52
|
+
console.log(postMeta.url);
|
|
53
|
+
console.log(post.toJson());
|
|
240
54
|
```
|
|
241
55
|
|
|
242
|
-
|
|
56
|
+
Each create method returns:
|
|
243
57
|
|
|
244
|
-
|
|
58
|
+
- `meta`: generated `id`, storage `path`, and full `url`
|
|
59
|
+
- a typed WASM model object with `.toJson()`
|
|
245
60
|
|
|
246
|
-
|
|
61
|
+
## Common Models
|
|
247
62
|
|
|
248
63
|
```js
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Example usage
|
|
261
|
-
if (isValidFileType(file.type)) {
|
|
262
|
-
// Proceed with upload
|
|
263
|
-
} else {
|
|
264
|
-
console.error(`Invalid file type: ${file.type}`);
|
|
265
|
-
}
|
|
64
|
+
const { user, meta } = specs.createUser(name, bio, image, links, status);
|
|
65
|
+
const { post, meta } = specs.createPost(content, kind, parent, embed, attachments, lock);
|
|
66
|
+
const { file, meta } = specs.createFile(name, src, contentType, size);
|
|
67
|
+
const { blob, meta } = specs.createBlob(bytes);
|
|
68
|
+
const { bookmark, meta } = specs.createBookmark(uri);
|
|
69
|
+
const { tag, meta } = specs.createTag(uri, label);
|
|
70
|
+
const { follow, meta } = specs.createFollow(pubkyId);
|
|
71
|
+
const { mute, meta } = specs.createMute(pubkyId);
|
|
72
|
+
const { feed, meta } = specs.createFeed(tags, reach, layout, sort, content, name);
|
|
73
|
+
const { last_read, meta } = specs.createLastRead();
|
|
266
74
|
```
|
|
267
75
|
|
|
268
|
-
|
|
76
|
+
For runnable examples covering posts, embeds, files, feeds, URI helpers, and MIME type validation, see [`example.js`](https://github.com/pubky/pubky-app-specs/blob/main/pkg/example.js).
|
|
269
77
|
|
|
270
|
-
|
|
78
|
+
## URI Helpers
|
|
271
79
|
|
|
272
80
|
```js
|
|
273
81
|
import {
|
|
@@ -281,129 +89,72 @@ import {
|
|
|
281
89
|
blobUriBuilder,
|
|
282
90
|
fileUriBuilder,
|
|
283
91
|
feedUriBuilder,
|
|
92
|
+
parse_uri,
|
|
284
93
|
} from "pubky-app-specs";
|
|
285
94
|
|
|
286
|
-
const
|
|
287
|
-
const
|
|
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
|
-
```
|
|
301
|
-
|
|
302
|
-
---
|
|
303
|
-
|
|
304
|
-
## 📌 Parsing a Pubky URI
|
|
305
|
-
|
|
306
|
-
The `parse_uri()` function converts a Pubky URI string into a strongly typed object.
|
|
95
|
+
const userUri = userUriBuilder(pubkyId);
|
|
96
|
+
const postUri = postUriBuilder(pubkyId, "0033SSE3B1FQ0");
|
|
97
|
+
const parsed = parse_uri(postUri);
|
|
307
98
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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
|
-
}
|
|
99
|
+
console.log(parsed.user_id);
|
|
100
|
+
console.log(parsed.resource);
|
|
101
|
+
console.log(parsed.resource_id);
|
|
321
102
|
```
|
|
322
103
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
A `ParsedUriResult` object with:
|
|
104
|
+
## Validation Limits
|
|
326
105
|
|
|
327
|
-
|
|
328
|
-
- **resource:** A string indicating the resource type.
|
|
329
|
-
- **resource_id:** An optional resource identifier.
|
|
330
|
-
|
|
331
|
-
---
|
|
332
|
-
|
|
333
|
-
## Validation limits
|
|
334
|
-
|
|
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.
|
|
337
|
-
|
|
338
|
-
### ✅ Recommended (no WASM)
|
|
339
|
-
|
|
340
|
-
**Named export from the package root:**
|
|
106
|
+
Validation limits are published as JSON so apps can reuse canonical limits without initializing WASM.
|
|
341
107
|
|
|
342
108
|
```js
|
|
343
|
-
import
|
|
109
|
+
import limits, {
|
|
110
|
+
getValidationLimits,
|
|
111
|
+
validationLimits,
|
|
112
|
+
} from "pubky-app-specs/validationLimits";
|
|
113
|
+
|
|
114
|
+
console.log(validationLimits.userNameMaxLength);
|
|
115
|
+
console.log(limits.postShortContentMaxLength);
|
|
344
116
|
|
|
345
|
-
console.log(validationLimits);
|
|
346
117
|
const copy = getValidationLimits();
|
|
347
118
|
```
|
|
348
119
|
|
|
349
|
-
|
|
120
|
+
For raw JSON imports:
|
|
350
121
|
|
|
351
122
|
```js
|
|
352
|
-
import limits from "pubky-app-specs/validationLimits";
|
|
353
|
-
// or
|
|
354
123
|
import limitsJson from "pubky-app-specs/validationLimits.json";
|
|
124
|
+
|
|
125
|
+
console.log(limitsJson.postAttachmentsMaxCount);
|
|
355
126
|
```
|
|
356
127
|
|
|
357
|
-
|
|
128
|
+
## MIME Types
|
|
358
129
|
|
|
359
130
|
```js
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
const
|
|
131
|
+
import { getValidMimeTypes } from "pubky-app-specs";
|
|
132
|
+
|
|
133
|
+
const validMimeTypes = getValidMimeTypes();
|
|
134
|
+
|
|
135
|
+
if (!validMimeTypes.includes(file.type)) {
|
|
136
|
+
throw new Error(`Unsupported file type: ${file.type}`);
|
|
137
|
+
}
|
|
363
138
|
```
|
|
364
139
|
|
|
365
|
-
|
|
140
|
+
## Specification
|
|
366
141
|
|
|
367
|
-
|
|
368
|
-
import { PubkySpecsBuilder, getValidationLimits } from "pubky-app-specs";
|
|
142
|
+
See the [full data model specification](https://github.com/pubky/pubky-app-specs/blob/main/SPEC.md) for URI layout, field rules, examples, and validation behavior.
|
|
369
143
|
|
|
370
|
-
|
|
144
|
+
## Building from Source
|
|
371
145
|
|
|
372
|
-
|
|
373
|
-
const limitsFromBuilder = builder.validationLimits;
|
|
374
|
-
```
|
|
146
|
+
Prerequisites: Rust, the `wasm32-unknown-unknown` target, [`wasm-pack`](https://rustwasm.github.io/wasm-pack/), and Node.js.
|
|
375
147
|
|
|
376
|
-
|
|
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
|
-
```
|
|
148
|
+
```bash
|
|
149
|
+
rustup target add wasm32-unknown-unknown
|
|
404
150
|
|
|
405
|
-
|
|
151
|
+
cd pkg
|
|
152
|
+
npm install
|
|
153
|
+
npm run build
|
|
154
|
+
npm run test
|
|
155
|
+
npm run example
|
|
156
|
+
```
|
|
406
157
|
|
|
407
|
-
##
|
|
158
|
+
## License
|
|
408
159
|
|
|
409
160
|
MIT
|
package/example.js
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
feedUriBuilder,
|
|
15
15
|
getValidMimeTypes,
|
|
16
16
|
} from "./index.js";
|
|
17
|
+
import { getValidationLimits, validationLimits } from "./validationLimits.js";
|
|
17
18
|
|
|
18
19
|
// =============================================================================
|
|
19
20
|
// ANSI color helpers for pretty output
|
|
@@ -30,6 +31,8 @@ const c = {
|
|
|
30
31
|
gray: "\x1b[90m",
|
|
31
32
|
white: "\x1b[37m",
|
|
32
33
|
bgBlue: "\x1b[44m",
|
|
34
|
+
bgGreen: "\x1b[42m",
|
|
35
|
+
black: "\x1b[30m",
|
|
33
36
|
};
|
|
34
37
|
|
|
35
38
|
const divider = () => console.log(c.gray + "─".repeat(70) + c.reset);
|
|
@@ -82,10 +85,7 @@ header("POSTS");
|
|
|
82
85
|
console.log(` ${c.yellow}▸ Simple Post${c.reset}`);
|
|
83
86
|
const { post, meta } = specsBuilder.createPost(
|
|
84
87
|
"Hello, Pubky world! This is my first post.",
|
|
85
|
-
PubkyAppPostKind.Short
|
|
86
|
-
null,
|
|
87
|
-
null,
|
|
88
|
-
null
|
|
88
|
+
PubkyAppPostKind.Short
|
|
89
89
|
);
|
|
90
90
|
field("ID", meta.id);
|
|
91
91
|
field("URL", meta.url);
|
|
@@ -97,9 +97,7 @@ console.log(` ${c.yellow}▸ Reply Post${c.reset}`);
|
|
|
97
97
|
const { post: replyPost, meta: replyMeta } = specsBuilder.createPost(
|
|
98
98
|
"This is a reply to the first post!",
|
|
99
99
|
PubkyAppPostKind.Short,
|
|
100
|
-
userMeta.url
|
|
101
|
-
null,
|
|
102
|
-
null
|
|
100
|
+
userMeta.url
|
|
103
101
|
);
|
|
104
102
|
field("ID", replyMeta.id);
|
|
105
103
|
field("Parent", replyPost.toJson().parent);
|
|
@@ -115,8 +113,7 @@ const { post: repost, meta: repostMeta } = specsBuilder.createPost(
|
|
|
115
113
|
"Check out this awesome video!",
|
|
116
114
|
PubkyAppPostKind.Short,
|
|
117
115
|
null,
|
|
118
|
-
embed
|
|
119
|
-
null
|
|
116
|
+
embed
|
|
120
117
|
);
|
|
121
118
|
field("ID", repostMeta.id);
|
|
122
119
|
field("Embed URI", repost.toJson().embed.uri);
|
|
@@ -137,6 +134,22 @@ const { post: postWithAttachments, meta: postWithAttachmentsMeta } = specsBuilde
|
|
|
137
134
|
);
|
|
138
135
|
field("ID", postWithAttachmentsMeta.id);
|
|
139
136
|
field("Attachments", `${postWithAttachments.toJson().attachments.length} files`);
|
|
137
|
+
console.log();
|
|
138
|
+
|
|
139
|
+
// Locked post (gated behind a lock server)
|
|
140
|
+
console.log(` ${c.yellow}▸ Locked Post${c.reset}`);
|
|
141
|
+
const lockUrl = `pubky://${RIO}/pub/locks/0034A0X7NJ52G`;
|
|
142
|
+
const { post: lockedPost, meta: lockedPostMeta } = specsBuilder.createPost(
|
|
143
|
+
"We were reckless adopting Lightning without understanding the tradeoffs.",
|
|
144
|
+
PubkyAppPostKind.Long,
|
|
145
|
+
null,
|
|
146
|
+
null,
|
|
147
|
+
null,
|
|
148
|
+
lockUrl
|
|
149
|
+
);
|
|
150
|
+
field("ID", lockedPostMeta.id);
|
|
151
|
+
field("Content", lockedPost.toJson().content);
|
|
152
|
+
field("Lock", lockedPost.lock);
|
|
140
153
|
|
|
141
154
|
// =============================================================================
|
|
142
155
|
// 3. Social Actions
|
|
@@ -285,11 +298,22 @@ testTypes.forEach(type => {
|
|
|
285
298
|
console.log(` ${icon} ${type}`);
|
|
286
299
|
});
|
|
287
300
|
|
|
301
|
+
// =============================================================================
|
|
302
|
+
// 8. Validation Limits
|
|
303
|
+
// =============================================================================
|
|
304
|
+
header("VALIDATION LIMITS");
|
|
305
|
+
const limitsCopy = getValidationLimits();
|
|
306
|
+
|
|
307
|
+
field("User name max", validationLimits.userNameMaxLength);
|
|
308
|
+
field("Short post max", validationLimits.postShortContentMaxLength);
|
|
309
|
+
field("Max attachments", validationLimits.postAttachmentsMaxCount);
|
|
310
|
+
field("Copy matches", JSON.stringify(limitsCopy) === JSON.stringify(validationLimits));
|
|
311
|
+
|
|
288
312
|
// =============================================================================
|
|
289
313
|
// Done!
|
|
290
314
|
// =============================================================================
|
|
291
315
|
console.log();
|
|
292
|
-
console.log(`${c.
|
|
293
|
-
console.log(`${c.
|
|
294
|
-
console.log(`${c.
|
|
316
|
+
console.log(`${c.bgGreen}${c.black}${c.bright} ${c.reset}`);
|
|
317
|
+
console.log(`${c.bgGreen}${c.black}${c.bright} ALL EXAMPLES COMPLETED SUCCESSFULLY! ${c.reset}`);
|
|
318
|
+
console.log(`${c.bgGreen}${c.black}${c.bright} ${c.reset}`);
|
|
295
319
|
console.log();
|
package/index.cjs
CHANGED
|
@@ -743,12 +743,13 @@ exports.PubkyAppFeedConfig = PubkyAppFeedConfig;
|
|
|
743
743
|
|
|
744
744
|
/**
|
|
745
745
|
* Enum representing the layout of the feed.
|
|
746
|
-
* @enum {0 | 1 | 2}
|
|
746
|
+
* @enum {0 | 1 | 2 | 3}
|
|
747
747
|
*/
|
|
748
748
|
const PubkyAppFeedLayout = Object.freeze({
|
|
749
749
|
Columns: 0, "0": "Columns",
|
|
750
750
|
Wide: 1, "1": "Wide",
|
|
751
751
|
Visual: 2, "2": "Visual",
|
|
752
|
+
List: 3, "3": "List",
|
|
752
753
|
});
|
|
753
754
|
exports.PubkyAppFeedLayout = PubkyAppFeedLayout;
|
|
754
755
|
|
|
@@ -1170,6 +1171,18 @@ class PubkyAppPost {
|
|
|
1170
1171
|
wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
|
|
1171
1172
|
}
|
|
1172
1173
|
}
|
|
1174
|
+
/**
|
|
1175
|
+
* @returns {string | undefined}
|
|
1176
|
+
*/
|
|
1177
|
+
get lock() {
|
|
1178
|
+
const ret = wasm.pubkyapppost_lock(this.__wbg_ptr);
|
|
1179
|
+
let v1;
|
|
1180
|
+
if (ret[0] !== 0) {
|
|
1181
|
+
v1 = getStringFromWasm0(ret[0], ret[1]).slice();
|
|
1182
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
|
|
1183
|
+
}
|
|
1184
|
+
return v1;
|
|
1185
|
+
}
|
|
1173
1186
|
/**
|
|
1174
1187
|
* Creates a new `PubkyAppPost` instance and sanitizes it.
|
|
1175
1188
|
* @param {string} content
|
|
@@ -1195,6 +1208,33 @@ class PubkyAppPost {
|
|
|
1195
1208
|
PubkyAppPostFinalization.register(this, this.__wbg_ptr, this);
|
|
1196
1209
|
return this;
|
|
1197
1210
|
}
|
|
1211
|
+
/**
|
|
1212
|
+
* Creates a new lockable `PubkyAppPost` instance and sanitizes it.
|
|
1213
|
+
* @param {string} content
|
|
1214
|
+
* @param {PubkyAppPostKind} kind
|
|
1215
|
+
* @param {string | null} [parent]
|
|
1216
|
+
* @param {PubkyAppPostEmbed | null} [embed]
|
|
1217
|
+
* @param {string[] | null} [attachments]
|
|
1218
|
+
* @param {string | null} [lock]
|
|
1219
|
+
* @returns {PubkyAppPost}
|
|
1220
|
+
*/
|
|
1221
|
+
static new_with_lock(content, kind, parent, embed, attachments, lock) {
|
|
1222
|
+
const ptr0 = passStringToWasm0(content, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
1223
|
+
const len0 = WASM_VECTOR_LEN;
|
|
1224
|
+
var ptr1 = isLikeNone(parent) ? 0 : passStringToWasm0(parent, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
1225
|
+
var len1 = WASM_VECTOR_LEN;
|
|
1226
|
+
let ptr2 = 0;
|
|
1227
|
+
if (!isLikeNone(embed)) {
|
|
1228
|
+
_assertClass(embed, PubkyAppPostEmbed);
|
|
1229
|
+
ptr2 = embed.__destroy_into_raw();
|
|
1230
|
+
}
|
|
1231
|
+
var ptr3 = isLikeNone(attachments) ? 0 : passArrayJsValueToWasm0(attachments, wasm.__wbindgen_malloc);
|
|
1232
|
+
var len3 = WASM_VECTOR_LEN;
|
|
1233
|
+
var ptr4 = isLikeNone(lock) ? 0 : passStringToWasm0(lock, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
1234
|
+
var len4 = WASM_VECTOR_LEN;
|
|
1235
|
+
const ret = wasm.pubkyapppost_new_with_lock(ptr0, len0, kind, ptr1, len1, ptr2, ptr3, len3, ptr4, len4);
|
|
1236
|
+
return PubkyAppPost.__wrap(ret);
|
|
1237
|
+
}
|
|
1198
1238
|
/**
|
|
1199
1239
|
* @returns {string | undefined}
|
|
1200
1240
|
*/
|
|
@@ -1784,14 +1824,16 @@ class PubkySpecsBuilder {
|
|
|
1784
1824
|
return MuteResult.__wrap(ret[0]);
|
|
1785
1825
|
}
|
|
1786
1826
|
/**
|
|
1827
|
+
* Optional `lock`: `pubky://` URL with a host pointing at a lock server.
|
|
1787
1828
|
* @param {string} content
|
|
1788
1829
|
* @param {PubkyAppPostKind} kind
|
|
1789
1830
|
* @param {string | null} [parent]
|
|
1790
1831
|
* @param {PubkyAppPostEmbed | null} [embed]
|
|
1791
1832
|
* @param {string[] | null} [attachments]
|
|
1833
|
+
* @param {string | null} [lock]
|
|
1792
1834
|
* @returns {PostResult}
|
|
1793
1835
|
*/
|
|
1794
|
-
createPost(content, kind, parent, embed, attachments) {
|
|
1836
|
+
createPost(content, kind, parent, embed, attachments, lock) {
|
|
1795
1837
|
const ptr0 = passStringToWasm0(content, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
1796
1838
|
const len0 = WASM_VECTOR_LEN;
|
|
1797
1839
|
var ptr1 = isLikeNone(parent) ? 0 : passStringToWasm0(parent, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
@@ -1803,7 +1845,9 @@ class PubkySpecsBuilder {
|
|
|
1803
1845
|
}
|
|
1804
1846
|
var ptr3 = isLikeNone(attachments) ? 0 : passArrayJsValueToWasm0(attachments, wasm.__wbindgen_malloc);
|
|
1805
1847
|
var len3 = WASM_VECTOR_LEN;
|
|
1806
|
-
|
|
1848
|
+
var ptr4 = isLikeNone(lock) ? 0 : passStringToWasm0(lock, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
1849
|
+
var len4 = WASM_VECTOR_LEN;
|
|
1850
|
+
const ret = wasm.pubkyspecsbuilder_createPost(this.__wbg_ptr, ptr0, len0, kind, ptr1, len1, ptr2, ptr3, len3, ptr4, len4);
|
|
1807
1851
|
if (ret[2]) {
|
|
1808
1852
|
throw takeFromExternrefTable0(ret[1]);
|
|
1809
1853
|
}
|