Connectors-NodeJS-SDK
Copilot instructions0 starsChanged 33 days agoMITView on GitHub
This repository contains the lightweight TypeScript SDK for Azure Logic Apps connectors. Code must follow the team's coding conventions. Variable naming rules: One class per file: Use standard async/await: Single line if all parameters fit: Multi-line when needed: Inline comments — use NOTE format: JSDoc documentation — required for all public APIs:
Where files are headingNew Copilot instructions files have more rules about branches and pull requests, and fewer about code style.
Of the Copilot instructions files we read, the 2,336 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repositoryOne other file it gives its agents.
- connection-setupSkill
The file
Show its rules and text
We split this copilot-instructions.md into the rules it gives an agent
24 rules. About 1 is common, 12 are distinctive, and 11 are very specific to this project.
≈1
Common · estimate
Many files like this have a rule of this kind.
≈12
Distinctive · estimate
This author's own choices. Worth a look.
11
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Distinctive: line 25
No empty lines between import groups
- Distinctive: line 41
Use complete, unabbreviated English terms for all identifiers
- Very specific: line 42
No single-letter variable names, even in lambdas (use item, method, parameter)
- Very specific: line 43
No placeholder names (blah, foo, temp, x) — always use meaningful names
- Very specific: line 63
Always use async/await, never .then() chains
- Common: line 64
Always handle errors with try/catch
- Distinctive: line 65
Prefer returning the awaited value
- Distinctive: line 79
Single line: if all parameters fit:
- Distinctive: line 113
NO empty line between comment and code it describes
- Distinctive: line 115
Do NOT comment on the 'what' unless the code is obscure.
- Very specific: line 130
Use @param for parameters
- Very specific: line 131
Use @remarks for additional context
- Very specific: line 153
Use ConnectorError for connector-specific errors
- Very specific: line 288
Test naming: descriptive sentence in test() or it() blocks
- Very specific: line 289
Use describe() to group related tests
- Very specific: line 290
Use async/await in tests, never .then()
- Very specific: line 292
Run with npm test or npx jest --config config/jest.config.js --verbose
- Distinctive: line 297
Never push directly to main
- Distinctive: line 298
Always create PR for review
- Distinctive: line 304
Do not expand repository structure with caches, catalogs, or replay scaffolding unless explicitly requested.
- Very specific: line 310
If the BPM generator or live Swagger is unavailable, stop and report the blocker.
- Distinctive: line 329
Do not delete or recreate a published release tag as a normal retry path.
- Distinctive: line 335
If a failed release left only a draft GitHub Release and no package was published, clean up the draft release if needed, then queue the …
- Distinctive: line 351
When adding a new generated connector client to the SDK:
≈ “Common” is an estimate: at least 1 in 5 of the 3,779 Copilot instructions files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Copilot Instructions for azure-logicapps-connector-sdk (TypeScript)
Overview
This repository contains the lightweight TypeScript SDK for Azure Logic Apps connectors. Code must follow the team's coding conventions.
Quick Reference: Coding Style Rules
File Structure
// Copyright (c) Microsoft Corporation. All rights reserved.
import { ConnectorClientBase } from "../azureConnectors/clientBase";
import { ConnectorError } from "../azureConnectors/connectorError";
export class YourClass {
}Rules:
- Copyright header on first line (single-line comment)
- Imports sorted: external packages first, then relative imports alphabetically
- No empty lines between import groups
Naming Conventions
| Element | Rule | Example |
| Classes | PascalCase | Office365Client |
| Interfaces | PascalCase | TokenProvider |
| Methods/functions | verb-noun camelCase | getEmails() |
| Constants | UPPER_SNAKE_CASE or PascalCase | DEFAULT_TIMEOUT |
| Private fields | camelCase with no prefix | private readonly connectionUrl: string; |
| Local variables | camelCase, complete English terms | parameter not p, method not m |
| Lambda parameters | Use descriptive names | items.filter(item => ...) not x => ... |
Variable naming rules:
- Use complete, unabbreviated English terms for all identifiers
- No single-letter variable names, even in lambdas (use
item,method,parameter) - No placeholder names (
blah,foo,temp,x) — always use meaningful names
File Organization
One class per file:
- Declare only one exported class per file
- File name should match the primary export
- Exception: Related types/interfaces can co-exist if tightly coupled (e.g., a client + its options)
Async/Await Format
Use standard async/await:
const result = await this.httpClient.sendAsync<Response>("GET", url);Rules:
- Always use
async/await, never.then()chains - Always handle errors with try/catch
- Prefer returning the awaited value
DO NOT:
// Wrong: Promise chains instead of async/await
this.httpClient.sendAsync("GET", url).then(result => { ... });
// Wrong: Unhandled promise
this.httpClient.sendAsync("GET", url);Method Calls with Multiple Parameters
Single line if all parameters fit:
this.doSomething(param1, param2);Multi-line when needed:
const result = await this.httpClient.sendAsync<Response>(
"POST",
url,
headers,
body,
);Rules:
- Trailing comma on the last parameter in multi-line calls
- Each parameter on its own line when breaking
Comments
Inline comments — use NOTE format:
// NOTE(username): Explanation of why this code exists.
const result = doSomething();Rules:
- Empty line ABOVE comment (unless first line in block)
- NO empty line between comment and code it describes
- Prefix:
// NOTE(username):where username is your GitHub username - Do NOT comment on the 'what' unless the code is obscure; instead comment on the 'why' when appropriate
JSDoc documentation — required for all public APIs:
/**
* Processes the incoming request and returns the result.
* @param request The request to process.
*/
public async process(request: Request): Promise<Response> {Rules:
- End descriptions with period
- Use
@paramfor parameters - Use
@remarksfor additional context
Error Handling
try {
const response = await this.httpClient.sendAsync<T>("GET", url);
} catch (error) {
if (error instanceof ConnectorError) {
console.error(`Connector error: '${error.message}'.`);
throw;
}
throw new Error(`Operation '${operationId}' failed.`);
}Rules:
- Wrap inserted values in single quotes in error messages
- End error messages with period
- All errors must have descriptive messages — never throw without context
- Use
ConnectorErrorfor connector-specific errors
DO:
throw new Error(`Parameter '${paramName}' cannot be null or empty.`);
throw new ConnectorError(connectorName, `GET ${path}`, statusCode, responseText);DO NOT:
throw new Error(); // No message
throw new Error("error"); // Non-descriptiveString Comparison
Use case-insensitive comparison when appropriate:
// Correct
str1.toLowerCase() === str2.toLowerCase()
// For exact match
str1 === str2DO NOT:
str1 == str2 // Loose equalitySpacing and Braces
Empty line after closing brace:
if (condition) {
doSomething();
}
doSomethingElse(); // Empty line aboveNO empty line before closing brace:
// Wrong
if (condition) {
doSomething();
}Variable Declaration
Use const by default, let when reassignment is needed:
const items = new Array<string>();
const response = await this.getResponseAsync();
let counter = 0;DO NOT use var.
Ternary Operators
Put ? and : at START of new line:
const result = condition
? valueIfTrue
: valueIfFalse;Logical Operators
Put || and && at END of line:
if (value1 === undefined ||
value2 === undefined ||
value3 === undefined) {Access Modifiers
ALWAYS explicit on class members:
public static readonly defaultValue = "default";
private readonly connectionUrl: string;Class Layout Order
- Static fields
- Instance fields
- Constructor
- Properties (getters)
- Public methods
- Private methods
Patterns to Avoid
| Anti-Pattern | Correct Pattern |
.then() chains | await with async/await |
var declarations | const or let |
any type | Specific types or unknown |
| Magic numbers | Named constants |
Magic strings (e.g., "type", "object") | Named constants |
Loose equality (==) | Strict equality (===) |
Array[0] without check | Validate array length first |
Testing
test("methodName should return expected result when given valid input", async () => {
// Arrange
const input = createTestInput();
// Act
const result = await service.processAsync(input);
// Assert
expect(result).toBeDefined();
});Rules:
- Test naming: descriptive sentence in
test()orit()blocks - Use
describe()to group related tests - Use async/await in tests, never
.then() - Jest framework with ts-jest preset
- Run with
npm testornpx jest --config config/jest.config.js --verbose
Git Workflow
- Branch naming:
feature/description,fix/description,docs/description - Never push directly to main
- Always create PR for review
Generated Code Ownership — Critical
- Paired generator/SDK PRs may publish output from the linked active BPM PR. Record its exact source commit and active/unmerged status. Showing the generated outcome does not wait for upstream merge; upstream integration remains a separate final SDK merge gate.
- Refreshes follow GENERATION.md: fetch live definitions with an explicit subscription/region and a new empty temporary
ARMCACHE_PATH. Reviewers make a separate live download; never seed either run from repository fixtures or producer responses. - Do not expand repository structure with caches, catalogs, or replay scaffolding unless explicitly requested. Existing Swagger snapshots are test fixtures, not refresh/review inputs. Remove temporary response stores after the run.
- Capture known response data in semantic variables without redundant aliases or repeated conditions. Execute changed consumers with empty/nonempty results, and exercise actual continuation requests and termination, including an empty first page with a next link.
- Everything under
src/generated/is owned by the BPMCodefulSdkGenerator. Never hand-edit generated clients, registries, barrel exports, imports, method signatures, error handling, or formatting, even to fix a build, lint, merge, or review failure. - When a generated file fails after merging or rebasing
main, first compare it with sibling generated files and the generator revision recorded ingeneration.manifest.json. Runtime contract changes such as renamed errors, response fields, method conventions, and options must be fixed in BPM when the current generator is wrong, then regenerated here from fresh live Swagger. - Replace generated files only with generator output. Update
generation.manifest.jsonwith the actual generator composition, Swagger hash, and canonical output hash; do not make the manifest legitimize a manual generated-file edit. - Hand-authored tests, samples, documentation, and runtime infrastructure may be updated directly to consume a regenerated API.
- If the BPM generator or live Swagger is unavailable, stop and report the blocker. Do not patch
src/generated/or fall back to cached inputs.
Releasing a New Version
Queue azure-pipelines/library-release.yml with the desired libraryVersion
(for example, 1.2.3 or 1.2.3-preview.1). Do not create the release branch
or tag manually as the normal release path.
The pipeline creates release/<version>, updates package.json and
package-lock.json, pauses for validation, builds the package, tags the release
branch as v<version>, creates a draft GitHub release with the .tgz asset,
and uploads the artifact to the Azure SDK partner drop after approval.
The prebuild script regenerates src/azureConnectors/sdkInfo.ts from the final
package metadata, and prepack rebuilds after any pipeline version change. Do
not edit sdkInfo.ts directly.
Re-releasing a Version
Do not delete or recreate a published release tag as a normal retry path. Release
tags are part of the supply-chain integrity boundary and are protected by tag
rulesets. If a release fails after the tag was pushed, use a new version (for
example the next patch version, or a new pre-release such as
v1.2.4-preview.1) and release from the current reviewed main commit.
If a failed release left only a draft GitHub Release and no package was published, clean up the draft release if needed, then queue the pipeline with a new version. Deleting or retagging an existing remote tag should be treated as break-glass admin work, not the standard process.
What the Release Workflow Does
- Creates and validates the versioned release branch.
- Builds and packs the npm package from that branch.
- Creates and pushes the
v<version>tag. - Creates a draft GitHub release and attaches the
.tgzartifact. - Pauses for release-note review.
- Uploads the artifact to the Azure SDK partner drop.
Adding a New Connector
When adding a new generated connector client to the SDK:
Steps
Generate the code using the CodefulSdkGenerator CLI from the BPM repo:
LogicAppsCompiler <outputDir> unused --typescriptDirectClient --connectors=<connector-name>- Verify generated files —
{Connector}Extensions.tslands insrc/generated/ - Check
connectorNames.ts— the new connector constant should be generated in alphabetical order - Check
ManagedConnectors.ts— the connector name should appear inAvailableConnectors - Add unit tests — create
{connector}Client.test.tsintests/following the pattern of existing tests (constructor, mocked API call, error handling) - Update
ROADMAP.md— mark the connector as complete in the appropriate phase - Update the connection setup skill — add the connector's API name to the supported list in
.github/skills/connection-setup/SKILL.md(Step 2) - Run all tests —
npm testmust pass with zero failures before committing - Create a PR — reference the GitHub issue (e.g.,
Closes #9)
Validation checklist
- Generated file compiles without errors (
npm run typecheck) - Existing connector tests still pass (no regressions)
connectorNamestest passes (ConnectorNames ↔ ManagedConnectors sync)- New connector tests cover: constructor, mocked success, mocked error, exception properties
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

