@docbox-nz/hapi-gateway 0.1.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.
Files changed (45) hide show
  1. package/.eslintignore +6 -0
  2. package/.eslintrc +131 -0
  3. package/.prettierignore +11 -0
  4. package/.prettierrc +6 -0
  5. package/LICENSE.md +21 -0
  6. package/README.md +152 -0
  7. package/cspell.json +6 -0
  8. package/dist/api/adminService.d.ts +16 -0
  9. package/dist/api/boxService.d.ts +43 -0
  10. package/dist/api/client.d.ts +45 -0
  11. package/dist/api/docboxFile.d.ts +15 -0
  12. package/dist/api/fileService.d.ts +251 -0
  13. package/dist/api/folderService.d.ts +45 -0
  14. package/dist/api/linkService.d.ts +115 -0
  15. package/dist/api/taskService.d.ts +23 -0
  16. package/dist/api/utils.d.ts +1 -0
  17. package/dist/error.d.ts +11 -0
  18. package/dist/index.browser.cjs +988 -0
  19. package/dist/index.browser.cjs.map +1 -0
  20. package/dist/index.browser.esm.js +984 -0
  21. package/dist/index.browser.esm.js.map +1 -0
  22. package/dist/index.browser.js +4390 -0
  23. package/dist/index.browser.js.map +1 -0
  24. package/dist/index.d.ts +4 -0
  25. package/dist/index.node.cjs +22660 -0
  26. package/dist/index.node.cjs.map +1 -0
  27. package/dist/index.node.esm.js +22657 -0
  28. package/dist/index.node.esm.js.map +1 -0
  29. package/dist/index.node.js +20809 -0
  30. package/dist/index.node.js.map +1 -0
  31. package/dist/options.d.ts +79 -0
  32. package/dist/types/box.d.ts +59 -0
  33. package/dist/types/file.d.ts +371 -0
  34. package/dist/types/folder.d.ts +153 -0
  35. package/dist/types/index.d.ts +22 -0
  36. package/dist/types/link.d.ts +136 -0
  37. package/dist/types/search.d.ts +177 -0
  38. package/dist/types/shared.d.ts +94 -0
  39. package/dist/types/user.d.ts +20 -0
  40. package/package.json +56 -0
  41. package/rollup.config.js +36 -0
  42. package/src/error.ts +46 -0
  43. package/src/index.ts +244 -0
  44. package/src/options.ts +95 -0
  45. package/tsconfig.json +15 -0
package/.eslintignore ADDED
@@ -0,0 +1,6 @@
1
+ // .eslintignore
2
+ build/*
3
+ dist/*
4
+ public/*
5
+ **/out/*
6
+ **/node_modules/*
package/.eslintrc ADDED
@@ -0,0 +1,131 @@
1
+ {
2
+ "root": true,
3
+ "env": {
4
+ "browser": true,
5
+ "es2021": true,
6
+ },
7
+ "plugins": [
8
+ "perfectionist",
9
+ "unused-imports",
10
+ "@typescript-eslint",
11
+ "prettier"
12
+ ],
13
+ "extends": [
14
+ "airbnb",
15
+ "airbnb-typescript",
16
+ "airbnb/hooks",
17
+ "prettier"
18
+ ],
19
+ "parser": "@typescript-eslint/parser",
20
+ "parserOptions": {
21
+ "ecmaVersion": "latest",
22
+ "sourceType": "module",
23
+ "project": "./tsconfig.json",
24
+ },
25
+ "settings": {
26
+ "import/resolver": {
27
+ "typescript": {
28
+ "alwaysTryTypes": true,
29
+ },
30
+ },
31
+ },
32
+ "rules": {
33
+ "max-classes-per-file": 10,
34
+ "no-return-await": 0,
35
+ "@typescript-eslint/return-await": 0,
36
+ "no-await-in-loop": 0,
37
+ "no-restricted-syntax": [
38
+ "error",
39
+ "ForInStatement",
40
+ "LabeledStatement",
41
+ "WithStatement"
42
+ ],
43
+ "no-alert": 0,
44
+ "camelcase": 0,
45
+ "no-console": 0,
46
+ "no-continue": 0,
47
+ "no-unused-vars": 0,
48
+ "no-param-reassign": 0,
49
+ "no-underscore-dangle": 0,
50
+ "no-restricted-exports": 0,
51
+ "no-promise-executor-return": 0,
52
+ "import/prefer-default-export": 0,
53
+ "@typescript-eslint/naming-convention": 0,
54
+ "jsx-a11y/control-has-associated-label": 0,
55
+ "@typescript-eslint/no-use-before-define": 0,
56
+ "@typescript-eslint/no-shadow": 0,
57
+ "prefer-destructuring": [
58
+ 1,
59
+ {
60
+ "object": true,
61
+ "array": false,
62
+ },
63
+ ],
64
+ "@typescript-eslint/no-unused-vars": [
65
+ 1,
66
+ {
67
+ "args": "none",
68
+ "argsIgnorePattern": "^_",
69
+ "varsIgnorePattern": "^_",
70
+ "caughtErrorsIgnorePattern": "^_",
71
+ },
72
+ ],
73
+ // unused-imports
74
+ // https://www.npmjs.com/package/eslint-plugin-unused-imports
75
+ "unused-imports/no-unused-imports": 1,
76
+ "unused-imports/no-unused-vars": [
77
+ 0,
78
+ {
79
+ "vars": "all",
80
+ "varsIgnorePattern": "^_",
81
+ "args": "after-used",
82
+ "argsIgnorePattern": "^_",
83
+ },
84
+ ],
85
+ // perfectionist
86
+ // https://eslint-plugin-perfectionist.azat.io/
87
+ "perfectionist/sort-named-imports": [
88
+ 1,
89
+ {
90
+ "order": "asc",
91
+ "type": "line-length",
92
+ },
93
+ ],
94
+ "perfectionist/sort-named-exports": [
95
+ 1,
96
+ {
97
+ "order": "asc",
98
+ "type": "line-length",
99
+ },
100
+ ],
101
+ "perfectionist/sort-exports": [
102
+ 1,
103
+ {
104
+ "order": "asc",
105
+ "type": "line-length",
106
+ },
107
+ ],
108
+ "perfectionist/sort-imports": [
109
+ 1,
110
+ {
111
+ "order": "asc",
112
+ "type": "line-length",
113
+ "newlines-between": "always",
114
+ "groups": [
115
+ [
116
+ "builtin",
117
+ "external"
118
+ ],
119
+ [
120
+ "parent",
121
+ "sibling",
122
+ "index"
123
+ ],
124
+ ],
125
+ "internal-pattern": [
126
+ "src/**"
127
+ ],
128
+ },
129
+ ],
130
+ },
131
+ }
@@ -0,0 +1,11 @@
1
+ build/*
2
+ dist/*
3
+ public/*
4
+ **/out/*
5
+ **/.next/*
6
+ **/node_modules/*
7
+
8
+ package-lock.json
9
+ yarn.lock
10
+
11
+ .eslintrc
package/.prettierrc ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "printWidth": 100,
3
+ "singleQuote": true,
4
+ "trailingComma": "es5",
5
+ "tabWidth": 2
6
+ }
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Provida Ltd.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,152 @@
1
+ # 📦 @docbox-nz/hapi-gateway
2
+
3
+ Docbox Gateway implementation for hapi
4
+
5
+ Provides routes for forwarding requests to docbox and methods for enforcing access control over said routes
6
+
7
+ ## Requirements
8
+ - Hapi.js v20.1.0 or newer
9
+ - Node.js 20+
10
+
11
+ ## Installation
12
+
13
+ To install the gateway use the following command (adjusted for your desired package manager):
14
+
15
+ ```sh
16
+ npm i @docbox-nz/hapi-gateway
17
+ ```
18
+
19
+ You will also need to ensure that you have `@hapi/hapi` installed this plugin supports versions `^20.1.0 || ^21.0.0`
20
+
21
+
22
+ ## Plugin setup
23
+
24
+ For a simple installation where not much additional logic is required, you can add the following to your server setup
25
+
26
+ ```js
27
+ import { DocboxGateway } from "@docbox-nz/hapi-gateway";
28
+
29
+ server.register({
30
+ plugin: DocboxGateway,
31
+ options: {
32
+ // Prefix all routes with /data
33
+ basePath: '/data',
34
+ // Base request options for docbox routes
35
+ baseRouteOptions: { },
36
+ // URL for the docbox API
37
+ docboxBaseURL: "http://docbox-server",
38
+
39
+ // Get the tenant for a request
40
+ getRequestTenant(request) {
41
+ // ..derive your target tenant
42
+ // this can be hard-coded for single tenant setups
43
+ return { id: '81284060-9542-4d66-9731-49ca3eb93bf9', env: "Development"}
44
+ },
45
+
46
+ // Get the user for a request
47
+ getRequestUser(request) {
48
+ // ..derive your request user
49
+ return {
50
+ id: "dd5ba8b5-7da2-4e8b-b255-9641faece80e",
51
+ name: "Example User",
52
+ imageId: "https://example.com/example.png"
53
+ }
54
+ },
55
+
56
+ // Check request read access
57
+ async isAllowedRead(request, scope, path) {
58
+ // ..assert request is allowed to access scope
59
+ return true;
60
+ },
61
+
62
+ // Check request write access
63
+ async isAllowedWrite(request, scope, path) {
64
+ // ..assert request is allowed to access scope
65
+ return true;
66
+ },
67
+ }
68
+ });
69
+ ```
70
+
71
+ ## Complex Routing Setup
72
+
73
+ If you have a more complex routing setup for your hapi app, you can use the `createDocboxRoutes` function to create a docbox setup and obtain a list of routes that you can manually add using `server.route`
74
+
75
+ ```js
76
+ import { createDocboxRoutes } from "@docbox-nz/hapi-gateway";
77
+
78
+ const routes = createDocboxRoutes({
79
+ // Prefix all routes with /data
80
+ basePath: '/data',
81
+ // Base request options for docbox routes
82
+ baseRouteOptions: { },
83
+ // URL for the docbox API
84
+ docboxBaseURL: "http://docbox-server",
85
+
86
+ // Get the tenant for a request
87
+ getRequestTenant(request) {
88
+ // ..derive your target tenant
89
+ // this can be hard-coded for single tenant setups
90
+ return { id: '81284060-9542-4d66-9731-49ca3eb93bf9', env: "Development"}
91
+ },
92
+
93
+ // Get the user for a request
94
+ getRequestUser(request) {
95
+ // ..derive your request user
96
+ return {
97
+ id: "dd5ba8b5-7da2-4e8b-b255-9641faece80e",
98
+ name: "Example User",
99
+ imageId: "https://example.com/example.png"
100
+ }
101
+ },
102
+
103
+ // Check request read access
104
+ async isAllowedRead(request, scope, path) {
105
+ // ..assert request is allowed to access scope
106
+ return true;
107
+ },
108
+
109
+ // Check request write access
110
+ async isAllowedWrite(request, scope, path) {
111
+ // ..assert request is allowed to access scope
112
+ return true;
113
+ },
114
+ });
115
+
116
+ module.exports = routes;
117
+ ```
118
+
119
+
120
+ ## Example access control
121
+
122
+ Access control is enforced on a scope level, you should check the `scope` (Document box scope) and decide whether the request should be allowed based
123
+ on some information extracted from the request (or some other available context)
124
+
125
+ > [!NOTE]
126
+ >
127
+ > The `isAllowedRead` and `isAllowedWrite` functions can be sync or async, this allows you to perform additional logic such as checking your database for permission requirements
128
+ >
129
+ > `isAllowedWrite` also enforces the access control for creating new document boxes. Requests to `POST /box` are document box creation requests.
130
+
131
+ ```js
132
+
133
+ function isAllowedWrite(request, scope, path) {
134
+
135
+ // Get authenticated user scopes
136
+ const userScopes = request.auth.credentials.scope
137
+
138
+ // User is trying to access the "admin-area" scope
139
+ if (scope === "admin-area") {
140
+
141
+ // Ensure the user has the required admin scope
142
+ if (userScopes.includes('admin')) {
143
+ return true;
144
+ }
145
+
146
+ }
147
+
148
+ // Deny by default
149
+ return false;
150
+ }
151
+
152
+ ```
package/cspell.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "words": [
3
+ "Docbox",
4
+ "Jacobtread"
5
+ ]
6
+ }
@@ -0,0 +1,16 @@
1
+ import { DocboxAdminSearchRequest, DocboxSearchResponseAdmin } from '../types';
2
+ import { DocboxClient } from './client';
3
+ export declare class AdminService {
4
+ private client;
5
+ constructor(client: DocboxClient);
6
+ /**
7
+ * Perform an admin search across multiple document boxes.
8
+ *
9
+ * This function will only work on your server handling authentication
10
+ * you should not allow the frontend to access these endpoints
11
+ *
12
+ * @param data Search request data
13
+ * @returns The search results
14
+ */
15
+ search(data: DocboxAdminSearchRequest): Promise<DocboxSearchResponseAdmin>;
16
+ }
@@ -0,0 +1,43 @@
1
+ import { DocboxSearchRequest, DocboxSearchResponse, DocumentBoxResponse, DocumentBoxScope, DocumentBoxStats } from '../types';
2
+ import { DocboxClient } from './client';
3
+ export declare class BoxService {
4
+ private client;
5
+ constructor(client: DocboxClient);
6
+ /**
7
+ * Get a document box for a scope
8
+ *
9
+ * @param scope Scope of the document box to get
10
+ * @param createIfMissing Whether to create the document box if it doesn't exist
11
+ */
12
+ get(scope: DocumentBoxScope, createIfMissing?: boolean): Promise<DocumentBoxResponse>;
13
+ /**
14
+ * Creates a new document box optional returning an existing one if there is one available
15
+ *
16
+ * @param scope Scope for the document box to create
17
+ * @param allowExisting Whether to allow returning an existing document box (If one is present)
18
+ * @returns The created document box
19
+ */
20
+ create(scope: DocumentBoxScope, allowExisting?: boolean): Promise<DocumentBoxResponse>;
21
+ /**
22
+ * Delete a specific document vox
23
+ *
24
+ * @param scope Scope of the document box to delete
25
+ * @returns
26
+ */
27
+ delete(scope: DocumentBoxScope): Promise<any>;
28
+ /**
29
+ * Search within the provided document box
30
+ *
31
+ * @param scope The scope of the document box to search
32
+ * @param data Search request data
33
+ * @returns The search results
34
+ */
35
+ search(scope: DocumentBoxScope, data: DocboxSearchRequest): Promise<DocboxSearchResponse>;
36
+ /**
37
+ * Get statistics for the provided document box
38
+ *
39
+ * @param scope The scope of the document box
40
+ * @returns The box stats
41
+ */
42
+ stats(scope: DocumentBoxScope): Promise<DocumentBoxStats>;
43
+ }
@@ -0,0 +1,45 @@
1
+ import type { AxiosRequestConfig, AxiosInstance } from 'axios';
2
+ import { FileService } from './fileService';
3
+ import { BoxService as DocumentBoxService } from './boxService';
4
+ import { LinkService } from './linkService';
5
+ import { FolderService } from './folderService';
6
+ import { TaskService } from './taskService';
7
+ import { AdminService } from './adminService';
8
+ export declare class DocboxClient {
9
+ client: AxiosInstance;
10
+ /**
11
+ * Document box related operations
12
+ */
13
+ documentBox: DocumentBoxService;
14
+ /**
15
+ * Task related operations
16
+ */
17
+ task: TaskService;
18
+ /**
19
+ * File related operations
20
+ */
21
+ file: FileService;
22
+ /**
23
+ * Link related operations
24
+ */
25
+ link: LinkService;
26
+ /**
27
+ * Folder related operations
28
+ */
29
+ folder: FolderService;
30
+ /**
31
+ * Admin related operations
32
+ */
33
+ admin: AdminService;
34
+ /**
35
+ * Creates a new docbox
36
+ *
37
+ * @param client
38
+ */
39
+ constructor(client: AxiosInstance);
40
+ httpGet<T = any, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<T>;
41
+ httpPost<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>): Promise<T>;
42
+ httpPut<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>): Promise<T>;
43
+ httpPatch<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>): Promise<T>;
44
+ httpDelete<T = any, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<T>;
45
+ }
@@ -0,0 +1,15 @@
1
+ import { DocFile } from '../types/file';
2
+ declare let FileGlobal: {
3
+ new (fileBits: BlobPart[], fileName: string, options?: FilePropertyBag): File;
4
+ prototype: File;
5
+ };
6
+ /**
7
+ * Wrapper around the browser File type to allow using a docbox file
8
+ * in place when handling already uploaded files in a form
9
+ */
10
+ export declare class DocboxFile extends FileGlobal {
11
+ file: DocFile;
12
+ get size(): number;
13
+ constructor(file: DocFile);
14
+ }
15
+ export {};