Compare commits
5 Commits
ccc865741c
...
v1.2.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
6b434adde4
|
|||
|
a966df95f0
|
|||
|
90b7b1cf01
|
|||
|
1f8c076051
|
|||
|
ba01a579b6
|
@@ -41,6 +41,12 @@ console.log(allPlaces);
|
|||||||
// List places for specific geohash prefixes (e.g. for a map view)
|
// List places for specific geohash prefixes (e.g. for a map view)
|
||||||
const areaPlaces = await places.getPlaces(['u33d', 'u33e']);
|
const areaPlaces = await places.getPlaces(['u33d', 'u33e']);
|
||||||
console.log(areaPlaces);
|
console.log(areaPlaces);
|
||||||
|
|
||||||
|
// Create a list
|
||||||
|
await places.lists.create('favorites', 'My Favorites');
|
||||||
|
|
||||||
|
// Add a place to a list (requires list ID, place ID, and place geohash)
|
||||||
|
await places.lists.addPlace('favorites', 'place-id-123', 'u33dc0');
|
||||||
```
|
```
|
||||||
|
|
||||||
## API Reference
|
## API Reference
|
||||||
@@ -52,3 +58,4 @@ console.log(areaPlaces);
|
|||||||
### Type Aliases
|
### Type Aliases
|
||||||
|
|
||||||
- [Place](docs/type-aliases/Place.md)
|
- [Place](docs/type-aliases/Place.md)
|
||||||
|
- [List](docs/type-aliases/List.md)
|
||||||
|
|||||||
92
dist/places.d.ts
vendored
92
dist/places.d.ts
vendored
@@ -57,6 +57,61 @@ declare const placeSchema: {
|
|||||||
};
|
};
|
||||||
readonly required: readonly ["id", "title", "lat", "lon", "geohash", "createdAt"];
|
readonly required: readonly ["id", "title", "lat", "lon", "geohash", "createdAt"];
|
||||||
};
|
};
|
||||||
|
declare const listSchema: {
|
||||||
|
readonly type: "object";
|
||||||
|
readonly properties: {
|
||||||
|
readonly id: {
|
||||||
|
readonly type: "string";
|
||||||
|
};
|
||||||
|
readonly title: {
|
||||||
|
readonly type: "string";
|
||||||
|
};
|
||||||
|
readonly color: {
|
||||||
|
readonly type: "string";
|
||||||
|
};
|
||||||
|
readonly placeRefs: {
|
||||||
|
readonly type: "array";
|
||||||
|
readonly items: {
|
||||||
|
readonly type: "object";
|
||||||
|
readonly properties: {
|
||||||
|
readonly id: {
|
||||||
|
readonly type: "string";
|
||||||
|
};
|
||||||
|
readonly geohash: {
|
||||||
|
readonly type: "string";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
readonly required: readonly ["id", "geohash"];
|
||||||
|
};
|
||||||
|
readonly default: readonly [];
|
||||||
|
};
|
||||||
|
readonly createdAt: {
|
||||||
|
readonly type: "string";
|
||||||
|
readonly format: "date-time";
|
||||||
|
};
|
||||||
|
readonly updatedAt: {
|
||||||
|
readonly type: "string";
|
||||||
|
readonly format: "date-time";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
readonly required: readonly ["id", "title", "placeRefs", "createdAt"];
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Represents a List object.
|
||||||
|
*
|
||||||
|
* Core properties enforced by schema:
|
||||||
|
* - `id`: Unique identifier (slug)
|
||||||
|
* - `title`: Human readable title
|
||||||
|
* - `placeRefs`: Array of place references containing `id` and `geohash`
|
||||||
|
* - `createdAt`: ISO date string
|
||||||
|
*
|
||||||
|
* Optional properties:
|
||||||
|
* - `color`: Hex color code
|
||||||
|
* - `updatedAt`: ISO date string
|
||||||
|
*/
|
||||||
|
export type List = FromSchema<typeof listSchema> & {
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* Represents a Place object.
|
* Represents a Place object.
|
||||||
*
|
*
|
||||||
@@ -126,6 +181,43 @@ export interface PlacesClient {
|
|||||||
* @returns An array of places.
|
* @returns An array of places.
|
||||||
*/
|
*/
|
||||||
getPlaces(prefixes?: string[]): Promise<Place[]>;
|
getPlaces(prefixes?: string[]): Promise<Place[]>;
|
||||||
|
lists: {
|
||||||
|
/**
|
||||||
|
* Get all lists.
|
||||||
|
* @returns Array of List objects.
|
||||||
|
*/
|
||||||
|
getAll(): Promise<List[]>;
|
||||||
|
/**
|
||||||
|
* Get a single list by ID (slug).
|
||||||
|
* @param id - The slug ID of the list.
|
||||||
|
*/
|
||||||
|
get(id: string): Promise<List | null>;
|
||||||
|
/**
|
||||||
|
* Create or update a list.
|
||||||
|
* @param id - The slug ID (e.g., "to-go").
|
||||||
|
* @param title - Human readable title.
|
||||||
|
* @param color - Optional hex color code.
|
||||||
|
*/
|
||||||
|
create(id: string, title: string, color?: string): Promise<List>;
|
||||||
|
/**
|
||||||
|
* Delete a list.
|
||||||
|
* @param id - The slug ID of the list.
|
||||||
|
*/
|
||||||
|
delete(id: string): Promise<void>;
|
||||||
|
/**
|
||||||
|
* Add a place to a list.
|
||||||
|
* @param listId - The slug ID of the list.
|
||||||
|
* @param placeId - The ID of the place.
|
||||||
|
* @param geohash - The geohash of the place.
|
||||||
|
*/
|
||||||
|
addPlace(listId: string, placeId: string, geohash: string): Promise<List>;
|
||||||
|
/**
|
||||||
|
* Remove a place from a list.
|
||||||
|
* @param listId - The slug ID of the list.
|
||||||
|
* @param placeId - The ID of the place.
|
||||||
|
*/
|
||||||
|
removePlace(listId: string, placeId: string): Promise<List>;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
declare const _default: {
|
declare const _default: {
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
118
dist/places.js
vendored
118
dist/places.js
vendored
@@ -27,9 +27,33 @@ const placeSchema = {
|
|||||||
},
|
},
|
||||||
required: ['id', 'title', 'lat', 'lon', 'geohash', 'createdAt'],
|
required: ['id', 'title', 'lat', 'lon', 'geohash', 'createdAt'],
|
||||||
};
|
};
|
||||||
|
const listSchema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
id: { type: 'string' },
|
||||||
|
title: { type: 'string' },
|
||||||
|
color: { type: 'string' },
|
||||||
|
placeRefs: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
id: { type: 'string' },
|
||||||
|
geohash: { type: 'string' },
|
||||||
|
},
|
||||||
|
required: ['id', 'geohash'],
|
||||||
|
},
|
||||||
|
default: [],
|
||||||
|
},
|
||||||
|
createdAt: { type: 'string', format: 'date-time' },
|
||||||
|
updatedAt: { type: 'string', format: 'date-time' },
|
||||||
|
},
|
||||||
|
required: ['id', 'title', 'placeRefs', 'createdAt'],
|
||||||
|
};
|
||||||
const Places = function (privateClient /*, publicClient: BaseClient */) {
|
const Places = function (privateClient /*, publicClient: BaseClient */) {
|
||||||
// Define Schema
|
// Define Schema
|
||||||
privateClient.declareType('place', placeSchema);
|
privateClient.declareType('place', placeSchema);
|
||||||
|
privateClient.declareType('list', listSchema);
|
||||||
// Helper to normalize place object
|
// Helper to normalize place object
|
||||||
function preparePlace(data) {
|
function preparePlace(data) {
|
||||||
const now = new Date().toISOString();
|
const now = new Date().toISOString();
|
||||||
@@ -67,7 +91,91 @@ const Places = function (privateClient /*, publicClient: BaseClient */) {
|
|||||||
const p2 = geohash.substring(2, 4);
|
const p2 = geohash.substring(2, 4);
|
||||||
return `${p1}/${p2}/${id}`;
|
return `${p1}/${p2}/${id}`;
|
||||||
}
|
}
|
||||||
|
const lists = {
|
||||||
|
async getAll() {
|
||||||
|
const result = await privateClient.getAll('_lists/');
|
||||||
|
if (!result)
|
||||||
|
return [];
|
||||||
|
// Normalize result: remoteStorage.getAll returns { 'slug': object }
|
||||||
|
return Object.values(result);
|
||||||
|
},
|
||||||
|
async get(id) {
|
||||||
|
const path = `_lists/${id}`;
|
||||||
|
return privateClient.getObject(path);
|
||||||
|
},
|
||||||
|
async create(id, title, color) {
|
||||||
|
const path = `_lists/${id}`;
|
||||||
|
let list = (await privateClient.getObject(path));
|
||||||
|
const now = new Date().toISOString();
|
||||||
|
if (list) {
|
||||||
|
// Update existing
|
||||||
|
list.title = title;
|
||||||
|
if (color)
|
||||||
|
list.color = color;
|
||||||
|
list.updatedAt = now;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Create new
|
||||||
|
list = {
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
color,
|
||||||
|
placeRefs: [],
|
||||||
|
createdAt: now,
|
||||||
|
updatedAt: now,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
await privateClient.storeObject('list', path, list);
|
||||||
|
return list;
|
||||||
|
},
|
||||||
|
async delete(id) {
|
||||||
|
await privateClient.remove(`_lists/${id}`);
|
||||||
|
},
|
||||||
|
async addPlace(listId, placeId, geohash) {
|
||||||
|
const path = `_lists/${listId}`;
|
||||||
|
const list = (await privateClient.getObject(path));
|
||||||
|
if (!list) {
|
||||||
|
throw new Error(`List not found: ${listId}`);
|
||||||
|
}
|
||||||
|
const index = list.placeRefs.findIndex((ref) => ref.id === placeId);
|
||||||
|
if (index === -1) {
|
||||||
|
// Add only if not present
|
||||||
|
list.placeRefs.push({ id: placeId, geohash });
|
||||||
|
list.updatedAt = new Date().toISOString();
|
||||||
|
await privateClient.storeObject('list', path, list);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
},
|
||||||
|
async removePlace(listId, placeId) {
|
||||||
|
const path = `_lists/${listId}`;
|
||||||
|
const list = (await privateClient.getObject(path));
|
||||||
|
if (!list) {
|
||||||
|
throw new Error(`List not found: ${listId}`);
|
||||||
|
}
|
||||||
|
const index = list.placeRefs.findIndex((ref) => ref.id === placeId);
|
||||||
|
if (index !== -1) {
|
||||||
|
// Remove only if present
|
||||||
|
list.placeRefs.splice(index, 1);
|
||||||
|
list.updatedAt = new Date().toISOString();
|
||||||
|
await privateClient.storeObject('list', path, list);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
},
|
||||||
|
async initDefaults() {
|
||||||
|
const defaults = [
|
||||||
|
{ id: 'to-go', title: 'Want to go', color: '#2e9e4f' }, // Green
|
||||||
|
{ id: 'to-do', title: 'To do', color: '#2a7fff' }, // Blue
|
||||||
|
];
|
||||||
|
for (const def of defaults) {
|
||||||
|
const existing = await this.get(def.id);
|
||||||
|
if (!existing) {
|
||||||
|
await this.create(def.id, def.title, def.color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
const places = {
|
const places = {
|
||||||
|
lists,
|
||||||
/**
|
/**
|
||||||
* Store a place.
|
* Store a place.
|
||||||
* Generates ID and Geohash if missing.
|
* Generates ID and Geohash if missing.
|
||||||
@@ -87,6 +195,16 @@ const Places = function (privateClient /*, publicClient: BaseClient */) {
|
|||||||
if (!id || !geohash) {
|
if (!id || !geohash) {
|
||||||
throw new Error('Both id and geohash are required to remove a place');
|
throw new Error('Both id and geohash are required to remove a place');
|
||||||
}
|
}
|
||||||
|
// Cleanup: Remove this place from all lists
|
||||||
|
const allLists = await lists.getAll();
|
||||||
|
await Promise.all(allLists.map(async (list) => {
|
||||||
|
const index = list.placeRefs.findIndex((ref) => ref.id === id);
|
||||||
|
if (index !== -1) {
|
||||||
|
list.placeRefs.splice(index, 1);
|
||||||
|
list.updatedAt = new Date().toISOString();
|
||||||
|
await privateClient.storeObject('list', `_lists/${list.id}`, list);
|
||||||
|
}
|
||||||
|
}));
|
||||||
const path = getPath(geohash, id);
|
const path = getPath(geohash, id);
|
||||||
return privateClient.remove(path);
|
return privateClient.remove(path);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
## Type Aliases
|
## Type Aliases
|
||||||
|
|
||||||
|
- [List](type-aliases/List.md)
|
||||||
- [Place](type-aliases/Place.md)
|
- [Place](type-aliases/Place.md)
|
||||||
|
|
||||||
## Variables
|
## Variables
|
||||||
|
|||||||
@@ -6,6 +6,144 @@
|
|||||||
|
|
||||||
# Interface: PlacesClient
|
# Interface: PlacesClient
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
### lists
|
||||||
|
|
||||||
|
> **lists**: `object`
|
||||||
|
|
||||||
|
#### addPlace()
|
||||||
|
|
||||||
|
> **addPlace**(`listId`, `placeId`, `geohash`): `Promise`\<[`List`](../type-aliases/List.md)\>
|
||||||
|
|
||||||
|
Add a place to a list.
|
||||||
|
|
||||||
|
##### Parameters
|
||||||
|
|
||||||
|
###### listId
|
||||||
|
|
||||||
|
`string`
|
||||||
|
|
||||||
|
The slug ID of the list.
|
||||||
|
|
||||||
|
###### placeId
|
||||||
|
|
||||||
|
`string`
|
||||||
|
|
||||||
|
The ID of the place.
|
||||||
|
|
||||||
|
###### geohash
|
||||||
|
|
||||||
|
`string`
|
||||||
|
|
||||||
|
The geohash of the place.
|
||||||
|
|
||||||
|
##### Returns
|
||||||
|
|
||||||
|
`Promise`\<[`List`](../type-aliases/List.md)\>
|
||||||
|
|
||||||
|
#### create()
|
||||||
|
|
||||||
|
> **create**(`id`, `title`, `color?`): `Promise`\<[`List`](../type-aliases/List.md)\>
|
||||||
|
|
||||||
|
Create or update a list.
|
||||||
|
|
||||||
|
##### Parameters
|
||||||
|
|
||||||
|
###### id
|
||||||
|
|
||||||
|
`string`
|
||||||
|
|
||||||
|
The slug ID (e.g., "to-go").
|
||||||
|
|
||||||
|
###### title
|
||||||
|
|
||||||
|
`string`
|
||||||
|
|
||||||
|
Human readable title.
|
||||||
|
|
||||||
|
###### color?
|
||||||
|
|
||||||
|
`string`
|
||||||
|
|
||||||
|
Optional hex color code.
|
||||||
|
|
||||||
|
##### Returns
|
||||||
|
|
||||||
|
`Promise`\<[`List`](../type-aliases/List.md)\>
|
||||||
|
|
||||||
|
#### delete()
|
||||||
|
|
||||||
|
> **delete**(`id`): `Promise`\<`void`\>
|
||||||
|
|
||||||
|
Delete a list.
|
||||||
|
|
||||||
|
##### Parameters
|
||||||
|
|
||||||
|
###### id
|
||||||
|
|
||||||
|
`string`
|
||||||
|
|
||||||
|
The slug ID of the list.
|
||||||
|
|
||||||
|
##### Returns
|
||||||
|
|
||||||
|
`Promise`\<`void`\>
|
||||||
|
|
||||||
|
#### get()
|
||||||
|
|
||||||
|
> **get**(`id`): `Promise`\<[`List`](../type-aliases/List.md) \| `null`\>
|
||||||
|
|
||||||
|
Get a single list by ID (slug).
|
||||||
|
|
||||||
|
##### Parameters
|
||||||
|
|
||||||
|
###### id
|
||||||
|
|
||||||
|
`string`
|
||||||
|
|
||||||
|
The slug ID of the list.
|
||||||
|
|
||||||
|
##### Returns
|
||||||
|
|
||||||
|
`Promise`\<[`List`](../type-aliases/List.md) \| `null`\>
|
||||||
|
|
||||||
|
#### getAll()
|
||||||
|
|
||||||
|
> **getAll**(): `Promise`\<[`List`](../type-aliases/List.md)[]\>
|
||||||
|
|
||||||
|
Get all lists.
|
||||||
|
|
||||||
|
##### Returns
|
||||||
|
|
||||||
|
`Promise`\<[`List`](../type-aliases/List.md)[]\>
|
||||||
|
|
||||||
|
Array of List objects.
|
||||||
|
|
||||||
|
#### removePlace()
|
||||||
|
|
||||||
|
> **removePlace**(`listId`, `placeId`): `Promise`\<[`List`](../type-aliases/List.md)\>
|
||||||
|
|
||||||
|
Remove a place from a list.
|
||||||
|
|
||||||
|
##### Parameters
|
||||||
|
|
||||||
|
###### listId
|
||||||
|
|
||||||
|
`string`
|
||||||
|
|
||||||
|
The slug ID of the list.
|
||||||
|
|
||||||
|
###### placeId
|
||||||
|
|
||||||
|
`string`
|
||||||
|
|
||||||
|
The ID of the place.
|
||||||
|
|
||||||
|
##### Returns
|
||||||
|
|
||||||
|
`Promise`\<[`List`](../type-aliases/List.md)\>
|
||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
### get()
|
### get()
|
||||||
|
|||||||
21
docs/type-aliases/List.md
Normal file
21
docs/type-aliases/List.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
[**@remotestorage/module-places**](../README.md)
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
[@remotestorage/module-places](../README.md) / List
|
||||||
|
|
||||||
|
# Type Alias: List
|
||||||
|
|
||||||
|
> **List** = `FromSchema`\<*typeof* `listSchema`\> & `object`
|
||||||
|
|
||||||
|
Represents a List object.
|
||||||
|
|
||||||
|
Core properties enforced by schema:
|
||||||
|
- `id`: Unique identifier (slug)
|
||||||
|
- `title`: Human readable title
|
||||||
|
- `placeRefs`: Array of place references containing `id` and `geohash`
|
||||||
|
- `createdAt`: ISO date string
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- `color`: Hex color code
|
||||||
|
- `updatedAt`: ISO date string
|
||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@remotestorage/module-places",
|
"name": "@remotestorage/module-places",
|
||||||
"version": "1.1.3",
|
"version": "1.2.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@remotestorage/module-places",
|
"name": "@remotestorage/module-places",
|
||||||
"version": "1.1.3",
|
"version": "1.2.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"latlon-geohash": "^2.0.0",
|
"latlon-geohash": "^2.0.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@remotestorage/module-places",
|
"name": "@remotestorage/module-places",
|
||||||
"version": "1.1.3",
|
"version": "1.2.1",
|
||||||
"description": "Manage favorite/saved places",
|
"description": "Manage favorite/saved places",
|
||||||
"homepage": "https://gitea.kosmos.org/raucao/remotestorage-module-places#remotestoragemodule-places",
|
"homepage": "https://gitea.kosmos.org/raucao/remotestorage-module-places#remotestoragemodule-places",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
@@ -55,6 +55,19 @@ const listSchema = {
|
|||||||
required: ['id', 'title', 'placeRefs', 'createdAt'],
|
required: ['id', 'title', 'placeRefs', 'createdAt'],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a List object.
|
||||||
|
*
|
||||||
|
* Core properties enforced by schema:
|
||||||
|
* - `id`: Unique identifier (slug)
|
||||||
|
* - `title`: Human readable title
|
||||||
|
* - `placeRefs`: Array of place references containing `id` and `geohash`
|
||||||
|
* - `createdAt`: ISO date string
|
||||||
|
*
|
||||||
|
* Optional properties:
|
||||||
|
* - `color`: Hex color code
|
||||||
|
* - `updatedAt`: ISO date string
|
||||||
|
*/
|
||||||
export type List = FromSchema<typeof listSchema> & { [key: string]: any };
|
export type List = FromSchema<typeof listSchema> & { [key: string]: any };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user