@particle-academy/telegram-js 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.
- package/CHANGELOG.md +62 -0
- package/LICENSE +21 -0
- package/README.md +51 -0
- package/dist/chunk-LFMQKSUM.js +124 -0
- package/dist/chunk-LFMQKSUM.js.map +1 -0
- package/dist/flow.cjs +158 -0
- package/dist/flow.cjs.map +1 -0
- package/dist/flow.d.cts +26 -0
- package/dist/flow.d.ts +26 -0
- package/dist/flow.js +43 -0
- package/dist/flow.js.map +1 -0
- package/dist/index.cjs +134 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +131 -0
- package/dist/index.d.ts +131 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/package.json +85 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@particle-academy/telegram-ui`,
|
|
4
|
+
`@particle-academy/telegram-js`, `particle-academy/telegram-php` and
|
|
5
|
+
`fancy-telegram`.
|
|
6
|
+
|
|
7
|
+
The four packages share one version, because they are generated from one
|
|
8
|
+
`provider/` definition and a version that meant something different in each
|
|
9
|
+
would be a version nobody could reason about.
|
|
10
|
+
|
|
11
|
+
## [0.1.0] — 2026-08-20
|
|
12
|
+
|
|
13
|
+
First release. Ported from the vendored connector at
|
|
14
|
+
`px-ui-sandbox/resources/flow-nodes/_telegram`.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- `get_updates` — start a run when a bot receives an update. A **poll**
|
|
19
|
+
trigger, not a webhook: `GET /getUpdates` with a persisted `offset` cursor.
|
|
20
|
+
- A faker for it, so the node runs on a canvas before any bot exists.
|
|
21
|
+
|
|
22
|
+
### The reason this provider exists in the set
|
|
23
|
+
|
|
24
|
+
**It breaks three assumptions Stripe never tested.**
|
|
25
|
+
|
|
26
|
+
1. **The trigger is not a webhook.** Telegram offers `getUpdates` long polling
|
|
27
|
+
OR `setWebhook`, never both for one bot. So the host's obligation here is a
|
|
28
|
+
schedule and a persisted cursor rather than a route and a signature — and a
|
|
29
|
+
poll trigger *calls* the provider, where a webhook trigger only republishes
|
|
30
|
+
what the host already verified. `delivery` was a declaration rather than an
|
|
31
|
+
assumption for exactly this case.
|
|
32
|
+
|
|
33
|
+
2. **The credential is a path segment.** `https://api.telegram.org/bot<token>/getUpdates`
|
|
34
|
+
— and the test environment is a further `/test` after the token. Auth and
|
|
35
|
+
estate are the same decision expressed in the URL, which is why `authorize`
|
|
36
|
+
has always been handed the resolved mode even though Stripe never used it.
|
|
37
|
+
|
|
38
|
+
3. **A rejection arrives as HTTP 200.** Telegram answers `200` with
|
|
39
|
+
`{"ok": false, "description": "..."}`. A status check alone reads that as
|
|
40
|
+
success and publishes an empty batch — a poll that silently finds nothing,
|
|
41
|
+
forever.
|
|
42
|
+
|
|
43
|
+
### The cursor is the part that bites
|
|
44
|
+
|
|
45
|
+
`offset` means "the first update id I have NOT handled", so the next cursor is
|
|
46
|
+
the highest `update_id` seen plus one. Off by one in either direction is a real
|
|
47
|
+
bug with no error attached: **too low replays updates forever, too high drops
|
|
48
|
+
one silently**. The trigger computes it and publishes it as `cursor`; the host
|
|
49
|
+
must persist it, because nothing else will.
|
|
50
|
+
|
|
51
|
+
An empty poll is the NORMAL case and gets its own `empty` port, so the main
|
|
52
|
+
path keeps meaning "something happened" while the host still has somewhere to
|
|
53
|
+
hang cursor bookkeeping.
|
|
54
|
+
|
|
55
|
+
### On not taking a dependency
|
|
56
|
+
|
|
57
|
+
There is no official Telegram SDK in any language. Calling the REST API
|
|
58
|
+
directly is therefore the correct choice here rather than a shortcut — the
|
|
59
|
+
alternative is a community wrapper, which is exactly the dependency the kit's
|
|
60
|
+
rules say not to take on a consumer's behalf.
|
|
61
|
+
|
|
62
|
+
[0.1.0]: https://github.com/Fancy-Friends/telegram/releases/tag/v0.1.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Particle Academy
|
|
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,51 @@
|
|
|
1
|
+
# Telegram
|
|
2
|
+
|
|
3
|
+
Telegram for [fancy-flow][flow] — as **four imported, versioned packages**, one
|
|
4
|
+
per runtime. Not vendored source: a copy cannot be upgraded, and third-party APIs
|
|
5
|
+
change.
|
|
6
|
+
|
|
7
|
+
[flow]: https://github.com/Particle-Academy/fancy-flow
|
|
8
|
+
|
|
9
|
+
| Runtime | Package | Install |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| Authoring surface (every host) | `@particle-academy/telegram-ui` | `npm install @particle-academy/telegram-ui` |
|
|
12
|
+
| Node | `@particle-academy/telegram-js` | `npm install @particle-academy/telegram-js` |
|
|
13
|
+
| PHP 8.4+ | `particle-academy/telegram-php` | `composer require particle-academy/telegram-php` |
|
|
14
|
+
| Python 3.11+ | `fancy-telegram` | `pip install fancy-telegram` |
|
|
15
|
+
|
|
16
|
+
The `ui` package is the editor surface and is React on every host — a PHP or
|
|
17
|
+
Python project installs it *and* its own runtime package, and never the `js` one.
|
|
18
|
+
|
|
19
|
+
## What it costs you
|
|
20
|
+
|
|
21
|
+
One dependency: `@particle-academy/fancy-connector-core` (or
|
|
22
|
+
`particle-academy/fancy-connector-core` on Composer), which the `js` and `php`
|
|
23
|
+
packages pull in themselves. The Python package has **zero** runtime
|
|
24
|
+
dependencies.
|
|
25
|
+
|
|
26
|
+
**No Telegram SDK.** Plain HTTP, deliberately: a vendor SDK is third-party code
|
|
27
|
+
subject to the kit's full approval bar, and one per provider is hundreds of
|
|
28
|
+
dependencies nobody is tracking.
|
|
29
|
+
|
|
30
|
+
## Run it before you have credentials
|
|
31
|
+
|
|
32
|
+
Every operation ships a **faker**, whether or not Telegram has a sandbox. Set a
|
|
33
|
+
node's mode to `fake` and it returns the shape Telegram actually publishes — the
|
|
34
|
+
same field names, deterministically — so you can wire the downstream nodes before
|
|
35
|
+
touching an account, a key, or a network.
|
|
36
|
+
|
|
37
|
+
## This repository is generated
|
|
38
|
+
|
|
39
|
+
`provider/` is the source. Everything under `packages/` is emitted from it and
|
|
40
|
+
**must not be hand-edited** — CI regenerates and diffs on every push, and the
|
|
41
|
+
next protocol sync destroys anything it finds. See [`AGENTS.md`](AGENTS.md).
|
|
42
|
+
|
|
43
|
+
## Two namespaces, which do not match on purpose
|
|
44
|
+
|
|
45
|
+
The repo is `github.com/Fancy-Friends/telegram`; the packages publish under
|
|
46
|
+
`particle-academy`. Nothing derives one from the other — the names come from
|
|
47
|
+
weaver's `friends.json` and nowhere else.
|
|
48
|
+
|
|
49
|
+
## Licence
|
|
50
|
+
|
|
51
|
+
MIT.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { callConnector } from '@particle-academy/fancy-connector-core';
|
|
2
|
+
|
|
3
|
+
// src/faker.ts
|
|
4
|
+
function fakeGetUpdates({ config, fake }) {
|
|
5
|
+
const boundChatId = fake.int(1e8, 999999999);
|
|
6
|
+
return {
|
|
7
|
+
"ok": true,
|
|
8
|
+
"result": [
|
|
9
|
+
{
|
|
10
|
+
"update_id": fake.int(1e5, 999999),
|
|
11
|
+
"message": {
|
|
12
|
+
"message_id": fake.int(1, 9999),
|
|
13
|
+
"date": 1767225600,
|
|
14
|
+
"text": config.sampleText !== void 0 && config.sampleText !== null && config.sampleText !== "" ? String(config.sampleText) : "hello from the faker",
|
|
15
|
+
"chat": {
|
|
16
|
+
"id": boundChatId,
|
|
17
|
+
"type": "private",
|
|
18
|
+
"first_name": "Ada",
|
|
19
|
+
"username": "ada_example"
|
|
20
|
+
},
|
|
21
|
+
"from": {
|
|
22
|
+
"id": boundChatId,
|
|
23
|
+
"is_bot": false,
|
|
24
|
+
"first_name": "Ada",
|
|
25
|
+
"username": "ada_example",
|
|
26
|
+
"language_code": "en"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
var telegramFaker = (operation, request) => {
|
|
34
|
+
switch (operation) {
|
|
35
|
+
case "get_updates":
|
|
36
|
+
return fakeGetUpdates(request);
|
|
37
|
+
default:
|
|
38
|
+
throw new Error(
|
|
39
|
+
`telegram: no fake response is defined for "${operation}". Add a fixture under provider/fixtures/ and regenerate \u2014 a connector without a faker cannot be developed against, tested, or demonstrated.`
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// src/service.ts
|
|
45
|
+
var CONNECTOR_API_VERSION = 1;
|
|
46
|
+
var TELEGRAM_BASE_URLS = {
|
|
47
|
+
"live": "https://api.telegram.org",
|
|
48
|
+
"sandbox": "https://api.telegram.org"
|
|
49
|
+
};
|
|
50
|
+
var TELEGRAM_REQUIRES = [
|
|
51
|
+
"botToken"
|
|
52
|
+
];
|
|
53
|
+
function telegramAuthorize(credentials, request, mode) {
|
|
54
|
+
const url = new URL(request.url);
|
|
55
|
+
const segment = mode === "sandbox" ? `/bot${credentials.botToken ?? ""}/test` : `/bot${credentials.botToken ?? ""}`;
|
|
56
|
+
url.pathname = `${segment}${url.pathname}`;
|
|
57
|
+
request.url = url.toString();
|
|
58
|
+
}
|
|
59
|
+
var TELEGRAM = {
|
|
60
|
+
service: "telegram",
|
|
61
|
+
title: "Telegram",
|
|
62
|
+
sandbox: "separate-account",
|
|
63
|
+
baseUrls: { ...TELEGRAM_BASE_URLS },
|
|
64
|
+
requires: [...TELEGRAM_REQUIRES],
|
|
65
|
+
authorize: telegramAuthorize,
|
|
66
|
+
faker: telegramFaker
|
|
67
|
+
};
|
|
68
|
+
var TELEGRAM_GET_UPDATES = {
|
|
69
|
+
service: "telegram",
|
|
70
|
+
operation: "get_updates",
|
|
71
|
+
delivery: "poll",
|
|
72
|
+
setup: "The host polls getUpdates on a schedule and persists the `offset` cursor between calls, passing the last `cursor` back in \u2014 Telegram queues nothing once an offset has acknowledged it, so a lost cursor is lost updates. getUpdates and setWebhook are MUTUALLY EXCLUSIVE for one bot: a host running both gets neither.",
|
|
73
|
+
minPollSeconds: 1,
|
|
74
|
+
faker: telegramFaker
|
|
75
|
+
};
|
|
76
|
+
var GET_UPDATES_OPERATION = "get_updates";
|
|
77
|
+
async function telegramGetUpdates(options) {
|
|
78
|
+
const config = options.config ?? {};
|
|
79
|
+
{
|
|
80
|
+
const n = Number(config.offset);
|
|
81
|
+
const given = config.offset !== void 0 && config.offset !== null && config.offset !== "";
|
|
82
|
+
if (given && !Number.isInteger(n)) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
`get_updates: "offset" must be a integer, got ${JSON.stringify(config.offset)}.`
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
{
|
|
89
|
+
const n = Number(config.limit);
|
|
90
|
+
const given = config.limit !== void 0 && config.limit !== null && config.limit !== "";
|
|
91
|
+
if (given && !(Number.isInteger(n) && n >= 1 && n <= 100)) {
|
|
92
|
+
throw new Error(
|
|
93
|
+
`get_updates: "limit" must be a integer, got ${JSON.stringify(config.limit)}.`
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return callConnector(TELEGRAM, {
|
|
98
|
+
operation: GET_UPDATES_OPERATION,
|
|
99
|
+
config,
|
|
100
|
+
input: options.input,
|
|
101
|
+
...options.credentials === void 0 ? {} : { credentials: options.credentials },
|
|
102
|
+
...options.mode === void 0 ? {} : { mode: options.mode },
|
|
103
|
+
...options.connectionId === void 0 ? {} : { connectionId: options.connectionId },
|
|
104
|
+
...options.attempts === void 0 ? {} : { attempts: options.attempts },
|
|
105
|
+
...options.transport === void 0 ? {} : { transport: options.transport },
|
|
106
|
+
request: {
|
|
107
|
+
method: "GET",
|
|
108
|
+
path: "/getUpdates",
|
|
109
|
+
query: {
|
|
110
|
+
...config.offset !== void 0 && config.offset !== null && config.offset !== "" ? { "offset": Math.trunc(Number(config.offset)) } : {},
|
|
111
|
+
"limit": config.limit !== void 0 && config.limit !== null && config.limit !== "" ? Math.trunc(Number(config.limit)) : 100,
|
|
112
|
+
...config.allowedUpdates !== void 0 && config.allowedUpdates !== null && config.allowedUpdates !== "" ? { "allowed_updates": JSON.stringify(allowedUpdatesList(config.allowedUpdates)) } : {}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
function allowedUpdatesList(value) {
|
|
118
|
+
const items = Array.isArray(value) ? value.map(String) : typeof value === "string" ? value.split(",") : [];
|
|
119
|
+
return items.map((item) => item.trim()).filter(Boolean);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export { CONNECTOR_API_VERSION, GET_UPDATES_OPERATION, TELEGRAM, TELEGRAM_BASE_URLS, TELEGRAM_GET_UPDATES, TELEGRAM_REQUIRES, telegramAuthorize, telegramFaker, telegramGetUpdates };
|
|
123
|
+
//# sourceMappingURL=chunk-LFMQKSUM.js.map
|
|
124
|
+
//# sourceMappingURL=chunk-LFMQKSUM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/faker.ts","../src/service.ts","../src/triggers/get-updates.ts"],"names":[],"mappings":"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","file":"chunk-LFMQKSUM.js","sourcesContent":["/**\n * GENERATED FILE — do not edit.\n *\n * Emitted from provider/fixtures/ by weaver's generator.\n * A hand-edit here is destroyed by the next protocol sync, which is worse than\n * being rejected, because it works until it silently does not. Fix\n * provider/fixtures/ (or weaver's template/) and regenerate:\n *\n * npm run provider -- telegram\n */\n\n/**\n * The Telegram faker.\n *\n * Shapes, not behaviour: the goal is that a downstream node sees the field\n * NAMES Telegram actually publishes, so an author can wire {{ $json.data.id }}\n * against a fake and have it keep working against the real thing.\n *\n * Deterministic — same inputs, same output. A faker returning a fresh uuid\n * every call cannot be asserted on, so its fixtures degrade to \"it did not\n * throw\", which is the assertion that catches nothing.\n */\n\nimport type { ConnectorFaker, FakeRequest } from \"@particle-academy/fancy-connector-core\";\n\nfunction fakeGetUpdates({ config, fake }: FakeRequest): unknown {\n const boundChatId = fake.int(100000000, 999999999);\n\n return {\n \"ok\": true,\n \"result\": [\n {\n \"update_id\": fake.int(100000, 999999),\n \"message\": {\n \"message_id\": fake.int(1, 9999),\n \"date\": 1767225600,\n \"text\": (config.sampleText !== undefined && config.sampleText !== null && config.sampleText !== \"\" ? String(config.sampleText) : \"hello from the faker\"),\n \"chat\": {\n \"id\": boundChatId,\n \"type\": \"private\",\n \"first_name\": \"Ada\",\n \"username\": \"ada_example\",\n },\n \"from\": {\n \"id\": boundChatId,\n \"is_bot\": false,\n \"first_name\": \"Ada\",\n \"username\": \"ada_example\",\n \"language_code\": \"en\",\n },\n },\n },\n ],\n };\n}\n\nexport const telegramFaker: ConnectorFaker = (operation, request) => {\n switch (operation) {\n case \"get_updates\":\n return fakeGetUpdates(request);\n\n default:\n // A faker asked for an operation it has no shape for must SAY so. Making\n // something up would produce a green run whose output silently has none\n // of the fields the author is about to reference.\n throw new Error(\n `telegram: no fake response is defined for \"${operation}\". ` +\n \"Add a fixture under provider/fixtures/ and regenerate — a connector without a faker \" +\n \"cannot be developed against, tested, or demonstrated.\",\n );\n }\n};\n","/**\n * GENERATED FILE — do not edit.\n *\n * Emitted from provider/manifest.json by weaver's generator.\n * A hand-edit here is destroyed by the next protocol sync, which is worse than\n * being rejected, because it works until it silently does not. Fix\n * provider/manifest.json (or weaver's template/) and regenerate:\n *\n * npm run provider -- telegram\n */\n\n/**\n * Telegram, as one service descriptor shared by every Telegram operation.\n *\n * @particle-academy/fancy-connector-core carries what is true of ALL\n * connectors. This carries what is true of Telegram: its base URL, its auth\n * scheme, its idempotency header, and its faker.\n *\n * ## The sandbox trap, written down where it is used\n *\n * Telegram's test environment is a genuinely SEPARATE ACCOUNT: you create a\n * new account inside it and register a new bot there, so the sandbox\n * credential is a different token rather than the same one pointed elsewhere.\n * The `/test` path segment is how you reach it; the account is what makes it\n * separate. Flood limits are NOT relaxed there, so it is a place to test, not\n * a place to hammer.\n */\n\nimport type { ConnectorMode, PreparedRequest, ServiceDescriptor } from \"@particle-academy/fancy-connector-core\";\n\nimport { telegramFaker } from \"./faker.js\";\n\n/**\n * The connector API version this package was GENERATED against.\n *\n * A literal, never imported. An imported constant lets an upgrade rewrite the\n * very claim it exists to detect, after which the copy agrees with itself\n * forever.\n */\nexport const CONNECTOR_API_VERSION = 1;\n\nexport const TELEGRAM_BASE_URLS = {\n \"live\": \"https://api.telegram.org\",\n \"sandbox\": \"https://api.telegram.org\"\n} as const;\n\n/** Credential keys a remote call cannot proceed without. */\nexport const TELEGRAM_REQUIRES = [\n \"botToken\"\n] as const;\n\n/**\n * Apply Telegram's auth scheme to an outgoing request.\n *\n * The bot token is a PATH SEGMENT, not a header --\n * https://api.telegram.org/bot<token>/getUpdates -- and the test environment\n * is a further `/test` AFTER the token. So this is the first provider whose\n * auth and whose estate are the same decision expressed in the URL, which is\n * why `authorize` has always been handed the resolved mode. The token\n * therefore ends up in the request URL, where access logs and error reporters\n * will record it. That is Telegram's design, not ours; a host should keep its\n * own logging away from it.\n *\n * The mode is USED here: for this provider auth and estate are the same\n * decision expressed in the URL, which is what this parameter has always been\n * for.\n */\nexport function telegramAuthorize(\n credentials: Record<string, string | undefined>,\n request: PreparedRequest,\n mode: ConnectorMode,\n): void {\n const url = new URL(request.url);\n\n // The estate is the SAME decision as the credential here, and it lives in\n // a further segment AFTER the token. A token pointed at a node marked\n // \"sandbox\" would otherwise reach the live bot, and succeed.\n const segment = mode === \"sandbox\"\n ? `/bot${credentials.botToken ?? \"\"}/test`\n : `/bot${credentials.botToken ?? \"\"}`;\n\n url.pathname = `${segment}${url.pathname}`;\n request.url = url.toString();\n}\n\n/** The Telegram service, for the TypeScript runtime. */\nexport const TELEGRAM: ServiceDescriptor = {\n service: \"telegram\",\n title: \"Telegram\",\n sandbox: \"separate-account\",\n baseUrls: { ...TELEGRAM_BASE_URLS },\n requires: [...TELEGRAM_REQUIRES],\n authorize: telegramAuthorize,\n faker: telegramFaker,\n};\n","/**\n * GENERATED FILE — do not edit.\n *\n * Emitted from provider/triggers/get-updates.json by weaver's generator.\n * A hand-edit here is destroyed by the next protocol sync, which is worse than\n * being rejected, because it works until it silently does not. Fix\n * provider/triggers/get-updates.json (or weaver's template/) and regenerate:\n *\n * npm run provider -- telegram\n */\n\n/**\n * Telegram's poll trigger — the delivery contract.\n *\n * A POLL trigger, so there is no signature and no route: Telegram does not\n * push, the host asks on a schedule and persists a cursor between calls.\n * Nothing queues what a stopped poller did not collect, which is why that\n * obligation is written down rather than assumed.\n */\n\nimport {\n callConnector,\n type ConnectorResult,\n type RequestedMode,\n type Transport,\n type TriggerDescriptor,\n} from \"@particle-academy/fancy-connector-core\";\nimport { telegramFaker } from \"../faker.js\";\nimport { TELEGRAM } from \"../service.js\";\n\nexport const TELEGRAM_GET_UPDATES: TriggerDescriptor = {\n service: \"telegram\",\n operation: \"get_updates\",\n delivery: \"poll\",\n setup:\n \"The host polls getUpdates on a schedule and persists the `offset` cursor between calls, passing the last `cursor` back in — Telegram queues nothing once an offset has acknowledged it, so a lost cursor is lost updates. getUpdates and setWebhook are MUTUALLY EXCLUSIVE for one bot: a host running both gets neither.\",\n minPollSeconds: 1,\n faker: telegramFaker,\n};\n\n/**\n * Poll Telegram once.\n *\n * GET /getUpdates — https://core.telegram.org/bots/api#getupdates\n *\n * In `fake` mode this resolves to the faker, so the node is runnable on a\n * canvas before any credential exists — with the same envelope a real poll\n * returns.\n */\n\nexport const GET_UPDATES_OPERATION = \"get_updates\";\n\nexport type GetUpdatesOptions = {\n /** The node's resolved config. Keys: offset, limit, allowedUpdates, sampleText. */\n config: Record<string, unknown>;\n credentials?: Record<string, string | undefined>;\n mode?: RequestedMode;\n connectionId?: string | null;\n input?: unknown;\n attempts?: number;\n /** Override the transport. The only way to exercise this without a network. */\n transport?: Transport;\n};\n\nexport async function telegramGetUpdates(options: GetUpdatesOptions): Promise<ConnectorResult> {\n const config = options.config ?? {};\n\n {\n const n = Number(config.offset);\n const given = config.offset !== undefined && config.offset !== null && config.offset !== \"\";\n if (given && !(Number.isInteger(n))) {\n throw new Error(\n `get_updates: \"offset\" must be a integer, got ${JSON.stringify(config.offset)}.`,\n );\n }\n }\n\n {\n const n = Number(config.limit);\n const given = config.limit !== undefined && config.limit !== null && config.limit !== \"\";\n if (given && !(Number.isInteger(n) && n >= 1 && n <= 100)) {\n throw new Error(\n `get_updates: \"limit\" must be a integer, got ${JSON.stringify(config.limit)}.`,\n );\n }\n }\n\n return callConnector(TELEGRAM, {\n operation: GET_UPDATES_OPERATION,\n config,\n input: options.input,\n ...(options.credentials === undefined ? {} : { credentials: options.credentials }),\n ...(options.mode === undefined ? {} : { mode: options.mode }),\n ...(options.connectionId === undefined ? {} : { connectionId: options.connectionId }),\n ...(options.attempts === undefined ? {} : { attempts: options.attempts }),\n ...(options.transport === undefined ? {} : { transport: options.transport }),\n request: {\n method: \"GET\",\n path: \"/getUpdates\",\n query: {\n ...(config.offset !== undefined && config.offset !== null && config.offset !== \"\" ? { \"offset\": Math.trunc(Number(config.offset)) } : {}),\n \"limit\": config.limit !== undefined && config.limit !== null && config.limit !== \"\" ? Math.trunc(Number(config.limit)) : 100,\n ...(config.allowedUpdates !== undefined && config.allowedUpdates !== null && config.allowedUpdates !== \"\" ? { \"allowed_updates\": JSON.stringify(allowedUpdatesList(config.allowedUpdates)) } : {}),\n },\n },\n });\n}\n\n/** One value, a \",\"-separated string, or an array — all end up a list. */\nfunction allowedUpdatesList(value: unknown): string[] {\n const items = Array.isArray(value)\n ? value.map(String)\n : typeof value === \"string\"\n ? value.split(\",\")\n : [];\n\n return items.map((item) => item.trim()).filter(Boolean);\n}\n"]}
|
package/dist/flow.cjs
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fancyConnectorCore = require('@particle-academy/fancy-connector-core');
|
|
4
|
+
var telegramUi = require('@particle-academy/telegram-ui');
|
|
5
|
+
|
|
6
|
+
// src/flow.ts
|
|
7
|
+
|
|
8
|
+
// src/faker.ts
|
|
9
|
+
function fakeGetUpdates({ config, fake }) {
|
|
10
|
+
const boundChatId = fake.int(1e8, 999999999);
|
|
11
|
+
return {
|
|
12
|
+
"ok": true,
|
|
13
|
+
"result": [
|
|
14
|
+
{
|
|
15
|
+
"update_id": fake.int(1e5, 999999),
|
|
16
|
+
"message": {
|
|
17
|
+
"message_id": fake.int(1, 9999),
|
|
18
|
+
"date": 1767225600,
|
|
19
|
+
"text": config.sampleText !== void 0 && config.sampleText !== null && config.sampleText !== "" ? String(config.sampleText) : "hello from the faker",
|
|
20
|
+
"chat": {
|
|
21
|
+
"id": boundChatId,
|
|
22
|
+
"type": "private",
|
|
23
|
+
"first_name": "Ada",
|
|
24
|
+
"username": "ada_example"
|
|
25
|
+
},
|
|
26
|
+
"from": {
|
|
27
|
+
"id": boundChatId,
|
|
28
|
+
"is_bot": false,
|
|
29
|
+
"first_name": "Ada",
|
|
30
|
+
"username": "ada_example",
|
|
31
|
+
"language_code": "en"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
var telegramFaker = (operation, request) => {
|
|
39
|
+
switch (operation) {
|
|
40
|
+
case "get_updates":
|
|
41
|
+
return fakeGetUpdates(request);
|
|
42
|
+
default:
|
|
43
|
+
throw new Error(
|
|
44
|
+
`telegram: no fake response is defined for "${operation}". Add a fixture under provider/fixtures/ and regenerate \u2014 a connector without a faker cannot be developed against, tested, or demonstrated.`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// src/service.ts
|
|
50
|
+
var TELEGRAM_BASE_URLS = {
|
|
51
|
+
"live": "https://api.telegram.org",
|
|
52
|
+
"sandbox": "https://api.telegram.org"
|
|
53
|
+
};
|
|
54
|
+
var TELEGRAM_REQUIRES = [
|
|
55
|
+
"botToken"
|
|
56
|
+
];
|
|
57
|
+
function telegramAuthorize(credentials, request, mode) {
|
|
58
|
+
const url = new URL(request.url);
|
|
59
|
+
const segment = mode === "sandbox" ? `/bot${credentials.botToken ?? ""}/test` : `/bot${credentials.botToken ?? ""}`;
|
|
60
|
+
url.pathname = `${segment}${url.pathname}`;
|
|
61
|
+
request.url = url.toString();
|
|
62
|
+
}
|
|
63
|
+
var TELEGRAM = {
|
|
64
|
+
service: "telegram",
|
|
65
|
+
title: "Telegram",
|
|
66
|
+
sandbox: "separate-account",
|
|
67
|
+
baseUrls: { ...TELEGRAM_BASE_URLS },
|
|
68
|
+
requires: [...TELEGRAM_REQUIRES],
|
|
69
|
+
authorize: telegramAuthorize,
|
|
70
|
+
faker: telegramFaker
|
|
71
|
+
};
|
|
72
|
+
var GET_UPDATES_OPERATION = "get_updates";
|
|
73
|
+
async function telegramGetUpdates(options) {
|
|
74
|
+
const config = options.config ?? {};
|
|
75
|
+
{
|
|
76
|
+
const n = Number(config.offset);
|
|
77
|
+
const given = config.offset !== void 0 && config.offset !== null && config.offset !== "";
|
|
78
|
+
if (given && !Number.isInteger(n)) {
|
|
79
|
+
throw new Error(
|
|
80
|
+
`get_updates: "offset" must be a integer, got ${JSON.stringify(config.offset)}.`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
{
|
|
85
|
+
const n = Number(config.limit);
|
|
86
|
+
const given = config.limit !== void 0 && config.limit !== null && config.limit !== "";
|
|
87
|
+
if (given && !(Number.isInteger(n) && n >= 1 && n <= 100)) {
|
|
88
|
+
throw new Error(
|
|
89
|
+
`get_updates: "limit" must be a integer, got ${JSON.stringify(config.limit)}.`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return fancyConnectorCore.callConnector(TELEGRAM, {
|
|
94
|
+
operation: GET_UPDATES_OPERATION,
|
|
95
|
+
config,
|
|
96
|
+
input: options.input,
|
|
97
|
+
...options.credentials === void 0 ? {} : { credentials: options.credentials },
|
|
98
|
+
...options.mode === void 0 ? {} : { mode: options.mode },
|
|
99
|
+
...options.connectionId === void 0 ? {} : { connectionId: options.connectionId },
|
|
100
|
+
...options.attempts === void 0 ? {} : { attempts: options.attempts },
|
|
101
|
+
...options.transport === void 0 ? {} : { transport: options.transport },
|
|
102
|
+
request: {
|
|
103
|
+
method: "GET",
|
|
104
|
+
path: "/getUpdates",
|
|
105
|
+
query: {
|
|
106
|
+
...config.offset !== void 0 && config.offset !== null && config.offset !== "" ? { "offset": Math.trunc(Number(config.offset)) } : {},
|
|
107
|
+
"limit": config.limit !== void 0 && config.limit !== null && config.limit !== "" ? Math.trunc(Number(config.limit)) : 100,
|
|
108
|
+
...config.allowedUpdates !== void 0 && config.allowedUpdates !== null && config.allowedUpdates !== "" ? { "allowed_updates": JSON.stringify(allowedUpdatesList(config.allowedUpdates)) } : {}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function allowedUpdatesList(value) {
|
|
114
|
+
const items = Array.isArray(value) ? value.map(String) : typeof value === "string" ? value.split(",") : [];
|
|
115
|
+
return items.map((item) => item.trim()).filter(Boolean);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/flow.ts
|
|
119
|
+
var telegramUpdatesTriggerExecutor = async (ctx) => {
|
|
120
|
+
const config = ctx.node.data?.config ?? {};
|
|
121
|
+
const result = await telegramGetUpdates({ config });
|
|
122
|
+
const data = result.data;
|
|
123
|
+
if (data?.ok === false) {
|
|
124
|
+
throw new Error(
|
|
125
|
+
`get_updates: getUpdates was rejected \u2014 ` + String(data.description ?? "no reason given")
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
const items = Array.isArray(data?.result) ? data.result : [];
|
|
129
|
+
const seen = items.map((item) => item?.update_id).filter((id) => typeof id === "number");
|
|
130
|
+
const previous = config.offset === void 0 || config.offset === null || config.offset === "" ? void 0 : Number(config.offset);
|
|
131
|
+
const cursor = seen.length === 0 ? previous : Math.max(...seen) + 1;
|
|
132
|
+
const value = {
|
|
133
|
+
mode: result.mode,
|
|
134
|
+
connection: result.connection,
|
|
135
|
+
cursor,
|
|
136
|
+
count: items.length,
|
|
137
|
+
updates: items,
|
|
138
|
+
update: items[0] ?? null
|
|
139
|
+
};
|
|
140
|
+
if (items.length === 0) {
|
|
141
|
+
return { __port: "empty", value };
|
|
142
|
+
}
|
|
143
|
+
ctx.emit({
|
|
144
|
+
type: "log",
|
|
145
|
+
level: "info",
|
|
146
|
+
nodeId: ctx.node.id,
|
|
147
|
+
message: `telegram: ${items.length} item(s), next cursor ${cursor} (${result.mode})`
|
|
148
|
+
});
|
|
149
|
+
return { __port: "out", value };
|
|
150
|
+
};
|
|
151
|
+
var TELEGRAM_RUNNABLE_KINDS = [
|
|
152
|
+
{ ...telegramUi.telegramUpdatesTriggerKind, executor: telegramUpdatesTriggerExecutor }
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
exports.TELEGRAM_RUNNABLE_KINDS = TELEGRAM_RUNNABLE_KINDS;
|
|
156
|
+
exports.telegramUpdatesTriggerExecutor = telegramUpdatesTriggerExecutor;
|
|
157
|
+
//# sourceMappingURL=flow.cjs.map
|
|
158
|
+
//# sourceMappingURL=flow.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/faker.ts","../src/service.ts","../src/triggers/get-updates.ts","../src/flow.ts"],"names":["callConnector","telegramUpdatesTriggerKind"],"mappings":"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","file":"flow.cjs","sourcesContent":["/**\n * GENERATED FILE — do not edit.\n *\n * Emitted from provider/fixtures/ by weaver's generator.\n * A hand-edit here is destroyed by the next protocol sync, which is worse than\n * being rejected, because it works until it silently does not. Fix\n * provider/fixtures/ (or weaver's template/) and regenerate:\n *\n * npm run provider -- telegram\n */\n\n/**\n * The Telegram faker.\n *\n * Shapes, not behaviour: the goal is that a downstream node sees the field\n * NAMES Telegram actually publishes, so an author can wire {{ $json.data.id }}\n * against a fake and have it keep working against the real thing.\n *\n * Deterministic — same inputs, same output. A faker returning a fresh uuid\n * every call cannot be asserted on, so its fixtures degrade to \"it did not\n * throw\", which is the assertion that catches nothing.\n */\n\nimport type { ConnectorFaker, FakeRequest } from \"@particle-academy/fancy-connector-core\";\n\nfunction fakeGetUpdates({ config, fake }: FakeRequest): unknown {\n const boundChatId = fake.int(100000000, 999999999);\n\n return {\n \"ok\": true,\n \"result\": [\n {\n \"update_id\": fake.int(100000, 999999),\n \"message\": {\n \"message_id\": fake.int(1, 9999),\n \"date\": 1767225600,\n \"text\": (config.sampleText !== undefined && config.sampleText !== null && config.sampleText !== \"\" ? String(config.sampleText) : \"hello from the faker\"),\n \"chat\": {\n \"id\": boundChatId,\n \"type\": \"private\",\n \"first_name\": \"Ada\",\n \"username\": \"ada_example\",\n },\n \"from\": {\n \"id\": boundChatId,\n \"is_bot\": false,\n \"first_name\": \"Ada\",\n \"username\": \"ada_example\",\n \"language_code\": \"en\",\n },\n },\n },\n ],\n };\n}\n\nexport const telegramFaker: ConnectorFaker = (operation, request) => {\n switch (operation) {\n case \"get_updates\":\n return fakeGetUpdates(request);\n\n default:\n // A faker asked for an operation it has no shape for must SAY so. Making\n // something up would produce a green run whose output silently has none\n // of the fields the author is about to reference.\n throw new Error(\n `telegram: no fake response is defined for \"${operation}\". ` +\n \"Add a fixture under provider/fixtures/ and regenerate — a connector without a faker \" +\n \"cannot be developed against, tested, or demonstrated.\",\n );\n }\n};\n","/**\n * GENERATED FILE — do not edit.\n *\n * Emitted from provider/manifest.json by weaver's generator.\n * A hand-edit here is destroyed by the next protocol sync, which is worse than\n * being rejected, because it works until it silently does not. Fix\n * provider/manifest.json (or weaver's template/) and regenerate:\n *\n * npm run provider -- telegram\n */\n\n/**\n * Telegram, as one service descriptor shared by every Telegram operation.\n *\n * @particle-academy/fancy-connector-core carries what is true of ALL\n * connectors. This carries what is true of Telegram: its base URL, its auth\n * scheme, its idempotency header, and its faker.\n *\n * ## The sandbox trap, written down where it is used\n *\n * Telegram's test environment is a genuinely SEPARATE ACCOUNT: you create a\n * new account inside it and register a new bot there, so the sandbox\n * credential is a different token rather than the same one pointed elsewhere.\n * The `/test` path segment is how you reach it; the account is what makes it\n * separate. Flood limits are NOT relaxed there, so it is a place to test, not\n * a place to hammer.\n */\n\nimport type { ConnectorMode, PreparedRequest, ServiceDescriptor } from \"@particle-academy/fancy-connector-core\";\n\nimport { telegramFaker } from \"./faker.js\";\n\n/**\n * The connector API version this package was GENERATED against.\n *\n * A literal, never imported. An imported constant lets an upgrade rewrite the\n * very claim it exists to detect, after which the copy agrees with itself\n * forever.\n */\nexport const CONNECTOR_API_VERSION = 1;\n\nexport const TELEGRAM_BASE_URLS = {\n \"live\": \"https://api.telegram.org\",\n \"sandbox\": \"https://api.telegram.org\"\n} as const;\n\n/** Credential keys a remote call cannot proceed without. */\nexport const TELEGRAM_REQUIRES = [\n \"botToken\"\n] as const;\n\n/**\n * Apply Telegram's auth scheme to an outgoing request.\n *\n * The bot token is a PATH SEGMENT, not a header --\n * https://api.telegram.org/bot<token>/getUpdates -- and the test environment\n * is a further `/test` AFTER the token. So this is the first provider whose\n * auth and whose estate are the same decision expressed in the URL, which is\n * why `authorize` has always been handed the resolved mode. The token\n * therefore ends up in the request URL, where access logs and error reporters\n * will record it. That is Telegram's design, not ours; a host should keep its\n * own logging away from it.\n *\n * The mode is USED here: for this provider auth and estate are the same\n * decision expressed in the URL, which is what this parameter has always been\n * for.\n */\nexport function telegramAuthorize(\n credentials: Record<string, string | undefined>,\n request: PreparedRequest,\n mode: ConnectorMode,\n): void {\n const url = new URL(request.url);\n\n // The estate is the SAME decision as the credential here, and it lives in\n // a further segment AFTER the token. A token pointed at a node marked\n // \"sandbox\" would otherwise reach the live bot, and succeed.\n const segment = mode === \"sandbox\"\n ? `/bot${credentials.botToken ?? \"\"}/test`\n : `/bot${credentials.botToken ?? \"\"}`;\n\n url.pathname = `${segment}${url.pathname}`;\n request.url = url.toString();\n}\n\n/** The Telegram service, for the TypeScript runtime. */\nexport const TELEGRAM: ServiceDescriptor = {\n service: \"telegram\",\n title: \"Telegram\",\n sandbox: \"separate-account\",\n baseUrls: { ...TELEGRAM_BASE_URLS },\n requires: [...TELEGRAM_REQUIRES],\n authorize: telegramAuthorize,\n faker: telegramFaker,\n};\n","/**\n * GENERATED FILE — do not edit.\n *\n * Emitted from provider/triggers/get-updates.json by weaver's generator.\n * A hand-edit here is destroyed by the next protocol sync, which is worse than\n * being rejected, because it works until it silently does not. Fix\n * provider/triggers/get-updates.json (or weaver's template/) and regenerate:\n *\n * npm run provider -- telegram\n */\n\n/**\n * Telegram's poll trigger — the delivery contract.\n *\n * A POLL trigger, so there is no signature and no route: Telegram does not\n * push, the host asks on a schedule and persists a cursor between calls.\n * Nothing queues what a stopped poller did not collect, which is why that\n * obligation is written down rather than assumed.\n */\n\nimport {\n callConnector,\n type ConnectorResult,\n type RequestedMode,\n type Transport,\n type TriggerDescriptor,\n} from \"@particle-academy/fancy-connector-core\";\nimport { telegramFaker } from \"../faker.js\";\nimport { TELEGRAM } from \"../service.js\";\n\nexport const TELEGRAM_GET_UPDATES: TriggerDescriptor = {\n service: \"telegram\",\n operation: \"get_updates\",\n delivery: \"poll\",\n setup:\n \"The host polls getUpdates on a schedule and persists the `offset` cursor between calls, passing the last `cursor` back in — Telegram queues nothing once an offset has acknowledged it, so a lost cursor is lost updates. getUpdates and setWebhook are MUTUALLY EXCLUSIVE for one bot: a host running both gets neither.\",\n minPollSeconds: 1,\n faker: telegramFaker,\n};\n\n/**\n * Poll Telegram once.\n *\n * GET /getUpdates — https://core.telegram.org/bots/api#getupdates\n *\n * In `fake` mode this resolves to the faker, so the node is runnable on a\n * canvas before any credential exists — with the same envelope a real poll\n * returns.\n */\n\nexport const GET_UPDATES_OPERATION = \"get_updates\";\n\nexport type GetUpdatesOptions = {\n /** The node's resolved config. Keys: offset, limit, allowedUpdates, sampleText. */\n config: Record<string, unknown>;\n credentials?: Record<string, string | undefined>;\n mode?: RequestedMode;\n connectionId?: string | null;\n input?: unknown;\n attempts?: number;\n /** Override the transport. The only way to exercise this without a network. */\n transport?: Transport;\n};\n\nexport async function telegramGetUpdates(options: GetUpdatesOptions): Promise<ConnectorResult> {\n const config = options.config ?? {};\n\n {\n const n = Number(config.offset);\n const given = config.offset !== undefined && config.offset !== null && config.offset !== \"\";\n if (given && !(Number.isInteger(n))) {\n throw new Error(\n `get_updates: \"offset\" must be a integer, got ${JSON.stringify(config.offset)}.`,\n );\n }\n }\n\n {\n const n = Number(config.limit);\n const given = config.limit !== undefined && config.limit !== null && config.limit !== \"\";\n if (given && !(Number.isInteger(n) && n >= 1 && n <= 100)) {\n throw new Error(\n `get_updates: \"limit\" must be a integer, got ${JSON.stringify(config.limit)}.`,\n );\n }\n }\n\n return callConnector(TELEGRAM, {\n operation: GET_UPDATES_OPERATION,\n config,\n input: options.input,\n ...(options.credentials === undefined ? {} : { credentials: options.credentials }),\n ...(options.mode === undefined ? {} : { mode: options.mode }),\n ...(options.connectionId === undefined ? {} : { connectionId: options.connectionId }),\n ...(options.attempts === undefined ? {} : { attempts: options.attempts }),\n ...(options.transport === undefined ? {} : { transport: options.transport }),\n request: {\n method: \"GET\",\n path: \"/getUpdates\",\n query: {\n ...(config.offset !== undefined && config.offset !== null && config.offset !== \"\" ? { \"offset\": Math.trunc(Number(config.offset)) } : {}),\n \"limit\": config.limit !== undefined && config.limit !== null && config.limit !== \"\" ? Math.trunc(Number(config.limit)) : 100,\n ...(config.allowedUpdates !== undefined && config.allowedUpdates !== null && config.allowedUpdates !== \"\" ? { \"allowed_updates\": JSON.stringify(allowedUpdatesList(config.allowedUpdates)) } : {}),\n },\n },\n });\n}\n\n/** One value, a \",\"-separated string, or an array — all end up a list. */\nfunction allowedUpdatesList(value: unknown): string[] {\n const items = Array.isArray(value)\n ? value.map(String)\n : typeof value === \"string\"\n ? value.split(\",\")\n : [];\n\n return items.map((item) => item.trim()).filter(Boolean);\n}\n","/**\n * GENERATED FILE — do not edit.\n *\n * Emitted from provider/actions/ + triggers/ by weaver's generator.\n * A hand-edit here is destroyed by the next protocol sync, which is worse than\n * being rejected, because it works until it silently does not. Fix\n * provider/actions/ + triggers/ (or weaver's template/) and regenerate:\n *\n * npm run provider -- telegram\n */\n\n/**\n * Telegram's node kinds with their TypeScript executors attached — for hosts\n * that EXECUTE on TS.\n *\n * The authoring surface in @particle-academy/telegram-ui carries no executor:\n * the editor is React on every host, so a PHP or Python project installs the\n * ui package and never this one.\n */\n\nimport type { NodeExecutor, NodeKindDefinition } from \"@particle-academy/fancy-flow/engine\";\nimport {\n idempotencyKeyFor,\n NO_IDEMPOTENCY_KEY_WARNING,\n resolveConnection,\n triggerEvent,\n type RequestedMode,\n} from \"@particle-academy/fancy-connector-core\";\nimport { TELEGRAM } from \"./service.js\";\n\nimport {\n telegramUpdatesTriggerKind,\n} from \"@particle-academy/telegram-ui\";\n\nimport { TELEGRAM_GET_UPDATES, telegramGetUpdates } from \"./triggers/get-updates.js\";\n\nexport const telegramUpdatesTriggerExecutor: NodeExecutor = async (ctx) => {\n const config = ((ctx.node.data as { config?: Record<string, unknown> })?.config ?? {});\n\n const result = await telegramGetUpdates({ config });\n const data = result.data as Record<string, unknown> | undefined;\n\n // Telegram answers HTTP 200 with `{ok: false}` for an application-level\n // failure. A status check alone reads that as success and publishes an\n // empty batch — a poll that silently finds nothing, forever, which is\n // indistinguishable from a quiet channel. The connector core cannot know\n // this; it is exactly the per-provider knowledge a definition exists to\n // hold.\n if (data?.ok === false) {\n throw new Error(\n `get_updates: getUpdates was rejected — ` +\n String(data.description ?? \"no reason given\"),\n );\n }\n\n const items = Array.isArray(data?.result) ? (data.result as unknown[]) : [];\n\n // `offset` means \"the first one I have NOT handled\", so the next cursor\n // is the highest id seen plus one. Off by one in either direction is a\n // real bug with no error attached: too low replays every item forever,\n // too high drops one silently. The HOST persists this and passes it back\n // in — nothing else will.\n const seen = items\n .map((item) => (item as { update_id?: unknown })?.update_id)\n .filter((id): id is number => typeof id === \"number\");\n const previous = config.offset === undefined || config.offset === null || config.offset === \"\"\n ? undefined\n : Number(config.offset);\n const cursor = seen.length === 0 ? previous : Math.max(...seen) + 1;\n\n const value = {\n mode: result.mode,\n connection: result.connection,\n cursor,\n count: items.length,\n updates: items,\n update: items[0] ?? null,\n };\n\n // A poll that found nothing is the NORMAL case, not a failure. Routing\n // it to its own port keeps the main path meaning \"something happened\",\n // and still gives the host somewhere to hang its cursor bookkeeping.\n if (items.length === 0) {\n return { __port: \"empty\", value };\n }\n\n ctx.emit({\n type: \"log\",\n level: \"info\",\n nodeId: ctx.node.id,\n message: `telegram: ${items.length} item(s), next cursor ${cursor} (${result.mode})`,\n });\n\n return { __port: \"out\", value };\n};\n\n/** The kinds a TypeScript host registers. */\nexport const TELEGRAM_RUNNABLE_KINDS: NodeKindDefinition[] = [\n { ...telegramUpdatesTriggerKind, executor: telegramUpdatesTriggerExecutor },\n];\n"]}
|
package/dist/flow.d.cts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { NodeKindDefinition, NodeExecutor } from '@particle-academy/fancy-flow/engine';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* GENERATED FILE — do not edit.
|
|
5
|
+
*
|
|
6
|
+
* Emitted from provider/actions/ + triggers/ by weaver's generator.
|
|
7
|
+
* A hand-edit here is destroyed by the next protocol sync, which is worse than
|
|
8
|
+
* being rejected, because it works until it silently does not. Fix
|
|
9
|
+
* provider/actions/ + triggers/ (or weaver's template/) and regenerate:
|
|
10
|
+
*
|
|
11
|
+
* npm run provider -- telegram
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Telegram's node kinds with their TypeScript executors attached — for hosts
|
|
15
|
+
* that EXECUTE on TS.
|
|
16
|
+
*
|
|
17
|
+
* The authoring surface in @particle-academy/telegram-ui carries no executor:
|
|
18
|
+
* the editor is React on every host, so a PHP or Python project installs the
|
|
19
|
+
* ui package and never this one.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
declare const telegramUpdatesTriggerExecutor: NodeExecutor;
|
|
23
|
+
/** The kinds a TypeScript host registers. */
|
|
24
|
+
declare const TELEGRAM_RUNNABLE_KINDS: NodeKindDefinition[];
|
|
25
|
+
|
|
26
|
+
export { TELEGRAM_RUNNABLE_KINDS, telegramUpdatesTriggerExecutor };
|
package/dist/flow.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { NodeKindDefinition, NodeExecutor } from '@particle-academy/fancy-flow/engine';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* GENERATED FILE — do not edit.
|
|
5
|
+
*
|
|
6
|
+
* Emitted from provider/actions/ + triggers/ by weaver's generator.
|
|
7
|
+
* A hand-edit here is destroyed by the next protocol sync, which is worse than
|
|
8
|
+
* being rejected, because it works until it silently does not. Fix
|
|
9
|
+
* provider/actions/ + triggers/ (or weaver's template/) and regenerate:
|
|
10
|
+
*
|
|
11
|
+
* npm run provider -- telegram
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Telegram's node kinds with their TypeScript executors attached — for hosts
|
|
15
|
+
* that EXECUTE on TS.
|
|
16
|
+
*
|
|
17
|
+
* The authoring surface in @particle-academy/telegram-ui carries no executor:
|
|
18
|
+
* the editor is React on every host, so a PHP or Python project installs the
|
|
19
|
+
* ui package and never this one.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
declare const telegramUpdatesTriggerExecutor: NodeExecutor;
|
|
23
|
+
/** The kinds a TypeScript host registers. */
|
|
24
|
+
declare const TELEGRAM_RUNNABLE_KINDS: NodeKindDefinition[];
|
|
25
|
+
|
|
26
|
+
export { TELEGRAM_RUNNABLE_KINDS, telegramUpdatesTriggerExecutor };
|
package/dist/flow.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { telegramGetUpdates } from './chunk-LFMQKSUM.js';
|
|
2
|
+
import '@particle-academy/fancy-connector-core';
|
|
3
|
+
import { telegramUpdatesTriggerKind } from '@particle-academy/telegram-ui';
|
|
4
|
+
|
|
5
|
+
var telegramUpdatesTriggerExecutor = async (ctx) => {
|
|
6
|
+
const config = ctx.node.data?.config ?? {};
|
|
7
|
+
const result = await telegramGetUpdates({ config });
|
|
8
|
+
const data = result.data;
|
|
9
|
+
if (data?.ok === false) {
|
|
10
|
+
throw new Error(
|
|
11
|
+
`get_updates: getUpdates was rejected \u2014 ` + String(data.description ?? "no reason given")
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
const items = Array.isArray(data?.result) ? data.result : [];
|
|
15
|
+
const seen = items.map((item) => item?.update_id).filter((id) => typeof id === "number");
|
|
16
|
+
const previous = config.offset === void 0 || config.offset === null || config.offset === "" ? void 0 : Number(config.offset);
|
|
17
|
+
const cursor = seen.length === 0 ? previous : Math.max(...seen) + 1;
|
|
18
|
+
const value = {
|
|
19
|
+
mode: result.mode,
|
|
20
|
+
connection: result.connection,
|
|
21
|
+
cursor,
|
|
22
|
+
count: items.length,
|
|
23
|
+
updates: items,
|
|
24
|
+
update: items[0] ?? null
|
|
25
|
+
};
|
|
26
|
+
if (items.length === 0) {
|
|
27
|
+
return { __port: "empty", value };
|
|
28
|
+
}
|
|
29
|
+
ctx.emit({
|
|
30
|
+
type: "log",
|
|
31
|
+
level: "info",
|
|
32
|
+
nodeId: ctx.node.id,
|
|
33
|
+
message: `telegram: ${items.length} item(s), next cursor ${cursor} (${result.mode})`
|
|
34
|
+
});
|
|
35
|
+
return { __port: "out", value };
|
|
36
|
+
};
|
|
37
|
+
var TELEGRAM_RUNNABLE_KINDS = [
|
|
38
|
+
{ ...telegramUpdatesTriggerKind, executor: telegramUpdatesTriggerExecutor }
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
export { TELEGRAM_RUNNABLE_KINDS, telegramUpdatesTriggerExecutor };
|
|
42
|
+
//# sourceMappingURL=flow.js.map
|
|
43
|
+
//# sourceMappingURL=flow.js.map
|
package/dist/flow.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/flow.ts"],"names":[],"mappings":";;;;AAoCO,IAAM,8BAAA,GAA+C,OAAO,GAAA,KAAQ;AACzE,EAAA,MAAM,MAAA,GAAW,GAAA,CAAI,IAAA,CAAK,IAAA,EAA+C,UAAU,EAAC;AAEpF,EAAA,MAAM,MAAA,GAAS,MAAM,kBAAA,CAAmB,EAAE,QAAQ,CAAA;AAClD,EAAA,MAAM,OAAO,MAAA,CAAO,IAAA;AAQpB,EAAA,IAAI,IAAA,EAAM,OAAO,KAAA,EAAO;AACtB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,4CAAA,CAAA,GACE,MAAA,CAAO,IAAA,CAAK,WAAA,IAAe,iBAAiB;AAAA,KAChD;AAAA,EACF;AAEA,EAAA,MAAM,KAAA,GAAQ,MAAM,OAAA,CAAQ,IAAA,EAAM,MAAM,CAAA,GAAK,IAAA,CAAK,SAAuB,EAAC;AAO1E,EAAA,MAAM,IAAA,GAAO,KAAA,CACV,GAAA,CAAI,CAAC,IAAA,KAAU,IAAA,EAAkC,SAAS,CAAA,CAC1D,MAAA,CAAO,CAAC,EAAA,KAAqB,OAAO,OAAO,QAAQ,CAAA;AACtD,EAAA,MAAM,QAAA,GAAW,MAAA,CAAO,MAAA,KAAW,MAAA,IAAa,MAAA,CAAO,MAAA,KAAW,IAAA,IAAQ,MAAA,CAAO,MAAA,KAAW,EAAA,GACxF,MAAA,GACA,MAAA,CAAO,OAAO,MAAM,CAAA;AACxB,EAAA,MAAM,MAAA,GAAS,KAAK,MAAA,KAAW,CAAA,GAAI,WAAW,IAAA,CAAK,GAAA,CAAI,GAAG,IAAI,CAAA,GAAI,CAAA;AAElE,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,MAAM,MAAA,CAAO,IAAA;AAAA,IACb,YAAY,MAAA,CAAO,UAAA;AAAA,IACnB,MAAA;AAAA,IACA,OAAO,KAAA,CAAM,MAAA;AAAA,IACb,OAAA,EAAS,KAAA;AAAA,IACT,MAAA,EAAQ,KAAA,CAAM,CAAC,CAAA,IAAK;AAAA,GACtB;AAKA,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,IAAA,OAAO,EAAE,MAAA,EAAQ,OAAA,EAAS,KAAA,EAAM;AAAA,EAClC;AAEA,EAAA,GAAA,CAAI,IAAA,CAAK;AAAA,IACP,IAAA,EAAM,KAAA;AAAA,IACN,KAAA,EAAO,MAAA;AAAA,IACP,MAAA,EAAQ,IAAI,IAAA,CAAK,EAAA;AAAA,IACjB,OAAA,EAAS,aAAa,KAAA,CAAM,MAAM,yBAAyB,MAAM,CAAA,EAAA,EAAK,OAAO,IAAI,CAAA,CAAA;AAAA,GAClF,CAAA;AAED,EAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,KAAA,EAAM;AAChC;AAGO,IAAM,uBAAA,GAAgD;AAAA,EAC3D,EAAE,GAAG,0BAAA,EAA4B,QAAA,EAAU,8BAAA;AAC7C","file":"flow.js","sourcesContent":["/**\n * GENERATED FILE — do not edit.\n *\n * Emitted from provider/actions/ + triggers/ by weaver's generator.\n * A hand-edit here is destroyed by the next protocol sync, which is worse than\n * being rejected, because it works until it silently does not. Fix\n * provider/actions/ + triggers/ (or weaver's template/) and regenerate:\n *\n * npm run provider -- telegram\n */\n\n/**\n * Telegram's node kinds with their TypeScript executors attached — for hosts\n * that EXECUTE on TS.\n *\n * The authoring surface in @particle-academy/telegram-ui carries no executor:\n * the editor is React on every host, so a PHP or Python project installs the\n * ui package and never this one.\n */\n\nimport type { NodeExecutor, NodeKindDefinition } from \"@particle-academy/fancy-flow/engine\";\nimport {\n idempotencyKeyFor,\n NO_IDEMPOTENCY_KEY_WARNING,\n resolveConnection,\n triggerEvent,\n type RequestedMode,\n} from \"@particle-academy/fancy-connector-core\";\nimport { TELEGRAM } from \"./service.js\";\n\nimport {\n telegramUpdatesTriggerKind,\n} from \"@particle-academy/telegram-ui\";\n\nimport { TELEGRAM_GET_UPDATES, telegramGetUpdates } from \"./triggers/get-updates.js\";\n\nexport const telegramUpdatesTriggerExecutor: NodeExecutor = async (ctx) => {\n const config = ((ctx.node.data as { config?: Record<string, unknown> })?.config ?? {});\n\n const result = await telegramGetUpdates({ config });\n const data = result.data as Record<string, unknown> | undefined;\n\n // Telegram answers HTTP 200 with `{ok: false}` for an application-level\n // failure. A status check alone reads that as success and publishes an\n // empty batch — a poll that silently finds nothing, forever, which is\n // indistinguishable from a quiet channel. The connector core cannot know\n // this; it is exactly the per-provider knowledge a definition exists to\n // hold.\n if (data?.ok === false) {\n throw new Error(\n `get_updates: getUpdates was rejected — ` +\n String(data.description ?? \"no reason given\"),\n );\n }\n\n const items = Array.isArray(data?.result) ? (data.result as unknown[]) : [];\n\n // `offset` means \"the first one I have NOT handled\", so the next cursor\n // is the highest id seen plus one. Off by one in either direction is a\n // real bug with no error attached: too low replays every item forever,\n // too high drops one silently. The HOST persists this and passes it back\n // in — nothing else will.\n const seen = items\n .map((item) => (item as { update_id?: unknown })?.update_id)\n .filter((id): id is number => typeof id === \"number\");\n const previous = config.offset === undefined || config.offset === null || config.offset === \"\"\n ? undefined\n : Number(config.offset);\n const cursor = seen.length === 0 ? previous : Math.max(...seen) + 1;\n\n const value = {\n mode: result.mode,\n connection: result.connection,\n cursor,\n count: items.length,\n updates: items,\n update: items[0] ?? null,\n };\n\n // A poll that found nothing is the NORMAL case, not a failure. Routing\n // it to its own port keeps the main path meaning \"something happened\",\n // and still gives the host somewhere to hang its cursor bookkeeping.\n if (items.length === 0) {\n return { __port: \"empty\", value };\n }\n\n ctx.emit({\n type: \"log\",\n level: \"info\",\n nodeId: ctx.node.id,\n message: `telegram: ${items.length} item(s), next cursor ${cursor} (${result.mode})`,\n });\n\n return { __port: \"out\", value };\n};\n\n/** The kinds a TypeScript host registers. */\nexport const TELEGRAM_RUNNABLE_KINDS: NodeKindDefinition[] = [\n { ...telegramUpdatesTriggerKind, executor: telegramUpdatesTriggerExecutor },\n];\n"]}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fancyConnectorCore = require('@particle-academy/fancy-connector-core');
|
|
4
|
+
|
|
5
|
+
// src/faker.ts
|
|
6
|
+
function fakeGetUpdates({ config, fake }) {
|
|
7
|
+
const boundChatId = fake.int(1e8, 999999999);
|
|
8
|
+
return {
|
|
9
|
+
"ok": true,
|
|
10
|
+
"result": [
|
|
11
|
+
{
|
|
12
|
+
"update_id": fake.int(1e5, 999999),
|
|
13
|
+
"message": {
|
|
14
|
+
"message_id": fake.int(1, 9999),
|
|
15
|
+
"date": 1767225600,
|
|
16
|
+
"text": config.sampleText !== void 0 && config.sampleText !== null && config.sampleText !== "" ? String(config.sampleText) : "hello from the faker",
|
|
17
|
+
"chat": {
|
|
18
|
+
"id": boundChatId,
|
|
19
|
+
"type": "private",
|
|
20
|
+
"first_name": "Ada",
|
|
21
|
+
"username": "ada_example"
|
|
22
|
+
},
|
|
23
|
+
"from": {
|
|
24
|
+
"id": boundChatId,
|
|
25
|
+
"is_bot": false,
|
|
26
|
+
"first_name": "Ada",
|
|
27
|
+
"username": "ada_example",
|
|
28
|
+
"language_code": "en"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
var telegramFaker = (operation, request) => {
|
|
36
|
+
switch (operation) {
|
|
37
|
+
case "get_updates":
|
|
38
|
+
return fakeGetUpdates(request);
|
|
39
|
+
default:
|
|
40
|
+
throw new Error(
|
|
41
|
+
`telegram: no fake response is defined for "${operation}". Add a fixture under provider/fixtures/ and regenerate \u2014 a connector without a faker cannot be developed against, tested, or demonstrated.`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// src/service.ts
|
|
47
|
+
var CONNECTOR_API_VERSION = 1;
|
|
48
|
+
var TELEGRAM_BASE_URLS = {
|
|
49
|
+
"live": "https://api.telegram.org",
|
|
50
|
+
"sandbox": "https://api.telegram.org"
|
|
51
|
+
};
|
|
52
|
+
var TELEGRAM_REQUIRES = [
|
|
53
|
+
"botToken"
|
|
54
|
+
];
|
|
55
|
+
function telegramAuthorize(credentials, request, mode) {
|
|
56
|
+
const url = new URL(request.url);
|
|
57
|
+
const segment = mode === "sandbox" ? `/bot${credentials.botToken ?? ""}/test` : `/bot${credentials.botToken ?? ""}`;
|
|
58
|
+
url.pathname = `${segment}${url.pathname}`;
|
|
59
|
+
request.url = url.toString();
|
|
60
|
+
}
|
|
61
|
+
var TELEGRAM = {
|
|
62
|
+
service: "telegram",
|
|
63
|
+
title: "Telegram",
|
|
64
|
+
sandbox: "separate-account",
|
|
65
|
+
baseUrls: { ...TELEGRAM_BASE_URLS },
|
|
66
|
+
requires: [...TELEGRAM_REQUIRES],
|
|
67
|
+
authorize: telegramAuthorize,
|
|
68
|
+
faker: telegramFaker
|
|
69
|
+
};
|
|
70
|
+
var TELEGRAM_GET_UPDATES = {
|
|
71
|
+
service: "telegram",
|
|
72
|
+
operation: "get_updates",
|
|
73
|
+
delivery: "poll",
|
|
74
|
+
setup: "The host polls getUpdates on a schedule and persists the `offset` cursor between calls, passing the last `cursor` back in \u2014 Telegram queues nothing once an offset has acknowledged it, so a lost cursor is lost updates. getUpdates and setWebhook are MUTUALLY EXCLUSIVE for one bot: a host running both gets neither.",
|
|
75
|
+
minPollSeconds: 1,
|
|
76
|
+
faker: telegramFaker
|
|
77
|
+
};
|
|
78
|
+
var GET_UPDATES_OPERATION = "get_updates";
|
|
79
|
+
async function telegramGetUpdates(options) {
|
|
80
|
+
const config = options.config ?? {};
|
|
81
|
+
{
|
|
82
|
+
const n = Number(config.offset);
|
|
83
|
+
const given = config.offset !== void 0 && config.offset !== null && config.offset !== "";
|
|
84
|
+
if (given && !Number.isInteger(n)) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`get_updates: "offset" must be a integer, got ${JSON.stringify(config.offset)}.`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
{
|
|
91
|
+
const n = Number(config.limit);
|
|
92
|
+
const given = config.limit !== void 0 && config.limit !== null && config.limit !== "";
|
|
93
|
+
if (given && !(Number.isInteger(n) && n >= 1 && n <= 100)) {
|
|
94
|
+
throw new Error(
|
|
95
|
+
`get_updates: "limit" must be a integer, got ${JSON.stringify(config.limit)}.`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return fancyConnectorCore.callConnector(TELEGRAM, {
|
|
100
|
+
operation: GET_UPDATES_OPERATION,
|
|
101
|
+
config,
|
|
102
|
+
input: options.input,
|
|
103
|
+
...options.credentials === void 0 ? {} : { credentials: options.credentials },
|
|
104
|
+
...options.mode === void 0 ? {} : { mode: options.mode },
|
|
105
|
+
...options.connectionId === void 0 ? {} : { connectionId: options.connectionId },
|
|
106
|
+
...options.attempts === void 0 ? {} : { attempts: options.attempts },
|
|
107
|
+
...options.transport === void 0 ? {} : { transport: options.transport },
|
|
108
|
+
request: {
|
|
109
|
+
method: "GET",
|
|
110
|
+
path: "/getUpdates",
|
|
111
|
+
query: {
|
|
112
|
+
...config.offset !== void 0 && config.offset !== null && config.offset !== "" ? { "offset": Math.trunc(Number(config.offset)) } : {},
|
|
113
|
+
"limit": config.limit !== void 0 && config.limit !== null && config.limit !== "" ? Math.trunc(Number(config.limit)) : 100,
|
|
114
|
+
...config.allowedUpdates !== void 0 && config.allowedUpdates !== null && config.allowedUpdates !== "" ? { "allowed_updates": JSON.stringify(allowedUpdatesList(config.allowedUpdates)) } : {}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
function allowedUpdatesList(value) {
|
|
120
|
+
const items = Array.isArray(value) ? value.map(String) : typeof value === "string" ? value.split(",") : [];
|
|
121
|
+
return items.map((item) => item.trim()).filter(Boolean);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
exports.CONNECTOR_API_VERSION = CONNECTOR_API_VERSION;
|
|
125
|
+
exports.GET_UPDATES_OPERATION = GET_UPDATES_OPERATION;
|
|
126
|
+
exports.TELEGRAM = TELEGRAM;
|
|
127
|
+
exports.TELEGRAM_BASE_URLS = TELEGRAM_BASE_URLS;
|
|
128
|
+
exports.TELEGRAM_GET_UPDATES = TELEGRAM_GET_UPDATES;
|
|
129
|
+
exports.TELEGRAM_REQUIRES = TELEGRAM_REQUIRES;
|
|
130
|
+
exports.telegramAuthorize = telegramAuthorize;
|
|
131
|
+
exports.telegramFaker = telegramFaker;
|
|
132
|
+
exports.telegramGetUpdates = telegramGetUpdates;
|
|
133
|
+
//# sourceMappingURL=index.cjs.map
|
|
134
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/faker.ts","../src/service.ts","../src/triggers/get-updates.ts"],"names":["callConnector"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * GENERATED FILE — do not edit.\n *\n * Emitted from provider/fixtures/ by weaver's generator.\n * A hand-edit here is destroyed by the next protocol sync, which is worse than\n * being rejected, because it works until it silently does not. Fix\n * provider/fixtures/ (or weaver's template/) and regenerate:\n *\n * npm run provider -- telegram\n */\n\n/**\n * The Telegram faker.\n *\n * Shapes, not behaviour: the goal is that a downstream node sees the field\n * NAMES Telegram actually publishes, so an author can wire {{ $json.data.id }}\n * against a fake and have it keep working against the real thing.\n *\n * Deterministic — same inputs, same output. A faker returning a fresh uuid\n * every call cannot be asserted on, so its fixtures degrade to \"it did not\n * throw\", which is the assertion that catches nothing.\n */\n\nimport type { ConnectorFaker, FakeRequest } from \"@particle-academy/fancy-connector-core\";\n\nfunction fakeGetUpdates({ config, fake }: FakeRequest): unknown {\n const boundChatId = fake.int(100000000, 999999999);\n\n return {\n \"ok\": true,\n \"result\": [\n {\n \"update_id\": fake.int(100000, 999999),\n \"message\": {\n \"message_id\": fake.int(1, 9999),\n \"date\": 1767225600,\n \"text\": (config.sampleText !== undefined && config.sampleText !== null && config.sampleText !== \"\" ? String(config.sampleText) : \"hello from the faker\"),\n \"chat\": {\n \"id\": boundChatId,\n \"type\": \"private\",\n \"first_name\": \"Ada\",\n \"username\": \"ada_example\",\n },\n \"from\": {\n \"id\": boundChatId,\n \"is_bot\": false,\n \"first_name\": \"Ada\",\n \"username\": \"ada_example\",\n \"language_code\": \"en\",\n },\n },\n },\n ],\n };\n}\n\nexport const telegramFaker: ConnectorFaker = (operation, request) => {\n switch (operation) {\n case \"get_updates\":\n return fakeGetUpdates(request);\n\n default:\n // A faker asked for an operation it has no shape for must SAY so. Making\n // something up would produce a green run whose output silently has none\n // of the fields the author is about to reference.\n throw new Error(\n `telegram: no fake response is defined for \"${operation}\". ` +\n \"Add a fixture under provider/fixtures/ and regenerate — a connector without a faker \" +\n \"cannot be developed against, tested, or demonstrated.\",\n );\n }\n};\n","/**\n * GENERATED FILE — do not edit.\n *\n * Emitted from provider/manifest.json by weaver's generator.\n * A hand-edit here is destroyed by the next protocol sync, which is worse than\n * being rejected, because it works until it silently does not. Fix\n * provider/manifest.json (or weaver's template/) and regenerate:\n *\n * npm run provider -- telegram\n */\n\n/**\n * Telegram, as one service descriptor shared by every Telegram operation.\n *\n * @particle-academy/fancy-connector-core carries what is true of ALL\n * connectors. This carries what is true of Telegram: its base URL, its auth\n * scheme, its idempotency header, and its faker.\n *\n * ## The sandbox trap, written down where it is used\n *\n * Telegram's test environment is a genuinely SEPARATE ACCOUNT: you create a\n * new account inside it and register a new bot there, so the sandbox\n * credential is a different token rather than the same one pointed elsewhere.\n * The `/test` path segment is how you reach it; the account is what makes it\n * separate. Flood limits are NOT relaxed there, so it is a place to test, not\n * a place to hammer.\n */\n\nimport type { ConnectorMode, PreparedRequest, ServiceDescriptor } from \"@particle-academy/fancy-connector-core\";\n\nimport { telegramFaker } from \"./faker.js\";\n\n/**\n * The connector API version this package was GENERATED against.\n *\n * A literal, never imported. An imported constant lets an upgrade rewrite the\n * very claim it exists to detect, after which the copy agrees with itself\n * forever.\n */\nexport const CONNECTOR_API_VERSION = 1;\n\nexport const TELEGRAM_BASE_URLS = {\n \"live\": \"https://api.telegram.org\",\n \"sandbox\": \"https://api.telegram.org\"\n} as const;\n\n/** Credential keys a remote call cannot proceed without. */\nexport const TELEGRAM_REQUIRES = [\n \"botToken\"\n] as const;\n\n/**\n * Apply Telegram's auth scheme to an outgoing request.\n *\n * The bot token is a PATH SEGMENT, not a header --\n * https://api.telegram.org/bot<token>/getUpdates -- and the test environment\n * is a further `/test` AFTER the token. So this is the first provider whose\n * auth and whose estate are the same decision expressed in the URL, which is\n * why `authorize` has always been handed the resolved mode. The token\n * therefore ends up in the request URL, where access logs and error reporters\n * will record it. That is Telegram's design, not ours; a host should keep its\n * own logging away from it.\n *\n * The mode is USED here: for this provider auth and estate are the same\n * decision expressed in the URL, which is what this parameter has always been\n * for.\n */\nexport function telegramAuthorize(\n credentials: Record<string, string | undefined>,\n request: PreparedRequest,\n mode: ConnectorMode,\n): void {\n const url = new URL(request.url);\n\n // The estate is the SAME decision as the credential here, and it lives in\n // a further segment AFTER the token. A token pointed at a node marked\n // \"sandbox\" would otherwise reach the live bot, and succeed.\n const segment = mode === \"sandbox\"\n ? `/bot${credentials.botToken ?? \"\"}/test`\n : `/bot${credentials.botToken ?? \"\"}`;\n\n url.pathname = `${segment}${url.pathname}`;\n request.url = url.toString();\n}\n\n/** The Telegram service, for the TypeScript runtime. */\nexport const TELEGRAM: ServiceDescriptor = {\n service: \"telegram\",\n title: \"Telegram\",\n sandbox: \"separate-account\",\n baseUrls: { ...TELEGRAM_BASE_URLS },\n requires: [...TELEGRAM_REQUIRES],\n authorize: telegramAuthorize,\n faker: telegramFaker,\n};\n","/**\n * GENERATED FILE — do not edit.\n *\n * Emitted from provider/triggers/get-updates.json by weaver's generator.\n * A hand-edit here is destroyed by the next protocol sync, which is worse than\n * being rejected, because it works until it silently does not. Fix\n * provider/triggers/get-updates.json (or weaver's template/) and regenerate:\n *\n * npm run provider -- telegram\n */\n\n/**\n * Telegram's poll trigger — the delivery contract.\n *\n * A POLL trigger, so there is no signature and no route: Telegram does not\n * push, the host asks on a schedule and persists a cursor between calls.\n * Nothing queues what a stopped poller did not collect, which is why that\n * obligation is written down rather than assumed.\n */\n\nimport {\n callConnector,\n type ConnectorResult,\n type RequestedMode,\n type Transport,\n type TriggerDescriptor,\n} from \"@particle-academy/fancy-connector-core\";\nimport { telegramFaker } from \"../faker.js\";\nimport { TELEGRAM } from \"../service.js\";\n\nexport const TELEGRAM_GET_UPDATES: TriggerDescriptor = {\n service: \"telegram\",\n operation: \"get_updates\",\n delivery: \"poll\",\n setup:\n \"The host polls getUpdates on a schedule and persists the `offset` cursor between calls, passing the last `cursor` back in — Telegram queues nothing once an offset has acknowledged it, so a lost cursor is lost updates. getUpdates and setWebhook are MUTUALLY EXCLUSIVE for one bot: a host running both gets neither.\",\n minPollSeconds: 1,\n faker: telegramFaker,\n};\n\n/**\n * Poll Telegram once.\n *\n * GET /getUpdates — https://core.telegram.org/bots/api#getupdates\n *\n * In `fake` mode this resolves to the faker, so the node is runnable on a\n * canvas before any credential exists — with the same envelope a real poll\n * returns.\n */\n\nexport const GET_UPDATES_OPERATION = \"get_updates\";\n\nexport type GetUpdatesOptions = {\n /** The node's resolved config. Keys: offset, limit, allowedUpdates, sampleText. */\n config: Record<string, unknown>;\n credentials?: Record<string, string | undefined>;\n mode?: RequestedMode;\n connectionId?: string | null;\n input?: unknown;\n attempts?: number;\n /** Override the transport. The only way to exercise this without a network. */\n transport?: Transport;\n};\n\nexport async function telegramGetUpdates(options: GetUpdatesOptions): Promise<ConnectorResult> {\n const config = options.config ?? {};\n\n {\n const n = Number(config.offset);\n const given = config.offset !== undefined && config.offset !== null && config.offset !== \"\";\n if (given && !(Number.isInteger(n))) {\n throw new Error(\n `get_updates: \"offset\" must be a integer, got ${JSON.stringify(config.offset)}.`,\n );\n }\n }\n\n {\n const n = Number(config.limit);\n const given = config.limit !== undefined && config.limit !== null && config.limit !== \"\";\n if (given && !(Number.isInteger(n) && n >= 1 && n <= 100)) {\n throw new Error(\n `get_updates: \"limit\" must be a integer, got ${JSON.stringify(config.limit)}.`,\n );\n }\n }\n\n return callConnector(TELEGRAM, {\n operation: GET_UPDATES_OPERATION,\n config,\n input: options.input,\n ...(options.credentials === undefined ? {} : { credentials: options.credentials }),\n ...(options.mode === undefined ? {} : { mode: options.mode }),\n ...(options.connectionId === undefined ? {} : { connectionId: options.connectionId }),\n ...(options.attempts === undefined ? {} : { attempts: options.attempts }),\n ...(options.transport === undefined ? {} : { transport: options.transport }),\n request: {\n method: \"GET\",\n path: \"/getUpdates\",\n query: {\n ...(config.offset !== undefined && config.offset !== null && config.offset !== \"\" ? { \"offset\": Math.trunc(Number(config.offset)) } : {}),\n \"limit\": config.limit !== undefined && config.limit !== null && config.limit !== \"\" ? Math.trunc(Number(config.limit)) : 100,\n ...(config.allowedUpdates !== undefined && config.allowedUpdates !== null && config.allowedUpdates !== \"\" ? { \"allowed_updates\": JSON.stringify(allowedUpdatesList(config.allowedUpdates)) } : {}),\n },\n },\n });\n}\n\n/** One value, a \",\"-separated string, or an array — all end up a list. */\nfunction allowedUpdatesList(value: unknown): string[] {\n const items = Array.isArray(value)\n ? value.map(String)\n : typeof value === \"string\"\n ? value.split(\",\")\n : [];\n\n return items.map((item) => item.trim()).filter(Boolean);\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { ServiceDescriptor, PreparedRequest, ConnectorMode, ConnectorFaker, RequestedMode, Transport, TriggerDescriptor, ConnectorResult } from '@particle-academy/fancy-connector-core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* GENERATED FILE — do not edit.
|
|
5
|
+
*
|
|
6
|
+
* Emitted from provider/manifest.json by weaver's generator.
|
|
7
|
+
* A hand-edit here is destroyed by the next protocol sync, which is worse than
|
|
8
|
+
* being rejected, because it works until it silently does not. Fix
|
|
9
|
+
* provider/manifest.json (or weaver's template/) and regenerate:
|
|
10
|
+
*
|
|
11
|
+
* npm run provider -- telegram
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Telegram, as one service descriptor shared by every Telegram operation.
|
|
15
|
+
*
|
|
16
|
+
* @particle-academy/fancy-connector-core carries what is true of ALL
|
|
17
|
+
* connectors. This carries what is true of Telegram: its base URL, its auth
|
|
18
|
+
* scheme, its idempotency header, and its faker.
|
|
19
|
+
*
|
|
20
|
+
* ## The sandbox trap, written down where it is used
|
|
21
|
+
*
|
|
22
|
+
* Telegram's test environment is a genuinely SEPARATE ACCOUNT: you create a
|
|
23
|
+
* new account inside it and register a new bot there, so the sandbox
|
|
24
|
+
* credential is a different token rather than the same one pointed elsewhere.
|
|
25
|
+
* The `/test` path segment is how you reach it; the account is what makes it
|
|
26
|
+
* separate. Flood limits are NOT relaxed there, so it is a place to test, not
|
|
27
|
+
* a place to hammer.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The connector API version this package was GENERATED against.
|
|
32
|
+
*
|
|
33
|
+
* A literal, never imported. An imported constant lets an upgrade rewrite the
|
|
34
|
+
* very claim it exists to detect, after which the copy agrees with itself
|
|
35
|
+
* forever.
|
|
36
|
+
*/
|
|
37
|
+
declare const CONNECTOR_API_VERSION = 1;
|
|
38
|
+
declare const TELEGRAM_BASE_URLS: {
|
|
39
|
+
readonly live: "https://api.telegram.org";
|
|
40
|
+
readonly sandbox: "https://api.telegram.org";
|
|
41
|
+
};
|
|
42
|
+
/** Credential keys a remote call cannot proceed without. */
|
|
43
|
+
declare const TELEGRAM_REQUIRES: readonly ["botToken"];
|
|
44
|
+
/**
|
|
45
|
+
* Apply Telegram's auth scheme to an outgoing request.
|
|
46
|
+
*
|
|
47
|
+
* The bot token is a PATH SEGMENT, not a header --
|
|
48
|
+
* https://api.telegram.org/bot<token>/getUpdates -- and the test environment
|
|
49
|
+
* is a further `/test` AFTER the token. So this is the first provider whose
|
|
50
|
+
* auth and whose estate are the same decision expressed in the URL, which is
|
|
51
|
+
* why `authorize` has always been handed the resolved mode. The token
|
|
52
|
+
* therefore ends up in the request URL, where access logs and error reporters
|
|
53
|
+
* will record it. That is Telegram's design, not ours; a host should keep its
|
|
54
|
+
* own logging away from it.
|
|
55
|
+
*
|
|
56
|
+
* The mode is USED here: for this provider auth and estate are the same
|
|
57
|
+
* decision expressed in the URL, which is what this parameter has always been
|
|
58
|
+
* for.
|
|
59
|
+
*/
|
|
60
|
+
declare function telegramAuthorize(credentials: Record<string, string | undefined>, request: PreparedRequest, mode: ConnectorMode): void;
|
|
61
|
+
/** The Telegram service, for the TypeScript runtime. */
|
|
62
|
+
declare const TELEGRAM: ServiceDescriptor;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* GENERATED FILE — do not edit.
|
|
66
|
+
*
|
|
67
|
+
* Emitted from provider/fixtures/ by weaver's generator.
|
|
68
|
+
* A hand-edit here is destroyed by the next protocol sync, which is worse than
|
|
69
|
+
* being rejected, because it works until it silently does not. Fix
|
|
70
|
+
* provider/fixtures/ (or weaver's template/) and regenerate:
|
|
71
|
+
*
|
|
72
|
+
* npm run provider -- telegram
|
|
73
|
+
*/
|
|
74
|
+
/**
|
|
75
|
+
* The Telegram faker.
|
|
76
|
+
*
|
|
77
|
+
* Shapes, not behaviour: the goal is that a downstream node sees the field
|
|
78
|
+
* NAMES Telegram actually publishes, so an author can wire {{ $json.data.id }}
|
|
79
|
+
* against a fake and have it keep working against the real thing.
|
|
80
|
+
*
|
|
81
|
+
* Deterministic — same inputs, same output. A faker returning a fresh uuid
|
|
82
|
+
* every call cannot be asserted on, so its fixtures degrade to "it did not
|
|
83
|
+
* throw", which is the assertion that catches nothing.
|
|
84
|
+
*/
|
|
85
|
+
|
|
86
|
+
declare const telegramFaker: ConnectorFaker;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* GENERATED FILE — do not edit.
|
|
90
|
+
*
|
|
91
|
+
* Emitted from provider/triggers/get-updates.json by weaver's generator.
|
|
92
|
+
* A hand-edit here is destroyed by the next protocol sync, which is worse than
|
|
93
|
+
* being rejected, because it works until it silently does not. Fix
|
|
94
|
+
* provider/triggers/get-updates.json (or weaver's template/) and regenerate:
|
|
95
|
+
*
|
|
96
|
+
* npm run provider -- telegram
|
|
97
|
+
*/
|
|
98
|
+
/**
|
|
99
|
+
* Telegram's poll trigger — the delivery contract.
|
|
100
|
+
*
|
|
101
|
+
* A POLL trigger, so there is no signature and no route: Telegram does not
|
|
102
|
+
* push, the host asks on a schedule and persists a cursor between calls.
|
|
103
|
+
* Nothing queues what a stopped poller did not collect, which is why that
|
|
104
|
+
* obligation is written down rather than assumed.
|
|
105
|
+
*/
|
|
106
|
+
|
|
107
|
+
declare const TELEGRAM_GET_UPDATES: TriggerDescriptor;
|
|
108
|
+
/**
|
|
109
|
+
* Poll Telegram once.
|
|
110
|
+
*
|
|
111
|
+
* GET /getUpdates — https://core.telegram.org/bots/api#getupdates
|
|
112
|
+
*
|
|
113
|
+
* In `fake` mode this resolves to the faker, so the node is runnable on a
|
|
114
|
+
* canvas before any credential exists — with the same envelope a real poll
|
|
115
|
+
* returns.
|
|
116
|
+
*/
|
|
117
|
+
declare const GET_UPDATES_OPERATION = "get_updates";
|
|
118
|
+
type GetUpdatesOptions = {
|
|
119
|
+
/** The node's resolved config. Keys: offset, limit, allowedUpdates, sampleText. */
|
|
120
|
+
config: Record<string, unknown>;
|
|
121
|
+
credentials?: Record<string, string | undefined>;
|
|
122
|
+
mode?: RequestedMode;
|
|
123
|
+
connectionId?: string | null;
|
|
124
|
+
input?: unknown;
|
|
125
|
+
attempts?: number;
|
|
126
|
+
/** Override the transport. The only way to exercise this without a network. */
|
|
127
|
+
transport?: Transport;
|
|
128
|
+
};
|
|
129
|
+
declare function telegramGetUpdates(options: GetUpdatesOptions): Promise<ConnectorResult>;
|
|
130
|
+
|
|
131
|
+
export { CONNECTOR_API_VERSION, GET_UPDATES_OPERATION, type GetUpdatesOptions, TELEGRAM, TELEGRAM_BASE_URLS, TELEGRAM_GET_UPDATES, TELEGRAM_REQUIRES, telegramAuthorize, telegramFaker, telegramGetUpdates };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { ServiceDescriptor, PreparedRequest, ConnectorMode, ConnectorFaker, RequestedMode, Transport, TriggerDescriptor, ConnectorResult } from '@particle-academy/fancy-connector-core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* GENERATED FILE — do not edit.
|
|
5
|
+
*
|
|
6
|
+
* Emitted from provider/manifest.json by weaver's generator.
|
|
7
|
+
* A hand-edit here is destroyed by the next protocol sync, which is worse than
|
|
8
|
+
* being rejected, because it works until it silently does not. Fix
|
|
9
|
+
* provider/manifest.json (or weaver's template/) and regenerate:
|
|
10
|
+
*
|
|
11
|
+
* npm run provider -- telegram
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Telegram, as one service descriptor shared by every Telegram operation.
|
|
15
|
+
*
|
|
16
|
+
* @particle-academy/fancy-connector-core carries what is true of ALL
|
|
17
|
+
* connectors. This carries what is true of Telegram: its base URL, its auth
|
|
18
|
+
* scheme, its idempotency header, and its faker.
|
|
19
|
+
*
|
|
20
|
+
* ## The sandbox trap, written down where it is used
|
|
21
|
+
*
|
|
22
|
+
* Telegram's test environment is a genuinely SEPARATE ACCOUNT: you create a
|
|
23
|
+
* new account inside it and register a new bot there, so the sandbox
|
|
24
|
+
* credential is a different token rather than the same one pointed elsewhere.
|
|
25
|
+
* The `/test` path segment is how you reach it; the account is what makes it
|
|
26
|
+
* separate. Flood limits are NOT relaxed there, so it is a place to test, not
|
|
27
|
+
* a place to hammer.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The connector API version this package was GENERATED against.
|
|
32
|
+
*
|
|
33
|
+
* A literal, never imported. An imported constant lets an upgrade rewrite the
|
|
34
|
+
* very claim it exists to detect, after which the copy agrees with itself
|
|
35
|
+
* forever.
|
|
36
|
+
*/
|
|
37
|
+
declare const CONNECTOR_API_VERSION = 1;
|
|
38
|
+
declare const TELEGRAM_BASE_URLS: {
|
|
39
|
+
readonly live: "https://api.telegram.org";
|
|
40
|
+
readonly sandbox: "https://api.telegram.org";
|
|
41
|
+
};
|
|
42
|
+
/** Credential keys a remote call cannot proceed without. */
|
|
43
|
+
declare const TELEGRAM_REQUIRES: readonly ["botToken"];
|
|
44
|
+
/**
|
|
45
|
+
* Apply Telegram's auth scheme to an outgoing request.
|
|
46
|
+
*
|
|
47
|
+
* The bot token is a PATH SEGMENT, not a header --
|
|
48
|
+
* https://api.telegram.org/bot<token>/getUpdates -- and the test environment
|
|
49
|
+
* is a further `/test` AFTER the token. So this is the first provider whose
|
|
50
|
+
* auth and whose estate are the same decision expressed in the URL, which is
|
|
51
|
+
* why `authorize` has always been handed the resolved mode. The token
|
|
52
|
+
* therefore ends up in the request URL, where access logs and error reporters
|
|
53
|
+
* will record it. That is Telegram's design, not ours; a host should keep its
|
|
54
|
+
* own logging away from it.
|
|
55
|
+
*
|
|
56
|
+
* The mode is USED here: for this provider auth and estate are the same
|
|
57
|
+
* decision expressed in the URL, which is what this parameter has always been
|
|
58
|
+
* for.
|
|
59
|
+
*/
|
|
60
|
+
declare function telegramAuthorize(credentials: Record<string, string | undefined>, request: PreparedRequest, mode: ConnectorMode): void;
|
|
61
|
+
/** The Telegram service, for the TypeScript runtime. */
|
|
62
|
+
declare const TELEGRAM: ServiceDescriptor;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* GENERATED FILE — do not edit.
|
|
66
|
+
*
|
|
67
|
+
* Emitted from provider/fixtures/ by weaver's generator.
|
|
68
|
+
* A hand-edit here is destroyed by the next protocol sync, which is worse than
|
|
69
|
+
* being rejected, because it works until it silently does not. Fix
|
|
70
|
+
* provider/fixtures/ (or weaver's template/) and regenerate:
|
|
71
|
+
*
|
|
72
|
+
* npm run provider -- telegram
|
|
73
|
+
*/
|
|
74
|
+
/**
|
|
75
|
+
* The Telegram faker.
|
|
76
|
+
*
|
|
77
|
+
* Shapes, not behaviour: the goal is that a downstream node sees the field
|
|
78
|
+
* NAMES Telegram actually publishes, so an author can wire {{ $json.data.id }}
|
|
79
|
+
* against a fake and have it keep working against the real thing.
|
|
80
|
+
*
|
|
81
|
+
* Deterministic — same inputs, same output. A faker returning a fresh uuid
|
|
82
|
+
* every call cannot be asserted on, so its fixtures degrade to "it did not
|
|
83
|
+
* throw", which is the assertion that catches nothing.
|
|
84
|
+
*/
|
|
85
|
+
|
|
86
|
+
declare const telegramFaker: ConnectorFaker;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* GENERATED FILE — do not edit.
|
|
90
|
+
*
|
|
91
|
+
* Emitted from provider/triggers/get-updates.json by weaver's generator.
|
|
92
|
+
* A hand-edit here is destroyed by the next protocol sync, which is worse than
|
|
93
|
+
* being rejected, because it works until it silently does not. Fix
|
|
94
|
+
* provider/triggers/get-updates.json (or weaver's template/) and regenerate:
|
|
95
|
+
*
|
|
96
|
+
* npm run provider -- telegram
|
|
97
|
+
*/
|
|
98
|
+
/**
|
|
99
|
+
* Telegram's poll trigger — the delivery contract.
|
|
100
|
+
*
|
|
101
|
+
* A POLL trigger, so there is no signature and no route: Telegram does not
|
|
102
|
+
* push, the host asks on a schedule and persists a cursor between calls.
|
|
103
|
+
* Nothing queues what a stopped poller did not collect, which is why that
|
|
104
|
+
* obligation is written down rather than assumed.
|
|
105
|
+
*/
|
|
106
|
+
|
|
107
|
+
declare const TELEGRAM_GET_UPDATES: TriggerDescriptor;
|
|
108
|
+
/**
|
|
109
|
+
* Poll Telegram once.
|
|
110
|
+
*
|
|
111
|
+
* GET /getUpdates — https://core.telegram.org/bots/api#getupdates
|
|
112
|
+
*
|
|
113
|
+
* In `fake` mode this resolves to the faker, so the node is runnable on a
|
|
114
|
+
* canvas before any credential exists — with the same envelope a real poll
|
|
115
|
+
* returns.
|
|
116
|
+
*/
|
|
117
|
+
declare const GET_UPDATES_OPERATION = "get_updates";
|
|
118
|
+
type GetUpdatesOptions = {
|
|
119
|
+
/** The node's resolved config. Keys: offset, limit, allowedUpdates, sampleText. */
|
|
120
|
+
config: Record<string, unknown>;
|
|
121
|
+
credentials?: Record<string, string | undefined>;
|
|
122
|
+
mode?: RequestedMode;
|
|
123
|
+
connectionId?: string | null;
|
|
124
|
+
input?: unknown;
|
|
125
|
+
attempts?: number;
|
|
126
|
+
/** Override the transport. The only way to exercise this without a network. */
|
|
127
|
+
transport?: Transport;
|
|
128
|
+
};
|
|
129
|
+
declare function telegramGetUpdates(options: GetUpdatesOptions): Promise<ConnectorResult>;
|
|
130
|
+
|
|
131
|
+
export { CONNECTOR_API_VERSION, GET_UPDATES_OPERATION, type GetUpdatesOptions, TELEGRAM, TELEGRAM_BASE_URLS, TELEGRAM_GET_UPDATES, TELEGRAM_REQUIRES, telegramAuthorize, telegramFaker, telegramGetUpdates };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { CONNECTOR_API_VERSION, GET_UPDATES_OPERATION, TELEGRAM, TELEGRAM_BASE_URLS, TELEGRAM_GET_UPDATES, TELEGRAM_REQUIRES, telegramAuthorize, telegramFaker, telegramGetUpdates } from './chunk-LFMQKSUM.js';
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
3
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
package/package.json
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@particle-academy/telegram-js",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Telegram for Node — the service descriptor, its faker, its webhook verification, and one function per operation. Plain HTTP on @particle-academy/fancy-connector-core; no vendor SDK.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/Fancy-Friends/telegram.git"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/Fancy-Friends/telegram#readme",
|
|
10
|
+
"bugs": "https://github.com/Fancy-Friends/telegram/issues",
|
|
11
|
+
"type": "module",
|
|
12
|
+
"main": "./dist/index.cjs",
|
|
13
|
+
"module": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"import": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
},
|
|
21
|
+
"require": {
|
|
22
|
+
"types": "./dist/index.d.cts",
|
|
23
|
+
"default": "./dist/index.cjs"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"./flow": {
|
|
27
|
+
"import": {
|
|
28
|
+
"types": "./dist/flow.d.ts",
|
|
29
|
+
"default": "./dist/flow.js"
|
|
30
|
+
},
|
|
31
|
+
"require": {
|
|
32
|
+
"types": "./dist/flow.d.cts",
|
|
33
|
+
"default": "./dist/flow.cjs"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"./package.json": "./package.json"
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist",
|
|
40
|
+
"README.md",
|
|
41
|
+
"CHANGELOG.md",
|
|
42
|
+
"LICENSE"
|
|
43
|
+
],
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsup",
|
|
46
|
+
"lint": "tsc --noEmit",
|
|
47
|
+
"test": "node --import tsx --test tests/*.test.ts",
|
|
48
|
+
"prepublishOnly": "tsup"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"@particle-academy/fancy-connector-core": ">=0.3.1 <2.0",
|
|
52
|
+
"@particle-academy/telegram-ui": "0.1.0"
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"@particle-academy/fancy-flow": ">=0.47.1 <2.0"
|
|
56
|
+
},
|
|
57
|
+
"peerDependenciesMeta": {
|
|
58
|
+
"@particle-academy/fancy-flow": {
|
|
59
|
+
"optional": true
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@particle-academy/fancy-flow": ">=0.47.1 <2.0",
|
|
64
|
+
"@types/node": "^26.2.0",
|
|
65
|
+
"tsup": "^8.5.0",
|
|
66
|
+
"tsx": "^4.19.0",
|
|
67
|
+
"typescript": "^5.8.0"
|
|
68
|
+
},
|
|
69
|
+
"publishConfig": {
|
|
70
|
+
"access": "public"
|
|
71
|
+
},
|
|
72
|
+
"keywords": [
|
|
73
|
+
"telegram",
|
|
74
|
+
"messaging",
|
|
75
|
+
"connector",
|
|
76
|
+
"api",
|
|
77
|
+
"fancy-ui",
|
|
78
|
+
"particle-academy"
|
|
79
|
+
],
|
|
80
|
+
"license": "MIT",
|
|
81
|
+
"sideEffects": false,
|
|
82
|
+
"engines": {
|
|
83
|
+
"node": ">=22"
|
|
84
|
+
}
|
|
85
|
+
}
|