Add README and API docs

This commit is contained in:
Râu Cao 2026-01-26 19:20:54 +07:00
parent 713efb81b5
commit bc5eea7841
Signed by: raucao
GPG Key ID: 37036C356E56CC51
9 changed files with 510 additions and 3 deletions

44
README.md Normal file
View File

@ -0,0 +1,44 @@
# @remotestorage/module-places
This module allows you to manage saved places (Points of Interest) using the [remoteStorage](https://remotestorage.io/) protocol.
## Installation
```bash
pnpm add @remotestorage/module-places
```
## Usage
```javascript
import RemoteStorage from 'remotestoragejs';
import PlacesModule from '@remotestorage/module-places';
const remoteStorage = new RemoteStorage({
modules: [PlacesModule],
});
// Access the module
const places = remoteStorage.places;
// Store a place
await places.store({
title: 'My Favorite Coffee Shop',
lat: 52.520008,
lon: 13.404954,
});
// List all places
const allPlaces = await places.getPlaces();
console.log(allPlaces);
```
## API Reference
### Interfaces
- [PlacesClient](docs/interfaces/PlacesClient.md)
### Type Aliases
- [Place](docs/type-aliases/Place.md)

17
docs/README.md Normal file
View File

@ -0,0 +1,17 @@
**@remotestorage/module-places**
***
# @remotestorage/module-places
## Interfaces
- [PlacesClient](interfaces/PlacesClient.md)
## Type Aliases
- [Place](type-aliases/Place.md)
## Variables
- [default](variables/default.md)

View File

@ -0,0 +1,135 @@
[**@remotestorage/module-places**](../README.md)
***
[@remotestorage/module-places](../README.md) / PlacesClient
# Interface: PlacesClient
## Methods
### get()
> **get**(`id`, `geohash`): `Promise`\<`unknown`\>
Get a single place.
Requires geohash to locate the folder.
#### Parameters
##### id
`string`
The ID of the place to retrieve.
##### geohash
`string`
The geohash of the place.
#### Returns
`Promise`\<`unknown`\>
The place object.
***
### getPlaces()
> **getPlaces**(`prefixes?`): `Promise`\<[`Place`](../type-aliases/Place.md)[]\>
Get places from specific prefixes.
#### Parameters
##### prefixes?
`string`[]
Optional array of 4-character geohash prefixes to load (e.g. ['w1q7', 'w1q8']).
If not provided, it will attempt to scan ALL prefixes (recursive).
#### Returns
`Promise`\<[`Place`](../type-aliases/Place.md)[]\>
An array of places.
***
### listByPrefix()
> **listByPrefix**(`prefix`): `Promise`\<`unknown`\>
List places matching a geohash prefix.
Supports 2-char ("ab") or 4-char ("abcd") prefixes.
If 2-char, it returns the sub-folders (prefixes), not places.
If 4-char, it returns the places in that sector.
#### Parameters
##### prefix
`string`
The geohash prefix to filter by.
#### Returns
`Promise`\<`unknown`\>
A map of objects found at the prefix.
***
### remove()
> **remove**(`id`, `geohash`): `Promise`\<`unknown`\>
Remove a place.
Requires geohash to locate the folder.
#### Parameters
##### id
`string`
The ID of the place to remove.
##### geohash
`string`
The geohash of the place.
#### Returns
`Promise`\<`unknown`\>
***
### store()
> **store**(`placeData`): `Promise`\<[`Place`](../type-aliases/Place.md)\>
Store a place.
Generates ID and Geohash if missing.
Path structure: <geohash-prefix-2>/<geohash-prefix-2>/<id>
#### Parameters
##### placeData
`Partial`\<[`Place`](../type-aliases/Place.md)\>
The data of the place to store.
#### Returns
`Promise`\<[`Place`](../type-aliases/Place.md)\>
The stored place object.

View File

@ -0,0 +1,27 @@
[**@remotestorage/module-places**](../README.md)
***
[@remotestorage/module-places](../README.md) / Place
# Type Alias: Place
> **Place** = `FromSchema`\<*typeof* `placeSchema`\> & `object`
Represents a Place object.
Core properties enforced by schema:
- `id`: Unique identifier (ULID)
- `title`: Name of the place
- `lat`: Latitude
- `lon`: Longitude
- `geohash`: Geohash for indexing
- `createdAt`: ISO date string
Optional properties:
- `description`: Text description
- `zoom`: Map zoom level
- `url`: Related URL
- `osmId`, `osmType`, `osmTags`: OpenStreetMap data
- `tags`: Array of string tags
- `updatedAt`: ISO date string

33
docs/variables/default.md Normal file
View File

@ -0,0 +1,33 @@
[**@remotestorage/module-places**](../README.md)
***
[@remotestorage/module-places](../README.md) / default
# Variable: default
> **default**: `object`
## Type Declaration
### builder()
> **builder**: (`privateClient`) => `object` = `Places`
#### Parameters
##### privateClient
`BaseClient`
#### Returns
`object`
##### exports
> **exports**: [`PlacesClient`](../interfaces/PlacesClient.md)
### name
> **name**: `string` = `'places'`

View File

@ -10,8 +10,9 @@
],
"scripts": {
"build": "rimraf dist && tsc",
"doc": "typedoc",
"test": "echo \"Error: no test specified\" && exit 1",
"version": "pnpm run build && git add dist"
"version": "pnpm run build && pnpm run doc && git add dist docs README.md"
},
"author": "Râu Cao <raucao@kosmos.org>",
"license": "MIT",
@ -19,6 +20,8 @@
"json-schema-to-ts": "^3.1.1",
"remotestoragejs": "^2.0.0-beta.8",
"rimraf": "^6.1.2",
"typedoc": "^0.28.16",
"typedoc-plugin-markdown": "^4.9.0",
"typescript": "^5.9.3"
},
"dependencies": {

169
pnpm-lock.yaml generated
View File

@ -24,6 +24,12 @@ importers:
rimraf:
specifier: ^6.1.2
version: 6.1.2
typedoc:
specifier: ^0.28.16
version: 0.28.16(typescript@5.9.3)
typedoc-plugin-markdown:
specifier: ^4.9.0
version: 4.9.0(typedoc@0.28.16(typescript@5.9.3))
typescript:
specifier: ^5.9.3
version: 5.9.3
@ -34,6 +40,9 @@ packages:
resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==}
engines: {node: '>=6.9.0'}
'@gerrit0/mini-shiki@3.21.0':
resolution: {integrity: sha512-9PrsT5DjZA+w3lur/aOIx3FlDeHdyCEFlv9U+fmsVyjPZh61G5SYURQ/1ebe2U63KbDmI2V8IhIUegWb8hjOyg==}
'@isaacs/balanced-match@4.0.1':
resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==}
engines: {node: 20 || >=22}
@ -42,12 +51,46 @@ packages:
resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==}
engines: {node: 20 || >=22}
'@shikijs/engine-oniguruma@3.21.0':
resolution: {integrity: sha512-OYknTCct6qiwpQDqDdf3iedRdzj6hFlOPv5hMvI+hkWfCKs5mlJ4TXziBG9nyabLwGulrUjHiCq3xCspSzErYQ==}
'@shikijs/langs@3.21.0':
resolution: {integrity: sha512-g6mn5m+Y6GBJ4wxmBYqalK9Sp0CFkUqfNzUy2pJglUginz6ZpWbaWjDB4fbQ/8SHzFjYbtU6Ddlp1pc+PPNDVA==}
'@shikijs/themes@3.21.0':
resolution: {integrity: sha512-BAE4cr9EDiZyYzwIHEk7JTBJ9CzlPuM4PchfcA5ao1dWXb25nv6hYsoDiBq2aZK9E3dlt3WB78uI96UESD+8Mw==}
'@shikijs/types@3.21.0':
resolution: {integrity: sha512-zGrWOxZ0/+0ovPY7PvBU2gIS9tmhSUUt30jAcNV0Bq0gb2S98gwfjIs1vxlmH5zM7/4YxLamT6ChlqqAJmPPjA==}
'@shikijs/vscode-textmate@10.0.2':
resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
'@types/hast@3.0.4':
resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
'@types/node@20.14.0':
resolution: {integrity: sha512-5cHBxFGJx6L4s56Bubp4fglrEpmyJypsqI6RgzMfBHWUJQGWAAi8cWcgetEbZXHYXo9C2Fa4EEds/uSyS4cxmA==}
'@types/tv4@1.2.33':
resolution: {integrity: sha512-7phCVTXC6Bj50IV1iKOwqGkR4JONJyMbRZnKTSuujv1S/tO9rG5OdCt7BMSjytO+zJmYdn1/I4fd3SH0gtO99g==}
'@types/unist@3.0.3':
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
brace-expansion@2.0.2:
resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
entities@4.5.0:
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
engines: {node: '>=0.12'}
esm@3.2.25:
resolution: {integrity: sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==}
engines: {node: '>=6'}
@ -68,14 +111,31 @@ packages:
latlon-geohash@2.0.0:
resolution: {integrity: sha512-OKBswTwrvTdtenV+9C9euBmvgGuqyjJNAzpQCarRz1m8/pYD2nz9fKkXmLs2S3jeXaLi3Ry76twQplKKUlgS/g==}
linkify-it@5.0.0:
resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==}
lru-cache@11.2.4:
resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==}
engines: {node: 20 || >=22}
lunr@2.3.9:
resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==}
markdown-it@14.1.0:
resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==}
hasBin: true
mdurl@2.0.0:
resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==}
minimatch@10.1.1:
resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==}
engines: {node: 20 || >=22}
minimatch@9.0.5:
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
engines: {node: '>=16 || 14 >=14.17'}
minipass@7.1.2:
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
engines: {node: '>=16 || 14 >=14.17'}
@ -87,6 +147,10 @@ packages:
resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==}
engines: {node: 20 || >=22}
punycode.js@2.3.1:
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
engines: {node: '>=6'}
remotestoragejs@2.0.0-beta.8:
resolution: {integrity: sha512-rtyHTG2VbtiKTRmbwjponRf5VTPJMcHv/ijNid1zX48C0Z0F8ZCBBfkKD2QCxTQyQvCupkWNy3wuIu4HE+AEng==}
@ -102,11 +166,27 @@ packages:
resolution: {integrity: sha512-afizzfpJgvPr+eDkREK4MxJ/+r8nEEHcmitwgnPUqpaP+FpwQyadnxNoSACbgc/b1LsZYtODGoPiFxQrgJgjvw==}
engines: {node: '>= 0.8.0'}
typedoc-plugin-markdown@4.9.0:
resolution: {integrity: sha512-9Uu4WR9L7ZBgAl60N/h+jqmPxxvnC9nQAlnnO/OujtG2ubjnKTVUFY1XDhcMY+pCqlX3N2HsQM2QTYZIU9tJuw==}
engines: {node: '>= 18'}
peerDependencies:
typedoc: 0.28.x
typedoc@0.28.16:
resolution: {integrity: sha512-x4xW77QC3i5DUFMBp0qjukOTnr/sSg+oEs86nB3LjDslvAmwe/PUGDWbe3GrIqt59oTqoXK5GRK9tAa0sYMiog==}
engines: {node: '>= 18', pnpm: '>= 10'}
hasBin: true
peerDependencies:
typescript: 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x
typescript@5.9.3:
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
engines: {node: '>=14.17'}
hasBin: true
uc.micro@2.1.0:
resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
ulid@3.0.2:
resolution: {integrity: sha512-yu26mwteFYzBAot7KVMqFGCVpsF6g8wXfJzQUHvu1no3+rRRSFcSV2nKeYvNPLD2J4b08jYBDhHUjeH0ygIl9w==}
hasBin: true
@ -121,22 +201,71 @@ packages:
resolution: {integrity: sha512-sID0rrVCqkVNUn8t6xuv9+6FViXjUVXq8H5rWOH2rz9fDNQEd4g0EA2XlcEdJXRz5BMEn4O1pJFdT+z4YHhoWw==}
engines: {node: '>= 6'}
yaml@2.8.2:
resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==}
engines: {node: '>= 14.6'}
hasBin: true
snapshots:
'@babel/runtime@7.28.6': {}
'@gerrit0/mini-shiki@3.21.0':
dependencies:
'@shikijs/engine-oniguruma': 3.21.0
'@shikijs/langs': 3.21.0
'@shikijs/themes': 3.21.0
'@shikijs/types': 3.21.0
'@shikijs/vscode-textmate': 10.0.2
'@isaacs/balanced-match@4.0.1': {}
'@isaacs/brace-expansion@5.0.0':
dependencies:
'@isaacs/balanced-match': 4.0.1
'@shikijs/engine-oniguruma@3.21.0':
dependencies:
'@shikijs/types': 3.21.0
'@shikijs/vscode-textmate': 10.0.2
'@shikijs/langs@3.21.0':
dependencies:
'@shikijs/types': 3.21.0
'@shikijs/themes@3.21.0':
dependencies:
'@shikijs/types': 3.21.0
'@shikijs/types@3.21.0':
dependencies:
'@shikijs/vscode-textmate': 10.0.2
'@types/hast': 3.0.4
'@shikijs/vscode-textmate@10.0.2': {}
'@types/hast@3.0.4':
dependencies:
'@types/unist': 3.0.3
'@types/node@20.14.0':
dependencies:
undici-types: 5.26.5
'@types/tv4@1.2.33': {}
'@types/unist@3.0.3': {}
argparse@2.0.1: {}
balanced-match@1.0.2: {}
brace-expansion@2.0.2:
dependencies:
balanced-match: 1.0.2
entities@4.5.0: {}
esm@3.2.25: {}
fsevents@2.3.3:
@ -155,12 +284,33 @@ snapshots:
latlon-geohash@2.0.0: {}
linkify-it@5.0.0:
dependencies:
uc.micro: 2.1.0
lru-cache@11.2.4: {}
lunr@2.3.9: {}
markdown-it@14.1.0:
dependencies:
argparse: 2.0.1
entities: 4.5.0
linkify-it: 5.0.0
mdurl: 2.0.0
punycode.js: 2.3.1
uc.micro: 2.1.0
mdurl@2.0.0: {}
minimatch@10.1.1:
dependencies:
'@isaacs/brace-expansion': 5.0.0
minimatch@9.0.5:
dependencies:
brace-expansion: 2.0.2
minipass@7.1.2: {}
package-json-from-dist@1.0.1: {}
@ -170,6 +320,8 @@ snapshots:
lru-cache: 11.2.4
minipass: 7.1.2
punycode.js@2.3.1: {}
remotestoragejs@2.0.0-beta.8:
dependencies:
'@types/node': 20.14.0
@ -190,8 +342,23 @@ snapshots:
tv4@1.3.0: {}
typedoc-plugin-markdown@4.9.0(typedoc@0.28.16(typescript@5.9.3)):
dependencies:
typedoc: 0.28.16(typescript@5.9.3)
typedoc@0.28.16(typescript@5.9.3):
dependencies:
'@gerrit0/mini-shiki': 3.21.0
lunr: 2.3.9
markdown-it: 14.1.0
minimatch: 9.0.5
typescript: 5.9.3
yaml: 2.8.2
typescript@5.9.3: {}
uc.micro@2.1.0: {}
ulid@3.0.2: {}
undici-types@5.26.5: {}
@ -199,3 +366,5 @@ snapshots:
webfinger.js@2.8.2: {}
xhr2@0.2.1: {}
yaml@2.8.2: {}

View File

@ -31,11 +31,81 @@ const placeSchema = {
required: ['id', 'title', 'lat', 'lon', 'geohash', 'createdAt'],
} as const;
type Place = FromSchema<typeof placeSchema> & { [key: string]: any };
/**
* Represents a Place object.
*
* Core properties enforced by schema:
* - `id`: Unique identifier (ULID)
* - `title`: Name of the place
* - `lat`: Latitude
* - `lon`: Longitude
* - `geohash`: Geohash for indexing
* - `createdAt`: ISO date string
*
* Optional properties:
* - `description`: Text description
* - `zoom`: Map zoom level
* - `url`: Related URL
* - `osmId`, `osmType`, `osmTags`: OpenStreetMap data
* - `tags`: Array of string tags
* - `updatedAt`: ISO date string
*/
export type Place = FromSchema<typeof placeSchema> & { [key: string]: any };
export interface PlacesClient {
/**
* Store a place.
* Generates ID and Geohash if missing.
* Path structure: <geohash-prefix-2>/<geohash-prefix-2>/<id>
*
* @param placeData - The data of the place to store.
* @returns The stored place object.
*/
store(placeData: Partial<Place>): Promise<Place>;
/**
* Remove a place.
* Requires geohash to locate the folder.
*
* @param id - The ID of the place to remove.
* @param geohash - The geohash of the place.
*/
remove(id: string, geohash: string): Promise<unknown>;
/**
* Get a single place.
* Requires geohash to locate the folder.
*
* @param id - The ID of the place to retrieve.
* @param geohash - The geohash of the place.
* @returns The place object.
*/
get(id: string, geohash: string): Promise<Place | unknown>;
/**
* List places matching a geohash prefix.
* Supports 2-char ("ab") or 4-char ("abcd") prefixes.
* If 2-char, it returns the sub-folders (prefixes), not places.
* If 4-char, it returns the places in that sector.
*
* @param prefix - The geohash prefix to filter by.
* @returns A map of objects found at the prefix.
*/
listByPrefix(prefix: string): Promise<unknown | { [key: string]: any }>;
/**
* Get places from specific prefixes.
*
* @param prefixes - Optional array of 4-character geohash prefixes to load (e.g. ['w1q7', 'w1q8']).
* If not provided, it will attempt to scan ALL prefixes (recursive).
* @returns An array of places.
*/
getPlaces(prefixes?: string[]): Promise<Place[]>;
}
const Places = function (
privateClient: BaseClient /*, publicClient: BaseClient */
) {
): { exports: PlacesClient } {
// Define Schema
privateClient.declareType('place', placeSchema as any);

9
typedoc.json Normal file
View File

@ -0,0 +1,9 @@
{
"$schema": "https://typedoc.org/schema.json",
"entryPoints": ["./src/places.ts"],
"out": "docs",
"plugin": ["typedoc-plugin-markdown"],
"disableSources": true,
"readme": "none",
"name": "@remotestorage/module-places"
}