From 1e89e198638c428c210ac708f1252d1af9f4c84c Mon Sep 17 00:00:00 2001 From: seb Date: Fri, 7 Aug 2026 04:05:01 +0200 Subject: [PATCH] docs --- API.article.md | 181 +++++++++++++++++++++++++++++++++ API.brand.md | 38 +++++++ API.category.md | 110 +++++++++++++++++++++ API.company.md | 80 +++++++++++++++ API.companysetting.md | 50 ++++++++++ API.companyuser.md | 38 +++++++ API.customergroup.md | 62 ++++++++++++ API.delivery.md | 62 ++++++++++++ API.entity.md | 62 ++++++++++++ API.entityaddress.md | 50 ++++++++++ API.entitycontact.md | 50 ++++++++++ API.google_auth.md | 84 ++++++++++++++++ API.lang.md | 62 ++++++++++++ API.md | 26 +++++ API.pic.md | 27 +++++ API.posterminal.md | 86 ++++++++++++++++ API.supplier.md | 50 ++++++++++ API.tax.md | 51 ++++++++++ API.unit.md | 38 +++++++ README.md | 2 - generate-api-doc.js | 225 ++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 22 files changed, 1433 insertions(+), 2 deletions(-) create mode 100644 API.article.md create mode 100644 API.brand.md create mode 100644 API.category.md create mode 100644 API.company.md create mode 100644 API.companysetting.md create mode 100644 API.companyuser.md create mode 100644 API.customergroup.md create mode 100644 API.delivery.md create mode 100644 API.entity.md create mode 100644 API.entityaddress.md create mode 100644 API.entitycontact.md create mode 100644 API.google_auth.md create mode 100644 API.lang.md create mode 100644 API.md create mode 100644 API.pic.md create mode 100644 API.posterminal.md create mode 100644 API.supplier.md create mode 100644 API.tax.md create mode 100644 API.unit.md create mode 100644 generate-api-doc.js diff --git a/API.article.md b/API.article.md new file mode 100644 index 0000000..283270e --- /dev/null +++ b/API.article.md @@ -0,0 +1,181 @@ +# article + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `article.addImage` + +*Source: `src/store/article/addImage.js`* + +Adds an image to an article by its SKU, processing it into AVIF variants. + +```js +const fn = addImage(pool); +const result = await fn(42, 'SKU-1', imageBuffer); +// => { picId, sort, full: { w, h, size }, thumb: { w, h }, fullHash, thumbHash } +``` + +## `article.createUnderParent` + +*Source: `src/store/article/createUnderParent.js`* + +Creates a new article under a given parent category, allocating a SKU and a default unit. + +```js +const fn = createUnderParent(pool); +const article = await fn({ googleAuthId: 42, parentId: 5, name: 'Cola' }); +// => { id, parentId, name, sku } +``` + +## `article.delete` + +*Source: `src/store/article/delete.js`* + +Deletes an article by its SKU, refusing when it still has children. + +```js +const fn = del(pool); +await fn(42, 'SKU-1'); +``` + +## `article.deleteImage` + +*Source: `src/store/article/deleteImage.js`* + +Deletes an image from an article by its SKU and full image hash. + +```js +const fn = deleteImage(pool); +await fn(42, 'SKU-1', 'abc123'); +``` + +## `article.getBySku` + +*Source: `src/store/article/getBySku.js`* + +Returns the full detail of an article by its SKU, including unit, brand, categories, photos, EANs and prices. + +```js +const fn = getBySku(pool); +const article = await fn(42, 'SKU-1'); +// => { article: { id, sku, name, unit, brand, categoryIds, photos, eans, prices, ... } } +``` + +## `article.getHistoryBySku` + +*Source: `src/store/article/getHistoryBySku.js`* + +Returns the change history of an article by its SKU. + +```js +const fn = getHistoryBySku(pool); +const history = await fn(42, 'SKU-1'); +// => [{ id, companyuserId, date, text }] +``` + +## `article.listExport` + +*Source: `src/store/article/listExport.js`* + +Returns articles for export, optionally scoped to a category, including category breadcrumbs and image hashes. + +```js +const fn = listExport(pool); +const articles = await fn(42, 1, null); +// => [{ id, sku, name, slug, unitSi, net, taxRate, eans, categoryBreadcrumbs, fullHashes, ... }] +``` + +## `article.listSearchIndex` + +*Source: `src/store/article/listSearchIndex.js`* + +Returns a lightweight search index of all articles for a company. + +```js +const fn = listSearchIndex(pool); +const articles = await fn(42, 1); +// => [{ id, sku, name, eans, categoryIds }] +``` + +## `article.orderImages` + +*Source: `src/store/article/orderImages.js`* + +Reorders the images of an article by its SKU. + +```js +const fn = orderImages(pool); +const result = await fn(42, 'SKU-1', { fullHashes: ['a', 'b'] }); +// => { fullHashes: ['a', 'b'] } +``` + +## `article.setBrandIdBySku` + +*Source: `src/store/article/setBrandIdBySku.js`* + +Sets (or clears) the brand of an article by its SKU. + +```js +const fn = setBrandIdBySku(pool); +const article = await fn(42, 'SKU-1', 3); +// => { id, sku, name, ... } +``` + +## `article.setCategoryIdsBySku` + +*Source: `src/store/article/setCategoryIdsBySku.js`* + +Replaces the category membership of an article by its SKU. + +```js +const fn = setCategoryIdsBySku(pool); +const article = await fn(42, 'SKU-1', [5, 9]); +// => { id, sku, name, ... } +``` + +## `article.setEansBySku` + +*Source: `src/store/article/setEansBySku.js`* + +Replaces the EAN list of an article by its SKU. + +```js +const fn = setEansBySku(pool); +const article = await fn(42, 'SKU-1', ['4001234567890']); +// => { id, sku, name, ... } +``` + +## `article.setPricesBySku` + +*Source: `src/store/article/setPricesBySku.js`* + +Replaces the price list of an article by its SKU. + +```js +const fn = setPricesBySku(pool); +const article = await fn(42, 'SKU-1', [{ price: 1.5, tax: 19, minmultiplier: 1 }]); +// => { id, sku, name, ... } +``` + +## `article.setWeightBySku` + +*Source: `src/store/article/setWeightBySku.js`* + +Sets the weight of an article by its SKU. + +```js +const fn = setWeightBySku(pool); +const article = await fn(42, 'SKU-1', 1.5); +// => { id, sku, name, ... } +``` + +## `article.updateBySku` + +*Source: `src/store/article/updateBySku.js`* + +Updates an article's name and/or unit (SI and amount), recording history. + +```js +const fn = updateBySku(pool); +const article = await fn(42, 'SKU-1', { name: 'Cola 1L', unitSi: 'l', unitamount: 1 }); +// => { id, sku, name, ... } +``` diff --git a/API.brand.md b/API.brand.md new file mode 100644 index 0000000..5f83177 --- /dev/null +++ b/API.brand.md @@ -0,0 +1,38 @@ +# brand + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `brand.delete` + +*Source: `src/store/brand/delete.js`* + +Deletes a brand for a company by its id. + +```js +const fn = del(pool); +await fn(42, 1, 3); +``` + +## `brand.list` + +*Source: `src/store/brand/list.js`* + +Lists the brands of a company. + +```js +const fn = list(pool); +const brands = await fn(42, 1); +// => [{ id, name, gsprpinfo }] +``` + +## `brand.upsert` + +*Source: `src/store/brand/upsert.js`* + +Creates or updates a brand for a company, keyed by name. + +```js +const fn = upsert(pool); +const brand = await fn(42, 1, { name: 'Coca-Cola', gsprpinfo: 'x' }); +// => { id, name, gsprpinfo } +``` diff --git a/API.category.md b/API.category.md new file mode 100644 index 0000000..501534b --- /dev/null +++ b/API.category.md @@ -0,0 +1,110 @@ +# category + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `category.addImage` + +*Source: `src/store/category/addImage.js`* + +Adds an image to a category, processing it into AVIF full and thumb variants. + +```js +const fn = addImage(pool); +const result = await fn(42, 5, imageBuffer); +// => { id, fullHash, thumbW, thumbH, thumbHash } +``` + +## `category.createUnderParent` + +*Source: `src/store/category/createUnderParent.js`* + +Creates a new category under a given parent category. + +```js +const fn = createUnderParent(pool); +const category = await fn({ googleAuthId: 42, parentId: 5, name: 'Drinks' }); +// => { id, parentId, sort, name, slug } +``` + +## `category.delete` + +*Source: `src/store/category/delete.js`* + +Deletes a category, refusing to delete the company's root category. + +```js +const fn = del(pool); +await fn({ googleAuthId: 42, id: 5 }); +``` + +## `category.deleteImage` + +*Source: `src/store/category/deleteImage.js`* + +Deletes the image of a category. + +```js +const fn = deleteImage(pool); +const result = await fn(42, 5); +// => { id, thumbW: null, thumbH: null, thumbHash: null } +``` + +## `category.getCategoryArticles` + +*Source: `src/store/category/getCategoryArticles.js`* + +Returns the articles belonging to a single category. + +```js +const fn = getCategoryArticles(pool); +const articles = await fn(42, 5); +// => [{ id, sku, name, ... }] +``` + +## `category.getTreeForCompany` + +*Source: `src/store/category/getTreeForCompany.js`* + +Returns the full category tree for a company together with its articles and the posterminal ids assigned to each category. + +```js +const fn = getTreeForCompany(pool); +const tree = await fn(42, 1); +// => { languageId, tree: [{ id, posterminalIds, ... }], articles: [...] } +``` + +## `category.move` + +*Source: `src/store/category/move.js`* + +Moves a category to a new parent, preventing cycles and cross-company moves. + +```js +const fn = move(pool); +const result = await fn({ googleAuthId: 42, id: 5, parentId: 9 }); +// => { id, parentId, sort } +``` + +## `category.order` + +*Source: `src/store/category/order.js`* + +Reorders the child categories of a given parent. + +```js +const fn = order(pool); +const result = await fn({ googleAuthId: 42, parentId: 5, categoryIds: [3, 1, 2] }); +// => { categoryIds: [3, 1, 2] } +``` + +## `category.rename` + +*Source: `src/store/category/rename.js`* + +Renames a category and updates its slug. + +```js +const fn = rename(pool); +const result = await fn({ googleAuthId: 42, id: 5, name: 'Soft Drinks' }); +// => { id, name, slug } +``` diff --git a/API.company.md b/API.company.md new file mode 100644 index 0000000..7e8e468 --- /dev/null +++ b/API.company.md @@ -0,0 +1,80 @@ +# company + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `company.create` + +*Source: `src/store/company/create.js`* + +Creates a new company together with its root category, POS customer group, default language and tax rates, and links it to the given Google auth user. + +```js +const fn = create(pool); +const company = await fn({ + iso639: 'de', + name: 'Acme', + taxrate: 19, + reducedtaxrate: 7, + googleAuthId: 42, +}); +// => { id, rootCategoryId, languageId, taxrateId, reducedtaxrateId, taxfreerateId, posCustomerGroupId } +``` + +## `company.delete` + +*Source: `src/store/company/delete.js`* + +Deletes a company by its id. + +```js +const fn = del(pool); +await fn(1); +``` + +## `company.getById` + +*Source: `src/store/company/getById.js`* + +Returns a single company by its id. + +```js +const fn = getById(pool); +const company = await fn(1); +// => { id, name, ... } +``` + +## `company.getByName` + +*Source: `src/store/company/getByName.js`* + +Returns a single company by its name. + +```js +const fn = getByName(pool); +const company = await fn('Acme'); +// => { id, name, ... } +``` + +## `company.list` + +*Source: `src/store/company/list.js`* + +Lists the companies accessible to the given Google auth user. + +```js +const fn = list(pool); +const companies = await fn(42); +// => [{ id, name, ... }] +``` + +## `company.update` + +*Source: `src/store/company/update.js`* + +Updates an existing company's name, language and tax rates. + +```js +const fn = update(pool); +const result = await fn(1, { iso639: 'de', name: 'Acme', taxrate: 19, reducedtaxrate: 7 }); +// => { id, rootCategoryId, languageId, taxrateId, reducedtaxrateId, taxfreerateId } +``` diff --git a/API.companysetting.md b/API.companysetting.md new file mode 100644 index 0000000..31acc6f --- /dev/null +++ b/API.companysetting.md @@ -0,0 +1,50 @@ +# companysetting + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `companysetting.delete` + +*Source: `src/store/companysetting/delete.js`* + +Deletes a company setting by key. + +```js +const fn = del(pool); +await fn(42, 1, 'theme'); +``` + +## `companysetting.get` + +*Source: `src/store/companysetting/get.js`* + +Returns a single company setting by key. + +```js +const fn = get(pool); +const setting = await fn(42, 1, 'theme'); +// => { key, value, frontend } +``` + +## `companysetting.list` + +*Source: `src/store/companysetting/list.js`* + +Lists the settings of a company, optionally only frontend-visible ones. + +```js +const fn = list(pool); +const settings = await fn(42, 1, { frontendOnly: true }); +// => [{ key, value, frontend }] +``` + +## `companysetting.set` + +*Source: `src/store/companysetting/set.js`* + +Sets (upserts) a company setting by key. + +```js +const fn = set(pool); +const setting = await fn(42, 1, { key: 'theme', value: 'dark', frontend: true }); +// => { key, value, frontend } +``` diff --git a/API.companyuser.md b/API.companyuser.md new file mode 100644 index 0000000..22f3606 --- /dev/null +++ b/API.companyuser.md @@ -0,0 +1,38 @@ +# companyuser + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `companyuser.add` + +*Source: `src/store/companyuser/add.js`* + +Adds a company user linking a company to a Google auth account. + +```js +const fn = add(pool); +const id = await fn(1, 42); +// => 7 +``` + +## `companyuser.delete` + +*Source: `src/store/companyuser/delete.js`* + +Deletes a company user link by its id. + +```js +const fn = del(pool); +await fn(7); +``` + +## `companyuser.getByEmail` + +*Source: `src/store/companyuser/getByEmail.js`* + +Returns the company user ids associated with the given email address. + +```js +const fn = getByEmail(pool); +const ids = await fn('user@example.com'); +// => [1, 2, 3] +``` diff --git a/API.customergroup.md b/API.customergroup.md new file mode 100644 index 0000000..5046957 --- /dev/null +++ b/API.customergroup.md @@ -0,0 +1,62 @@ +# customergroup + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `customergroup.create` + +*Source: `src/store/customergroup/create.js`* + +Creates a new customer group for a company. + +```js +const fn = create(pool); +const group = await fn(42, 1, { name: 'Wholesale' }); +// => { id, name, sort } +``` + +## `customergroup.delete` + +*Source: `src/store/customergroup/delete.js`* + +Deletes a customer group for a company by its id. + +```js +const fn = del(pool); +await fn(42, 1, 5); +``` + +## `customergroup.list` + +*Source: `src/store/customergroup/list.js`* + +Lists the customer groups of a company. + +```js +const fn = list(pool); +const groups = await fn(42, 1); +// => [{ id, name, sort }] +``` + +## `customergroup.order` + +*Source: `src/store/customergroup/order.js`* + +Reorders the customer groups of a company. + +```js +const fn = order(pool); +const result = await fn(42, 1, { customergroupIds: [3, 1, 2] }); +// => { customergroupIds: [3, 1, 2] } +``` + +## `customergroup.update` + +*Source: `src/store/customergroup/update.js`* + +Updates the name of a customer group for a company. + +```js +const fn = update(pool); +const group = await fn(42, 1, 5, { name: 'Retail' }); +// => { id, name, sort } +``` diff --git a/API.delivery.md b/API.delivery.md new file mode 100644 index 0000000..fcbe41a --- /dev/null +++ b/API.delivery.md @@ -0,0 +1,62 @@ +# delivery + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `delivery.create` + +*Source: `src/store/delivery/create.js`* + +Creates a new delivery for a company with its lines. + +```js +const fn = create(pool); +const delivery = await fn(42, 1, { number: 'D-1', date: '2026-01-01', supplierId: 5, lines: [...] }); +// => { id, number, type, entityId, date, lines: [...] } +``` + +## `delivery.delete` + +*Source: `src/store/delivery/delete.js`* + +Deletes a delivery by its id within a company. + +```js +const fn = del(pool); +await fn(42, 1, 5); +``` + +## `delivery.getById` + +*Source: `src/store/delivery/getById.js`* + +Returns a single delivery by its id within a company. + +```js +const fn = getById(pool); +const delivery = await fn(42, 1, 5); +// => { id, number, type, entityId, date, lines: [...] } +``` + +## `delivery.list` + +*Source: `src/store/delivery/list.js`* + +Lists the deliveries of a company. + +```js +const fn = list(pool); +const deliveries = await fn(42, 1); +// => [{ id, number, type, entityId, date }] +``` + +## `delivery.update` + +*Source: `src/store/delivery/update.js`* + +Updates a delivery's header and/or lines. + +```js +const fn = update(pool); +const delivery = await fn(42, 1, 5, { number: 'D-2', lines: [...] }); +// => { id, number, type, entityId, date, lines: [...] } +``` diff --git a/API.entity.md b/API.entity.md new file mode 100644 index 0000000..d409b77 --- /dev/null +++ b/API.entity.md @@ -0,0 +1,62 @@ +# entity + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `entity.create` + +*Source: `src/store/entity/create.js`* + +Creates a new entity (customer) in a customer group, recording history. + +```js +const fn = create(pool); +const entity = await fn(42, 1, { customergroupId: 5, name: 'Doe', firstName: 'John' }); +// => { id, customergroupId, firstName, name, createdAt, updatedAt } +``` + +## `entity.delete` + +*Source: `src/store/entity/delete.js`* + +Deletes an entity by its id within a company. + +```js +const fn = del(pool); +await fn(42, 1, 5); +``` + +## `entity.getById` + +*Source: `src/store/entity/getById.js`* + +Returns a single entity by its id within a company. + +```js +const fn = getById(pool); +const entity = await fn(42, 1, 5); +// => { id, customergroupId, firstName, name, createdAt, updatedAt } +``` + +## `entity.list` + +*Source: `src/store/entity/list.js`* + +Lists the entities (customers) of a company, optionally filtered by customer group or restricted to the 'customer' role. + +```js +const fn = list(pool); +const entities = await fn(42, 1, { customergroupId: 5 }); +// => [{ id, customergroupId, firstName, name, createdAt, updatedAt }] +``` + +## `entity.update` + +*Source: `src/store/entity/update.js`* + +Updates the name and/or first name of an entity, recording history. + +```js +const fn = update(pool); +const entity = await fn(42, 1, 5, { name: 'Doe', firstName: 'Jane' }); +// => { id, customergroupId, firstName, name, createdAt, updatedAt } +``` diff --git a/API.entityaddress.md b/API.entityaddress.md new file mode 100644 index 0000000..b9d9a8a --- /dev/null +++ b/API.entityaddress.md @@ -0,0 +1,50 @@ +# entityaddress + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `entityaddress.create` + +*Source: `src/store/entityaddress/create.js`* + +Creates a new address for an entity. + +```js +const fn = create(pool); +const address = await fn(42, 1, 5, { addressType: 'billing', street: 'Main St', city: 'Berlin' }); +// => { id, entityId, firstName, name, street, streetNumber, zip, city, county, addressType, sort } +``` + +## `entityaddress.delete` + +*Source: `src/store/entityaddress/delete.js`* + +Deletes an address of an entity. + +```js +const fn = del(pool); +await fn(42, 1, 5, 9); +``` + +## `entityaddress.list` + +*Source: `src/store/entityaddress/list.js`* + +Lists the addresses of an entity. + +```js +const fn = list(pool); +const addresses = await fn(42, 1, 5); +// => [{ id, entityId, firstName, name, street, streetNumber, zip, city, county, addressType, sort }] +``` + +## `entityaddress.update` + +*Source: `src/store/entityaddress/update.js`* + +Updates an address of an entity. + +```js +const fn = update(pool); +const address = await fn(42, 1, 5, 9, { city: 'Hamburg' }); +// => { id, entityId, firstName, name, street, streetNumber, zip, city, county, addressType, sort } +``` diff --git a/API.entitycontact.md b/API.entitycontact.md new file mode 100644 index 0000000..0add735 --- /dev/null +++ b/API.entitycontact.md @@ -0,0 +1,50 @@ +# entitycontact + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `entitycontact.create` + +*Source: `src/store/entitycontact/create.js`* + +Creates a new contact for an entity. + +```js +const fn = create(pool); +const contact = await fn(42, 1, 5, { contactType: 'email', contact: 'a@b.c' }); +// => { id, entityId, contactType, contact, sort } +``` + +## `entitycontact.delete` + +*Source: `src/store/entitycontact/delete.js`* + +Deletes a contact of an entity. + +```js +const fn = del(pool); +await fn(42, 1, 5, 9); +``` + +## `entitycontact.list` + +*Source: `src/store/entitycontact/list.js`* + +Lists the contacts of an entity. + +```js +const fn = list(pool); +const contacts = await fn(42, 1, 5); +// => [{ id, entityId, contactType, contact, sort }] +``` + +## `entitycontact.update` + +*Source: `src/store/entitycontact/update.js`* + +Updates a contact of an entity. + +```js +const fn = update(pool); +const contact = await fn(42, 1, 5, 9, { contact: 'b@c.d' }); +// => { id, entityId, contactType, contact, sort } +``` diff --git a/API.google_auth.md b/API.google_auth.md new file mode 100644 index 0000000..bb2ddab --- /dev/null +++ b/API.google_auth.md @@ -0,0 +1,84 @@ +# google_auth + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `google_auth.add` + +*Source: `src/store/google_auth/add.js`* + +Adds a new allowed Google auth email. + +```js +const fn = add(pool); +const id = await fn('user@example.com'); +// => 1 +``` + +## `google_auth.getByEmail` + +*Source: `src/store/google_auth/getByEmail.js`* + +Returns a Google auth row by email. + +```js +const fn = getByEmail(pool); +const auth = await fn('user@example.com'); +// => { id, email, ... } +``` + +## `google_auth.getById` + +*Source: `src/store/google_auth/getById.js`* + +Returns a Google auth row by its id. + +```js +const fn = getById(pool); +const auth = await fn(42); +// => { id, email, ... } +``` + +## `google_auth.listAllowedEmails` + +*Source: `src/store/google_auth/listAllowedEmails.js`* + +Lists all allowed Google auth emails. + +```js +const fn = listAllowedEmails(pool); +const emails = await fn(); +// => [{ id, email }] +``` + +## `google_auth.removeAllowedEmail` + +*Source: `src/store/google_auth/removeAllowedEmail.js`* + +Removes an allowed Google auth email. + +```js +const fn = removeAllowedEmail(pool); +await fn('user@example.com'); +``` + +## `google_auth.setProfile` + +*Source: `src/store/google_auth/setProfile.js`* + +Updates the profile (picture, picture binary, sub) of a Google auth user. + +```js +const fn = setProfile(pool); +await fn(42, { picture: 'url', pictureBinary: buffer, sub: 'sub' }); +``` + +## `google_auth.setSelectedCompany` + +*Source: `src/store/google_auth/setSelectedCompany.js`* + +Sets the currently selected company for a Google auth user. + +```js +const fn = setSelectedCompany(pool); +await fn(42, 1); +``` diff --git a/API.lang.md b/API.lang.md new file mode 100644 index 0000000..5d20b48 --- /dev/null +++ b/API.lang.md @@ -0,0 +1,62 @@ +# lang + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `lang.create` + +*Source: `src/store/lang/create.js`* + +Creates a new language by its ISO 639 code. + +```js +const fn = create(pool); +const id = await fn('de'); +// => 1 +``` + +## `lang.delete` + +*Source: `src/store/lang/delete.js`* + +Deletes a language by its id. + +```js +const fn = del(pool); +await fn(1); +``` + +## `lang.ensure` + +*Source: `src/store/lang/ensure.js`* + +Returns the id of a language by ISO code, creating it if it does not exist. + +```js +const fn = ensure(pool); +const id = await fn('de'); +// => 1 +``` + +## `lang.getByIso639` + +*Source: `src/store/lang/getByIso639.js`* + +Returns a language row by its ISO 639 code. + +```js +const fn = getByIso639(pool); +const lang = await fn('de'); +// => { id, iso639 } +``` + +## `lang.list` + +*Source: `src/store/lang/list.js`* + +Lists all languages. + +```js +const fn = list(pool); +const languages = await fn(); +// => [{ id, iso639 }] +``` diff --git a/API.md b/API.md new file mode 100644 index 0000000..f82fa37 --- /dev/null +++ b/API.md @@ -0,0 +1,26 @@ +# LibDashStore API + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each method is an async function that takes a `pool` (mssql connection pool) at construction time and returns a callable function. Methods are grouped by the namespace they are exposed under. + +## Table of Contents + +- [companyuser](API.companyuser.md) +- [company](API.company.md) +- [category](API.category.md) +- [article](API.article.md) +- [lang](API.lang.md) +- [tax](API.tax.md) +- [unit](API.unit.md) +- [companysetting](API.companysetting.md) +- [brand](API.brand.md) +- [customergroup](API.customergroup.md) +- [entity](API.entity.md) +- [entityaddress](API.entityaddress.md) +- [entitycontact](API.entitycontact.md) +- [supplier](API.supplier.md) +- [delivery](API.delivery.md) +- [posterminal](API.posterminal.md) +- [google_auth](API.google_auth.md) +- [pic](API.pic.md) diff --git a/API.pic.md b/API.pic.md new file mode 100644 index 0000000..e792d04 --- /dev/null +++ b/API.pic.md @@ -0,0 +1,27 @@ +# pic + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `pic.getImageByHash` + +*Source: `src/store/pic/getImageByHash.js`* + +Returns the full-size image (AVIF) for a given hash. + +```js +const fn = getImageByHash(pool); +const image = await fn(42, 'abc123'); +// => { buffer, w, h, size, contentType: 'image/avif' } +``` + +## `pic.getThumbByHash` + +*Source: `src/store/pic/getThumbByHash.js`* + +Returns the thumbnail image (AVIF) for a given hash. + +```js +const fn = getThumbByHash(pool); +const thumb = await fn(42, 'abc123'); +// => { buffer, w, h, contentType: 'image/avif' } +``` diff --git a/API.posterminal.md b/API.posterminal.md new file mode 100644 index 0000000..294ac18 --- /dev/null +++ b/API.posterminal.md @@ -0,0 +1,86 @@ +# posterminal + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `posterminal.delete` + +*Source: `src/store/posterminal/delete.js`* + +Deletes a posterminal by its id within a company. + +```js +const fn = del(pool); +await fn(42, 1, 5); +``` + +## `posterminal.list` + +*Source: `src/store/posterminal/list.js`* + +Lists the posterminals of a company. + +```js +const fn = list(pool); +const terminals = await fn(42, 1); +// => [{ id, name, token, pairingpin }] +``` + +## `posterminal.setOff` + +*Source: `src/store/posterminal/setOff.js`* + +Removes a category assignment from a posterminal (turns it off). + +```js +const fn = setOff(pool); +const result = await fn(42, 1, 5, 9); +// => { id, categoryIds: [...] } +``` + +## `posterminal.setOffAll` + +*Source: `src/store/posterminal/setOffAll.js`* + +Removes all category assignments from a posterminal. + +```js +const fn = setOffAll(pool); +const result = await fn(42, 1, 5); +// => { id, categoryIds: [] } +``` + +## `posterminal.setOn` + +*Source: `src/store/posterminal/setOn.js`* + +Assigns a category to a posterminal (turns it on for that category). + +```js +const fn = setOn(pool); +const result = await fn(42, 1, 5, 9); +// => { id, categoryIds: [9, ...] } +``` + +## `posterminal.setOnAll` + +*Source: `src/store/posterminal/setOnAll.js`* + +Assigns all categories of a company to a posterminal. + +```js +const fn = setOnAll(pool); +const result = await fn(42, 1, 5); +// => { id, categoryIds: [...] } +``` + +## `posterminal.upsert` + +*Source: `src/store/posterminal/upsert.js`* + +Creates or updates a posterminal for a company. + +```js +const fn = upsert(pool); +const terminal = await fn(42, 1, { name: 'Kasse 1', pairingpin: '1234', token: 'abc' }); +// => { id, name, token, pairingpin } +``` diff --git a/API.supplier.md b/API.supplier.md new file mode 100644 index 0000000..5abab79 --- /dev/null +++ b/API.supplier.md @@ -0,0 +1,50 @@ +# supplier + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `supplier.create` + +*Source: `src/store/supplier/create.js`* + +Creates a new supplier for a company, recording history. + +```js +const fn = create(pool); +const supplier = await fn(42, 1, { name: 'Acme Supplies' }); +// => { id, name, createdAt, updatedAt } +``` + +## `supplier.delete` + +*Source: `src/store/supplier/delete.js`* + +Deletes a supplier by its id within a company. + +```js +const fn = del(pool); +await fn(42, 1, 5); +``` + +## `supplier.list` + +*Source: `src/store/supplier/list.js`* + +Lists the suppliers of a company. + +```js +const fn = list(pool); +const suppliers = await fn(42, 1); +// => [{ id, name, createdAt, updatedAt }] +``` + +## `supplier.update` + +*Source: `src/store/supplier/update.js`* + +Updates the name of a supplier, recording history. + +```js +const fn = update(pool); +const supplier = await fn(42, 1, 5, { name: 'Acme GmbH' }); +// => { id, name, createdAt, updatedAt } +``` diff --git a/API.tax.md b/API.tax.md new file mode 100644 index 0000000..d6f77c4 --- /dev/null +++ b/API.tax.md @@ -0,0 +1,51 @@ +# tax + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `tax.create` + +*Source: `src/store/tax/create.js`* + +Creates a new tax rate. + +```js +const fn = create(pool); +const id = await fn(19); +// => 1 +``` + +## `tax.ensure` + +*Source: `src/store/tax/ensure.js`* + +Returns the id of a tax rate, creating it if it does not exist. + +```js +const fn = ensure(pool); +const id = await fn(19); +// => 1 +``` + +## `tax.getByRate` + +*Source: `src/store/tax/getByRate.js`* + +Returns a tax row by its rate. + +```js +const fn = getByRate(pool); +const tax = await fn(19); +// => { id, rate } +``` + +## `tax.list` + +*Source: `src/store/tax/list.js`* + +Lists all tax rates. + +```js +const fn = list(pool); +const taxes = await fn(); +// => [{ id, rate }] +``` diff --git a/API.unit.md b/API.unit.md new file mode 100644 index 0000000..7d10790 --- /dev/null +++ b/API.unit.md @@ -0,0 +1,38 @@ +# unit + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `unit.delete` + +*Source: `src/store/unit/delete.js`* + +Deletes a unit for a company by its SI code. + +```js +const fn = del(pool); +await fn(42, 1, 'l'); +``` + +## `unit.list` + +*Source: `src/store/unit/list.js`* + +Lists the units available for a company. + +```js +const fn = list(pool); +const units = await fn(42, 1); +// => [{ id, si, basesi, basesifactor, symbol, name }] +``` + +## `unit.upsert` + +*Source: `src/store/unit/upsert.js`* + +Creates or updates a unit for a company, keyed by its SI code. + +```js +const fn = upsert(pool); +const unit = await fn(42, 1, { si: 'l', basesi: 'm3', basesifactor: 0.001, symbol: 'L', name: 'Liter' }); +// => { id, si, basesi, basesifactor, symbol, name } +``` diff --git a/README.md b/README.md index fe3db67..f459dcc 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,6 @@ ID fields in the JS API use camelCase `…Id` (DB columns stay snake_case). `goo ## Schema -**Kein Migrations-Code:** Wir gehen von einer frischen DB aus (`npm run reset-db`). Schema nur in `src/schema.js`; Anpassungen an einer laufenden DB manuell per `sqlcmd`, nicht im Repo. - | Method | Description | | --- | --- | | `initialize()` | Runs all `SCHEMA_SCRIPTS` (`IF NOT EXISTS`). Does **not** purge. | diff --git a/generate-api-doc.js b/generate-api-doc.js new file mode 100644 index 0000000..1c4f0fa --- /dev/null +++ b/generate-api-doc.js @@ -0,0 +1,225 @@ +import { readdirSync, readFileSync, writeFileSync, statSync } from 'node:fs'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const storeDir = join(__dirname, 'src', 'store'); +const outputPath = join(__dirname, 'API.md'); + +// Modules that are exposed on the LibDashStore instance (from src/index.js). +// Order here controls the order of sections in the generated document. +const MODULE_ORDER = [ + 'companyuser', + 'company', + 'category', + 'article', + 'lang', + 'tax', + 'unit', + 'companysetting', + 'brand', + 'customergroup', + 'entity', + 'entityaddress', + 'entitycontact', + 'supplier', + 'delivery', + 'quote', + 'order', + 'posterminal', + 'google_auth', + 'pic', +]; + +// Files that are internal helpers and should not appear as public API entries. +const INTERNAL_FILES = new Set([ + 'request.js', + 'slugify.js', + 'initialize.js', + 'purge.js', + 'helpers.js', + 'writeLines.js', + 'shapeSetting.js', + 'shapeUnit.js', + 'ensureDefault.js', + 'ensureLieferantenGroup.js', + 'resolveCompanyAccess.js', + 'resolveCategoryAccess.js', + 'resolveCustomerGroupAccess.js', + 'resolveEntityAccess.js', + 'resolvePicAccess.js', + 'resolveArticleBySku.js', + 'queryBySku.js', + 'queryCategoryArticles.js', + 'getCategoryPosterminalIds.js', + 'nextSku.js', + 'createStore.js', + 'index.js', +]); + +/** + * Extract the leading JSDoc block from a source string. + * @param {string} source + * @returns {{ description: string, example: string } | null} + */ +function extractJsDoc(source) { + const match = source.match(/\/\*\*([\s\S]*?)\*\//); + if (!match) return null; + + const block = match[1]; + const lines = block + .split('\n') + .map((l) => l.replace(/^\s*\*\s?/, '').replace(/^\s*\*/, '')); + + const description = []; + const example = []; + let inExample = false; + + for (const line of lines) { + if (line.trim() === '@example') { + inExample = true; + continue; + } + if (line.trim().startsWith('@')) { + inExample = false; + continue; + } + if (inExample) { + example.push(line); + } else if (line.trim()) { + description.push(line.trim()); + } + } + + return { + description: description.join(' ').trim(), + example: example.join('\n').trim(), + }; +} + +/** + * Recursively collect all .js files under a directory. + * @param {string} dir + * @returns {string[]} absolute file paths + */ +function collectFiles(dir) { + const out = []; + for (const entry of readdirSync(dir)) { + const full = join(dir, entry); + if (statSync(full).isDirectory()) { + out.push(...collectFiles(full)); + } else if (entry.endsWith('.js')) { + out.push(full); + } + } + return out; +} + +/** + * Build a map of module name -> array of { name, file, description, example }. + * @returns {Map>} + */ +function buildModules() { + const modules = new Map(); + + for (const file of collectFiles(storeDir)) { + const rel = file.slice(storeDir.length + 1).split('/'); + const moduleName = rel[0]; + const fileName = rel[rel.length - 1]; + + if (INTERNAL_FILES.has(fileName)) continue; + + const source = readFileSync(file, 'utf8'); + const doc = extractJsDoc(source); + if (!doc) continue; + + const fnName = fileName.replace(/\.js$/, ''); + if (!modules.has(moduleName)) { + modules.set(moduleName, []); + } + modules.get(moduleName).push({ + name: fnName, + file: rel.join('/'), + description: doc.description, + example: doc.example, + }); + } + + return modules; +} + +function renderSection(moduleName, entries) { + const lines = []; + lines.push(`# ${moduleName}`); + lines.push(''); + lines.push( + 'This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`.', + ); + lines.push(''); + + for (const entry of entries) { + lines.push(`## \`${moduleName}.${entry.name}\``); + lines.push(''); + lines.push(`*Source: \`src/store/${entry.file}\`*`); + lines.push(''); + if (entry.description) { + lines.push(entry.description); + lines.push(''); + } + if (entry.example) { + lines.push('```js'); + lines.push(entry.example); + lines.push('```'); + lines.push(''); + } + } + + return lines.join('\n'); +} + +function render() { + const modules = buildModules(); + + const ordered = MODULE_ORDER.filter((m) => modules.has(m)); + const extra = [...modules.keys()].filter((m) => !MODULE_ORDER.includes(m)).sort(); + const moduleNames = [...ordered, ...extra]; + + // Write one file per section: API.
.md + const written = []; + for (const moduleName of moduleNames) { + const sectionPath = join(__dirname, `API.${moduleName}.md`); + const markdown = renderSection(moduleName, modules.get(moduleName)); + writeFileSync(sectionPath, markdown, 'utf8'); + written.push({ moduleName, sectionPath, bytes: markdown.length }); + } + + // Write the index API.md linking to each section file. + const lines = []; + lines.push('# LibDashStore API'); + lines.push(''); + lines.push( + 'This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`.', + ); + lines.push(''); + lines.push( + 'The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each method is an async function that takes a `pool` (mssql connection pool) at construction time and returns a callable function. Methods are grouped by the namespace they are exposed under.', + ); + lines.push(''); + lines.push('## Table of Contents'); + lines.push(''); + + for (const { moduleName } of written) { + lines.push(`- [${moduleName}](API.${moduleName}.md)`); + } + + lines.push(''); + + return { index: lines.join('\n'), written }; +} + +const { index, written } = render(); +writeFileSync(outputPath, index, 'utf8'); +console.log(`Wrote ${outputPath} (${index.length} bytes)`); +for (const { moduleName, sectionPath, bytes } of written) { + console.log(`Wrote ${sectionPath} (${bytes} bytes)`); +} diff --git a/package.json b/package.json index e22905f..6809ec3 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ }, "scripts": { "schema-graph": "node generate-schema-graph.js", + "api-doc": "node generate-api-doc.js", "init-schema": "node scripts/init-schema.js", "purge-db": "node scripts/purge-db.js", "reset-db": "node scripts/reset-db.js",