@timesheet/plugin-xero 1.0.1

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 ADDED
@@ -0,0 +1,41 @@
1
+ # Xero Sync
2
+
3
+ > Intended integration between Timesheet and Xero. Early scaffold, not yet functional.
4
+
5
+ This package is an early scaffold. The handlers are wired into the plugin runtime and return placeholder results (for example, `testConnection` reports OK and `syncTaskToExternal` echoes the task id), but no calls are made to the Xero API yet. The manifest below describes the intended shape of the integration rather than working behavior.
6
+
7
+ - Package: `@timesheet/plugin-xero`
8
+ - Manifest id: `xero-sync`
9
+ - Category: accounting
10
+ - Status: scaffold (no Xero API integration implemented)
11
+
12
+ ## Authentication
13
+
14
+ OAuth 2.0. Scopes are placeholders (`read`, `write`) and will be replaced with the real Xero scopes when the integration is implemented.
15
+
16
+ ## Configuration
17
+
18
+ | Option | Required | Default | Description |
19
+ | --- | --- | --- | --- |
20
+ | `syncDirection` | yes | `bidirectional` | One of `bidirectional`, `timesheet-to-external`, `external-to-timesheet`. |
21
+
22
+ ## Mappings
23
+
24
+ - **Project mapping**: Timesheet project to Xero (placeholder, not yet wired to real Xero entities).
25
+
26
+ ## Triggers
27
+
28
+ - **Task Created** (event): scaffolded handler for new Timesheet tasks.
29
+ - **Xero Webhook** (webhook): scaffolded inbound endpoint.
30
+ - **Scheduled Full Sync** (daily at 02:00 UTC): scaffolded background sync.
31
+ - **Manual Sync** (user action): scaffolded sync from the integration settings page.
32
+
33
+ ## Development
34
+
35
+ ```bash
36
+ npm install # or: npm ci
37
+ npm run build # compile TypeScript into dist/
38
+ npm run typecheck
39
+ ```
40
+
41
+ The package ships `dist/` and `manifest.json`; the sandboxed plugin runtime loads it by package name, version, and integrity. Shared tests live in `integrations/tests/` and run from the `integrations/` root with `npm test`.
@@ -0,0 +1,5 @@
1
+ import { WebhookInput } from '@timesheet/integration-sdk';
2
+ export declare const handleWebhook: import("@timesheet/integration-sdk").IntegrationHandler<WebhookInput, {
3
+ system: string;
4
+ handled: boolean;
5
+ }, Record<string, unknown>>;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleWebhook = void 0;
4
+ const integration_sdk_1 = require("@timesheet/integration-sdk");
5
+ const SYSTEM = 'xero';
6
+ exports.handleWebhook = (0, integration_sdk_1.defineHandler)(async (input, context) => {
7
+ context.logger.info('Handling webhook', {
8
+ system: SYSTEM,
9
+ method: input.method,
10
+ installationId: context.installationId
11
+ });
12
+ return {
13
+ system: SYSTEM,
14
+ handled: true
15
+ };
16
+ });
@@ -0,0 +1,2 @@
1
+ import { ExternalEntity } from '@timesheet/integration-sdk';
2
+ export declare const listExternalProjects: import("@timesheet/integration-sdk").IntegrationHandler<void, ExternalEntity[], Record<string, unknown>>;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listExternalProjects = void 0;
4
+ const integration_sdk_1 = require("@timesheet/integration-sdk");
5
+ const SYSTEM = 'xero';
6
+ exports.listExternalProjects = (0, integration_sdk_1.defineHandler)(async (_input, context) => {
7
+ context.logger.info('Listing external projects', {
8
+ system: SYSTEM,
9
+ installationId: context.installationId
10
+ });
11
+ return [
12
+ { id: 'xero-project-1', name: 'Xero Sync Project 1' },
13
+ { id: 'xero-project-2', name: 'Xero Sync Project 2' }
14
+ ];
15
+ });
@@ -0,0 +1,5 @@
1
+ export declare const runFullSync: import("@timesheet/integration-sdk").IntegrationHandler<void, {
2
+ system: string;
3
+ status: string;
4
+ syncedCount: number;
5
+ }, Record<string, unknown>>;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runFullSync = void 0;
4
+ const integration_sdk_1 = require("@timesheet/integration-sdk");
5
+ const SYSTEM = 'xero';
6
+ exports.runFullSync = (0, integration_sdk_1.defineHandler)(async (_input, context) => {
7
+ context.logger.info('Running full sync', {
8
+ system: SYSTEM,
9
+ installationId: context.installationId,
10
+ syncDirection: context.config?.syncDirection ?? 'bidirectional'
11
+ });
12
+ return {
13
+ system: SYSTEM,
14
+ status: 'completed',
15
+ syncedCount: 0
16
+ };
17
+ });
@@ -0,0 +1,5 @@
1
+ import { WebhookInput } from '@timesheet/integration-sdk';
2
+ export declare const syncTaskFromExternal: import("@timesheet/integration-sdk").IntegrationHandler<WebhookInput, {
3
+ system: string;
4
+ accepted: boolean;
5
+ }, Record<string, unknown>>;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.syncTaskFromExternal = void 0;
4
+ const integration_sdk_1 = require("@timesheet/integration-sdk");
5
+ const SYSTEM = 'xero';
6
+ exports.syncTaskFromExternal = (0, integration_sdk_1.defineHandler)(async (input, context) => {
7
+ context.logger.info('Syncing task from external payload', {
8
+ system: SYSTEM,
9
+ method: input.method,
10
+ installationId: context.installationId
11
+ });
12
+ return {
13
+ system: SYSTEM,
14
+ accepted: true
15
+ };
16
+ });
@@ -0,0 +1,6 @@
1
+ import { TaskCreatedInput } from '@timesheet/integration-sdk';
2
+ export declare const syncTaskToExternal: import("@timesheet/integration-sdk").IntegrationHandler<TaskCreatedInput, {
3
+ system: string;
4
+ taskId: string;
5
+ direction: string;
6
+ }, Record<string, unknown>>;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.syncTaskToExternal = void 0;
4
+ const integration_sdk_1 = require("@timesheet/integration-sdk");
5
+ const SYSTEM = 'xero';
6
+ exports.syncTaskToExternal = (0, integration_sdk_1.defineHandler)(async (input, context) => {
7
+ context.logger.info('Syncing task to external system', {
8
+ system: SYSTEM,
9
+ taskId: input.taskId,
10
+ installationId: context.installationId
11
+ });
12
+ return {
13
+ system: SYSTEM,
14
+ taskId: input.taskId,
15
+ direction: 'timesheet-to-external'
16
+ };
17
+ });
@@ -0,0 +1,5 @@
1
+ export declare const testConnection: import("@timesheet/integration-sdk").IntegrationHandler<void, {
2
+ system: string;
3
+ ok: boolean;
4
+ installationId: string;
5
+ }, Record<string, unknown>>;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.testConnection = void 0;
4
+ const integration_sdk_1 = require("@timesheet/integration-sdk");
5
+ const SYSTEM = 'xero';
6
+ exports.testConnection = (0, integration_sdk_1.defineHandler)(async (_input, context) => {
7
+ context.logger.info('Testing integration connection', {
8
+ system: SYSTEM,
9
+ installationId: context.installationId
10
+ });
11
+ return {
12
+ system: SYSTEM,
13
+ ok: true,
14
+ installationId: context.installationId
15
+ };
16
+ });
@@ -0,0 +1,8 @@
1
+ export { syncTaskToExternal } from './handlers/syncTaskToExternal';
2
+ export { syncTaskFromExternal } from './handlers/syncTaskFromExternal';
3
+ export { handleWebhook } from './handlers/handleWebhook';
4
+ export { runFullSync } from './handlers/runFullSync';
5
+ export { testConnection } from './handlers/testConnection';
6
+ export { listExternalProjects } from './handlers/listExternalProjects';
7
+ export declare const PLUGIN_SYSTEM = "xero";
8
+ export declare const PLUGIN_NAME = "Xero Sync";
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PLUGIN_NAME = exports.PLUGIN_SYSTEM = exports.listExternalProjects = exports.testConnection = exports.runFullSync = exports.handleWebhook = exports.syncTaskFromExternal = exports.syncTaskToExternal = void 0;
4
+ var syncTaskToExternal_1 = require("./handlers/syncTaskToExternal");
5
+ Object.defineProperty(exports, "syncTaskToExternal", { enumerable: true, get: function () { return syncTaskToExternal_1.syncTaskToExternal; } });
6
+ var syncTaskFromExternal_1 = require("./handlers/syncTaskFromExternal");
7
+ Object.defineProperty(exports, "syncTaskFromExternal", { enumerable: true, get: function () { return syncTaskFromExternal_1.syncTaskFromExternal; } });
8
+ var handleWebhook_1 = require("./handlers/handleWebhook");
9
+ Object.defineProperty(exports, "handleWebhook", { enumerable: true, get: function () { return handleWebhook_1.handleWebhook; } });
10
+ var runFullSync_1 = require("./handlers/runFullSync");
11
+ Object.defineProperty(exports, "runFullSync", { enumerable: true, get: function () { return runFullSync_1.runFullSync; } });
12
+ var testConnection_1 = require("./handlers/testConnection");
13
+ Object.defineProperty(exports, "testConnection", { enumerable: true, get: function () { return testConnection_1.testConnection; } });
14
+ var listExternalProjects_1 = require("./handlers/listExternalProjects");
15
+ Object.defineProperty(exports, "listExternalProjects", { enumerable: true, get: function () { return listExternalProjects_1.listExternalProjects; } });
16
+ exports.PLUGIN_SYSTEM = 'xero';
17
+ exports.PLUGIN_NAME = 'Xero Sync';
package/manifest.json ADDED
@@ -0,0 +1,150 @@
1
+ {
2
+ "id": "xero-sync",
3
+ "name": "Xero Sync",
4
+ "version": "1.0.1",
5
+ "description": "Timesheet Xero Sync plugin integration",
6
+ "category": "accounting",
7
+ "tags": ["sync", "timesheet", "xero"],
8
+ "dataAccess": ["projects", "tasks", "colleagues", "settings"],
9
+ "externalAuth": [
10
+ {
11
+ "id": "xero",
12
+ "type": "oauth2",
13
+ "oauth": {
14
+ "authorizeUrl": "https://example.com/oauth/authorize",
15
+ "tokenUrl": "https://example.com/oauth/token",
16
+ "scopes": ["read", "write"]
17
+ }
18
+ }
19
+ ],
20
+ "configSchema": {
21
+ "type": "object",
22
+ "properties": {
23
+ "syncDirection": {
24
+ "type": "string",
25
+ "title": "Sync Direction",
26
+ "enum": ["bidirectional", "timesheet-to-external", "external-to-timesheet"],
27
+ "default": "bidirectional",
28
+ "x-ui-widget": "radio"
29
+ }
30
+ },
31
+ "required": ["syncDirection"]
32
+ },
33
+ "mappingSchema": {
34
+ "system": "xero",
35
+ "mappings": [
36
+ {
37
+ "id": "projects",
38
+ "title": "Project Mapping",
39
+ "description": "Map Timesheet projects to Xero Sync projects",
40
+ "localEntity": {
41
+ "type": "project",
42
+ "label": "Timesheet Project",
43
+ "display": "{{title}}"
44
+ },
45
+ "externalEntity": {
46
+ "type": "project",
47
+ "label": "Xero Sync Project",
48
+ "fetchAction": "list-external-projects"
49
+ },
50
+ "required": true,
51
+ "minMappings": 1
52
+ }
53
+ ]
54
+ },
55
+ "triggers": [
56
+ {
57
+ "id": "task-created",
58
+ "type": "event",
59
+ "name": "Task Created",
60
+ "description": "Sync when a new task is created",
61
+ "events": ["task.create"],
62
+ "configurable": true
63
+ },
64
+ {
65
+ "id": "integration-webhook",
66
+ "type": "webhook",
67
+ "name": "Xero Sync Webhook",
68
+ "description": "Receive inbound changes from Xero Sync",
69
+ "configurable": false,
70
+ "webhook": {
71
+ "signature": {
72
+ "header": "x-timesheet-signature",
73
+ "algorithm": "hmac-sha256",
74
+ "secretConfigKey": "webhookSecret"
75
+ }
76
+ }
77
+ },
78
+ {
79
+ "id": "full-sync",
80
+ "type": "schedule",
81
+ "name": "Scheduled Full Sync",
82
+ "description": "Run background synchronization",
83
+ "schedule": "0 2 * * *",
84
+ "timezone": "UTC",
85
+ "configurable": true
86
+ },
87
+ {
88
+ "id": "manual-sync",
89
+ "type": "user_action",
90
+ "name": "Manual Sync",
91
+ "description": "Trigger a sync from settings",
92
+ "userAction": {
93
+ "label": "Sync Now",
94
+ "placement": "settings"
95
+ }
96
+ }
97
+ ],
98
+ "actions": [
99
+ {
100
+ "id": "sync-task-to-external",
101
+ "name": "Sync task to Xero Sync",
102
+ "handler": "syncTaskToExternal"
103
+ },
104
+ {
105
+ "id": "sync-task-from-external",
106
+ "name": "Sync task from Xero Sync",
107
+ "handler": "syncTaskFromExternal"
108
+ },
109
+ {
110
+ "id": "handle-webhook",
111
+ "handler": "handleWebhook",
112
+ "internal": true
113
+ },
114
+ {
115
+ "id": "run-full-sync",
116
+ "name": "Run full sync",
117
+ "handler": "runFullSync"
118
+ },
119
+ {
120
+ "id": "test-connection",
121
+ "name": "Test connection",
122
+ "handler": "testConnection"
123
+ },
124
+ {
125
+ "id": "list-external-projects",
126
+ "handler": "listExternalProjects",
127
+ "internal": true
128
+ }
129
+ ],
130
+ "pages": [
131
+ {
132
+ "id": "dashboard",
133
+ "title": "Sync Dashboard",
134
+ "icon": "chart-bar",
135
+ "layout": "dashboard",
136
+ "widgets": [
137
+ {
138
+ "id": "manual-sync-btn",
139
+ "type": "action_button",
140
+ "title": "Manual Sync",
141
+ "config": {
142
+ "actionId": "run-full-sync",
143
+ "label": "Run Full Sync",
144
+ "variant": "primary"
145
+ }
146
+ }
147
+ ]
148
+ }
149
+ ]
150
+ }
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@timesheet/plugin-xero",
3
+ "version": "1.0.1",
4
+ "main": "dist/index.js",
5
+ "types": "dist/index.d.ts",
6
+ "files": [
7
+ "dist",
8
+ "manifest.json"
9
+ ],
10
+ "scripts": {
11
+ "build": "rm -rf dist && tsc -p tsconfig.json",
12
+ "typecheck": "tsc --noEmit",
13
+ "prepublishOnly": "npm run build"
14
+ },
15
+ "dependencies": {
16
+ "@timesheet/integration-sdk": "^0.5.0"
17
+ },
18
+ "devDependencies": {
19
+ "@types/node": "^20.19.43",
20
+ "typescript": "^5.9.3"
21
+ }
22
+ }