@t4h.framework/sftp 0.5.0 → 0.6.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.
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
name: framework-sftp
|
|
3
3
|
description: >-
|
|
4
4
|
Guides correct use of @t4h.framework/sftp in T4H Framework workflows: SFTP
|
|
5
|
-
|
|
6
|
-
Binary file payloads, and
|
|
5
|
+
activities, SftpClaim runtime dependency, the reconciler-aware Sftp client,
|
|
6
|
+
Binary file payloads, and testing with TestWorkflowEnvironment. Use when
|
|
7
7
|
implementing SFTP upload/download/list in workflows, wiring SftpClaim providers,
|
|
8
|
-
mocking
|
|
8
|
+
mocking SftpClaim in workflow tests, working in packages/sftp, or integrating
|
|
9
9
|
remote file transfer (sftp:// connection strings, put/get, mkdir, stat, exists).
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -63,16 +63,12 @@ Node `>=22`. See [README.md](../../../README.md).
|
|
|
63
63
|
|
|
64
64
|
## Architecture
|
|
65
65
|
|
|
66
|
-
`Workflow` → **`Sftp`** (`History.bind` per activity) →
|
|
66
|
+
`Workflow` → **`Sftp`** (`History.bind` per activity) → shipped `Sftp*Activity` → **`SftpClaim.<method>(input)`** (runtime impl).
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
- **`run`** delegates to **`this[CLAIMS_KEY].sftp.<method>(payload)`** (claim method name matches activity: `get`, `put`, `delete`, etc.).
|
|
73
|
-
- Void activities: **`toOutput()`** returns **`undefined`**.
|
|
74
|
-
|
|
75
|
-
`Sftp` stores **`public readonly connectionString`** and forwards each method to the bound activity reconciler.
|
|
68
|
+
From a workflow you call the **`Sftp`** client; it forwards each method to the
|
|
69
|
+
bound, replay-safe activity for you. The claim method name matches the client
|
|
70
|
+
method (`get`, `put`, `delete`, …) and the runtime supplies the `SftpClaim`
|
|
71
|
+
implementation.
|
|
76
72
|
|
|
77
73
|
---
|
|
78
74
|
|
|
@@ -120,7 +116,7 @@ import { Sftp } from '@t4h.framework/sftp'
|
|
|
120
116
|
const sftp = new Sftp('sftp://user:pass@sftp.example.com:22')
|
|
121
117
|
```
|
|
122
118
|
|
|
123
|
-
All calls
|
|
119
|
+
All calls run inside a workflow (the runtime, or `TestWorkflowEnvironment` in tests, provides the reconciler context).
|
|
124
120
|
|
|
125
121
|
### Methods
|
|
126
122
|
|
|
@@ -176,9 +172,12 @@ Use **`Binary`** from `@t4h.framework/core` for upload/download content (`put`,
|
|
|
176
172
|
|
|
177
173
|
---
|
|
178
174
|
|
|
179
|
-
##
|
|
175
|
+
## Using SFTP in a workflow via `History.reconciler`
|
|
180
176
|
|
|
181
|
-
Prefer **`Sftp`**
|
|
177
|
+
Prefer the **`Sftp`** client. When you need the exported activity directly,
|
|
178
|
+
drive the **shipped** `Sftp*Activity` class through `History.reconciler` — this
|
|
179
|
+
is a ready, replay-safe helper. **Never define or extend your own activity**;
|
|
180
|
+
only pass the activity classes this package exports.
|
|
182
181
|
|
|
183
182
|
```typescript
|
|
184
183
|
import { History } from '@t4h.framework/core'
|
|
@@ -282,75 +281,30 @@ type SftpStat = {
|
|
|
282
281
|
|
|
283
282
|
## Testing
|
|
284
283
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
284
|
+
Test the **workflow** with `TestWorkflowEnvironment` from
|
|
285
|
+
`@t4h.framework/core/testing`, mocking `SftpClaim` — the single claim every
|
|
286
|
+
`Sftp*Activity` resolves. Provide only the methods your workflow triggers
|
|
287
|
+
(`get`, `put`, `delete`, …). See the **framework-workflow-testing** skill for the
|
|
288
|
+
harness API.
|
|
290
289
|
|
|
291
290
|
```typescript
|
|
292
|
-
import {
|
|
293
|
-
import { describe, expect, it, vi } from 'vitest'
|
|
291
|
+
import { TestWorkflowEnvironment, mockClaim } from '@t4h.framework/core/testing'
|
|
294
292
|
import { SftpClaim } from '@t4h.framework/sftp'
|
|
295
|
-
import { SftpGetActivity, type SftpGetActivityInput } from '@t4h.framework/sftp'
|
|
296
|
-
|
|
297
|
-
const connectionString = 'sftp://user:pass@sftp.example.com:22'
|
|
298
|
-
const mockGet = vi.fn().mockReturnValue('binary-data' as any)
|
|
299
|
-
|
|
300
|
-
Claim.run(
|
|
301
|
-
[{ provide: SftpClaim, value: { get: mockGet } as unknown as SftpClaim }],
|
|
302
|
-
() => {
|
|
303
|
-
const activity: SftpGetActivity = Reflect.construct(SftpGetActivity, [])
|
|
304
|
-
const input: SftpGetActivityInput = {
|
|
305
|
-
connectionString,
|
|
306
|
-
filepath: '/remote/file.txt',
|
|
307
|
-
}
|
|
308
|
-
const output = activity.run(input)
|
|
309
|
-
expect(mockGet).toHaveBeenCalledWith(input)
|
|
310
|
-
expect(output).toBe('binary-data')
|
|
311
|
-
},
|
|
312
|
-
)
|
|
313
|
-
```
|
|
314
293
|
|
|
315
|
-
|
|
294
|
+
const mockGet = vi.fn().mockImplementation(async () => someBinary)
|
|
316
295
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
Pattern from `models/__tests__/Sftp.spec.ts`:
|
|
320
|
-
|
|
321
|
-
```typescript
|
|
322
|
-
import { History, PushActivity, type Activity } from '@t4h.framework/core'
|
|
323
|
-
import { Sftp, SftpGetActivity } from '@t4h.framework/sftp'
|
|
296
|
+
const env = TestWorkflowEnvironment.create({ now: 0 })
|
|
324
297
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
} catch (error) {
|
|
329
|
-
if (error instanceof PushActivity) return error as PushActivity<Activity>
|
|
330
|
-
throw error
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
const client = new Sftp('sftp://user:pass@sftp.example.com:22')
|
|
335
|
-
const trigger = await captureReconcilerTrigger(() =>
|
|
336
|
-
client.get('/remote/file.txt'),
|
|
337
|
-
)
|
|
338
|
-
expect(trigger.activity.constructor).toBe(SftpGetActivity)
|
|
339
|
-
```
|
|
340
|
-
|
|
341
|
-
Replay with canned output:
|
|
298
|
+
const output = await env.execute(workflow, input, {
|
|
299
|
+
claims: [mockClaim(SftpClaim, { get: mockGet })],
|
|
300
|
+
})
|
|
342
301
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
[{ output: mockBinary, type: 'sync' }],
|
|
346
|
-
() => client.get('/remote/file.txt'),
|
|
347
|
-
)
|
|
348
|
-
expect(result).toBe(mockBinary)
|
|
302
|
+
// each SftpClaim method receives the activity's serializable input
|
|
303
|
+
expect(mockGet.mock.calls[0][0]).toMatchObject({ filepath: '/remote/file.txt' })
|
|
349
304
|
```
|
|
350
305
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
Use `WorkflowTesting.run` with a mocked `SftpClaim` provider. See **framework-core** skill for `WorkflowTesting` and claim wiring.
|
|
306
|
+
An unconfigured claim method throws a clear error, so mock every method the
|
|
307
|
+
workflow reaches.
|
|
354
308
|
|
|
355
309
|
---
|
|
356
310
|
|
|
@@ -363,7 +317,7 @@ Use `WorkflowTesting.run` with a mocked `SftpClaim` provider. See **framework-co
|
|
|
363
317
|
5. Use **`filepath`** for get/put/append; **`path`** for most other operations; **`srcPath`/`destPath`** for copy/rename.
|
|
364
318
|
6. Use **`exists`** before destructive ops when idempotency matters; use **`delete(..., true)`** for tolerant deletes.
|
|
365
319
|
7. Use **`mkdir(..., true)`** / **`rmdir(..., true)`** only when recursive tree ops are intended.
|
|
366
|
-
8.
|
|
320
|
+
8. Test workflows with **`TestWorkflowEnvironment`** + **`mockClaim(SftpClaim, ...)`**; assert on the mock's `mock.calls`.
|
|
367
321
|
9. Do not document or import APIs not exported from `@t4h.framework/sftp`.
|
|
368
322
|
|
|
369
|
-
See also: `packages/sftp/README.md
|
|
323
|
+
See also: `packages/sftp/README.md`; **framework-workflow-testing** for the test harness.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAElD,wBAAgB,aAAa,CAAC,cAAc,GAAE,OAAO,CAAC,SAAS,CAAM,0DAKpE"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { mockClaim } from '@t4h.framework/core/testing';
|
|
2
|
+
import { SftpClaim } from '../models/SftpClaim.js';
|
|
3
|
+
export function mockSftpClaim(implementation = {}) {
|
|
4
|
+
return mockClaim(SftpClaim, {
|
|
5
|
+
list: async () => [],
|
|
6
|
+
...implementation,
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAA;AAEvD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAElD,MAAM,UAAU,aAAa,CAAC,iBAAqC,EAAE;IACnE,OAAO,SAAS,CAAC,SAAS,EAAE;QAC1B,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,EAAE;QACpB,GAAG,cAAc;KAClB,CAAC,CAAA;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@t4h.framework/sftp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "SFTP module for the T4H Framework",
|
|
5
5
|
"homepage": "https://github.com/tech4humans-brasil/framework/tree/main/packages/sftp",
|
|
6
6
|
"bugs": "https://github.com/tech4humans-brasil/framework/issues",
|
|
@@ -31,12 +31,12 @@
|
|
|
31
31
|
"test:watch": "vitest"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@t4h.framework/core": "^0.
|
|
34
|
+
"@t4h.framework/core": "^0.8.0",
|
|
35
35
|
"typescript": "^5.9.3",
|
|
36
36
|
"vitest": "^4.0.18"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@t4h.framework/core": "^0.
|
|
39
|
+
"@t4h.framework/core": "^0.8.0"
|
|
40
40
|
},
|
|
41
41
|
"packageManager": "yarn@4.12.0",
|
|
42
42
|
"engines": {
|